diff --git a/controller/search.go b/controller/search.go index 4a970a96dd..8f80e31947 100644 --- a/controller/search.go +++ b/controller/search.go @@ -260,21 +260,11 @@ func (c *SearchController) Show(ctx *app.ShowSearchContext) error { var err error result, count, err = appl.SearchItems().SearchFullText(ctx.Context, *ctx.Q, &offset, &limit, ctx.SpaceID) if err != nil { - cause := errs.Cause(err) - switch cause.(type) { - case errors.BadParameterError: - log.Error(ctx, map[string]interface{}{ - "err": err, - "expression": *ctx.Q, - }, "unable to list the work items") - return goa.ErrBadRequest(fmt.Sprintf("error listing work items for expression: %s: %s", *ctx.Q, err)) - default: - log.Error(ctx, map[string]interface{}{ - "err": err, - "expression": *ctx.Q, - }, "unable to list the work items") - return goa.ErrInternal(fmt.Sprintf("unable to list the work items expression: %s: %s", *ctx.Q, err)) - } + log.Error(ctx, map[string]interface{}{ + "err": err, + "expression": *ctx.Q, + }, "unable to list the work items") + return errs.Wrapf(err, "unable to list the work items for expression: %s", *ctx.Q) } return nil }) diff --git a/controller/search_blackbox_test.go b/controller/search_blackbox_test.go index 771132e7bc..8b43af6575 100644 --- a/controller/search_blackbox_test.go +++ b/controller/search_blackbox_test.go @@ -311,6 +311,26 @@ func (s *searchControllerTestSuite) TestSearchWorkItemsSpaceContext() { assert.Len(s.T(), sr.Data, 8) } +func (s *searchControllerTestSuite) TestFullTextSearch() { + fxt := tf.NewTestFixture(s.T(), s.DB, + tf.CreateWorkItemEnvironment(), + tf.WorkItems(3, tf.SetWorkItemTitles("foo", "work item with 'single quotes' in title", "bar")), + ) + // regression test for: + // https://github.com/openshiftio/openshift.io/issues/4288 + // https://github.com/fabric8-services/fabric8-wit/issues/2273 + s.T().Run("search for work item with single quotes in name", func(t *testing.T) { + // when + q := "with 'single" + spaceIDStr := fxt.Spaces[0].ID.String() + _, sr := test.ShowSearchOK(t, nil, nil, s.controller, nil, nil, nil, nil, &q, &spaceIDStr) + // then + require.NotNil(t, sr) + require.Len(t, sr.Data, 1) + require.Equal(t, fxt.WorkItems[1].ID, *sr.Data[0].ID) + }) +} + func (s *searchControllerTestSuite) TestSearchWorkItemsWithoutSpaceContext() { // given 2 spaces with 10 workitems in the first and 5 in the second space // random title used in work items diff --git a/search/search_repository.go b/search/search_repository.go index 7e765b1e05..fe45bdaead 100644 --- a/search/search_repository.go +++ b/search/search_repository.go @@ -136,8 +136,8 @@ func trimProtocolFromURLString(urlString string) string { } func escapeCharFromURLString(urlString string) string { - // Replacer will escape `:` and `)` `(`. - var replacer = strings.NewReplacer(":", "\\:", "(", "\\(", ")", "\\)") + // Replacer will escape `:` and `)` `(`, and `'`. + var replacer = strings.NewReplacer(":", "\\:", "(", "\\(", ")", "\\)", "'", "") return replacer.Replace(urlString) } @@ -588,7 +588,7 @@ func (r *GormSearchRepository) search(ctx context.Context, sqlSearchQueryParamet rows, err := db.Rows() defer closeable.Close(ctx, rows) if err != nil { - return nil, 0, errs.WithStack(err) + return nil, 0, errs.Wrapf(err, "failed to execute search query") } result := []workitem.WorkItemStorage{} diff --git a/search/search_repository_blackbox_test.go b/search/search_repository_blackbox_test.go index a079c66c9c..421a51133b 100644 --- a/search/search_repository_blackbox_test.go +++ b/search/search_repository_blackbox_test.go @@ -518,6 +518,21 @@ func (s *searchRepositoryBlackboxTest) TestSearchFullText() { assert.Equal(t, 2, count) assert.Condition(t, containsAllWorkItems(res, *fxt.WorkItems[1], *fxt.WorkItems[0])) }) + // regression test for: + // https://github.com/openshiftio/openshift.io/issues/4288 + // https://github.com/fabric8-services/fabric8-wit/issues/2273 + t.Run("search for work item with single quotes in name", func(t *testing.T) { + // given + fxt := tf.NewTestFixture(t, s.DB, tf.WorkItems(3, tf.SetWorkItemTitles("foo", "title with 'single quotes' in it", "bar"))) + spaceID := fxt.Spaces[0].ID.String() + query := "with 'single quotes'" + // when + res, count, err := s.searchRepo.SearchFullText(context.Background(), query, nil, nil, &spaceID) + // then + require.NoError(t, err) + require.Equal(t, 1, count) + require.Equal(t, fxt.WorkItems[1].ID, res[0].ID) + }) }) s.T().Run("Filter with limits", func(t *testing.T) { diff --git a/search/search_repository_whitebox_test.go b/search/search_repository_whitebox_test.go index e6cd04d3f4..5a07116271 100644 --- a/search/search_repository_whitebox_test.go +++ b/search/search_repository_whitebox_test.go @@ -208,6 +208,9 @@ func TestGetSearchQueryFromURLString(t *testing.T) { searchQuery = getSearchQueryFromURLString("google.me.io/everything/100") assert.Equal(t, "(100:*A | google.me.io/everything/100:*)", searchQuery) + + searchQuery = getSearchQueryFromURLString("abcd.something.com?q='(foo):bar john doe") + assert.Equal(t, "abcd.something.com?q=\\(foo\\)\\:bar john doe:*", searchQuery) } func TestIsOperator(t *testing.T) {