or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdexporters.mdindex.mdjunit-integration.mdtest-builders.mdutilities.md

utilities.mddocs/

0

# Time and Context Utilities

1

2

Utilities for controlling time during tests and managing context storage for test isolation and deterministic behavior. These utilities enable precise control over temporal aspects of telemetry and context propagation during testing.

3

4

## Capabilities

5

6

### Test Clock

7

8

Controllable clock implementation that allows manipulation of time during tests for deterministic and predictable timing behavior.

9

10

```java { .api }

11

@ThreadSafe

12

class TestClock implements Clock {

13

// Factory methods

14

static TestClock create();

15

static TestClock create(Instant instant);

16

17

// Time manipulation

18

synchronized void setTime(Instant instant);

19

synchronized void advance(Duration duration);

20

synchronized void advance(long duration, TimeUnit unit);

21

22

// Clock interface methods

23

synchronized long now();

24

synchronized long nanoTime();

25

}

26

```

27

28

Usage examples:

29

30

```java

31

// Create a test clock with current time

32

TestClock clock = TestClock.create();

33

34

// Create a test clock with specific time

35

TestClock fixedClock = TestClock.create(Instant.parse("2023-01-01T12:00:00Z"));

36

37

// Use in OpenTelemetry configuration

38

OpenTelemetrySdk sdk = OpenTelemetrySdk.builder()

39

.setTracerProvider(

40

SdkTracerProvider.builder()

41

.setClock(clock)

42

.build())

43

.build();

44

45

// Control time during test execution

46

Tracer tracer = sdk.getTracer("test");

47

48

// Set specific start time

49

clock.setTime(Instant.parse("2023-01-01T10:00:00Z"));

50

Span span = tracer.spanBuilder("test-span").startSpan();

51

52

// Advance time and end span

53

clock.advance(Duration.ofSeconds(5));

54

span.end();

55

56

// Verify timing

57

List<SpanData> spans = spanExporter.getFinishedSpanItems();

58

assertThat(spans.get(0))

59

.startsAt(Instant.parse("2023-01-01T10:00:00Z"))

60

.endsAt(Instant.parse("2023-01-01T10:00:05Z"));

61

```

62

63

Advanced time control examples:

64

65

```java

66

@Test

67

void testTimeBasedBehavior() {

68

TestClock clock = TestClock.create(Instant.parse("2023-01-01T00:00:00Z"));

69

70

// Configure service with test clock

71

MyTimedService service = new MyTimedService(openTelemetry, clock);

72

73

// Test behavior at specific times

74

service.performScheduledTask(); // Task at midnight

75

76

// Advance to next hour

77

clock.advance(Duration.ofHours(1));

78

service.performScheduledTask(); // Task at 1 AM

79

80

// Verify time-based metrics

81

assertThat(metricReader.collectAllMetrics())

82

.extracting(MetricData::getName)

83

.contains("scheduled.task.executions")

84

.hasSize(2);

85

}

86

87

@Test

88

void testTimeoutBehavior() {

89

TestClock clock = TestClock.create();

90

TimeoutService service = new TimeoutService(openTelemetry, clock);

91

92

// Start an operation with 30-second timeout

93

clock.setTime(Instant.parse("2023-01-01T12:00:00Z"));

94

service.startLongRunningOperation();

95

96

// Advance past timeout

97

clock.advance(Duration.ofSeconds(35));

98

service.checkForTimeouts();

99

100

// Verify timeout span

101

assertThat(spanExporter.getFinishedSpanItems())

102

.first()

103

.hasName("long.running.operation")

104

.hasStatusSatisfying(status ->

105

status.hasCode(StatusCode.ERROR)

106

.hasDescription("Operation timed out")

107

);

108

}

109

110

@Test

111

void testMetricCollectionTiming() {

112

TestClock clock = TestClock.create();

113

114

// Configure metric reader with test clock

115

InMemoryMetricReader reader = InMemoryMetricReader.builder()

116

.setClock(clock)

117

.build();

118

119

SdkMeterProvider meterProvider = SdkMeterProvider.builder()

120

.registerMetricReader(reader)

121

.setClock(clock)

122

.build();

123

124

Meter meter = meterProvider.get("test");

125

LongCounter counter = meter.counterBuilder("test.counter").build();

126

127

// Record metrics at specific times

128

clock.setTime(Instant.parse("2023-01-01T12:00:00Z"));

129

counter.add(10);

130

131

clock.advance(Duration.ofMinutes(1));

132

counter.add(5);

133

134

// Collect metrics and verify timestamps

135

Collection<MetricData> metrics = reader.collectAllMetrics();

136

// Verify metric timestamps align with controlled time

137

}

138

```

139

140

### Context Storage Provider

141

142

Configurable context storage provider that allows switching context storage implementations during tests for testing context propagation and isolation.

143

144

```java { .api }

145

class SettableContextStorageProvider implements ContextStorageProvider {

146

// Static configuration methods

147

static void setContextStorage(ContextStorage storage);

148

static ContextStorage getContextStorage();

149

150

// ContextStorageProvider interface method

151

ContextStorage get();

152

}

153

```

