Skip to content

Commit cfa8e79

Browse files
Add tests to ensure cross service tracing
1 parent d098d76 commit cfa8e79

2 files changed

Lines changed: 240 additions & 4 deletions

File tree

systest/tracing/jaeger1/jaeger1_test.go

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,30 @@ type JaegerServicesResponse struct {
3030
Errors []any `json:"errors"`
3131
}
3232

33+
// JaegerTrace represents a single trace from Jaeger
34+
type JaegerTrace struct {
35+
TraceID string `json:"traceID"`
36+
Spans []JaegerSpan `json:"spans"`
37+
Processes map[string]JaegerProcess `json:"processes"`
38+
}
39+
40+
// JaegerSpan represents a span within a trace
41+
type JaegerSpan struct {
42+
TraceID string `json:"traceID"`
43+
SpanID string `json:"spanID"`
44+
OperationName string `json:"operationName"`
45+
ProcessID string `json:"processID"`
46+
}
47+
48+
// JaegerProcess represents a process (service) in the trace
49+
type JaegerProcess struct {
50+
ServiceName string `json:"serviceName"`
51+
}
52+
3353
// JaegerTracesResponse represents the response from Jaeger's /api/traces endpoint
3454
type JaegerTracesResponse struct {
35-
Data []any `json:"data"`
36-
Errors []any `json:"errors"`
55+
Data []JaegerTrace `json:"data"`
56+
Errors []any `json:"errors"`
3757
}
3858

