Skip to content

Commit 1173321

Browse files
committed
add new suite paratest-snowflake-real-storage
1 parent 494a1a4 commit 1173321

2 files changed

Lines changed: 183 additions & 0 deletions

File tree

phpunit.xml.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,5 +321,8 @@
321321
<testsuite name="snowflake-network-policies">
322322
<directory>tests/Backend/NetworkPolicies</directory>
323323
</testsuite>
324+
<testsuite name="paratest-snowflake-real-storage">
325+
<directory>tests/Backend/Features/RealReadOnlyBranches</directory>
326+
</testsuite>
324327
</testsuites>
325328
</phpunit>
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Keboola\Test\Backend\Features\RealReadOnlyBranches;
6+
7+
use Keboola\StorageApi\ClientException;
8+
use Keboola\StorageApi\DevBranches;
9+
use Keboola\StorageApi\Workspaces;
10+
use Keboola\Test\Backend\Workspaces\ParallelWorkspacesTestCase;
11+
use Keboola\Test\Backend\Workspaces\Backend\WorkspaceBackendFactory;
12+
13+
class SnowflakeRealBranchesTest extends ParallelWorkspacesTestCase
14+
{
15+
private DevBranches $branches;
16+
17+
public function setUp(): void
18+
{
19+
parent::setUp();
20+
$this->branches = new DevBranches($this->_client);
21+
$this->cleanupTestBranches($this->_client);
22+
}
23+
24+
/**
25+
* This test verifies visibility of buckets from workspaces across default and dev branches
26+
* when project has storage-branches feature set only.
27+
* Scenario:
28+
* 1. Create bucket in default branch.
29+
* 2. Create dev branch and create bucket inside it.
30+
* 3. Assert backendPath for both buckets.
31+
* 4. Create workspace in default branch – ensure dev bucket NOT visible.
32+
* 5. Create workspace in dev branch – ensure BOTH buckets visible.
33+
* 6. Drop dev branch – ensure its bucket and workspace are deleted (no longer accessible).
34+
*/
35+
public function testBucketsVisibilityBetweenBranchWorkspaces(): void
36+
{
37+
$this->allowTestForBackendsOnly([
38+
self::BACKEND_SNOWFLAKE,
39+
]);
40+
$tokenInfo = $this->_client->verifyToken();
41+
if (!in_array('storage-branches', $tokenInfo['owner']['features'], true)) {
42+
$this->markTestSkipped('Project does not have storage-branches feature.');
43+
}
44+
45+
// Default branch bucket already created in setUp() via initEmptyTestBucketsForParallelTests
46+
$defaultBucketId = $this->getTestBucketId(self::STAGE_IN);
47+
$defaultInBucket = $this->_client->getBucket($defaultBucketId);
48+
$defaultOutBucket = $this->_client->getBucket($this->getTestBucketId(self::STAGE_OUT));
49+
// create table in bucket
50+
$csv = $this->createTempCsv();
51+
$csv->writeRow(['Name', 'Id']);
52+
$csv->writeRow(['aabb', 'test']);
53+
$this->_client->createTableAsync(
54+
$defaultInBucket['id'],
55+
'test1',
56+
$csv,
57+
);
58+
59+
// Prepare unique suffix for dev resources
60+
$devBucketName = $this->getTestBucketName($this->generateDescriptionForTestObject());
61+
62+
// Create dev branch and its bucket
63+
$branch = $this->branches->createBranch($this->generateDescriptionForTestObject());
64+
$branchId = $branch['id'];
65+
66+
$devClient = $this->_client->getBranchAwareClient($branchId);
67+
68+
$devBucketId = $this->initEmptyBucket($devBucketName, self::STAGE_IN, $this->generateDescriptionForTestObject(), $devClient);
69+
$devBucket = $devClient->getBucket($devBucketId);
70+
$devClient->createTableAsync(
71+
$devBucket['id'],
72+
'test1',
73+
$csv,
74+
);
75+
76+
// Assert backendPath for both buckets
77+
$this->assertStringStartsWith('in.c-', $defaultInBucket['backendPath'][1]);
78+
$this->assertStringStartsWith($branch['id'] . '_in.c-', $devBucket['backendPath'][1]);
79+
80+
// Workspace in default branch – should NOT see dev bucket
81+
$wsDefault = $this->initTestWorkspace(
82+
self::BACKEND_SNOWFLAKE,
83+
[],
84+
true,
85+
true,
86+
$this->_client
87+
);
88+
$wsBackend = WorkspaceBackendFactory::createWorkspaceBackend($wsDefault, true);
89+
// get list of schemas visible to workspace user
90+
/**
91+
* @var array<array{name:string}> $schemas
92+
*/
93+
//@phpstan-ignore-next-line
94+
$schemas = $wsBackend->getDb()->fetchAllAssociative('SHOW SCHEMAS WITH PRIVILEGES USAGE;');
95+
$this->assertExpectedContainsSchemaNames([
96+
$wsDefault['connection']['schema'],
97+
$defaultInBucket['backendPath'][1],
98+
$defaultOutBucket['backendPath'][1],
99+
], $schemas);
100+
$this->assertExpectedNotContainsSchemaNames([
101+
$devBucket['backendPath'][1],
102+
], $schemas);
103+
104+
// Workspace in dev branch – should see both buckets (create via helpers with dev client)
105+
$wsDev = $this->initTestWorkspace(
106+
self::BACKEND_SNOWFLAKE,
107+
[],
108+
true,
109+
true,
110+
$devClient,
111+
);
112+
$wsDevBackend = WorkspaceBackendFactory::createWorkspaceBackend($wsDev, true);
113+
/**
114+
* @var array<array{name:string}> $schemas
115+
*/
116+
//@phpstan-ignore-next-line
117+
$schemas = $wsDevBackend->getDb()->fetchAllAssociative('SHOW SCHEMAS WITH PRIVILEGES USAGE;');
118+
// get list of schemas visible to workspace user in dv branch
119+
$this->assertExpectedContainsSchemaNames([
120+
$devBucket['backendPath'][1],
121+
$wsDev['connection']['schema'], // user can see dev branch schema
122+
$defaultInBucket['backendPath'][1],
123+
$defaultOutBucket['backendPath'][1],
124+
], $schemas);
125+
126+
// Drop dev branch – dev bucket + dev workspace should be gone
127+
$this->branches->deleteBranch($branchId);
128+
129+
// Default bucket must still exist
130+
$remainingDefaultBucket = $this->_client->getBucket($defaultBucketId);
131+
$this->assertSame($defaultBucketId, $remainingDefaultBucket['id']);
132+
133+
try {
134+
(new Workspaces($this->workspaceSapiClient->getBranchAwareClient($branchId)))
135+
->getWorkspace($wsDev['id']);
136+
$this->fail('Dev workspace still exists after branch deletion');
137+
} catch (ClientException $e) {
138+
$this->assertSame(404, $e->getCode());
139+
}
140+
141+
try {
142+
$devClient->getBucket($devBucketId);
143+
$this->fail('Dev bucket still exists after branch deletion');
144+
} catch (ClientException $e) {
145+
$this->assertSame(404, $e->getCode());
146+
}
147+
}
148+
149+
/**
150+
* @param string[] $expected
151+
* @param array<array{name:string}> $schemas
152+
*/
153+
private function assertExpectedContainsSchemaNames(array $expected, array $schemas): void
154+
{
155+
$schemaNames = array_map(fn($r) => $r['name'], $schemas);
156+
foreach ($expected as $expectedSchema) {
157+
$this->assertContains(
158+
$expectedSchema,
159+
$schemaNames,
160+
sprintf('Schema "%s" not found in "%s"', $expectedSchema, implode(', ', $schemaNames)),
161+
);
162+
}
163+
}
164+
165+
/**
166+
* @param string[] $notExpected
167+
* @param array<array{name:string}> $schemas
168+
*/
169+
private function assertExpectedNotContainsSchemaNames(array $notExpected, array $schemas): void
170+
{
171+
$schemaNames = array_map(fn($r) => $r['name'], $schemas);
172+
foreach ($notExpected as $expectedSchema) {
173+
$this->assertNotContains(
174+
$expectedSchema,
175+
$schemaNames,
176+
sprintf('Schema "%s" was found in "%s" that was not expected.', $expectedSchema, implode(', ', $schemaNames)),
177+
);
178+
}
179+
}
180+
}

0 commit comments

Comments
 (0)