@@ -14,4 +14,82 @@ public function test_cpu_count()
1414
1515 $ this ->assertTrue ($ cpuCount > 0 );
1616 }
17+
18+ public function test_container_cpu_count_reads_cgroup_v2_quota ()
19+ {
20+ $ extension = $ this ->fakeExtensionWithFiles ([
21+ '/sys/fs/cgroup/cpu.max ' => '200000 100000 ' ,
22+ ]);
23+
24+ $ this ->assertSame (2 , $ extension ->readContainerCpuCount ());
25+ }
26+
27+ public function test_container_cpu_count_reads_cgroup_v1_quota ()
28+ {
29+ $ extension = $ this ->fakeExtensionWithFiles ([
30+ '/sys/fs/cgroup/cpu/cpu.cfs_quota_us ' => '250000 ' ,
31+ '/sys/fs/cgroup/cpu/cpu.cfs_period_us ' => '100000 ' ,
32+ ]);
33+
34+ $ this ->assertSame (3 , $ extension ->readContainerCpuCount ());
35+ }
36+
37+ public function test_container_cpu_count_returns_null_when_unlimited_or_missing ()
38+ {
39+ $ extension = $ this ->fakeExtensionWithFiles ([
40+ '/sys/fs/cgroup/cpu.max ' => 'max 100000 ' ,
41+ ]);
42+
43+ $ this ->assertNull ($ extension ->readContainerCpuCount ());
44+ }
45+
46+ public function test_container_cpu_count_ignores_invalid_v2_data ()
47+ {
48+ $ extension = $ this ->fakeExtensionWithFiles ([
49+ '/sys/fs/cgroup/cpu.max ' => '200000 ' ,
50+ ]);
51+
52+ $ this ->assertNull ($ extension ->readContainerCpuCount ());
53+ }
54+
55+ public function test_cpu_count_respects_cgroup_v2_limit ()
56+ {
57+ $ extension = $ this ->getMockBuilder (SwooleExtension::class)
58+ ->onlyMethods (['containerCpuCount ' ])
59+ ->getMock ();
60+
61+ $ extension ->method ('containerCpuCount ' )->willReturn (2 );
62+
63+ $ this ->assertSame (2 , $ extension ->cpuCount ());
64+ }
65+
66+ public function test_cpu_count_falls_back_when_no_cgroup_limit ()
67+ {
68+ $ extension = $ this ->getMockBuilder (SwooleExtension::class)
69+ ->onlyMethods (['containerCpuCount ' ])
70+ ->getMock ();
71+
72+ $ extension ->method ('containerCpuCount ' )->willReturn (null );
73+
74+ $ this ->assertTrue ($ extension ->cpuCount () >= 1 );
75+ }
76+
77+ protected function fakeExtensionWithFiles (array $ files ): object
78+ {
79+ return new class ($ files ) extends SwooleExtension
80+ {
81+ public function __construct (private array $ files )
82+ {
83+ parent ::__construct (
84+ isReadable: fn (string $ path ): bool => array_key_exists ($ path , $ this ->files ),
85+ fileGetContents: fn (string $ path ): string |false => $ this ->files [$ path ] ?? false ,
86+ );
87+ }
88+
89+ public function readContainerCpuCount (): ?int
90+ {
91+ return $ this ->containerCpuCount ();
92+ }
93+ };
94+ }
1795}
0 commit comments