or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

config-storage.mdengine-implementation.mdhierarchical-engine.mdindex.mdtest-descriptors.mdtest-discovery.mdtest-execution.md

hierarchical-engine.mddocs/

0

# Hierarchical Engine Support

1

2

Framework for building hierarchical test engines with parallel execution, resource management, and structured execution contexts. This support package provides abstractions for engines that organize tests in tree structures with sophisticated execution control.

3

4

## Capabilities

5

6

### HierarchicalTestEngine

7

8

Abstract base class for implementing test engines with hierarchical test organization, providing execution orchestration and lifecycle management.

9

10

```java { .api }

11

/**

12

* Abstract base class for hierarchical test engines with tree-structured test organization.

13

* @param C the execution context type extending EngineExecutionContext

14

*/

15

public abstract class HierarchicalTestEngine<C extends EngineExecutionContext>

16

implements TestEngine {

17

18

/**

19

* Final implementation of test execution using hierarchical framework.

20

* @param request the execution request

21

*/

22

@Override

23

public final void execute(ExecutionRequest request);

24

25

/**

26

* Create the root execution context for test execution.

27

* @param request the execution request

28

* @return root execution context

29

*/

30

protected abstract C createExecutionContext(ExecutionRequest request);

31

32

/**

33

* Create the executor service for managing test execution.

34

* @param request the execution request

35

* @return hierarchical test executor service

36

*/

37

protected HierarchicalTestExecutorService createExecutorService(ExecutionRequest request);

38

39

/**

40

* Create the throwable collector factory for error handling.

41

* @param request the execution request

42

* @return throwable collector factory

43

*/

44

protected ThrowableCollector.Factory createThrowableCollectorFactory(ExecutionRequest request);

45

}

46

```

47

48

**Usage Example:**

49

50

```java

51

public class MyHierarchicalEngine extends HierarchicalTestEngine<MyExecutionContext> {

52

53

@Override

54

public String getId() {

55

return "my-hierarchical-engine";

56

}

57

58

@Override

59

public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) {

60

// Discovery implementation

61

return new MyEngineDescriptor(uniqueId);

62

}

63

64

@Override

65

protected MyExecutionContext createExecutionContext(ExecutionRequest request) {

66

return new MyExecutionContext(

67

request.getConfigurationParameters(),

68

request.getStore()

69

);

70

}

71

72

@Override

73

protected HierarchicalTestExecutorService createExecutorService(ExecutionRequest request) {

74

boolean parallelExecution = request.getConfigurationParameters()

75

.getBoolean("parallel.enabled").orElse(false);

76

77

if (parallelExecution) {

78

return new ForkJoinPoolHierarchicalTestExecutorService();

79

} else {

80

return new SameThreadHierarchicalTestExecutorService();

81

}

82

}

83

}

84

```

85

86

### Node Interface

87

88

Core interface representing an individual node in the hierarchical test execution tree, with lifecycle methods and execution control.

89

90

