Skip to content

Commit 2080024

Browse files
committed
fixup: upgarding test-harnes
Signed-off-by: Simon Schrottner <[email protected]>
1 parent 5f51211 commit 2080024

File tree

15 files changed

+83
-63
lines changed

15 files changed

+83
-63
lines changed

Diff for: libs/providers/flagd/src/e2e/step-definitions/configSteps.ts

+4
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,9 @@ export const configSteps: Steps = (state: State) => {
3838
expect(configElement).toBe(expected);
3939
},
4040
);
41+
42+
then('we should have an error', () => {
43+
44+
});
4145
};
4246
};

Diff for: libs/providers/flagd/src/e2e/step-definitions/eventSteps.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,25 @@ export const eventSteps: Steps =
3434
then(/^the (.*) event handler should have been executed$/, async (type: string) => {
3535
await waitFor(() => expect(state.events.find((value) => value.type == type)).toBeDefined(), { timeout: 20000 });
3636
expect(state.events.find((value) => value.type == type)).toBeDefined();
37-
state.events = state.events.filter((a) => a.type !== type);
37+
state.events = [];
3838
});
3939

4040
then(/^the (.*) event handler should have been executed within (\d+)ms$/, async (type: string, ms: number) => {
4141
await waitFor(() => expect(state.events.find((value) => value.type == type)).toBeDefined(), { timeout: ms });
4242
const actual = state.events.find((value) => value.type == type);
4343
expect(actual).toBeDefined();
44-
state.events = state.events.filter((a) => a.type !== type);
44+
state.events = [];
4545
console.error('here bin cih');
4646
});
4747

48-
when(/^a (.*) event was fired$/, () => {});
48+
when(/^a (.*) event was fired$/, async (type: string) => {
49+
await waitFor(() => expect(state.events.find((value) => value.type == type)), { timeout: 2000 });
50+
expect(state.events.find((value) => value.type == type)).toBeDefined();
51+
state.events = [];
52+
});
53+
54+
then('the flag should be part of the event payload', async () => {
55+
await waitFor(() => expect(state.events.find((value) => value.type == 'change')), { timeout: 2000 });
56+
state.events = [];
57+
});
4958
};

Diff for: libs/providers/flagd/src/e2e/step-definitions/flagSteps.ts

-11
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,4 @@ export const flagSteps: Steps =
6464
then(/^the variant should be "(.*)"$/, (arg0) => {
6565
expect(state.details?.variant).toBe(arg0);
6666
});
67-
when('the flag was modified', async () => {
68-
await waitFor(
69-
() =>
70-
expect(
71-
state.events.find(
72-
(value) => value.type == 'change' && (value.details?.flagsChanged as string[]).includes(state.flag!.name),
73-
),
74-
).toBeDefined(),
75-
{ timeout: 5000 },
76-
);
77-
});
7867
};

Diff for: libs/providers/flagd/src/e2e/step-definitions/providerSteps.ts

+31-31
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,59 @@ import { OpenFeature } from '@openfeature/server-sdk';
22
import { FlagdContainer } from '../tests/flagdContainer';
33
import { State, Steps } from './state';
44
import { FlagdProvider } from '../../lib/flagd-provider';
5-
6-
type Containers = Record<string, FlagdContainer> & { default: FlagdContainer };
5+
import { waitFor } from "./utils";
76

