Skip to content
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

Replace block executor registry with dependency injection #532

Merged
merged 5 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/docs/docs/dev/04-guides/06-jayvee-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {
JayveeExecExtension,
} from '@jvalue/jayvee-execution';

export class MyExecExtension implements JayveeExecExtension {
export class MyExecExtension extends JayveeExecExtension {
getBlockExecutors(): BlockExecutorClass[] {
return [];
}
Expand All @@ -72,7 +72,7 @@ In `libs/extensions/std/exec/src/extension.ts`:

import { MyExecExtension } from '@jvalue/jayvee-extensions/<extension-name>/exec';

export class StdExecExtension implements JayveeExecExtension {
export class StdExecExtension extends JayveeExecExtension {
private readonly wrappedExtensions: JayveeExecExtension[] = [
// ...
// Register your execution extension here:
Expand Down Expand Up @@ -177,7 +177,7 @@ In `libs/extensions/<extension-name>/exec/src/extension.ts`:

import { MyExtractorExecutor } from './lib/my-extractor-executor';

export class MyExecExtension implements JayveeExecExtension {
export class MyExecExtension extends JayveeExecExtension {
getBlockExecutors(): BlockExecutorClass[] {
return [
// ...
Expand Down
33 changes: 11 additions & 22 deletions apps/docs/docs/dev/12-jayvee-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ These kind of tests are mainly located inside the [language-server](https://gith
The testing utils are located inside the `language-server` in a dedicated [test folder](https://github.com/jvalue/jayvee/tree/main/libs/language-server/src/test).
These utils can be imported using `@jvalue/jayvee-language-server/test` and contain the following parts:

[**langium-utils.ts**](https://github.com/jvalue/jayvee/blob/main/libs/language-server/src/test/langium-utils.ts):
[**langium-utils.ts**](https://github.com/jvalue/jayvee/blob/main/libs/language-server/src/test/langium-utils.ts):
This utils file contains two functions:
- `parseHelper` to simplify parsing the input (content of a *.jv file) and returning the corresponding `LangiumDocument`, and
- `validationHelper` parse and validate the created document.
Expand Down Expand Up @@ -100,34 +100,23 @@ pipeline Pipeline {
### Existing tests
Currently there are already tests for the following parts:
- Language-server validation checks (located [here](https://github.com/jvalue/jayvee/tree/main/libs/language-server/src/lib/validation))
- Language-server constraint validation (located [here](https://github.com/jvalue/jayvee/tree/dev/libs/language-server/src/lib/constraint))
- Custom block (property) validation of the three existing extensions (std extension located [here](https://github.com/jvalue/jayvee/blob/dev/libs/extensions/std/lang/src))
- Grammar validation tests for all official full examples from the [/example](https://github.com/jvalue/jayvee/tree/main/example) folder (located [here](https://github.com/jvalue/jayvee/blob/dev/libs/extensions/std/lang/src/example-validation.spec.ts))
- Grammar validation tests for all block examples of the std extension (located [here](https://github.com/jvalue/jayvee/blob/dev/libs/extensions/std/lang/src/meta-inf-example-validation.spec.ts))
- Language-server constraint validation (located [here](https://github.com/jvalue/jayvee/tree/main/libs/language-server/src/lib/constraint))
- Custom block (property) validation of the three existing extensions (std extension located [here](https://github.com/jvalue/jayvee/blob/main/libs/extensions/std/lang/src))
- Grammar validation tests for all official full examples from the [/example](https://github.com/jvalue/jayvee/tree/main/example) folder (located [here](https://github.com/jvalue/jayvee/blob/main/libs/extensions/std/lang/src/example-validation.spec.ts))
- Grammar validation tests for all block examples of the std extension (located [here](https://github.com/jvalue/jayvee/blob/main/libs/extensions/std/lang/src/meta-inf-example-validation.spec.ts))

## Execution tests
These kind of tests are mainly located inside the [interpreter](https://github.com/jvalue/jayvee/tree/main/libs/language-server), the [interpreter-lib](https://github.com/jvalue/jayvee/tree/dev/libs/interpreter-lib), the [execution lib](https://github.com/jvalue/jayvee/tree/dev/libs/execution) as well as the execution parts of each extension (for example [std/exec](https://github.com/jvalue/jayvee/tree/main/libs/extensions/std/exec)).
These kind of tests are mainly located inside the [interpreter](https://github.com/jvalue/jayvee/tree/main/libs/language-server), the [interpreter-lib](https://github.com/jvalue/jayvee/tree/main/libs/interpreter-lib), the [execution lib](https://github.com/jvalue/jayvee/tree/main/libs/execution) as well as the execution parts of each extension (for example [std/exec](https://github.com/jvalue/jayvee/tree/main/libs/extensions/std/exec)).

### Testing utils
The testing utils for execution tests are spread between the extensions, with the interfaces and base utils located inside the [execution lib](https://github.com/jvalue/jayvee/tree/dev/libs/execution).
The testing utils for execution tests are spread between the extensions, with the interfaces and base utils located inside the [execution lib](https://github.com/jvalue/jayvee/tree/main/libs/execution).
They can be imported using `@jvalue/jayvee-extensions/rdbms/test`, `@jvalue/jayvee-extensions/std/test` and `@jvalue/jayvee-execution/test`.

[**utils.ts**](https://github.com/jvalue/jayvee/blob/dev/libs/execution/test/utils.ts):
At the moment this only contains two functions:
- `clearBlockExecutorRegistry` for clearing the registry containing all `BlockExecutor`s, and
- `clearConstraintExecutorRegistry` clearing the corresponding `ConstraintExecutor`s registry.
They are required in case the tested method initializes Jayvee itself (see [smoke test](#existing-tests-1)).

[**test-logger.ts**](https://github.com/jvalue/jayvee/blob/dev/libs/execution/test/test-logger.ts):
This contains a subclass of the [`DefaultLogger`](https://github.com/jvalue/jayvee/blob/dev/libs/execution/src/lib/logging/default-logger.ts) used for tests which require a `Logger` implementation. The `TestLogger` contains the following tests functionality:
- `getLogs`: retrieve the cached logs that the logger received.
- `clearLogs`: clear the cached logs.

[**block-executor-mocks.ts**](https://github.com/jvalue/jayvee/blob/dev/libs/execution/test/block-executor-mock.ts):
joluj marked this conversation as resolved.
Show resolved Hide resolved
[**block-executor-mocks.ts**](https://github.com/jvalue/jayvee/blob/main/libs/execution/test/block-executor-mock.ts):
`BlockExecutorMock` interface for defining mocks for `AbstractBlockExecutor`. Generally only loader and executor blocks require mocks, because they interact with "the outside world" (i.e. `HttpExtractor` making http calls).
Due to how vastly different each `BlockExecutor` can be, this interface is very simple, containing only a `setup(...args: unknown[])` and a `restore()` method. See below for existing implementations.

[**rdbms/exec/test**](https://github.com/jvalue/jayvee/tree/dev/libs/extensions/rdbms/exec/test):
[**rdbms/exec/test**](https://github.com/jvalue/jayvee/tree/main/libs/extensions/rdbms/exec/test):
Contains the implementation of `BlockExecutorMock` for `PostgresLoaderExecutor` and `SQLiteLoaderExecutor`.
Both of these executors are mocked using `jest.mock` to mock the corresponding libraries (`pg` and `sqlite3`)
**Usage:**
Expand Down Expand Up @@ -187,7 +176,7 @@ describe('Dummy describe', () => {
});
```

[**std/exec/test/mocks**](https://github.com/jvalue/jayvee/tree/dev/libs/extensions/std/exec/test):
[**std/exec/test/mocks**](https://github.com/jvalue/jayvee/tree/main/libs/extensions/std/exec/test):
Contains the implementation of `BlockExecutorMock` for `HttpExtractorExecutorMock`.
This implementation uses [nock](https://www.npmjs.com/package/nock) for mocking HTTP(S) responses.
The `setup` method is further specified requiring one parameter `registerMocks: () => Array<nock.Scope>`, which returns all used `nock.Scope` (i.e. the return value of `nock('<URL>')`), see usage below:
Expand Down Expand Up @@ -251,4 +240,4 @@ describe('Dummy describe', () => {

### Existing tests
Currently there are already tests for the following parts:
- Smoke test for official examples (located [here](https://github.com/jvalue/jayvee/blob/dev/apps/interpreter/src/examples-smoke-test.spec.ts))
- Smoke test for official examples (located [here](https://github.com/jvalue/jayvee/blob/main/apps/interpreter/src/examples-smoke-test.spec.ts))
10 changes: 1 addition & 9 deletions apps/interpreter/src/examples-smoke-test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@

import * as path from 'path';

import {
clearBlockExecutorRegistry,
clearConstraintExecutorRegistry,
processExitMockImplementation,
} from '@jvalue/jayvee-execution/test';
import { processExitMockImplementation } from '@jvalue/jayvee-execution/test';
import {
PostgresLoaderExecutorMock,
SQLiteLoaderExecutorMock,
Expand Down Expand Up @@ -72,10 +68,6 @@ describe('jv example smoke tests', () => {
httpExtractorMock.restore();
postgresLoaderMock.restore();
sqliteLoaderMock.restore();

// Clear registries
clearBlockExecutorRegistry();
clearConstraintExecutorRegistry();
});

it('should have no errors when executing cars.jv example', async () => {
Expand Down
8 changes: 0 additions & 8 deletions apps/interpreter/src/parse-only.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ import * as fs from 'node:fs';
import * as path from 'path';
import * as process from 'process';

import {
clearBlockExecutorRegistry,
clearConstraintExecutorRegistry,
} from '@jvalue/jayvee-execution/test';
import {
RunOptions,
interpretModel,
Expand Down Expand Up @@ -52,10 +48,6 @@ describe('Parse Only', () => {
jest.spyOn(process, 'exit').mockImplementation(() => {
throw new Error();
});

// Reset jayvee specific stuff
clearBlockExecutorRegistry();
clearConstraintExecutorRegistry();
});

it('should exit with 0 on a valid option', async () => {
Expand Down
7 changes: 3 additions & 4 deletions libs/execution/src/lib/blocks/block-execution-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import {
PipelineWrapper,
} from '@jvalue/jayvee-language-server';

import { ExecutionContext } from '../execution-context';
import { type ExecutionContext } from '../execution-context';
import { Logger } from '../logging/logger';
import { IOTypeImplementation, NONE } from '../types';

// eslint-disable-next-line import/no-cycle
import { createBlockExecutor } from './block-executor-registry';
import * as R from './execution-result';

export interface ExecutionOrderItem {
Expand Down Expand Up @@ -94,7 +92,8 @@ export async function executeBlock(
return R.ok(null);
}

const blockExecutor = createBlockExecutor(block);
const blockExecutor =
executionContext.executionExtension.createBlockExecutor(block);

const startTime = new Date();

Expand Down
57 changes: 0 additions & 57 deletions libs/execution/src/lib/blocks/block-executor-registry.ts

This file was deleted.

2 changes: 1 addition & 1 deletion libs/execution/src/lib/blocks/block-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IOType, isBlockDefinition } from '@jvalue/jayvee-language-server';

import { isBlockTargetedForDebugLogging } from '../debugging/debug-configuration';
import { DebugLogVisitor } from '../debugging/debug-log-visitor';
import { ExecutionContext } from '../execution-context';
import { type ExecutionContext } from '../execution-context';
import { IOTypeImplementation } from '../types/io-types/io-type-implementation';

import * as R from './execution-result';
Expand Down
5 changes: 2 additions & 3 deletions libs/execution/src/lib/blocks/composite-block-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ import {
isCompositeBlocktypeDefinition,
} from '@jvalue/jayvee-language-server';

import { ExecutionContext } from '../execution-context';
import { IOTypeImplementation } from '../types';
import { type ExecutionContext } from '../execution-context';
import { type IOTypeImplementation } from '../types';

// eslint-disable-next-line import/no-cycle
import { executeBlocks } from './block-execution-util';
import { AbstractBlockExecutor, BlockExecutor } from './block-executor';
import { BlockExecutorClass } from './block-executor-class';
Expand Down
1 change: 0 additions & 1 deletion libs/execution/src/lib/blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@

export * from './block-executor';
export * from './block-executor-class';
export * from './block-executor-registry';
export * from './execution-result';
export * from './block-execution-util';
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg
//
// SPDX-License-Identifier: AGPL-3.0-only

import { strict as assert } from 'assert';

import {
ConstraintDefinition,
Registry,
isExpressionConstraintDefinition,
isTypedConstraintDefinition,
} from '@jvalue/jayvee-language-server';
import { assertUnreachable } from 'langium';

import { ConstraintExecutor } from './constraint-executor';
import { AllowlistConstraintExecutor } from './executors/allowlist-constraint-executor';
import { DenylistConstraintExecutor } from './executors/denylist-constraint-executor';
import { ExpressionConstraintExecutor } from './executors/expression-constraint-executor';
import { LengthConstraintExecutor } from './executors/length-constraint-executor';
import { RangeConstraintExecutor } from './executors/range-constraint-executor';
import { RegexConstraintExecutor } from './executors/regex-constraint-executor';
import { TypedConstraintExecutorClass } from './typed-constraint-executor-class';

export interface JayveeConstraintExtension {
registerConstraintExecutor(executorClass: TypedConstraintExecutorClass): void;

getConstraintExecutors(): TypedConstraintExecutorClass<ConstraintExecutor>[];

createConstraintExecutor(
constraint: ConstraintDefinition,
): ConstraintExecutor;
}

export class DefaultConstraintExtension
extends Registry<TypedConstraintExecutorClass>
implements JayveeConstraintExtension
{
constructor() {
super();

this.registerConstraintExecutor(AllowlistConstraintExecutor);
this.registerConstraintExecutor(DenylistConstraintExecutor);
this.registerConstraintExecutor(RegexConstraintExecutor);
this.registerConstraintExecutor(LengthConstraintExecutor);
this.registerConstraintExecutor(RangeConstraintExecutor);
}

registerConstraintExecutor(executorClass: TypedConstraintExecutorClass) {
this.register(executorClass.type, executorClass);
}

getConstraintExecutors() {
return this.getAll();
}

createConstraintExecutor(
constraint: ConstraintDefinition,
): ConstraintExecutor {
if (isTypedConstraintDefinition(constraint)) {
const constraintType = constraint.type.ref?.name;
assert(
constraintType !== undefined,
`Could not resolve reference to constraint type of ${constraint.name}`,
);
const constraintExecutor = this.get(constraintType);
assert(
constraintExecutor !== undefined,
`No executor was registered for constraint type ${constraintType}`,
);

return new constraintExecutor();
} else if (isExpressionConstraintDefinition(constraint)) {
return new ExpressionConstraintExecutor(constraint);
}
assertUnreachable(constraint);
}
}
65 changes: 0 additions & 65 deletions libs/execution/src/lib/constraints/constraint-executor-registry.ts

This file was deleted.

Loading
Loading