```java { .api }

91

/**

92

* Interface for nodes in hierarchical test execution, providing lifecycle methods and execution control.

93

* @param C the execution context type

94

*/

95

public interface Node<C extends EngineExecutionContext> {

96

97

/**

98

* Prepare execution context before test execution begins.

99

* @param context the current execution context

100

* @return updated execution context

101

* @throws Exception if preparation fails

102

*/

103

default C prepare(C context) throws Exception {

104

return context;

105

}

106

107

/**

108

* Determine if this node should be skipped during execution.

109

* @param context the current execution context

110

* @return skip result indicating whether to skip and reason

111

* @throws Exception if skip determination fails

112

*/

113

default SkipResult shouldBeSkipped(C context) throws Exception {

114

return SkipResult.doNotSkip();

115

}

116

117

/**

118

* Execute before behavior (setup) for this node.

119

* @param context the current execution context

120

* @return updated execution context

121

* @throws Exception if before behavior fails

122

*/

123

default C before(C context) throws Exception {

124

return context;

125

}

126

127

/**

128

* Execute the main behavior of this node.

129

* @param context the current execution context

130

* @param dynamicTestExecutor executor for registering dynamic tests

131

* @return updated execution context

132

* @throws Exception if execution fails

133

*/

134

default C execute(C context, DynamicTestExecutor dynamicTestExecutor) throws Exception {

135

return context;

136

}

137

138

/**

139

* Execute after behavior (teardown) for this node.

140

* @param context the current execution context

141

* @throws Exception if after behavior fails

142

*/

143

default void after(C context) throws Exception {

144

// Default: no after behavior

145

}

146

147

/**

148

* Clean up resources after execution completes.

149

* @param context the current execution context

150

* @throws Exception if cleanup fails

151

*/

152

default void cleanUp(C context) throws Exception {

153

// Default: no cleanup

154

}

155

156

/**

157

* Wrap around the execution of child nodes.

158

* @param context the current execution context

159

* @param invocation the child execution invocation to wrap

160

* @throws Exception if around behavior fails

161

*/

162

default void around(C context, Invocation<C> invocation) throws Exception {

163

invocation.proceed(context);

164

}

165

166

/**

167

* Get exclusive resources required by this node.

168

* @return set of exclusive resources

169

*/

170

default Set<ExclusiveResource> getExclusiveResources() {

171

return Collections.emptySet();

172

}

173

174

/**

175

* Get the preferred execution mode for this node.

176

* @return execution mode (SAME_THREAD or CONCURRENT)

177

*/

178

default ExecutionMode getExecutionMode() {

179

return ExecutionMode.SAME_THREAD;

180

}

181

182

/**

183

* Result of skip determination.

184

*/

185

class SkipResult {

186

public static SkipResult skip(String reason);

187

public static SkipResult doNotSkip();

188

189

public boolean isSkipped();

190

public Optional<String> getReason();

191

}

192

193

/**

194

* Execution mode for nodes.

195

*/

196

enum ExecutionMode {

197

/** Execute in same thread as parent */

198

SAME_THREAD,

199

/** Execute concurrently with siblings */

200

CONCURRENT

201

}

202

203

/**

204

* Interface for registering dynamic tests during execution.

205

*/

206

interface DynamicTestExecutor {

207

void execute(TestDescriptor testDescriptor);

208

}

209

210

/**

211

* Represents an execution invocation that can be wrapped.

212

* @param C the execution context type

213

*/

214

interface Invocation<C> {

215

C proceed(C context) throws Exception;

216

}

217

}

218

```

219

220

**Usage Example:**

221

222

```java

223

public class MyTestNode implements Node<MyExecutionContext> {

224

private final Method testMethod;

225

private final Object testInstance;

226

227

@Override

228

public SkipResult shouldBeSkipped(MyExecutionContext context) throws Exception {

229

if (testMethod.isAnnotationPresent(Disabled.class)) {

230

return SkipResult.skip("Test is disabled");

231

}

232

return SkipResult.doNotSkip();

233

}

234

235

@Override

236

public MyExecutionContext before(MyExecutionContext context) throws Exception {

237

// Set up test instance

238

return context.withTestInstance(createTestInstance());

239

}

240

241

@Override

242

public MyExecutionContext execute(MyExecutionContext context,

243

DynamicTestExecutor dynamicTestExecutor) throws Exception {

244

// Execute test method

245

testMethod.invoke(context.getTestInstance());

246

247

// Register dynamic tests if needed

248

if (isDynamicTestContainer()) {

249

generateDynamicTests().forEach(dynamicTestExecutor::execute);

250

}

251

252

return context;

253

}

254

255

@Override

256

public void after(MyExecutionContext context) throws Exception {

257

// Clean up test instance resources

258

cleanupTestInstance(context.getTestInstance());

259

}

260

261

@Override

262

public Set<ExclusiveResource> getExclusiveResources() {

263

return Set.of(ExclusiveResource.SYSTEM_PROPERTIES);

264

}

265

266

@Override

267

public ExecutionMode getExecutionMode() {

268

return testMethod.isAnnotationPresent(Parallel.class)

269

? ExecutionMode.CONCURRENT

270

: ExecutionMode.SAME_THREAD;

271

}

272

}

273

```

