Skip to content

Commit 1e9d4ef

Browse files
authored
feat: Add contract test support (#138)
1 parent 59d8b8f commit 1e9d4ef

File tree

4 files changed

+104
-5
lines changed

4 files changed

+104
-5
lines changed

src/LaunchDarkly/LDClient.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,11 @@ public function migrationVariation(string $key, LDContext $context, Stage $defau
243243
/** @var ?FeatureFlag $flag */
244244
$flag = $result['flag'];
245245

246-
$valueAsString = Stage::tryFrom($detail->getValue());
246+
$value = $detail->getValue();
247+
$valueAsString = null;
248+
if (is_string($value)) {
249+
$valueAsString = Stage::tryFrom($detail->getValue());
250+
}
247251

248252
if ($valueAsString !== null) {
249253
$tracker = new OpTracker(

src/LaunchDarkly/Migrations/Migrator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public function write(
7474
$stage = $variationResult['stage'];
7575
/** @var OpTracker */
7676
$tracker = $variationResult['tracker'];
77-
$tracker->operation(Operation::READ);
77+
$tracker->operation(Operation::WRITE);
7878

7979
$old = new Executor(Origin::OLD, $this->writeConfig->old, $tracker, $this->trackLatency, $this->trackErrors, $payload);
8080
$new = new Executor(Origin::NEW, $this->writeConfig->new, $tracker, $this->trackLatency, $this->trackErrors, $payload);

test-service/SdkClientEntity.php

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,16 @@
44

55
namespace Tests;
66

7+
use Closure;
8+
use GuzzleHttp\Client;
79
use LaunchDarkly\Integrations\Guzzle;
810
use LaunchDarkly\LDClient;
911
use LaunchDarkly\LDContext;
12+
use LaunchDarkly\Migrations\ExecutionOrder;
13+
use LaunchDarkly\Migrations\MigratorBuilder;
14+
use LaunchDarkly\Migrations\Operation;
15+
use LaunchDarkly\Migrations\Stage;
16+
use LaunchDarkly\Types\Result;
1017
use Monolog\Formatter\LineFormatter;
1118
use Monolog\Handler\StreamHandler;
1219
use Monolog\Logger;
@@ -87,10 +94,16 @@ public function doCommand(mixed $reqParams): mixed
8794

8895
case 'contextBuild':
8996
return $this->doContextBuild($commandParams);
90-
97+
9198
case 'contextConvert':
9299
return $this->doContextConvert($commandParams);
93-
100+
101+
case 'migrationVariation':
102+
return $this->doMigrationVariation($commandParams);
103+
104+
case 'migrationOperation':
105+
return $this->doMigrationOperation($commandParams);
106+
94107
default:
95108
return false; // means invalid command
96109
}
@@ -208,6 +221,86 @@ private function doContextConvert(array $params): array
208221
}
209222
}
210223

224+
private function doMigrationVariation(array $params): array
225+
{
226+
try {
227+
$results = $this->_client->migrationVariation(
228+
$params['key'],
229+
$this->makeContext($params['context']),
230+
Stage::from($params['defaultStage'])
231+
);
232+
233+
return ['result' => $results['stage']->value];
234+
} catch (\Throwable $e) {
235+
return ['error' => "$e"];
236+
}
237+
}
238+
239+
private function doMigrationOperation(array $params): array
240+
{
241+
$builder = new MigratorBuilder($this->_client);
242+
243+
// PHP doesn't support concurrent, so we just do the best we can.
244+
if ($params['readExecutionOrder'] == 'concurrent') {
245+
$params['readExecutionOrder'] = 'serial';
246+
}
247+
248+
$builder->readExecutionOrder(ExecutionOrder::from($params['readExecutionOrder']));
249+
$builder->trackLatency($params['trackLatency']);
250+
$builder->trackErrors($params['trackErrors']);
251+
252+
$callback = function (string $endpoint): Closure {
253+
return function ($payload) use ($endpoint): Result {
254+
$client = new Client();
255+
$response = $client->request('POST', $endpoint, ['body' => $payload]);
256+
257+
$statusCode = $response->getStatusCode();
258+
if ($statusCode == 200) {
259+
return Result::success($response->getBody()->getContents());
260+
};
261+
262+
return Result::error("Request failed with status code {$statusCode}");
263+
};
264+
};
265+
266+
$consistency = null;
267+
if ($params['trackConsistency'] ?? false) {
268+
$consistency = fn ($lhs, $rhs) => $lhs == $rhs;
269+
}
270+
271+
$builder->read(($callback)($params['oldEndpoint']), ($callback)($params['newEndpoint']), $consistency);
272+
$builder->write(($callback)($params['oldEndpoint']), ($callback)($params['newEndpoint']));
273+
274+
$results = $builder->build();
275+
276+
if (!$results->isSuccessful()) {
277+
return ['result' => $results->error];
278+
}
279+
280+
/** @var \LaunchDarkly\Migrations\Migrator */
281+
$migrator = $results->value;
282+
283+
if ($params['operation'] == Operation::READ->value) {
284+
$result = $migrator->read(
285+
$params['key'],
286+
$this->makeContext($params['context']),
287+
Stage::from($params['defaultStage']),
288+
$params['payload'],
289+
);
290+
291+
return ['result' => $result->isSuccessful() ? $result->value : $result->error];
292+
}
293+
294+
$result = $migrator->write(
295+
$params['key'],
296+
$this->makeContext($params['context']),
297+
Stage::from($params['defaultStage']),
298+
$params['payload'],
299+
);
300+
301+
return ['result' => $result->authoritative->isSuccessful() ? $result->authoritative->value : $result->authoritative->error];
302+
}
303+
211304
private function makeContext(array $data): LDContext
212305
{
213306
return LDContext::fromJson($data);

test-service/TestService.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ public function getStatus(): array
7373
'all-flags-details-only-for-tracked-flags',
7474
'all-flags-with-reasons',
7575
'context-type',
76-
'secure-mode-hash'
76+
'secure-mode-hash',
77+
'migrations',
78+
'event-sampling'
7779
],
7880
'clientVersion' => \LaunchDarkly\LDClient::VERSION
7981
];

0 commit comments

Comments
 (0)