154

155

Usage examples:

156

157

```java

158

// Configure context storage for testing

159

@BeforeEach

160

void setUp() {

161

// Set up thread-local context storage for isolation

162

SettableContextStorageProvider.setContextStorage(

163

ContextStorage.defaultStorage()

164

);

165

}

166

167

@Test

168

void testContextPropagation() {

169

OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();

170

Tracer tracer = openTelemetry.getTracer("test");

171

172

// Create parent span

173

Span parentSpan = tracer.spanBuilder("parent").startSpan();

174

175

try (Scope scope = parentSpan.makeCurrent()) {

176

// Context should propagate to child operations

177

MyService service = new MyService(openTelemetry);

178

service.performOperation(); // Should create child span

179

180

// Verify parent-child relationship

181

assertThat(spanExporter.getFinishedSpanItems())

182

.hasSize(1)

183

.first()

184

.hasParent(parentSpan);

185

} finally {

186

parentSpan.end();

187

}

188

}

189

190

@Test

191

void testContextIsolation() {

192

// Test that contexts don't leak between operations

193

OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();

194

Tracer tracer = openTelemetry.getTracer("test");

195

196

// First operation with its own context

197

Span span1 = tracer.spanBuilder("operation-1").startSpan();

198

try (Scope scope1 = span1.makeCurrent()) {

199

performFirstOperation();

200

} finally {

201

span1.end();

202

}

203

204

// Second operation should not see first operation's context

205

Span span2 = tracer.spanBuilder("operation-2").startSpan();

206

try (Scope scope2 = span2.makeCurrent()) {

207

performSecondOperation();

208

} finally {

209

span2.end();

210

}

211

212

// Verify no cross-contamination

213

List<SpanData> spans = spanExporter.getFinishedSpanItems();

214

assertThat(spans).hasSize(2);

215

assertThat(spans.get(0)).hasNoParent();

216

assertThat(spans.get(1)).hasNoParent();

217

}

218

219

// Custom context storage for advanced testing scenarios

220

@Test

221

void testCustomContextStorage() {

222

// Create custom context storage that tracks access

223

TrackingContextStorage trackingStorage = new TrackingContextStorage();

224

SettableContextStorageProvider.setContextStorage(trackingStorage);

225

226

OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();

227

Tracer tracer = openTelemetry.getTracer("test");

228

229

Span span = tracer.spanBuilder("tracked-operation").startSpan();

230

try (Scope scope = span.makeCurrent()) {

231

// Perform operations that should access context

232

performTrackedOperation();

233

} finally {

234

span.end();

235

}

236

237

// Verify context access patterns

238

assertThat(trackingStorage.getAccessCount()).isGreaterThan(0);

239

assertThat(trackingStorage.getLastAccessedContext()).isNotNull();

240

}

241

```

242

243

### Integration with Other Testing Utilities

244

245

Examples showing how time and context utilities work together with other testing components:

246

247

```java

248

@Test

249

void testCompleteTemporalScenario() {

250

// Set up controlled time and context

251

TestClock clock = TestClock.create(Instant.parse("2023-01-01T09:00:00Z"));

252

SettableContextStorageProvider.setContextStorage(ContextStorage.defaultStorage());

253

254

// Configure OpenTelemetry with test utilities

255

InMemorySpanExporter spanExporter = InMemorySpanExporter.create();

256

InMemoryMetricReader metricReader = InMemoryMetricReader.create();

257

258

OpenTelemetrySdk sdk = OpenTelemetrySdk.builder()

259

.setTracerProvider(

260

SdkTracerProvider.builder()

261

.setClock(clock)

262

.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())

263

.build())

264

.setMeterProvider(

265

SdkMeterProvider.builder()

266

.setClock(clock)

267

.registerMetricReader(metricReader)

268

.build())

269

.build();

270

271

// Simulate time-based business logic

272

TimedBusinessService service = new TimedBusinessService(sdk, clock);

273

274

// Execute operation at 9:00 AM

275

service.startDailyProcessing();

276

277

// Advance to 9:30 AM

278

clock.advance(Duration.ofMinutes(30));

279

service.performMidProcessingCheck();

280

281

// Advance to 10:00 AM

282

clock.advance(Duration.ofMinutes(30));

283

service.completeDailyProcessing();

284

285

// Verify temporal correctness

286

List<SpanData> spans = spanExporter.getFinishedSpanItems();

287

assertThat(spans)

288

.extracting(SpanData::getName)

289

.containsExactly(

290

"daily.processing.start",

291

"mid.processing.check",

292

"daily.processing.complete"

293

);

294

295

// Verify timing relationships

296

assertThat(spans.get(0)).startsAt(Instant.parse("2023-01-01T09:00:00Z"));

297

assertThat(spans.get(1)).startsAt(Instant.parse("2023-01-01T09:30:00Z"));

298

assertThat(spans.get(2)).startsAt(Instant.parse("2023-01-01T10:00:00Z"));

299

300

// Verify metrics collected at correct times

301

Collection<MetricData> metrics = metricReader.collectAllMetrics();

302

assertThat(metrics)

303

.filteredOn(metric -> "processing.duration".equals(metric.getName()))

304

.hasSize(1);

305

}

306

307

@Test

308

void testConcurrentContextIsolation() {

309

TestClock clock = TestClock.create();

310

311

// Set up concurrent context isolation

312

SettableContextStorageProvider.setContextStorage(

313

new ThreadLocalContextStorage()

314

);

315

316

OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();

317

318

// Execute concurrent operations

319

CountDownLatch latch = new CountDownLatch(3);

320

ExecutorService executor = Executors.newFixedThreadPool(3);

321

322

for (int i = 0; i < 3; i++) {

323

final int operationId = i;

324

executor.submit(() -> {

325

try {

326

Tracer tracer = openTelemetry.getTracer("test");

327

Span span = tracer.spanBuilder("concurrent-operation-" + operationId).startSpan();

328

329

try (Scope scope = span.makeCurrent()) {

330

// Each thread should have isolated context

331

performConcurrentOperation(operationId);

332

Thread.sleep(100); // Simulate work

333

} finally {

334

span.end();

335

latch.countDown();

336

}

337

} catch (InterruptedException e) {

338

Thread.currentThread().interrupt();

339

}

340

});

341

}

342

343

// Wait for completion

344

assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();

345

346

// Verify each operation created its own span without interference

347

List<SpanData> spans = spanExporter.getFinishedSpanItems();

348

assertThat(spans).hasSize(3);

349

assertThat(spans).allSatisfy(span -> assertThat(span).hasNoParent());

350

351

executor.shutdown();

352

}

353

```