3959
func TestMain(m *testing.M) {
@@ -139,3 +159,101 @@ func TestJaegerTracesHaveSpans(t *testing.T) {
139159
t.Logf("Found %d traces for service alpha1", len(traces.Data))
140160
require.NotEmpty(t, traces.Data, "Should have traces for alpha1 service")
141161
}
162+
163+
// TestCrossServiceTraceContext verifies that traces propagate correctly between alpha and zero.
164+
// A mutation triggers alpha->zero communication (for timestamps/commit), and both services
165+
// should appear in the same trace with the same trace ID.
166+
func TestCrossServiceTraceContext(t *testing.T) {
167+
jaegerAddr := testutil.ContainerAddr("jaeger", 16686)
168+
alphaAddr := testutil.ContainerAddr("alpha1", 9080)
169+
170+
dg, err := testutil.DgraphClient(alphaAddr)
171+
require.NoError(t, err)
172+
173+
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
174+
defer cancel()
175+
176+
// Run a mutation - this triggers alpha->zero communication for timestamps and commit
177+
_, err = dg.NewTxn().Mutate(ctx, &api.Mutation{
178+
SetNquads: []byte(`_:cross <name> "cross-service-trace-test" .`),
179+
CommitNow: true,
180+
})
181+
require.NoError(t, err)
182+
183+
// Give Jaeger time to process traces
184+
time.Sleep(5 * time.Second)
185+
186+
// Verify both services are registered
187+
servicesURL := fmt.Sprintf("http://%s/api/services", jaegerAddr)
188+
resp, err := http.Get(servicesURL)
189+
require.NoError(t, err)
190+
defer resp.Body.Close()
191+
192+
body, err := io.ReadAll(resp.Body)
193+
require.NoError(t, err)
194+
195+
var services JaegerServicesResponse
196+
err = json.Unmarshal(body, &services)
197+
require.NoError(t, err)
198+
199+
t.Logf("Registered services: %v", services.Data)
200+
201+
// Check both alpha1 and zero1 are registered
202+
foundAlpha := false
203+
foundZero := false
204+
for _, svc := range services.Data {
205+
if svc == "alpha1" {
206+
foundAlpha = true
207+
}
208+
if svc == "zero1" {
209+
foundZero = true
210+
}
211+
}
212+
require.True(t, foundAlpha, "Service 'alpha1' should be registered")
213+
require.True(t, foundZero, "Service 'zero1' should be registered")
214+
215+
// Query for traces from alpha1
216+
tracesURL := fmt.Sprintf("http://%s/api/traces?service=alpha1&limit=50", jaegerAddr)
217+
resp, err = http.Get(tracesURL)
218+
require.NoError(t, err)
219+
defer resp.Body.Close()
220+
221+
body, err = io.ReadAll(resp.Body)
222+
require.NoError(t, err)
223+
224+
var traces JaegerTracesResponse
225+
err = json.Unmarshal(body, &traces)
226+
require.NoError(t, err)
227+
228+
require.NotEmpty(t, traces.Data, "Should have traces for alpha1")
229+
230+
// Look for traces that contain both alpha1 and zero1 spans
231+
// This proves cross-service trace context propagation is working
232+
multiServiceTraceFound := false
233+
for _, trace := range traces.Data {
234+
servicesInTrace := make(map[string]bool)
235+
for _, span := range trace.Spans {
236+
if proc, ok := trace.Processes[span.ProcessID]; ok {
237+
servicesInTrace[proc.ServiceName] = true
238+
}
239+
}
240+
241+
hasAlpha := servicesInTrace["alpha1"]
242+
hasZero := servicesInTrace["zero1"]
243+
244+
if hasAlpha && hasZero {
245+
multiServiceTraceFound = true
246+
t.Logf("Found cross-service trace %s with services: %v", trace.TraceID, servicesInTrace)
247+
248+
// Verify all spans share the same trace ID - this proves context propagation
249+
for _, span := range trace.Spans {
250+
require.Equal(t, trace.TraceID, span.TraceID,
251+
"All spans in cross-service trace must share the same trace ID")
252+
}
253+
break
254+
}
255+
}
256+
257+
require.True(t, multiServiceTraceFound,
258+
"Should find at least one trace containing both alpha1 and zero1 spans (proves context propagation)")
259+
}

systest/tracing/jaeger2/jaeger2_test.go

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,30 @@ type JaegerServicesResponse struct {
3030
Errors []any `json:"errors"`
3131
}
3232

33+
// JaegerTrace represents a single trace from Jaeger
34+
type JaegerTrace struct {
35+
TraceID string `json:"traceID"`
36+
Spans []JaegerSpan `json:"spans"`
37+
Processes map[string]JaegerProcess `json:"processes"`
38+
}
39+
40+
// JaegerSpan represents a span within a trace
41+
type JaegerSpan struct {
42+
TraceID string `json:"traceID"`
43+
SpanID string `json:"spanID"`
44+
OperationName string `json:"operationName"`
45+
ProcessID string `json:"processID"`
46+
}
47+
48+
// JaegerProcess represents a process (service) in the trace
49+
type JaegerProcess struct {
50+
ServiceName string `json:"serviceName"`
51+
}
52+
3353
// JaegerTracesResponse represents the response from Jaeger's /api/traces endpoint
3454
type JaegerTracesResponse struct {
35-
Data []any `json:"data"`
36-
Errors []any `json:"errors"`
55+
Data []JaegerTrace `json:"data"`
56+
Errors []any `json:"errors"`
3757
}
3858

3959
func TestMain(m *testing.M) {
@@ -139,3 +159,101 @@ func TestJaeger2TracesHaveSpans(t *testing.T) {
139159
t.Logf("Found %d traces for service alpha1 in Jaeger 2.x", len(traces.Data))
140160
require.NotEmpty(t, traces.Data, "Should have traces for alpha1 service in Jaeger 2.x")
141161
}
162+
163+
// TestCrossServiceTraceContext verifies that traces propagate correctly between alpha and zero.
164+
// A mutation triggers alpha->zero communication (for timestamps/commit), and both services
165+
// should appear in the same trace with the same trace ID.
166+
func TestCrossServiceTraceContext(t *testing.T) {
167+
jaegerAddr := testutil.ContainerAddr("jaeger", 16686)
168+
alphaAddr := testutil.ContainerAddr("alpha1", 9080)
169+
170+
dg, err := testutil.DgraphClient(alphaAddr)
171+
require.NoError(t, err)
172+
173+
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
174+
defer cancel()
175+
176+
// Run a mutation - this triggers alpha->zero communication for timestamps and commit
177+
_, err = dg.NewTxn().Mutate(ctx, &api.Mutation{
178+
SetNquads: []byte(`_:cross <name> "cross-service-trace-test-v2" .`),
179+
CommitNow: true,
180+
})
181+
require.NoError(t, err)
182+
183+
// Give Jaeger time to process traces
184+
time.Sleep(5 * time.Second)
185+
186+
// Verify both services are registered
187+
servicesURL := fmt.Sprintf("http://%s/api/services", jaegerAddr)
188+
resp, err := http.Get(servicesURL)
189+
require.NoError(t, err)
190+
defer resp.Body.Close()
191+
192+
body, err := io.ReadAll(resp.Body)
193+
require.NoError(t, err)
194+
195+
var services JaegerServicesResponse
196+
err = json.Unmarshal(body, &services)
197+
require.NoError(t, err)
198+
199+
t.Logf("Registered services: %v", services.Data)
200+
201+
// Check both alpha1 and zero1 are registered
202+
foundAlpha := false
203+
foundZero := false
204+
for _, svc := range services.Data {
205+
if svc == "alpha1" {
206+
foundAlpha = true
207+
}
208+
if svc == "zero1" {
209+
foundZero = true
210+
}
211+
}
212+
require.True(t, foundAlpha, "Service 'alpha1' should be registered")
213+
require.True(t, foundZero, "Service 'zero1' should be registered")
214+
215+
// Query for traces from alpha1
216+
tracesURL := fmt.Sprintf("http://%s/api/traces?service=alpha1&limit=50", jaegerAddr)
217+
resp, err = http.Get(tracesURL)
218+
require.NoError(t, err)
219+
defer resp.Body.Close()
220+
221+
body, err = io.ReadAll(resp.Body)
222+
require.NoError(t, err)
223+
224+
var traces JaegerTracesResponse
225+
err = json.Unmarshal(body, &traces)
226+
require.NoError(t, err)
227+
228+
require.NotEmpty(t, traces.Data, "Should have traces for alpha1")
229+
230+
// Look for traces that contain both alpha1 and zero1 spans
231+
// This proves cross-service trace context propagation is working
232+
multiServiceTraceFound := false
233+
for _, trace := range traces.Data {
234+
servicesInTrace := make(map[string]bool)
235+
for _, span := range trace.Spans {
236+
if proc, ok := trace.Processes[span.ProcessID]; ok {
237+
servicesInTrace[proc.ServiceName] = true
238+
}
239+
}
240+
241+
hasAlpha := servicesInTrace["alpha1"]
242+
hasZero := servicesInTrace["zero1"]
243+
244+
if hasAlpha && hasZero {
245+
multiServiceTraceFound = true
246+
t.Logf("Found cross-service trace %s with services: %v", trace.TraceID, servicesInTrace)
247+
248+
// Verify all spans share the same trace ID - this proves context propagation
249+
for _, span := range trace.Spans {
250+
require.Equal(t, trace.TraceID, span.TraceID,
251+
"All spans in cross-service trace must share the same trace ID")
252+
}
253+
break
254+
}
255+
}
256+
257+
require.True(t, multiServiceTraceFound,
258+
"Should find at least one trace containing both alpha1 and zero1 spans (proves context propagation)")
259+
}

0 commit comments

Comments
 (0)