87
export const providerSteps: Steps =
98
(state: State) =>
109
({ given, when, then }) => {
11-
const containers: Containers = {
12-
default: FlagdContainer.build(),
13-
};
10+
const container: FlagdContainer = FlagdContainer.build();
1411
beforeAll(async () => {
1512
console.log('Setting flagd provider...');
1613

17-
const promises = [];
18-
19-
for (const container of Object.values(containers)) {
20-
promises.push(container.start());
21-
}
22-
23-
return Promise.all(promises);
14+
return container.start();
2415
}, 50000);
2516

2617
afterAll(async () => {
2718
await OpenFeature.close();
28-
for (const container of Object.values(containers)) {
29-
await container.stop();
30-
}
19+
await container.stop();
3120
});
3221

3322
beforeEach(async () => {
34-
const promises = [];
35-
36-
for (const container of Object.values(containers)) {
37-
promises.push(container.start());
23+
if (container.isStarted()) {
24+
return container.start();
3825
}
39-
40-
return Promise.all(promises);
26+
return Promise.resolve();
4127
}, 50000);
42-
43-
function getContainer(providerType: string): FlagdContainer {
44-
if (Object.hasOwn(containers, providerType)) {
45-
return containers[providerType];
28+
afterEach(async () => {
29+
if (state.client) {
30+
await fetch('http://' + container.getLaunchpadUrl() + '/stop');
31+
await new Promise((r) => setTimeout(r, 100));
4632
}
47-
return containers.default;
48-
}
33+
return Promise.resolve();
34+
}, 50000);
4935

5036
given(/a (.*) flagd provider/, async (providerType: string) => {
51-
const container = getContainer(providerType);
5237
const flagdOptions: Record<string, unknown> = {
5338
resolverType: state.resolverType,
39+
deadlineMs: 2000,
5440
};
41+
let type = 'default';
5542
switch (providerType) {
5643
default:
5744
flagdOptions['port'] = container.getPort(state.resolverType);
5845
break;
5946
case 'unavailable':
6047
flagdOptions['port'] = 9999;
6148
break;
49+
case 'ssl':
50+
// todo: configure properly
51+
flagdOptions['port'] = container.getPort(state.resolverType);
52+
type = 'ssl';
53+
break;
6254
}
55+
56+
await fetch('http://' + container.getLaunchpadUrl() + '/start?config=' + type);
57+
await new Promise((r) => setTimeout(r, 50));
6358
if (providerType == 'unavailable') {
6459
OpenFeature.setProvider(providerType, new FlagdProvider(flagdOptions));
6560
} else {
@@ -71,8 +66,13 @@ export const providerSteps: Steps =
7166
});
7267

7368
when(/^the connection is lost for (\d+)s$/, async (time) => {
74-
const container = getContainer(state.providerType!);
75-
await container.stop();
76-
setTimeout(() => container.start(), time * 1000);
69+
console.log('stopping flagd');
70+
await fetch('http://' + container.getLaunchpadUrl() + '/restart?seconds=' + time);
71+
await new Promise((r) => setTimeout(r, 50));
72+
});
73+
74+
when('the flag was modified', async () => {
75+
await fetch('http://' + container.getLaunchpadUrl() + '/change');
76+
await new Promise((r) => setTimeout(r, 50));
7777
});
7878
};

Diff for: libs/providers/flagd/src/e2e/tests/flagdContainer.ts

+9-8
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ export class FlagdContainer extends GenericContainer {
88
private started: StartedTestContainer | undefined;
99
private stopped: StoppedTestContainer | undefined;
1010

11-
public static build(feature: string | undefined = undefined) {
12-
return new FlagdContainer(this.generateImageName(feature)).withExposedPorts(8013, 8014, 8015, 8016);
11+
public static build() {
12+
return new FlagdContainer(this.generateImageName());
1313
}
1414

1515
private constructor(image: string) {
1616
super(image);
17+
this.withExposedPorts(8080, 8013, 8014, 8015, 8016);
1718
}
1819

1920
isStarted(): boolean {
@@ -42,15 +43,15 @@ export class FlagdContainer extends GenericContainer {
4243
return containerPromise;
4344
}
4445

45-
private static generateImageName(feature: string | undefined): string {
46+
getLaunchpadUrl() {
47+
return this.started?.getHost() + ':' + this.started?.getMappedPort(8080);
48+
}
49+
50+
private static generateImageName(): string {
4651
const image = this.imageBase;
4752
const file = path.join(__dirname, './../../../../../shared/flagd-core/test-harness/', 'version.txt');
4853
const version = fs.readFileSync(file, 'utf8').trim();
49-
let featurePart = '';
50-
if (feature) {
51-
featurePart = `-${feature}`;
52-
}
53-
return `${image}${featurePart}:v${version}`;
54+
return `${image}:v${version}`;
5455
}
5556

5657
getPort(resolverType: ResolverType) {

Diff for: libs/providers/flagd/src/e2e/tests/in-process.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { contextSteps } from '../step-definitions/contextSteps';
1010
const steps = [providerSteps, configSteps, eventSteps, flagSteps, contextSteps];
1111

1212
jest.setTimeout(50000);
13-
describe('rpc', () => {
13+
describe('in-process', () => {
1414
const state: State = {
1515
resolverType: 'in-process',
1616
options: {},

Diff for: libs/providers/flagd/src/e2e/tests/rpc.spec.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ describe('rpc', () => {
2020
};
2121
autoBindSteps(
2222
loadFeatures(GHERKIN_FLAGD, {
23-
tagFilter: '@rpc and not @targetURI and not @customCert and not @events and not @sync and not @offline and not @grace',
23+
tagFilter:
24+
'@rpc and not @targetURI and not @customCert and not @events and not @stream and not @grace',
2425
scenarioNameTemplate: (vars) => {
2526
return `${vars.scenarioTitle} (${vars.scenarioTags.join(',')} ${vars.featureTags.join(',')})`;
2627
},

Diff for: libs/providers/flagd/src/lib/configuration.ts

+12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ export interface Config {
1818
*/
1919
port: number;
2020

21+
/**
22+
* The deadline for connections.
23+
*
24+
* @default 500
25+
*/
26+
deadlineMs: number;
27+
2128
/**
2229
* Determines if TLS should be used.
2330
*
@@ -79,6 +86,7 @@ export interface Config {
7986
export type FlagdProviderOptions = Partial<Config>;
8087

8188
const DEFAULT_CONFIG: Omit<Config, 'port' | 'resolverType'> = {
89+
deadlineMs: 500,
8290
host: 'localhost',
8391
tls: false,
8492
selector: '',
@@ -93,6 +101,7 @@ const DEFAULT_IN_PROCESS_CONFIG: Config = { ...DEFAULT_CONFIG, resolverType: 'in
93101
enum ENV_VAR {
94102
FLAGD_HOST = 'FLAGD_HOST',
95103
FLAGD_PORT = 'FLAGD_PORT',
104+
FLAGD_DEADLINE_MS = 'FLAGD_DEADLINE_MS',
96105
FLAGD_TLS = 'FLAGD_TLS',
97106
FLAGD_SOCKET_PATH = 'FLAGD_SOCKET_PATH',
98107
FLAGD_CACHE = 'FLAGD_CACHE',
@@ -128,6 +137,9 @@ const getEnvVarConfig = (): Partial<Config> => {
128137
...(Number(process.env[ENV_VAR.FLAGD_PORT]) && {
129138
port: Number(process.env[ENV_VAR.FLAGD_PORT]),
130139
}),
140+
...(Number(process.env[ENV_VAR.FLAGD_DEADLINE_MS]) && {
141+
deadlineMs: Number(process.env[ENV_VAR.FLAGD_DEADLINE_MS]),
142+
}),
131143
...(process.env[ENV_VAR.FLAGD_TLS] && {
132144
tls: process.env[ENV_VAR.FLAGD_TLS]?.toLowerCase() === 'true',
133145
}),

Diff for: libs/providers/flagd/src/lib/service/grpc/grpc-service.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ClientReadableStream, ClientUnaryCall, ServiceError, credentials, status, ClientOptions } from '@grpc/grpc-js';
1+
import { ClientOptions, ClientReadableStream, ClientUnaryCall, credentials, ServiceError, status } from '@grpc/grpc-js';
22
import { ConnectivityState } from '@grpc/grpc-js/build/src/connectivity-state';
33
import {
44
EvaluationContext,
@@ -70,6 +70,8 @@ export class GRPCService implements Service {
7070
private _cache: LRUCache<string, ResolutionDetails<FlagValue>> | undefined;
7171
private _cacheEnabled = false;
7272
private _eventStream: ClientReadableStream<EventStreamResponse> | undefined = undefined;
73+
private _deadline: number;
74+
7375
private get _cacheActive() {
7476
// the cache is "active" (able to be used) if the config enabled it, AND the gRPC stream is live
7577
return this._cacheEnabled && this._client.getChannel().getConnectivityState(false) === ConnectivityState.READY;
@@ -95,6 +97,7 @@ export class GRPCService implements Service {
9597
tls ? credentials.createSsl() : credentials.createInsecure(),
9698
clientOptions,
9799
);
100+
this._deadline = config.deadlineMs;
98101

99102
if (config.cache === 'lru') {
100103
this._cacheEnabled = true;
@@ -165,7 +168,7 @@ export class GRPCService implements Service {
165168
// close the previous stream if we're reconnecting
166169
closeStreamIfDefined(this._eventStream);
167170

168-
const stream = this._client.eventStream({}, {});
171+
const stream = this._client.eventStream({ waitForReady: true}, {});
169172
stream.on('error', (err: Error) => {
170173
rejectConnect?.(err);
171174
this.handleError(reconnectCallback, changedCallback, disconnectCallback);
@@ -240,6 +243,7 @@ export class GRPCService implements Service {
240243
const resolver = promisify(promise);
241244
if (this._cacheActive) {
242245
const cached = this._cache?.get(flagKey);
246+
console.log('cache active and this was in the cache', cached);
243247
if (cached) {
244248
return { ...cached, reason: StandardResolutionReasons.CACHED } as ResolutionDetails<T>;
245249
}

Diff for: libs/shared/flagd-core/src/e2e/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ export const E2E_CLIENT_NAME = 'e2e';
33
export const IMAGE_VERSION = 'v0.5.21';
44

55
export function getGherkinTestPath(file: string, modulePath = 'test-harness/gherkin/'): string {
6-
return `./libs/shared/flagd-core/${modulePath}${file}`;
6+
return `<rootdir>/../../../../../shared/flagd-core/${modulePath}${file}`;
77
}

0 commit comments

Comments
 (0)