Skip to content

Commit e076b96

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

File tree

9 files changed

+81
-59
lines changed

9 files changed

+81
-59
lines changed

libs/providers/flagd/src/e2e/constants.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export const FLAGD_NAME = 'flagd';
44
export const UNSTABLE_CLIENT_NAME = 'unstable';
55
export const UNAVAILABLE_CLIENT_NAME = 'unavailable';
66

7-
export const GHERKIN_FLAGD = getGherkinTestPath('*.feature');
7+
export const GHERKIN_FLAGD = getGherkinTestPath('rpc-caching.feature');
88
export const GHERKIN_CONFIG = getGherkinTestPath('config.feature');
99
export const GHERKIN_FLAGD_FEATURE = getGherkinTestPath('flagd.feature');
1010
export const GHERKIN_FLAGD_TESTING = getGherkinTestPath('testing.feature');

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
};

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: 1000 });
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: 1000 });
56+
state.events = [];
57+
});
4958
};

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
};

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+
deadline: 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, 500));
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
};

libs/providers/flagd/src/e2e/tests/flagdContainer.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ 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()).withExposedPorts(8080, 8013, 8014, 8015, 8016);
1313
}
1414

1515
private constructor(image: string) {
@@ -42,15 +42,15 @@ export class FlagdContainer extends GenericContainer {
4242
return containerPromise;
4343
}
4444

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

5656
getPort(resolverType: ResolverType) {

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
},

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
}),

libs/providers/flagd/src/lib/service/grpc/grpc-service.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ 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;
7374
private get _cacheActive() {
7475
// the cache is "active" (able to be used) if the config enabled it, AND the gRPC stream is live
7576
return this._cacheEnabled && this._client.getChannel().getConnectivityState(false) === ConnectivityState.READY;
@@ -95,6 +96,7 @@ export class GRPCService implements Service {
9596
tls ? credentials.createSsl() : credentials.createInsecure(),
9697
clientOptions,
9798
);
99+
this._deadline = config.deadlineMs;
98100

99101
if (config.cache === 'lru') {
100102
this._cacheEnabled = true;
@@ -165,11 +167,15 @@ export class GRPCService implements Service {
165167
// close the previous stream if we're reconnecting
166168
closeStreamIfDefined(this._eventStream);
167169

168-
const stream = this._client.eventStream({}, {});
169-
stream.on('error', (err: Error) => {
170-
rejectConnect?.(err);
171-
this.handleError(reconnectCallback, changedCallback, disconnectCallback);
170+
this._client.waitForReady(this._deadline, (err) => {
171+
console.log('waiting to be ready', err);
172+
if (err) {
173+
rejectConnect?.(err);
174+
this.handleError(reconnectCallback, changedCallback, disconnectCallback);
175+
}
172176
});
177+
const stream = this._client.eventStream({}, {});
178+
173179
stream.on('data', (message) => {
174180
if (message.type === EVENT_PROVIDER_READY) {
175181
this.logger?.debug(`${FlagdProvider.name}: streaming connection established with flagd`);
@@ -240,6 +246,7 @@ export class GRPCService implements Service {
240246
const resolver = promisify(promise);
241247
if (this._cacheActive) {
242248
const cached = this._cache?.get(flagKey);
249+
console.log('cache active and this was in the cache', cached);
243250
if (cached) {
244251
return { ...cached, reason: StandardResolutionReasons.CACHED } as ResolutionDetails<T>;
245252
}

0 commit comments

Comments
 (0)