-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Storage Integration Testing #236
Conversation
"github.com/uber/jaeger/model" | ||
) | ||
|
||
type TraceByKey []*model.Trace |
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.
did you mean "by trace id"?
|
||
func compareModelTags(t *testing.T, expected []model.KeyValue, actual []model.KeyValue) { | ||
sort.Sort(TagByKey(expected)) | ||
sort.Sort(TagByKey(actual)) |
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.
does this mean ES backend does not preserve the order of tags in the Span document?
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 think ES does, but this is for any general backend.
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.
fair enough. I would suggest having a single "normalize" function that does all the sorting on a given trace, and after that ideally just use assert.Equal on the whole object. If you run into issues with pointers being slightly different, you can convert the whole thing to a JSON and do equals on strings.
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 downside to doing that would be that it would be difficult to see where the traces differ.
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 necessarily. First, you can use pretty
to print the diffs, as done here. Another trick I used was to write out the JSON to files (when the test fails) so that they can be compared with other tools like diff
.
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.
just kidding, i think assert.EqualValues
tells us where
// this function exists solely to make it easier for developer to find out where the difference is | ||
func compareModelLogs(t *testing.T, expected []model.Log, actual []model.Log) { | ||
sort.Sort(LogByTimestamp(expected)) | ||
sort.Sort(LogByTimestamp(actual)) |
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.
same question - why doesn't the backend simply preserve the order of logs?
|
||
const ( | ||
byService QueryType = iota | ||
bysNoN |
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.
?
bysNTags | ||
bysNDuration | ||
byNumOfTraces | ||
// Add more queryTypes 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.
why do we need these enums instead of simply having distinct test cases as data or as test methods? Each scenario requires special data to be inserted into storage before querying.
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're right. I think I used this earlier when I needed the enums, but i changed the format and we no longer need it. i'll refactor
there might be unused stuff that i haven't caught, let me know if you find anything such |
revert idl |
model/sort_traces.go
Outdated
func (s spanBySpanID) Less(i, j int) bool { return s[i].SpanID < s[j].SpanID } | ||
|
||
// SortTraces checks two traces' length and sorts their spans. | ||
func SortTraces(expected *Trace, actual *Trace) 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.
I was more thinking sort just one trace and leave the comparisons to domain_trace_compare_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.
Hmm, so I did this before, and the issue with this was that I would get index out of bound error with the assert.Equals, and the error message wouldn't be very helpful. the current way catches these because they'll do a length check on the way
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.
sort the traces separately but still do the length checks in domain_trace_compare_test.go?
return errors.New("elastic search is not ready") | ||
} | ||
|
||
// DO NOT RUN IF YOU HAVE IMPORTANT SPANS IN ELASTICSEARCH |
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.
is this comment still valid? hopefully people arent stupid enough to run integration tests in production
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 trust people
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 forgot one test case where we return more than one trace, tis the last one I swear
model/sort.go
Outdated
func (s spanBySpanID) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||
func (s spanBySpanID) Less(i, j int) bool { return s[i].SpanID < s[j].SpanID } | ||
|
||
// SortTrace checks two traces' length and sorts their spans. |
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.
update comment
"github.com/uber/jaeger/model" | ||
) | ||
|
||
type TraceByTraceID []*model.Trace |
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 move this to model as well?
expectedSpan := expected.Spans[i] | ||
actualSpan := actual.Spans[i] | ||
require.True(t, len(expectedSpan.Tags) == len(actualSpan.Tags)) | ||
require.True(t, len(expectedSpan.Logs) == len(actualSpan.Logs)) |
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.
compare process tag lengths
func (s *StorageIntegration) IntegrationTestGetServices(t *testing.T) { | ||
t.Log("Testing GetServices ...") | ||
|
||
// TODO |
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.
?
func (s *StorageIntegration) IntegrationTestGetOperations(t *testing.T) { | ||
t.Log("Testing GetOperations ...") | ||
|
||
// TODO |
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.
?
} | ||
|
||
func (s *StorageIntegration) integrationTestFindTracesByQuery(t *testing.T, query *spanstore.TraceQueryParameters, expectedFixture string) { | ||
expectedTrace, err := getTraceFixture(expectedFixture) |
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.
these 3 lines seem to be repeated in every test
|
||
var found bool | ||
var actual []*model.Trace | ||
for i := 0; i < 30; 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.
const 30 to iterations
or something
var found bool | ||
var actual []*model.Trace | ||
for i := 0; i < 30; i++ { | ||
s.logger.Info(fmt.Sprintf("Waiting for storage backend to update documents, iteration %d out of %d", i+1, 30)) |
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 comment repeated everywhere, DRY it
s.logger.Info(fmt.Sprintf("Waiting for storage backend to update documents, iteration %d out of %d", i+1, 30)) | ||
actual, err = s.reader.FindTraces(query) | ||
if err == nil { | ||
if len(actual) == query.NumTraces { |
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.
but NumTrace in your queries are always 1000, so this never gets hit
s.logger.Info(fmt.Sprintf("Waiting for storage backend to update documents, iteration %d out of %d", i+1, 30)) | ||
actual, err = s.reader.GetTrace(traceID) | ||
if err == nil { | ||
found = len(actual.Spans) == len(expected.Spans) |
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, this one you can inline
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 doesn't include multiple traces test yet?
model/sort.go
Outdated
func (s traceByTraceID) Len() int { return len(s) } | ||
func (s traceByTraceID) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||
func (s traceByTraceID) Less(i, j int) bool { | ||
if len(s[i].Spans) != len(s[j].Spans) { |
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.
number of spans should have no bearing on the order of the traces unless the traceIDs are identical
t.Log("Testing GetTrace ...") | ||
|
||
expected := s.getBasicFixture(t) | ||
expectedTraceID := model.TraceID{Low: 17} |
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.
so you cant get this from expected instead of hard coding 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.
oh thats what you meant ok i can do that
s.logger.Info(fmt.Sprintf(waitForBackendComment, i+1, iterations)) | ||
actual, err := s.reader.GetTrace(expectedTraceID) | ||
if err == nil { | ||
if found = len(actual.Spans) == len(expected.Spans); found { |
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 don't need the found variable, you can just do the length check here and L148
s.logger.Info(fmt.Sprintf(waitForBackendComment, i+1, iterations)) | ||
actual, err = s.reader.FindTraces(query) | ||
if err == nil { | ||
if len(actual) == query.NumTraces { |
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.
so we dont need this right?
found = true | ||
break | ||
} | ||
found = tracesMatch(actual, expected) |
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 can't we do:
if tracesMatch(actual, expected) {
break
}
and then CompareSliceOfTraces below after the for loop once? Given CompareSliceOfTraces uses require
will stop execution anyway for bad traces, just do it once
|
||
func (s traceByTraceID) Len() int { return len(s) } | ||
func (s traceByTraceID) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||
func (s traceByTraceID) Less(i, j int) bool { |
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.
s[i].Spans[0].TraceID.Low < s[j].Spans[0].TraceID.Low
is the only check you need now thinking about it. You can't (shouldn't) have two traces with the same id so using the traceid as the tie breaker is all you need.
s.logger.Info(fmt.Sprintf(waitForBackendComment, i+1, iterations)) | ||
var err error | ||
actual, err = s.reader.GetTrace(expectedTraceID) | ||
if err == 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.
can combine these two if stmts
expected, err := getTraceFixtures(expectedFixtures) | ||
require.NoError(t, err) | ||
require.NoError(t, s.writeTraces(expected)) | ||
require.NoError(t, s.refresh()) |
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.
require.NoError(t, s.refresh())
here but the other tests dont do require.
* create integration test framework for storage + create elasticsearch integration test * refactor queries format * rename comparison fns to fit its behavior * fix rand.Uint64() (does not exist in go1.7) * revert env var check * refactor trace w/ query checker to separate file + test * import list reorder * change itest direction * change integration test format * make fmt/lint * make fmt/lint * prettify output when test fails * fmt * delete query to trace checker * remove unnecessary code * add integration test script * fix syntax * add comment about fixtures and queries * fix travis yml to run es integ test * remove es integ test from install travis * fix typo * fix err check bug * fmt * move sorting fns to model * fix imports * fix code reviews * change trace fixtures to describe the trace * revert idl * trust people * sort refactored * fix trace comparison test + raise timeout for es-integration test * code review * remove numtraces check * add multiple-trace test case * code review
w/ an example on ElasticSearch