274

275

### Execution Context

276

277

Base interface for execution contexts that carry state through the hierarchical execution process.

278

279

```java { .api }

280

/**

281

* Base interface for execution contexts in hierarchical test engines.

282

*/

283

public interface EngineExecutionContext {

284

/**

285

* Get the configuration parameters for execution.

286

* @return configuration parameters

287

*/

288

ConfigurationParameters getConfigurationParameters();

289

290

/**

291

* Get the engine execution listener.

292

* @return execution listener

293

*/

294

EngineExecutionListener getEngineExecutionListener();

295

296

/**

297

* Get the hierarchical store for this context level.

298

* @return namespaced hierarchical store

299

*/

300

NamespacedHierarchicalStore<Namespace> getStore();

301

}

302

```

303

304

### Executor Services

305

306

Services for managing the execution of hierarchical test structures with support for parallel and sequential execution.

307

308

```java { .api }

309

/**

310

* Service for executing hierarchical test structures.

311

*/

312

public interface HierarchicalTestExecutorService {

313

/**

314

* Submit a test task for execution.

315

* @param task the test task to execute

316

* @return future representing the task execution

317

*/

318

Future<?> submit(TestTask task);

319

320

/**

321

* Invoke all tasks and wait for completion.

322

* @param tasks the tasks to execute

323

* @throws InterruptedException if interrupted while waiting

324

*/

325

void invokeAll(Collection<? extends TestTask> tasks) throws InterruptedException;

326

327

/**

328

* Close the executor service and clean up resources.

329

*/

330

void close();

331

}

332

333

/**

334

* Same-thread implementation of hierarchical test executor service.

335

*/

336

public class SameThreadHierarchicalTestExecutorService implements HierarchicalTestExecutorService {

337

// Executes all tasks sequentially in the current thread

338

}

339

```

340

341

### Resource Management

342

343

System for managing exclusive resources and preventing conflicts between concurrent test execution.

344

345

```java { .api }

346

/**

347

* Represents an exclusive resource that tests may require.

348

*/

349

public class ExclusiveResource {

350

/**

351

* Create an exclusive resource with a key.

352

* @param key the resource key

353

* @return exclusive resource

354

*/

355

public static ExclusiveResource from(String key);

356

357

/**

358

* Get the resource key.

359

* @return resource key

360

*/

361

public String getKey();

362

363

// Predefined common resources

364

public static final ExclusiveResource SYSTEM_PROPERTIES;

365

public static final ExclusiveResource SYSTEM_OUT;

366

public static final ExclusiveResource SYSTEM_ERR;

367

public static final ExclusiveResource LOCALE;

368

public static final ExclusiveResource TIME_ZONE;

369

}

370

371

/**

372

* Interface for resource locks.

373

*/

374

public interface ResourceLock {

375

/**

376

* Acquire the lock.

377

* @throws InterruptedException if interrupted while acquiring

378

*/

379

void acquire() throws InterruptedException;

380

381

/**

382

* Release the lock.

383

*/

384

void release();

385

}

386

387

/**

388

* No-operation lock implementation.

389

*/

390

public class NopLock implements ResourceLock {

391

public static final NopLock INSTANCE = new NopLock();

392

393

@Override

394

public void acquire() { /* no-op */ }

395

396

@Override

397

public void release() { /* no-op */ }

398

}

399

400

/**

401

* Lock for a single exclusive resource.

402

*/

403

public class SingleLock implements ResourceLock {

404

public SingleLock(ExclusiveResource resource);

405

// Implementation details...

406

}

407

```

408

409

### Parallel Execution Configuration

410

411

Configuration system for controlling parallel test execution behavior.

412

413

