Skip to content

Commit 3907e07

Browse files
committed
FOUR-30789: Fix Nayra endpoint for dockerized phpunit
1 parent 7a79558 commit 3907e07

2 files changed

Lines changed: 144 additions & 9 deletions

File tree

ProcessMaker/Models/ScriptDockerNayraTrait.php

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ private function bringUpNayra($restart = false)
186186
throw new ScriptException('Error starting Nayra Docker');
187187
}
188188

189+
$endpoint = self::buildNayraEndpointAfterStartup($docker, $instanceName, $this->schema);
189190
$this->cacheNayraEndpointAfterReadiness($endpoint);
190191
}
191192

@@ -256,6 +257,11 @@ private function waitContainerNetwork($docker, $instanceName)
256257
* @return bool Returns true if the Nayra addresses were found, false otherwise.
257258
*/
258259
private static function findNayraAddresses($docker, $instanceName, $times): bool
260+
{
261+
return self::resolveNayraContainerAddress($docker, $instanceName, $times) !== null;
262+
}
263+
264+
private static function resolveNayraContainerAddress($docker, $instanceName, $times): ?string
259265
{
260266
$ip = '';
261267
$nayraDockerNetwork = config('app.nayra_docker_network');
@@ -264,15 +270,17 @@ private static function findNayraAddresses($docker, $instanceName, $times): bool
264270
if ($i > 0) {
265271
sleep(1);
266272
}
273+
$output = [];
274+
$status = 0;
267275
if ($nayraDockerNetwork === 'host') {
268-
$ip = exec(
276+
$ip = static::execDockerCommand(
269277
$docker . " exec {$instanceName}_nayra hostname -i 2>/dev/null",
270278
$output,
271279
$status
272280
);
273281
$ip = explode(' ', trim($ip))[0];
274282
} else {
275-
$ip = exec(
283+
$ip = static::execDockerCommand(
276284
$docker . ' inspect --format '
277285
. ($nayraDockerNetwork
278286
? "'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'"
@@ -288,11 +296,16 @@ private static function findNayraAddresses($docker, $instanceName, $times): bool
288296
}
289297
if ($ip) {
290298
self::setNayraAddresses([$ip]);
291-
return true;
299+
return $ip;
292300
}
293301
}
294302

295-
return false;
303+
return null;
304+
}
305+
306+
protected static function execDockerCommand(string $command, array &$output, int &$status): string|false
307+
{
308+
return exec($command, $output, $status);
296309
}
297310

298311
/**
@@ -360,9 +373,31 @@ private function buildNayraEndpoint(): string
360373
return self::buildNayraEndpointUrl($this->schema);
361374
}
362375

363-
private static function buildNayraEndpointUrl(string $schema = 'http'): string
376+
private static function buildNayraEndpointUrl(string $schema = 'http', ?string $host = null): string
364377
{
365-
return $schema . '://' . self::getNayraEndpointHost() . ':' . self::getNayraPortValue();
378+
return $schema . '://' . ($host ?? self::getNayraEndpointHost()) . ':' . self::getNayraPortValue();
379+
}
380+
381+
private static function buildNayraEndpointAfterStartup(
382+
string $docker,
383+
string $instanceName,
384+
string $schema = 'http',
385+
int $addressAttempts = 30
386+
): string {
387+
if (self::shouldUseContainerHostNetworkEndpoint()) {
388+
$host = self::resolveNayraContainerAddress($docker, $instanceName, $addressAttempts);
389+
if ($host) {
390+
return self::buildNayraEndpointUrl($schema, $host);
391+
}
392+
}
393+
394+
return self::buildNayraEndpointUrl($schema);
395+
}
396+
397+
private static function shouldUseContainerHostNetworkEndpoint(): bool
398+
{
399+
return config('app.nayra_docker_network') === 'host'
400+
&& !config('app.processmaker_scripts_docker_host');
366401
}
367402

368403
private static function getNayraEndpointHost(): string
@@ -505,7 +540,7 @@ public static function bringUpNayraExecutor(BuildScriptExecutors $builder, strin
505540
: '')
506541
. $image
507542
);
508-
$endpoint = self::buildNayraEndpointUrl();
543+
$endpoint = self::buildNayraEndpointAfterStartup($docker, $instanceName);
509544
if (!static::nayraEndpointIsRunning($endpoint)) {
510545
throw new UnexpectedValueException('Could not connect to the nayra container');
511546
}

tests/unit/ProcessMaker/Models/ScriptDockerNayraTraitTest.php

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ class ScriptDockerNayraTraitFunctionState
1313

1414
public const LOCAL_NAYRA_HOST = 'http://127.0.0.1:8081';
1515

16+
public const HOST_NETWORK_IP = '172.17.0.' . '1';
17+
18+
public const HOST_NETWORK_NAYRA_HOST = 'http://' . self::HOST_NETWORK_IP . ':8081';
19+
20+
public const NAYRA_TEST_IMAGE = 'processmaker4/nayra:test';
21+
1622
public const OK_HEADER = 'HTTP/1.1 200 OK';
1723

1824
public const SCRIPT_CODE = '<?php return [];';
@@ -21,6 +27,12 @@ class ScriptDockerNayraTraitFunctionState
2127

2228
public static array $requestedHeaders = [];
2329

30+
public static array $execCommands = [];
31+
32+
public static string $containerAddress = self::HOST_NETWORK_IP;
33+
34+
public static int $containerAddressStatus = 0;
35+
2436
public static ?string $curlUrl = null;
2537

2638
public static array $curlOptions = [];
@@ -37,6 +49,9 @@ public static function reset(): void
3749
{
3850
self::$headers = [];
3951
self::$requestedHeaders = [];
52+
self::$execCommands = [];
53+
self::$containerAddress = self::HOST_NETWORK_IP;
54+
self::$containerAddressStatus = 0;
4055
self::$curlUrl = null;
4156
self::$curlOptions = [];
4257
self::$curlHandles = [];
@@ -58,6 +73,7 @@ class ScriptDockerNayraTraitTestHarness
5873
getNayraPort as public exposedGetNayraPort;
5974
getNayraContainerName as public exposedGetNayraContainerName;
6075
cacheNayraEndpointAfterReadiness as public exposedCacheNayraEndpointAfterReadiness;
76+
buildNayraEndpointAfterStartup as public exposedBuildNayraEndpointAfterStartup;
6177
}
6278

6379
public int $bringUpNayraCalls = 0;
@@ -96,6 +112,15 @@ protected static function getNayraEndpointReadinessAttempts(): int
96112
return 1;
97113
}
98114

115+
protected static function execDockerCommand(string $command, array &$output, int &$status): string|false
116+
{
117+
ScriptDockerNayraTraitFunctionState::$execCommands[] = $command;
118+
$status = ScriptDockerNayraTraitFunctionState::$containerAddressStatus;
119+
$output = $status ? [] : [ScriptDockerNayraTraitFunctionState::$containerAddress];
120+
121+
return $status ? false : ScriptDockerNayraTraitFunctionState::$containerAddress;
122+
}
123+
99124
protected function curlInit(string $url): object
100125
{
101126
ScriptDockerNayraTraitFunctionState::$curlUrl = $url;
@@ -299,6 +324,39 @@ public function testRemoteDockerHostIsUsedForFallbackNayraEndpoint()
299324
$this->assertSame('http://qa-remotedocker:8080', $runner->exposedGetNayraInstanceUrl());
300325
}
301326

327+
public function testLocalHostNetworkNayraEndpointUsesDockerReportedAddressAfterStartup()
328+
{
329+
config(['app.nayra_docker_network' => 'host']);
330+
331+
$runner = new ScriptDockerNayraTraitTestHarness();
332+
333+
$this->assertSame(
334+
ScriptDockerNayraTraitFunctionState::HOST_NETWORK_NAYRA_HOST,
335+
$runner->exposedBuildNayraEndpointAfterStartup('docker', 'processmaker', 'http', 1)
336+
);
337+
$this->assertCount(1, ScriptDockerNayraTraitFunctionState::$execCommands);
338+
$this->assertStringContainsString(
339+
'exec processmaker_nayra hostname -i 2>/dev/null',
340+
ScriptDockerNayraTraitFunctionState::$execCommands[0]
341+
);
342+
}
343+
344+
public function testLocalHostNetworkNayraEndpointDoesNotOverrideRemoteDockerHost()
345+
{
346+
config([
347+
'app.nayra_docker_network' => 'host',
348+
'app.processmaker_scripts_docker_host' => 'tcp://qa-remotedocker:2375',
349+
]);
350+
351+
$runner = new ScriptDockerNayraTraitTestHarness();
352+
353+
$this->assertSame(
354+
'http://qa-remotedocker:8081',
355+
$runner->exposedBuildNayraEndpointAfterStartup('DOCKER_HOST=tcp://qa-remotedocker:2375 docker', 'processmaker', 'http', 1)
356+
);
357+
$this->assertSame([], ScriptDockerNayraTraitFunctionState::$execCommands);
358+
}
359+
302360
public function testMultitenantNayraUsesStableContainerNameAcrossTenants()
303361
{
304362
config([
@@ -414,7 +472,10 @@ public function testBringUpNayraExecutorCachesEndpointAfterItIsReachable()
414472
];
415473
$builder = new ScriptDockerNayraTraitBuildScriptExecutorsHarness();
416474

417-
ScriptDockerNayraTraitTestHarness::bringUpNayraExecutor($builder, 'processmaker4/nayra:test');
475+
ScriptDockerNayraTraitTestHarness::bringUpNayraExecutor(
476+
$builder,
477+
ScriptDockerNayraTraitFunctionState::NAYRA_TEST_IMAGE
478+
);
418479

419480
$this->assertSame(
420481
ScriptDockerNayraTraitFunctionState::LOCAL_NAYRA_HOST,
@@ -443,7 +504,10 @@ public function testBringUpNayraExecutorDoesNotCacheEndpointWhenItIsUnreachable(
443504
$builder = new ScriptDockerNayraTraitBuildScriptExecutorsHarness();
444505

445506
try {
446-
ScriptDockerNayraTraitTestHarness::bringUpNayraExecutor($builder, 'processmaker4/nayra:test');
507+
ScriptDockerNayraTraitTestHarness::bringUpNayraExecutor(
508+
$builder,
509+
ScriptDockerNayraTraitFunctionState::NAYRA_TEST_IMAGE
510+
);
447511
$this->fail('Expected Nayra executor startup to fail when the endpoint is unreachable.');
448512
} catch (UnexpectedValueException $exception) {
449513
$this->assertSame('Could not connect to the nayra container', $exception->getMessage());
@@ -457,4 +521,40 @@ public function testBringUpNayraExecutorDoesNotCacheEndpointWhenItIsUnreachable(
457521
$this->assertCount(3, $builder->commands);
458522
$this->assertSame([], $builder->events);
459523
}
524+
525+
public function testBringUpNayraExecutorCachesHostNetworkEndpointAfterItIsReachable()
526+
{
527+
config(['app.nayra_docker_network' => 'host']);
528+
ScriptDockerNayraTraitFunctionState::$headers = [
529+
ScriptDockerNayraTraitFunctionState::HOST_NETWORK_NAYRA_HOST => [
530+
ScriptDockerNayraTraitFunctionState::OK_HEADER,
531+
],
532+
];
533+
$builder = new ScriptDockerNayraTraitBuildScriptExecutorsHarness();
534+
535+
ScriptDockerNayraTraitTestHarness::bringUpNayraExecutor(
536+
$builder,
537+
ScriptDockerNayraTraitFunctionState::NAYRA_TEST_IMAGE
538+
);
539+
540+
$this->assertSame(
541+
ScriptDockerNayraTraitFunctionState::HOST_NETWORK_NAYRA_HOST,
542+
ScriptDockerNayraTraitTestHarness::getNayraEndpoint()
543+
);
544+
$this->assertSame(
545+
[ScriptDockerNayraTraitFunctionState::HOST_NETWORK_NAYRA_HOST],
546+
ScriptDockerNayraTraitFunctionState::$requestedHeaders
547+
);
548+
$this->assertCount(1, ScriptDockerNayraTraitFunctionState::$execCommands);
549+
$this->assertStringContainsString(
550+
'exec processmaker_nayra hostname -i 2>/dev/null',
551+
ScriptDockerNayraTraitFunctionState::$execCommands[0]
552+
);
553+
$this->assertCount(3, $builder->commands);
554+
$this->assertStringContainsString('docker run -d -e PORT=8081', $builder->commands[2]);
555+
$this->assertContains(
556+
'Nayra endpoint: ' . ScriptDockerNayraTraitFunctionState::HOST_NETWORK_NAYRA_HOST,
557+
$builder->infoMessages
558+
);
559+
}
460560
}

0 commit comments

Comments
 (0)