22
33namespace Utopia \Tests \Adapter ;
44
5- use PHPUnit \Framework \TestCase ;
6- use ReflectionClass ;
75use Utopia \Query \Query ;
6+ use Utopia \Tests \Usage \Adapter \ClickHouseTestCase ;
87use Utopia \Usage \Adapter \ClickHouse as ClickHouseAdapter ;
98use Utopia \Usage \Usage ;
109
1312 * by_service / by_method_status) is created by setup() and that writes to
1413 * the raw events table fan out into each rollup table.
1514 */
16- class ClickHouseDimRollupTest extends TestCase
15+ class ClickHouseDimRollupTest extends ClickHouseTestCase
1716{
1817 private Usage $ usage ;
1918
@@ -29,21 +28,7 @@ class ClickHouseDimRollupTest extends TestCase
2928
3029 protected function setUp (): void
3130 {
32- $ host = getenv ('CLICKHOUSE_HOST ' ) ?: 'clickhouse ' ;
33- $ username = getenv ('CLICKHOUSE_USER ' ) ?: 'default ' ;
34- $ password = getenv ('CLICKHOUSE_PASSWORD ' ) ?: 'clickhouse ' ;
35- $ port = (int ) (getenv ('CLICKHOUSE_PORT ' ) ?: 8123 );
36- $ secure = (bool ) (getenv ('CLICKHOUSE_SECURE ' ) ?: false );
37-
38- $ this ->adapter = new ClickHouseAdapter ($ host , $ username , $ password , $ port , $ secure );
39- $ this ->adapter ->setNamespace ('utopia_usage_dim_rollup ' );
40- $ this ->adapter ->setSharedTables (true );
41- $ this ->adapter ->setTenant ('1 ' );
42-
43- if ($ database = getenv ('CLICKHOUSE_DATABASE ' )) {
44- $ this ->adapter ->setDatabase ($ database );
45- }
46-
31+ $ this ->adapter = $ this ->makeAdapter ('utopia_usage_dim_rollup ' );
4732 $ this ->usage = new Usage ($ this ->adapter );
4833 $ this ->usage ->setup ();
4934 $ this ->usage ->purge ();
@@ -87,9 +72,6 @@ public function testWritesPropagateToEachRollup(): void
8772 ],
8873 ], Usage::TYPE_EVENT ));
8974
90- // MVs are synchronous on insert by default in ClickHouse, but the
91- // SummingMergeTree won't merge identical sort keys until background
92- // merges run — we count rows, not sum, to check propagation.
9375 foreach ($ this ->rollups as $ rollup ) {
9476 $ table = $ this ->getDimRollupTable ($ rollup ['name ' ]);
9577 $ count = $ this ->countRows ($ table );
@@ -124,9 +106,6 @@ public function testPurgeByIdFiltersDropAllRollupRowsForThatDay(): void
124106 ['metric ' => $ metric , 'value ' => 11 , 'tags ' => ['path ' => '/v1/x ' , 'method ' => 'GET ' , 'status ' => '200 ' , 'service ' => 'storage ' , 'country ' => 'us ' ]],
125107 ], Usage::TYPE_EVENT ));
126108
127- // id only exists on raw events — rollups don't store it. The purge
128- // helper must NOT attempt `WHERE id = ...` against the rollups; it
129- // should fall through to whole-day deletion.
130109 $ this ->usage ->purge ([
131110 Query::equal ('metric ' , [$ metric ]),
132111 Query::equal ('id ' , ['nonexistent-id ' ]),
@@ -151,10 +130,6 @@ public function testPurgeByPathClearsAllRollupsForThatDay(): void
151130 ['metric ' => $ metric , 'value ' => 7 , 'tags ' => ['path ' => '/v1/x ' , 'method ' => 'GET ' , 'status ' => '200 ' , 'service ' => 'storage ' , 'country ' => 'us ' ]],
152131 ], Usage::TYPE_EVENT ));
153132
154- // Purge by a column (path) that only the by_path rollup stores.
155- // Cross-dim rollups (by_country, by_service, by_method_status) cannot
156- // narrow by path, but they must still drop their stale row for the
157- // affected day or routed reads will over-report.
158133 $ this ->usage ->purge ([
159134 Query::equal ('metric ' , [$ metric ]),
160135 Query::equal ('path ' , ['/v1/x ' ]),
@@ -173,49 +148,26 @@ public function testPurgeByPathClearsAllRollupsForThatDay(): void
173148
174149 private function getDimRollupTable (string $ name ): string
175150 {
176- $ reflection = new ReflectionClass ($ this ->adapter );
177- $ method = $ reflection ->getMethod ('getDimRollupTableName ' );
178- $ method ->setAccessible (true );
179- $ raw = $ method ->invoke ($ this ->adapter , $ name );
180- return is_string ($ raw ) ? $ raw : '' ;
151+ return $ this ->resolveTableName ($ this ->adapter , 'getDimRollupTableName ' , [$ name ]);
181152 }
182153
183154 private function tableExists (string $ table ): bool
184155 {
185- $ reflection = new ReflectionClass ($ this ->adapter );
186- $ dbProp = $ reflection ->getProperty ('database ' );
187- $ dbProp ->setAccessible (true );
188- $ databaseValue = $ dbProp ->getValue ($ this ->adapter );
189- $ database = is_string ($ databaseValue ) ? $ databaseValue : '' ;
190-
191- $ sql = "EXISTS TABLE ` {$ database }`.` {$ table }` FORMAT JSON " ;
192- $ query = $ reflection ->getMethod ('query ' );
193- $ query ->setAccessible (true );
194- $ raw = $ query ->invoke ($ this ->adapter , $ sql , []);
195- $ rawString = is_string ($ raw ) ? $ raw : '' ;
196- $ json = json_decode ($ rawString , true );
156+ $ database = $ this ->databaseName ($ this ->adapter );
157+ $ raw = $ this ->queryRaw ($ this ->adapter , "EXISTS TABLE ` {$ database }`.` {$ table }` FORMAT JSON " );
158+ $ json = json_decode ($ raw , true );
197159 if (is_array ($ json ) && isset ($ json ['data ' ][0 ]) && is_array ($ json ['data ' ][0 ])) {
198- $ row = $ json ['data ' ][0 ];
199- $ value = $ row ['result ' ] ?? 0 ;
160+ $ value = $ json ['data ' ][0 ]['result ' ] ?? 0 ;
200161 return ((int ) $ value ) === 1 ;
201162 }
202163 return false ;
203164 }
204165
205166 private function countRows (string $ table ): int
206167 {
207- $ reflection = new ReflectionClass ($ this ->adapter );
208- $ dbProp = $ reflection ->getProperty ('database ' );
209- $ dbProp ->setAccessible (true );
210- $ databaseValue = $ dbProp ->getValue ($ this ->adapter );
211- $ database = is_string ($ databaseValue ) ? $ databaseValue : '' ;
212-
213- $ sql = "SELECT count() AS c FROM ` {$ database }`.` {$ table }` FORMAT JSON " ;
214- $ query = $ reflection ->getMethod ('query ' );
215- $ query ->setAccessible (true );
216- $ raw = $ query ->invoke ($ this ->adapter , $ sql , []);
217- $ rawString = is_string ($ raw ) ? $ raw : '' ;
218- $ json = json_decode ($ rawString , true );
168+ $ database = $ this ->databaseName ($ this ->adapter );
169+ $ raw = $ this ->queryRaw ($ this ->adapter , "SELECT count() AS c FROM ` {$ database }`.` {$ table }` FORMAT JSON " );
170+ $ json = json_decode ($ raw , true );
219171 if (is_array ($ json ) && isset ($ json ['data ' ][0 ]) && is_array ($ json ['data ' ][0 ])) {
220172 return (int ) ($ json ['data ' ][0 ]['c ' ] ?? 0 );
221173 }
@@ -224,19 +176,11 @@ private function countRows(string $table): int
224176
225177 private function sumValue (string $ table , string $ metric ): int
226178 {
227- $ reflection = new ReflectionClass ($ this ->adapter );
228- $ dbProp = $ reflection ->getProperty ('database ' );
229- $ dbProp ->setAccessible (true );
230- $ databaseValue = $ dbProp ->getValue ($ this ->adapter );
231- $ database = is_string ($ databaseValue ) ? $ databaseValue : '' ;
232-
179+ $ database = $ this ->databaseName ($ this ->adapter );
233180 $ sql = "SELECT sum(value) AS s FROM ` {$ database }`.` {$ table }` "
234181 . "WHERE metric = ' " . addslashes ($ metric ) . "' FORMAT JSON " ;
235- $ query = $ reflection ->getMethod ('query ' );
236- $ query ->setAccessible (true );
237- $ raw = $ query ->invoke ($ this ->adapter , $ sql , []);
238- $ rawString = is_string ($ raw ) ? $ raw : '' ;
239- $ json = json_decode ($ rawString , true );
182+ $ raw = $ this ->queryRaw ($ this ->adapter , $ sql );
183+ $ json = json_decode ($ raw , true );
240184 if (is_array ($ json ) && isset ($ json ['data ' ][0 ]) && is_array ($ json ['data ' ][0 ])) {
241185 return (int ) ($ json ['data ' ][0 ]['s ' ] ?? 0 );
242186 }
0 commit comments