Skip to content

Commit 3305edd

Browse files
committed
(test): Add 217 unit tests for TLS, Config, byte tracking, endpoint validation, routing cache, TCP adapter, and more
1 parent 18d464f commit 3305edd

10 files changed

+2465
-0
lines changed

tests/AdapterByteTrackingTest.php

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
<?php
2+
3+
namespace Utopia\Tests;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use Utopia\Proxy\Adapter;
7+
use Utopia\Proxy\Protocol;
8+
9+
class AdapterByteTrackingTest extends TestCase
10+
{
11+
protected MockResolver $resolver;
12+
13+
protected function setUp(): void
14+
{
15+
if (!\extension_loaded('swoole')) {
16+
$this->markTestSkipped('ext-swoole is required to run adapter tests.');
17+
}
18+
19+
$this->resolver = new MockResolver();
20+
}
21+
22+
public function testRecordBytesInitializesCounters(): void
23+
{
24+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
25+
26+
$adapter->recordBytes('resource-1', inbound: 100, outbound: 200);
27+
28+
// Verify via notifyClose which flushes byte counters
29+
$adapter->notifyClose('resource-1');
30+
$disconnects = $this->resolver->getDisconnects();
31+
32+
$this->assertSame(100, $disconnects[0]['metadata']['inboundBytes']);
33+
$this->assertSame(200, $disconnects[0]['metadata']['outboundBytes']);
34+
}
35+
36+
public function testRecordBytesAccumulatesValues(): void
37+
{
38+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
39+
40+
$adapter->recordBytes('resource-1', inbound: 100, outbound: 200);
41+
$adapter->recordBytes('resource-1', inbound: 50, outbound: 75);
42+
$adapter->recordBytes('resource-1', inbound: 25, outbound: 25);
43+
44+
$adapter->notifyClose('resource-1');
45+
$disconnects = $this->resolver->getDisconnects();
46+
47+
$this->assertSame(175, $disconnects[0]['metadata']['inboundBytes']);
48+
$this->assertSame(300, $disconnects[0]['metadata']['outboundBytes']);
49+
}
50+
51+
public function testRecordBytesDefaultsToZero(): void
52+
{
53+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
54+
55+
$adapter->recordBytes('resource-1');
56+
57+
$adapter->notifyClose('resource-1');
58+
$disconnects = $this->resolver->getDisconnects();
59+
60+
$this->assertSame(0, $disconnects[0]['metadata']['inboundBytes']);
61+
$this->assertSame(0, $disconnects[0]['metadata']['outboundBytes']);
62+
}
63+
64+
public function testRecordBytesInboundOnly(): void
65+
{
66+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
67+
68+
$adapter->recordBytes('resource-1', inbound: 500);
69+
70+
$adapter->notifyClose('resource-1');
71+
$disconnects = $this->resolver->getDisconnects();
72+
73+
$this->assertSame(500, $disconnects[0]['metadata']['inboundBytes']);
74+
$this->assertSame(0, $disconnects[0]['metadata']['outboundBytes']);
75+
}
76+
77+
public function testRecordBytesOutboundOnly(): void
78+
{
79+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
80+
81+
$adapter->recordBytes('resource-1', outbound: 300);
82+
83+
$adapter->notifyClose('resource-1');
84+
$disconnects = $this->resolver->getDisconnects();
85+
86+
$this->assertSame(0, $disconnects[0]['metadata']['inboundBytes']);
87+
$this->assertSame(300, $disconnects[0]['metadata']['outboundBytes']);
88+
}
89+
90+
public function testRecordBytesTracksMultipleResources(): void
91+
{
92+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
93+
94+
$adapter->recordBytes('resource-1', inbound: 100, outbound: 200);
95+
$adapter->recordBytes('resource-2', inbound: 300, outbound: 400);
96+
97+
$adapter->notifyClose('resource-1');
98+
$adapter->notifyClose('resource-2');
99+
$disconnects = $this->resolver->getDisconnects();
100+
101+
$this->assertSame(100, $disconnects[0]['metadata']['inboundBytes']);
102+
$this->assertSame(200, $disconnects[0]['metadata']['outboundBytes']);
103+
$this->assertSame(300, $disconnects[1]['metadata']['inboundBytes']);
104+
$this->assertSame(400, $disconnects[1]['metadata']['outboundBytes']);
105+
}
106+
107+
public function testNotifyCloseFlushesAndClearsCounters(): void
108+
{
109+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
110+
111+
$adapter->recordBytes('resource-1', inbound: 100, outbound: 200);
112+
$adapter->notifyClose('resource-1');
113+
114+
// Second close should not include byte data
115+
$adapter->notifyClose('resource-1');
116+
$disconnects = $this->resolver->getDisconnects();
117+
118+
$this->assertArrayHasKey('inboundBytes', $disconnects[0]['metadata']);
119+
$this->assertArrayNotHasKey('inboundBytes', $disconnects[1]['metadata']);
120+
}
121+
122+
public function testNotifyCloseWithoutByteRecordingOmitsByteMetadata(): void
123+
{
124+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
125+
126+
$adapter->notifyClose('resource-1', ['reason' => 'timeout']);
127+
$disconnects = $this->resolver->getDisconnects();
128+
129+
$this->assertArrayNotHasKey('inboundBytes', $disconnects[0]['metadata']);
130+
$this->assertSame('timeout', $disconnects[0]['metadata']['reason']);
131+
}
132+
133+
public function testNotifyCloseMergesByteDataWithExistingMetadata(): void
134+
{
135+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
136+
137+
$adapter->recordBytes('resource-1', inbound: 100, outbound: 200);
138+
$adapter->notifyClose('resource-1', ['reason' => 'client_disconnect']);
139+
$disconnects = $this->resolver->getDisconnects();
140+
141+
$this->assertSame(100, $disconnects[0]['metadata']['inboundBytes']);
142+
$this->assertSame(200, $disconnects[0]['metadata']['outboundBytes']);
143+
$this->assertSame('client_disconnect', $disconnects[0]['metadata']['reason']);
144+
}
145+
146+
public function testTrackFlushesAccumulatedBytes(): void
147+
{
148+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
149+
$adapter->setActivityInterval(0);
150+
151+
$adapter->recordBytes('resource-1', inbound: 100, outbound: 200);
152+
$adapter->track('resource-1');
153+
154+
$activities = $this->resolver->getActivities();
155+
$this->assertCount(1, $activities);
156+
$this->assertSame(100, $activities[0]['metadata']['inboundBytes']);
157+
$this->assertSame(200, $activities[0]['metadata']['outboundBytes']);
158+
}
159+
160+
public function testTrackResetsCountersAfterFlush(): void
161+
{
162+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
163+
$adapter->setActivityInterval(0);
164+
165+
$adapter->recordBytes('resource-1', inbound: 100, outbound: 200);
166+
$adapter->track('resource-1');
167+
168+
// Record more bytes and track again
169+
$adapter->recordBytes('resource-1', inbound: 50, outbound: 25);
170+
171+
// Need to wait for throttle to pass (interval is 0 but time() is same second)
172+
// Force a new second
173+
sleep(1);
174+
$adapter->track('resource-1');
175+
176+
$activities = $this->resolver->getActivities();
177+
$this->assertCount(2, $activities);
178+
$this->assertSame(50, $activities[1]['metadata']['inboundBytes']);
179+
$this->assertSame(25, $activities[1]['metadata']['outboundBytes']);
180+
}
181+
182+
public function testTrackWithoutBytesOmitsByteMetadata(): void
183+
{
184+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
185+
$adapter->setActivityInterval(0);
186+
187+
$adapter->track('resource-1', ['type' => 'query']);
188+
189+
$activities = $this->resolver->getActivities();
190+
$this->assertCount(1, $activities);
191+
$this->assertArrayNotHasKey('inboundBytes', $activities[0]['metadata']);
192+
$this->assertSame('query', $activities[0]['metadata']['type']);
193+
}
194+
195+
public function testNotifyCloseClearsActivityTimestamp(): void
196+
{
197+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
198+
$adapter->setActivityInterval(9999);
199+
200+
// Track once to set the timestamp
201+
$adapter->track('resource-1');
202+
$this->assertCount(1, $this->resolver->getActivities());
203+
204+
// Normally this would be throttled
205+
$adapter->track('resource-1');
206+
$this->assertCount(1, $this->resolver->getActivities());
207+
208+
// Close clears the timestamp
209+
$adapter->notifyClose('resource-1');
210+
211+
// Now tracking should work again immediately
212+
$adapter->track('resource-1');
213+
$this->assertCount(2, $this->resolver->getActivities());
214+
}
215+
216+
public function testSetActivityIntervalReturnsSelf(): void
217+
{
218+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
219+
220+
$result = $adapter->setActivityInterval(60);
221+
$this->assertSame($adapter, $result);
222+
}
223+
224+
public function testSetSkipValidationReturnsSelf(): void
225+
{
226+
$adapter = new Adapter($this->resolver, name: 'Test', protocol: Protocol::TCP);
227+
228+
$result = $adapter->setSkipValidation(true);
229+
$this->assertSame($adapter, $result);
230+
}
231+
}

0 commit comments

Comments
 (0)