-
Notifications
You must be signed in to change notification settings - Fork 86
Random test failures because of work item creation error (#1676) #1677
Random test failures because of work item creation error (#1676) #1677
Conversation
…services#1655) Using the `Last-Modified` response header when possible Also, making sure that the list of spaces is always ordered by `updated_at DESC` to get the most recents spaces first. Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
…vices#1676) Move the `work item number sequence` in its own subpackage, and create its dedicated repository with 2 methods: `Create` and `NextVal`. Use a new `ID` column for the primary key, so GORM will issue a proper `INSERT` query when a new number sequence is created. Make sure a space has a sequence initialized upon its own creation Other minor fixes in tests (eg: length of area name, etc.) Fixes fabric8-services#1676 Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
531e75a
to
3481ff7
Compare
@@ -73,18 +73,19 @@ func (rest *TestSearchSpacesREST) UnSecuredController() (*goa.Service, *SearchCo | |||
|
|||
func (rest *TestSearchSpacesREST) TestSpacesSearchOK() { | |||
// given | |||
idents, err := createTestData(rest.db) | |||
prefix := time.Now().Format("2006_Jan_2_15_04_05_") // using a unique prefix to make sure the test data will not collide with existing, older spaces. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use a uuid.NewV4().String()
as a prefix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hum, I need to check. I found some issues just before about some invalid name length, so I wanted to use a shorter value, but a uuid
should be fine. Let me fix that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@xcoulon snapshot fabric8-wit image is available for testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not reviewed everything yet, but I found some problem.
req := &http.Request{Host: "localhost"} | ||
params := url.Values{} | ||
ctx := goa.NewContext(context.Background(), nil, req, params) | ||
createdWorkItem, err := wir.Create(ctx, fxt.Spaces[0].ID, workitem.SystemBug, workItem.Fields, s.modifierID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry but I have to reject this change because you're mixing up a newly defined test fixture space with a WIT that belongs to the system space. That only works because of a hack. Can you instead maybe just also ask for a WIT in your test fixture above (tf.WorkItemTypes(1)
)? Then you can use that WIT's ID instead of workitem.SystemBug
. Right now the two WITs (the new one and workitem.SystemBug
) are compatible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, let me check that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed: I'm now using a WorkItemType created by the TestFixture.
if err != nil { | ||
s.T().Fatalf("Couldn't create test data: %+v", err) | ||
} | ||
createdWorkItem, err := wir.Create(ctx, space.SystemSpace, workitem.SystemBug, workItem.Fields, s.modifierID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask why you don't use a test fixture here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do that, indeed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, too.
uuid "github.com/satori/go.uuid" | ||
) | ||
|
||
// WorkItemNumberSequence the sequence for work item numbers in a space | ||
type WorkItemNumberSequence struct { | ||
SpaceID uuid.UUID `sql:"type:uuid" gorm:"primary_key"` | ||
ID uuid.UUID `sql:"type:uuid" gorm:"primary_key"` | ||
SpaceID uuid.UUID `sql:"type:uuid"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of the most important changes of this PR, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, indeed
@xcoulon snapshot fabric8-wit image is available for testing. |
Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
Refactored the test to use the TestFixture to initialise the work items from the data set. Remove the `optionalKeywords` which contained the work item number but failed when the 3rd work item was retrieved because its number ('3') would match the description. This worked in the past when the number did not exist and the search was based on the ID (UUID). Also, searching on a URL did not seem to make sense since there was no such value in the work item fields. Also, add a test to search by number using the `number:%d` query. Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
Codecov Report
@@ Coverage Diff @@
## master #1677 +/- ##
==========================================
+ Coverage 56.65% 56.66% +0.01%
==========================================
Files 125 126 +1
Lines 14533 14549 +16
==========================================
+ Hits 8233 8244 +11
- Misses 5662 5666 +4
- Partials 638 639 +1
Continue to review full report at Codecov.
|
@xcoulon snapshot fabric8-wit image is available for testing. |
} | ||
assert.True(s.T(), | ||
strings.Contains(workItemTitle, keyWord) || strings.Contains(workItemDescription, keyWord), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay! a question
what would happen when user types in just 10
to search. Will it return a WI with id=10? Can we have a test for that too?
Currently, we are using this search
when a user wants to link WIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pranavgore09 I added a test for searching by WI number, but not by id . Also, I used the number:
prefix, but maybe I should also add a test to search without the prefix ? My question is: ID
is supposed to be an internal UUID, so do we expect users to use it to look-up a work item ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh! yeah, I was concerned with UUID in the search bar, but yes we may not need that case.
Generally, number
will be used. Not sure if UI need to make this change or they are already using number
only. I will confirm with the team and respond here.
thanks @xcoulon for an explanation.
And test without prefix would be helpful IMHO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah on UI we are using number
while search and not uuid
!
search/search_repository.go
Outdated
@@ -481,7 +481,7 @@ func generateSQLSearchInfo(keywords searchKeyword) (sqlParameter string) { | |||
// extracted this function from List() in order to close the rows object with "defer" for more readability | |||
// workaround for https://github.com/lib/pq/issues/81 | |||
func (r *GormSearchRepository) search(ctx context.Context, sqlSearchQueryParameter string, workItemTypes []uuid.UUID, start *int, limit *int, spaceID *string) ([]workitem.WorkItemStorage, uint64, error) { | |||
log.Info(ctx, nil, "Searching work items...") | |||
defer r.db.LogMode(false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
never mind, I forgot to remove that line ;) (there was a r.db.LogMode(true)
on top of this one, which I used to check some requests)
@xcoulon snapshot fabric8-wit image is available for testing. |
func (r *GormWorkItemNumberSequenceRepository) NextVal(ctx context.Context, spaceID uuid.UUID) (*WorkItemNumberSequence, error) { | ||
// retrieve the current issue number in the given space | ||
numberSequence := WorkItemNumberSequence{} | ||
tx := r.db.Model(&WorkItemNumberSequence{}).Set("gorm:query_option", "FOR UPDATE").Where("space_id = ?", spaceID).First(&numberSequence) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Evaluate UPDATE table set number = number+1 where... RETURNING number to avoid get and save on each call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, I'll try that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, I could probably get rid of the SELECT... FOR UPDATE
statement using an UPSERT ... RETURNING
as you suggested below, in which case there might be no need for the new ID
column either. Let me try that
uuid "github.com/satori/go.uuid" | ||
) | ||
|
||
// WorkItemNumberSequence the sequence for work item numbers in a space | ||
type WorkItemNumberSequence struct { | ||
SpaceID uuid.UUID `sql:"type:uuid" gorm:"primary_key"` | ||
ID uuid.UUID `sql:"type:uuid" gorm:"primary_key"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use SpaceID as primary key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought GORM might be confused if I tried to INSERT
a new record while the primary
key was provided (it might run an UPDATE
query instead)
search/search_repository.go
Outdated
@@ -572,6 +572,7 @@ func (r *GormSearchRepository) SearchFullText(ctx context.Context, rawSearchStri | |||
} | |||
|
|||
sqlSearchQueryParameter := generateSQLSearchInfo(parsedSearchDict) | |||
log.Warn(ctx, map[string]interface{}{"search query": sqlSearchQueryParameter}, "searching for work items") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Warn?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, so I have colors in my console when working on it :) Obviously, this was not intended to be part of the PR...
|
||
// WorkItemNumberSequenceRepository the interface for the work item number sequence repository | ||
type WorkItemNumberSequenceRepository interface { | ||
Create(ctx context.Context, spaceID uuid.UUID) (*WorkItemNumberSequence, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we care about create? You have all the info on nextVal to create it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, I think it's worth creating the "sequence" upon space creation, so we can effectively lock the row in the table when adding a work item. I suspect that this is what causes the duplicate key
issue during the tests.
// WorkItemNumberSequenceRepository the interface for the work item number sequence repository | ||
type WorkItemNumberSequenceRepository interface { | ||
Create(ctx context.Context, spaceID uuid.UUID) (*WorkItemNumberSequence, error) | ||
NextVal(ctx context.Context, spaceID uuid.UUID) (*WorkItemNumberSequence, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why return WorkItemNumberSequence and not just the Number?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, indeed
// Create returns the next work item sequence number for the given space ID. Creates an entry in the DB if none was found before | ||
func (r *GormWorkItemNumberSequenceRepository) Create(ctx context.Context, spaceID uuid.UUID) (*WorkItemNumberSequence, error) { | ||
// retrieve the current issue number in the given space | ||
numberSequence := WorkItemNumberSequence{SpaceID: spaceID, CurrentVal: 0} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CurrVal could be set to 0 as default value on table work_item_number_sequences
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, as-per golang, there's no need to make it explicit here, indeed. But I liked the idea of showing that the sequence is initialized to 0
upon creation, and the first call to NextVal()
will return 1
Create and NextVal could be combined into a single UPSERT SQL: INSERT INTO work_item_number_sequences (space_id) VALUES (?)
ON CONFLICT (space_id) DO UPDATE SET number = work_item_number_sequences.number+1
RETURNING number (roughly) |
@@ -0,0 +1,5 @@ | |||
-- modify the `work_item_number_sequences` to include an independant ID column for the primary key | |||
alter table work_item_number_sequences drop constraint work_item_number_sequences_pkey; | |||
alter table work_item_number_sequences add column id uuid primary key DEFAULT uuid_generate_v4() NOT NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add a test for checking the existence of id
column in migration/migration_blackbox_test.go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, you're right
@aslak yes, we could actually having this kind of |
@xcoulon Nothing to lock, but SpaceID is still a primary ID and is unique. Both can't work even concurrently. I would suspect the 'second' would hit on conflict |
}, | ||
searchString: `(pranav) {shoubhik} [aslak] `, | ||
minimumResults: 1, | ||
}, | ||
} | ||
fxt := tf.NewTestFixture(s.T(), s.DB, tf.Identities(2), tf.WorkItems(len(testDataSet), func(fxt *tf.TestFixture, idx int) error { | ||
fxt := tf.NewTestFixture(s.T(), s.DB, tf.Identities(2, tf.SetIdentityUsernamesFromString([]string{"creator", "assignee"})), tf.WorkItems(len(testDataSet), func(fxt *tf.TestFixture, idx int) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice try :). Notice that all but the last two WIs, all belong to sbose78 and in your change they all belong to one entity. Please see my longish comment on my first idea how to fix it and my second attempt on why even that is bad: #1677 (review)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does it cause any issue ? we don't search by creator or assignee anyways
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, then. I didn't look at the test itself but only at the test data. And you didn't refactor it 1:1, which was the only cause of my complaint ;)
workitem.SystemTitle: "Search Test creator", | ||
workitem.SystemDescription: rendering.NewMarkupContentFromLegacy("Description"), | ||
workitem.SystemCreator: fxt.Identities[0].ID.String(), | ||
workitem.SystemAssignees: []string{fxt.Identities[1].ID.String()}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use tf.IdentityByUsername("creator").ID.String()
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@xcoulon snapshot fabric8-wit image is available for testing. |
workitem.SystemDescription: rendering.NewMarkupContentFromLegacy("Description"), | ||
workitem.SystemCreator: fxt.Identities[0].ID.String(), | ||
workitem.SystemAssignees: []string{fxt.Identities[1].ID.String()}, | ||
workitem.SystemState: "closed", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use workitem.SystemStateClosed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
@xcoulon snapshot fabric8-wit image is available for testing. |
Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
@xcoulon snapshot fabric8-wit image is available for testing. |
tf.Spaces(1, func(fxt *tf.TestFixture, idx int) error { | ||
fxt.Spaces[idx].OwnerId = fxt.Identities[0].ID | ||
return nil | ||
}), tf.WorkItemTypes(1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fixture's comment is a little bit off because you're not creating 2 work items at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Fields: map[string]interface{}{ | ||
func (s *searchRepositoryWhiteboxTest) TestSearch() { | ||
// create 2 work items, the second one having the number of the first one in its title | ||
baseFxt, err := tf.NewFixture(s.DB, tf.Identities(2, tf.SetIdentityUsernames([]string{"creator", "assignee"})), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use NewTestFixture
and give it your test variable, for the fixture to automatically fail if something goes wrong. Then you can get rid of the require.Nil(s.T(), err)
below.
// create 2 work items, the second one having the number of the first one in its title | ||
baseFxt, err := tf.NewFixture(s.DB, tf.Identities(2, tf.SetIdentityUsernames([]string{"creator", "assignee"})), | ||
tf.Spaces(1, func(fxt *tf.TestFixture, idx int) error { | ||
fxt.Spaces[idx].OwnerId = fxt.Identities[0].ID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to write this down explicitly as a space owner is automatically set to the first identity. Look at makeSpaces()
.
That being said, the whole fixture (6 lines) can be compressed to just:
tf.NewTestFixture(s.DB, s.T(), tf.Identities(2), tf.Spaces(1), tf.WorkItemTypes(1))
Below you're using baseFxt.Identities[0].ID.String(),
without specifying an identities username. Therefore you might as well just put my fixture recipe (tf.Identities(2), tf.Spaces(1), tf.WorkItemTypes(1)
) from above into every test fixture of every sub-test below. Then you can get rid of these three lines that adjusted the space and the creator:
fxt.WorkItems[idx].SpaceID = baseFxt.Spaces[0].ID
fxt.WorkItems[idx].Type = baseFxt.WorkItemTypes[0].ID
//...
workitem.SystemCreator: baseFxt.Identities[0].ID.String(),
Please note, that it would help me a lot if you do this because when space templates come in and you create two fixtures that use each other, things can become complicated to adjust for me.
If the sate of a workitem is also irrelevant, you can simply ignore it and instead of specifying the whole map
of Fields you might as well only set those keys you want. Know, that we pre-fill the state to workitem.SystemStateNew
and the creator field to the first identity known to the fixture.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I simplified the test here. Please let mw know if it's good for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the `baseFxt`, and let each work item be created with the default TestFixture settings (ie, each one in its own space with its own creator and state) Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
@xcoulon snapshot fabric8-wit image is available for testing. |
} | ||
creatorID, err := uuid.FromString(creatorIDStr) | ||
if err != nil { | ||
return errs.Wrapf(err, "failed to convert \"%s\" field to uuid.UUID", workitem.SystemCreator) | ||
return errs.Wrapf(err, "failed to convert \"%s\" field to uuid.UUID: %v", workitem.SystemCreator, fxt.WorkItems[i].Fields[workitem.SystemCreator]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks
@@ -18,3 +20,7 @@ const ( | |||
func (w WorkItemNumberSequence) TableName() string { | |||
return workitemNumberTableName | |||
} | |||
|
|||
func (w *WorkItemNumberSequence) String() string { | |||
return fmt.Sprintf("SpaceId=%s Number=%d", w.SpaceID.String(), w.CurrentVal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make this SprintID
instead of SprintId
. See also https://github.com/golang/go/wiki/CodeReviewComments#initialisms
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
} | ||
|
||
// NextVal returns the next work item sequence number for the given space ID. Creates an entry in the DB if none was found before | ||
func (r *GormWorkItemNumberSequenceRepository) NextVal(ctx context.Context, spaceID uuid.UUID) (*int, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add a test for this method maybe. WDYT @xcoulon ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a test with concurrent routines, using a WaitGroup
workitem/workitem_repository.go
Outdated
db, | ||
numbersequence.NewWorkItemNumberSequenceRepository(db), | ||
&GormWorkItemTypeRepository{db}, | ||
&GormRevisionRepository{db}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you maybe add struct member names like member: value
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
tf.WorkItemTypes(1, func(fxt *tf.TestFixture, idx int) error { | ||
fxt.WorkItemTypes[idx].SpaceID = fxt.Spaces[0].ID | ||
return nil | ||
})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use fxt := tf.NewTestFixture(s.T(), s.DB, tf.CreateWorkItemEnvironment())
instead of this complicated fixture. What you do in this fixture is exactly what is being done for you already btw.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, that's actually simpler ;)
assert.Equal(s.T(), 0, report.failures) | ||
} | ||
|
||
// then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This // then
looks quite lonely ;)
Should this test also double check that no WI did get the same Number?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, WI with same numbers will cause a duplicate key
error at the DB level.
}(i) | ||
} | ||
// wait for all items to be created | ||
for i := 0; i < routines; i++ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to properly wait for all go routines to finish, you should use a wait group as we do here.
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// DO HERE WHAT YOU DO IN YOUR GO ROUTINES
}()
}
wg.Wait()
Then you can do this to access each report and get rid of the routines
variable for good, since it is only used when spawning the go routines.
for _, report := range done {
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that syntax is nicer and I can use the WaitGroup
feature indeed , but AFAICT, my code already waits for routines to complete. Or did I miss something ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the top of my head (not writing go routines every day): I think you have a blocking read from a channel that waits until there is nothing more to read. But you don't have a close call of that channel and I just find it much easier with the wait group.
|
||
sr := NewGormSearchRepository(tx) | ||
func (s *searchRepositoryWhiteboxTest) searchFor(spaceID uuid.UUID, searchQuery string) ([]workitem.WorkItem, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just put this above the test cases in func (s *searchRepositoryWhiteboxTest) TestSearch() {
? This function searchFor
is only used there and I would consider our tests much easier to maintain if we can avoid any helper functions. In the code of TestSearch
we would only have to replace
searchResults, err := s.searchFor(fxt.Spaces[0].ID, searchQuery)
with
spaceIDStr := fxt.Spaces[0].ID.String()
searchResult, _, err := sr.SearchFullText(ctx, fmt.Sprintf("\"%s\"", searchQuery), &start, &limit, &spaceIDStr)
correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay
workItemList, _, err := sr.SearchFullText(ctx, searchString, &start, &limit, nil) | ||
if err != nil { | ||
s.T().Fatal("Error gettig search result ", err) | ||
func verify(t *testing.T, searchQuery string, searchResults []workitem.WorkItem, expectedCount int) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment on this method would be nice. What does it verify?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
@xcoulon snapshot fabric8-wit image is available for testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Except the missing additional WIs.
This highlighted some cases where searching by number or URL can match more than 1 work item. Also: move some log statements to `DEBUG` instead of `INFO` to reduce the noise during test executions Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
@xcoulon snapshot fabric8-wit image is available for testing. |
[test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm requesting changes mostly due to the log change that you did. The sub-tests would also be nice.
@@ -161,9 +161,9 @@ func (m *GormIdentityRepository) Create(ctx context.Context, model *Identity) er | |||
}, "unable to create the identity") | |||
return errs.WithStack(err) | |||
} | |||
log.Info(ctx, map[string]interface{}{ | |||
log.Debug(ctx, map[string]interface{}{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to just reduce the test output by setting F8_LOG_LEVEL=error
instead of changing the level code-wise. Most repo create functions use log.Info
. Also run tests with go test
instead of go test -v
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know I can do that (F8_LOG_LEVEL=error
and go test
without the verbose
flag), but do we really need those logs statements at the INFO
level ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not. Did you cover all "created X" log messages? Then it is fine to change to Debug if you ask me. I mostly feared mixing concerns of this PR.
assert.Equal(t, queryNumber, searchResults[0].Number) | ||
}) | ||
|
||
s.T().Run("Search by number - multiple matches", func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of nesting those tests to get a better context and not repeat yourself?
s.T().Run("by number", func(t*testing.T)) {
t.Run("single match", func(t*testing.T)) {
})
t.Run("multiple match", func(t*testing.T)) {
})
})
s.T().Run("by URL", func(t*testing.T)) {
t.Run("single match", func(t*testing.T)) {
})
t.Run("multiple match", func(t*testing.T)) {
})
})
…oncurrency tests Signed-off-by: Xavier Coulon <xcoulon@redhat.com>
@xcoulon snapshot fabric8-wit image is available for testing. |
@@ -161,9 +161,9 @@ func (m *GormIdentityRepository) Create(ctx context.Context, model *Identity) er | |||
}, "unable to create the identity") | |||
return errs.WithStack(err) | |||
} | |||
log.Info(ctx, map[string]interface{}{ | |||
log.Debug(ctx, map[string]interface{}{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not. Did you cover all "created X" log messages? Then it is fine to change to Debug if you ask me. I mostly feared mixing concerns of this PR.
@xcoulon snapshot fabric8-wit image is available for testing. |
thanks for the reviews, @kwk and @aslakknutsen ! |
Move the
work item number sequence
in its own subpackage, andcreate its dedicated repository with 2 methods:
Create
andNextVal
.Use a new
ID
column for the primary key, so GORM will issue a properINSERT
query when a new number sequence is created.Make sure a space has a sequence initialized upon its own creation
Refactored the search space tests
Other minor Fixes in tests (eg: length of area name, etc.)
Fixes #1676
Signed-off-by: Xavier Coulon xcoulon@redhat.com