```java { .api }

414

/**

415

* Configuration for parallel test execution.

416

*/

417

public interface ParallelExecutionConfiguration {

418

/**

419

* Get the parallelism level.

420

* @return number of parallel threads

421

*/

422

int getParallelism();

423

424

/**

425

* Get the minimum runnable count.

426

* @return minimum runnable tasks to maintain

427

*/

428

int getMinimumRunnable();

429

430

/**

431

* Get the maximum pool size.

432

* @return maximum thread pool size

433

*/

434

int getMaxPoolSize();

435

436

/**

437

* Get the core pool size.

438

* @return core thread pool size

439

*/

440

int getCorePoolSize();

441

442

/**

443

* Get the keep alive time in seconds.

444

* @return keep alive time for idle threads

445

*/

446

int getKeepAliveSeconds();

447

}

448

449

/**

450

* Strategy for creating parallel execution configuration.

451

*/

452

public interface ParallelExecutionConfigurationStrategy {

453

/**

454

* Create configuration from configuration parameters.

455

* @param configurationParameters the configuration parameters

456

* @return parallel execution configuration

457

*/

458

ParallelExecutionConfiguration createConfiguration(ConfigurationParameters configurationParameters);

459

}

460

461

/**

462

* Default implementation of parallel execution configuration.

463

*/

464

public class DefaultParallelExecutionConfiguration implements ParallelExecutionConfiguration {

465

public DefaultParallelExecutionConfiguration(ConfigurationParameters configurationParameters);

466

// Implementation details...

467

}

468

```

469

470

### Error Handling

471

472

Sophisticated error collection and handling for hierarchical test execution.

473

474

```java { .api }

475

/**

476

* Collector for gathering and managing throwables during test execution.

477

*/

478

public class ThrowableCollector {

479

/**

480

* Factory for creating throwable collectors.

481

*/

482

public interface Factory {

483

ThrowableCollector create();

484

}

485

486

/**

487

* Execute code and collect any throwables.

488

* @param executable the code to execute

489

*/

490

public void execute(Executable executable);

491

492

/**

493

* Add a throwable to the collection.

494

* @param throwable the throwable to add

495

*/

496

public void add(Throwable throwable);

497

498

/**

499

* Get the first throwable in the collection.

500

* @return optional first throwable

501

*/

502

public Optional<Throwable> getThrowable();

503

504

/**

505

* Check if any throwables have been collected.

506

* @return true if throwables exist

507

*/

508

public boolean isEmpty();

509

510

/**

511

* Assert that no throwables have been collected.

512

* @throws Exception if throwables exist

513

*/

514

public void assertEmpty() throws Exception;

515

516

/**

517

* Executable interface for code that may throw exceptions.

518

*/

519

@FunctionalInterface

520

public interface Executable {

521

void execute() throws Throwable;

522

}

523

}

524

525

/**

526

* OpenTest4J-aware throwable collector with enhanced assertion handling.

527

*/

528

public class OpenTest4JAwareThrowableCollector extends ThrowableCollector {

529

// Enhanced handling for OpenTest4J assertion failures

530

}

531

```

532

533

**Usage Example:**

534

535

```java

536

public class MyContainerNode implements Node<MyExecutionContext> {

537

538

@Override

539

public MyExecutionContext execute(MyExecutionContext context,

540

DynamicTestExecutor dynamicTestExecutor) throws Exception {

541

ThrowableCollector collector = context.getThrowableCollector();

542

543

// Execute multiple child operations, collecting errors

544

collector.execute(() -> setupDatabase());

545

collector.execute(() -> loadTestData());

546

collector.execute(() -> configureSystem());

547

548

// Assert that all setup completed successfully

549

collector.assertEmpty();

550

551

return context;

552

}

553

554

@Override

555

public Set<ExclusiveResource> getExclusiveResources() {

556

return Set.of(

557

ExclusiveResource.from("database"),

558

ExclusiveResource.SYSTEM_PROPERTIES

559

);

560

}

561

562

@Override

563

public ExecutionMode getExecutionMode() {

564

return ExecutionMode.CONCURRENT;

565

}

566

}

567

```