354

355

## Types

356

357

```java { .api }

358

// Time control interface

359

interface Clock {

360

/**

361

* Returns the current epoch time in milliseconds.

362

*/

363

long now();

364

365

/**

366

* Returns the current time in nanoseconds for high-resolution timing.

367

*/

368

long nanoTime();

369

}

370

371

// Context storage interfaces

372

interface ContextStorageProvider {

373

/**

374

* Returns the ContextStorage implementation to use.

375

*/

376

ContextStorage get();

377

}

378

379

interface ContextStorage {

380

/**

381

* Returns the default context storage implementation.

382

*/

383

static ContextStorage defaultStorage();

384

385

/**

386

* Attaches a context, returning a scope for cleanup.

387

*/

388

Scope attach(Context context);

389

390

/**

391

* Returns the current context.

392

*/

393

Context current();

394

}

395

396

// Time manipulation types

397

class Duration {

398

static Duration of(long amount, TemporalUnit unit);

399

static Duration ofNanos(long nanos);

400

static Duration ofSeconds(long seconds);

401

static Duration ofMinutes(long minutes);

402

static Duration ofHours(long hours);

403

static Duration ofDays(long days);

404

}

405

406

enum TimeUnit {

407

NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS;

408

409

long toNanos(long duration);

410

long toMicros(long duration);

411

long toMillis(long duration);

412

long toSeconds(long duration);

413

}

414

415

class Instant {

416

static Instant now();

417

static Instant parse(CharSequence text);

418

static Instant ofEpochMilli(long epochMilli);

419

static Instant ofEpochSecond(long epochSecond);

420

421

long toEpochMilli();

422

long getEpochSecond();

423

int getNano();

424

Instant plus(Duration duration);

425

Instant minus(Duration duration);

426

}

427

428

// Context propagation types

429

interface Context {

430

static Context current();

431

static Context root();

432

433

<T> T get(ContextKey<T> key);

434

<T> Context with(ContextKey<T> key, T value);

435

}

436

437

interface Scope extends AutoCloseable {

438

void close();

439

}

440

441

class ContextKey<T> {

442

static <T> ContextKey<T> named(String name);

443

String getName();

444

}

445

```

446

447

## Best Practices

448

449

### Time Control Best Practices

450

451

```java

452

// Use fixed start times for deterministic tests

453

TestClock clock = TestClock.create(Instant.parse("2023-01-01T00:00:00Z"));

454

455

// Advance time in meaningful increments

456

clock.advance(Duration.ofSeconds(1)); // For second-precision tests

457

clock.advance(Duration.ofMillis(100)); // For millisecond-precision tests

458

459

// Reset clock state between tests

460

@BeforeEach

461

void resetClock() {

462

clock.setTime(Instant.parse("2023-01-01T00:00:00Z"));

463

}

464

```

465

466

### Context Isolation Best Practices

467

468

```java

469

// Ensure context cleanup in tests

470

@AfterEach

471

void cleanupContext() {

472

// Reset to default storage if changed

473

SettableContextStorageProvider.setContextStorage(ContextStorage.defaultStorage());

474

}

475

476

// Use try-with-resources for context scopes

477

try (Scope scope = span.makeCurrent()) {

478

// Operations within context

479

} // Automatic cleanup

480

```