Skip to content

Commit 3588723

Browse files
pjcdawkinsclaude
andauthored
fix(legacy): handle old-format tunnel-info.json (#29)
* fix(legacy): handle old-format tunnel-info.json in TunnelManager The tunnel refactor in legacy-cli 5.x changed the serialization format of tunnel-info.json, adding an 'id' field and using it as the outer key. Old-format data (from CLI 4.x) lacks this field, causing a TypeError when TunnelManager::unserialize() passes null to Tunnel::__construct(). Fall back to generating the ID from metadata fields when 'id' is absent. Closes CLI-117 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(legacy): add TunnelManager unserialize tests Cover new-format deserialization, old (4.x) format without 'id' field, and stability of the derived ID. Uses reflection to test the private unserialize() method directly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8707228 commit 3588723

2 files changed

Lines changed: 126 additions & 1 deletion

File tree

‎legacy/src/Service/TunnelManager.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,9 @@ private function unserialize(string $jsonData): array
190190
foreach ($data as $item) {
191191
$metadata = $item;
192192
unset($metadata['id'], $metadata['localPort'], $metadata['remoteHost'], $metadata['remotePort'], $metadata['pid']);
193-
$tunnels[] = new Tunnel($item['id'], $item['localPort'], $item['remoteHost'], $item['remotePort'], $metadata, $item['pid']);
193+
// Handle old-format tunnel data that lacks an 'id' field.
194+
$id = $item['id'] ?? $this->getId($metadata);
195+
$tunnels[] = new Tunnel($id, $item['localPort'], $item['remoteHost'], $item['remotePort'], $metadata, $item['pid']);
194196
}
195197
return $tunnels;
196198
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Platformsh\Cli\Tests\Service;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Platformsh\Cli\Service\Config;
9+
use Platformsh\Cli\Service\Io;
10+
use Platformsh\Cli\Service\Relationships;
11+
use Platformsh\Cli\Service\TunnelManager;
12+
use Platformsh\Cli\Tunnel\Tunnel;
13+
14+
class TunnelManagerTest extends TestCase
15+
{
16+
private function createManager(): TunnelManager
17+
{
18+
$config = $this->createMock(Config::class);
19+
$io = $this->createMock(Io::class);
20+
$relationships = $this->createMock(Relationships::class);
21+
22+
return new TunnelManager($config, $io, $relationships);
23+
}
24+
25+
/**
26+
* Calls the private unserialize() method via reflection.
27+
*
28+
* @return Tunnel[]
29+
*/
30+
private function callUnserialize(TunnelManager $manager, string $json): array
31+
{
32+
$method = new \ReflectionMethod($manager, 'unserialize');
33+
34+
return $method->invoke($manager, $json);
35+
}
36+
37+
public function testUnserializeNewFormat(): void
38+
{
39+
$tunnels = $this->callUnserialize($this->createManager(), (string) json_encode([
40+
'proj1--main--app--database--0' => [
41+
'projectId' => 'proj1',
42+
'environmentId' => 'main',
43+
'appName' => 'app',
44+
'relationship' => 'database',
45+
'serviceKey' => 0,
46+
'service' => ['scheme' => 'mysql', 'host' => 'database.internal', 'port' => 3306],
47+
'id' => 'proj1--main--app--database--0',
48+
'localPort' => 30000,
49+
'remoteHost' => 'database.internal',
50+
'remotePort' => 3306,
51+
'pid' => 12345,
52+
],
53+
]));
54+
55+
$this->assertCount(1, $tunnels);
56+
$tunnel = $tunnels[0];
57+
$this->assertSame('proj1--main--app--database--0', $tunnel->id);
58+
$this->assertSame(30000, $tunnel->localPort);
59+
$this->assertSame('database.internal', $tunnel->remoteHost);
60+
$this->assertSame(3306, $tunnel->remotePort);
61+
$this->assertSame(12345, $tunnel->pid);
62+
$this->assertSame('proj1', $tunnel->metadata['projectId']);
63+
}
64+
65+
public function testUnserializeOldFormatWithoutId(): void
66+
{
67+
// 4.x-style tunnel-info.json: no 'id' field in the entry.
68+
$tunnels = $this->callUnserialize($this->createManager(), (string) json_encode([
69+
'some-old-key' => [
70+
'projectId' => 'abc123',
71+
'environmentId' => 'staging',
72+
'appName' => 'web',
73+
'relationship' => 'redis',
74+
'serviceKey' => 1,
75+
'service' => ['scheme' => 'redis', 'host' => 'redis.internal', 'port' => 6379],
76+
'localPort' => 30001,
77+
'remoteHost' => 'redis.internal',
78+
'remotePort' => 6379,
79+
'pid' => 99999,
80+
],
81+
]));
82+
83+
$this->assertCount(1, $tunnels);
84+
$tunnel = $tunnels[0];
85+
// The ID should be derived from metadata fields.
86+
$this->assertSame('abc123--staging--web--redis--1', $tunnel->id);
87+
$this->assertSame(30001, $tunnel->localPort);
88+
$this->assertSame('redis.internal', $tunnel->remoteHost);
89+
$this->assertSame(6379, $tunnel->remotePort);
90+
$this->assertSame(99999, $tunnel->pid);
91+
$this->assertSame('abc123', $tunnel->metadata['projectId']);
92+
$this->assertSame('staging', $tunnel->metadata['environmentId']);
93+
$this->assertSame('web', $tunnel->metadata['appName']);
94+
$this->assertSame('redis', $tunnel->metadata['relationship']);
95+
$this->assertSame(1, $tunnel->metadata['serviceKey']);
96+
}
97+
98+
public function testUnserializeOldFormatDerivedIdIsStable(): void
99+
{
100+
$json = (string) json_encode([
101+
'key' => [
102+
'projectId' => 'proj2',
103+
'environmentId' => 'dev',
104+
'appName' => null,
105+
'relationship' => 'db',
106+
'serviceKey' => 0,
107+
'service' => ['scheme' => 'pgsql', 'host' => 'pg.internal', 'port' => 5432],
108+
'localPort' => 30002,
109+
'remoteHost' => 'pg.internal',
110+
'remotePort' => 5432,
111+
'pid' => null,
112+
],
113+
]);
114+
115+
$manager = $this->createManager();
116+
$tunnels1 = $this->callUnserialize($manager, $json);
117+
$tunnels2 = $this->callUnserialize($manager, $json);
118+
119+
$this->assertSame($tunnels1[0]->id, $tunnels2[0]->id);
120+
// Null appName becomes empty string in the ID.
121+
$this->assertSame('proj2--dev----db--0', $tunnels1[0]->id);
122+
}
123+
}

0 commit comments

Comments
 (0)