forked from open-telemetry/opentelemetry-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCracLifecycleIntegrationTest.java
More file actions
165 lines (142 loc) · 6.05 KB
/
CracLifecycleIntegrationTest.java
File metadata and controls
165 lines (142 loc) · 6.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.crac.Context;
import org.crac.Resource;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
/**
* Integration-style lifecycle tests for CRaC (Coordinated Restore at Checkpoint) support.
*
* <p>These tests use {@link MockCracContext} to simulate the CRaC checkpoint/restore lifecycle
* without a CRaC-enabled JDK. Resources register with the mock context; the test then drives {@code
* beforeCheckpoint} and {@code afterRestore} callbacks directly.
*
* <p>See: <a href="https://github.com/open-telemetry/opentelemetry-java/issues/6756">#6756</a>
*/
class CracLifecycleIntegrationTest {
/**
* Demonstrates the failure mode when the SDK is naively shut down at checkpoint with no
* corresponding restore logic. This is what happens today without proper CRaC support: the SDK is
* a one-shot object, so spans emitted after a restore are silently dropped.
*/
@Test
void spansDroppedAfterRestore_naiveCracIntegration() throws Exception {
MockCracContext cracContext = new MockCracContext();
InMemorySpanExporter exporter = new InMemorySpanExporter();
OpenTelemetrySdk sdk = buildSdk(exporter);
Tracer tracer = sdk.getTracer("crac-lifecycle-test");
// Naive CRaC resource: shuts the SDK down at checkpoint, does nothing on restore.
cracContext.register(
new Resource() {
@Override
public void beforeCheckpoint(Context<? extends Resource> context) {
sdk.getSdkTracerProvider().shutdown().join(10, TimeUnit.SECONDS);
}
@Override
public void afterRestore(Context<? extends Resource> context) {
// No restore logic — this is the gap that #6756 addresses.
}
});
emitSpan(tracer, "before-checkpoint");
sdk.getSdkTracerProvider().forceFlush().join(10, TimeUnit.SECONDS);
assertThat(exporter.exportedCount()).isEqualTo(1);
cracContext.simulateCheckpoint();
cracContext.simulateRestore();
// Post-restore span is silently dropped: the SDK is shut down and has no way to reinitialize.
emitSpan(tracer, "after-restore");
sdk.getSdkTracerProvider().forceFlush().join(10, TimeUnit.SECONDS);
assertThat(exporter.exportedCount()).isEqualTo(1);
}
/**
* Describes the desired behavior once the SDK properly implements {@link Resource}: spans emitted
* after a CRaC restore should be exported normally.
*
* <p>This test is disabled until <a
* href="https://github.com/open-telemetry/opentelemetry-java/issues/6756">#6756</a> is addressed.
* When that work lands, the SDK (or an adapter it exposes) should register with the CRaC context
* so that {@code beforeCheckpoint} flushes and quiesces, and {@code afterRestore} reinitializes
* exporters and processors. Replace the TODO below with the real SDK API.
*/
@Test
@Disabled("Expected to fail until #6756 adds checkpoint/restore-safe SDK lifecycle")
void spansExportedAfterRestore_properCracIntegration() throws Exception {
MockCracContext cracContext = new MockCracContext();
InMemorySpanExporter exporter = new InMemorySpanExporter();
OpenTelemetrySdk sdk = buildSdk(exporter);
Tracer tracer = sdk.getTracer("crac-lifecycle-test");
// TODO(#6756): replace this placeholder with the real SDK CRaC API, e.g.:
// cracContext.register(sdk.asCracResource());
cracContext.register(
new Resource() {
@Override
public void beforeCheckpoint(Context<? extends Resource> context) throws Exception {
sdk.getSdkTracerProvider().shutdown().join(10, TimeUnit.SECONDS);
}
@Override
public void afterRestore(Context<? extends Resource> context) throws Exception {
// Reinitialize: reopen connections, restart background threads.
// No SDK API exists for this yet — this is the body of #6756.
}
});
emitSpan(tracer, "before-checkpoint");
sdk.getSdkTracerProvider().forceFlush().join(10, TimeUnit.SECONDS);
assertThat(exporter.exportedCount()).isEqualTo(1);
cracContext.simulateCheckpoint();
cracContext.simulateRestore();
emitSpan(tracer, "after-restore");
sdk.getSdkTracerProvider().forceFlush().join(10, TimeUnit.SECONDS);
assertThat(exporter.exportedCount()).isEqualTo(2);
}
private static OpenTelemetrySdk buildSdk(SpanExporter exporter) {
return OpenTelemetrySdk.builder()
.setTracerProvider(
SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(exporter))
.build())
.build();
}
private static void emitSpan(Tracer tracer, String name) {
Span span = tracer.spanBuilder(name).startSpan();
span.end();
}
private static final class InMemorySpanExporter implements SpanExporter {
private final List<SpanData> spans = new ArrayList<>();
private boolean shutdown;
@Override
public CompletableResultCode export(Collection<SpanData> spans) {
if (shutdown) {
return CompletableResultCode.ofFailure();
}
this.spans.addAll(spans);
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode flush() {
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode shutdown() {
shutdown = true;
return CompletableResultCode.ofSuccess();
}
int exportedCount() {
return spans.size();
}
}
}