Skip to content

Commit f34e587

Browse files
feeblefakieKodaiD
andauthored
Backport to branch(3.16) : Add Cassandra permission test (#2833)
Co-authored-by: Kodai Doki <[email protected]>
1 parent c5aaba8 commit f34e587

15 files changed

+1439
-6
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: Test Permissions
2+
3+
on:
4+
workflow_dispatch:
5+
6+
env:
7+
TERM: dumb
8+
JAVA_VERSION: '8'
9+
JAVA_VENDOR: 'temurin'
10+
11+
jobs:
12+
integration-test-permission-cassandra-3-0:
13+
name: Cassandra 3.0 Permission Integration Test
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }})
20+
uses: actions/setup-java@v4
21+
with:
22+
java-version: ${{ env.JAVA_VERSION }}
23+
distribution: ${{ env.JAVA_VENDOR }}
24+
25+
- name: Setup Gradle
26+
uses: gradle/actions/setup-gradle@v4
27+
28+
- name: Start Cassandra with authentication enabled
29+
run: |
30+
docker run -d --name cassandra \
31+
-p 9042:9042 \
32+
-e CASSANDRA_PASSWORD_SEEDER=yes \
33+
-e CASSANDRA_PASSWORD=cassandra \
34+
-e CASSANDRA_AUTHENTICATOR=PasswordAuthenticator \
35+
-e CASSANDRA_AUTHORIZER=CassandraAuthorizer \
36+
bitnami/cassandra:3.0
37+
38+
- name: Wait for Cassandra to be ready
39+
run: sleep 30
40+
41+
- name: Execute Gradle 'integrationTestCassandraPermission' task
42+
run: ./gradlew integrationTestCassandraPermission
43+
44+
- name: Upload Gradle test reports
45+
if: always()
46+
uses: actions/upload-artifact@v4
47+
with:
48+
name: cassandra_3.0_permission_integration_test_reports
49+
path: core/build/reports/tests/integrationTestCassandraPermission
50+
51+
integration-test-permission-cassandra-3-11:
52+
name: Cassandra 3.11 Permission Integration Test
53+
runs-on: ubuntu-latest
54+
55+
steps:
56+
- uses: actions/checkout@v4
57+
58+
- name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }})
59+
uses: actions/setup-java@v4
60+
with:
61+
java-version: ${{ env.JAVA_VERSION }}
62+
distribution: ${{ env.JAVA_VENDOR }}
63+
64+
- name: Setup Gradle
65+
uses: gradle/actions/setup-gradle@v4
66+
67+
- name: Start Cassandra with authentication enabled
68+
run: |
69+
docker run -d --name cassandra \
70+
-p 9042:9042 \
71+
-e CASSANDRA_PASSWORD_SEEDER=yes \
72+
-e CASSANDRA_PASSWORD=cassandra \
73+
-e CASSANDRA_AUTHENTICATOR=PasswordAuthenticator \
74+
-e CASSANDRA_AUTHORIZER=CassandraAuthorizer \
75+
bitnami/cassandra:3.11
76+
77+
- name: Wait for Cassandra to be ready
78+
run: sleep 30
79+
80+
- name: Execute Gradle 'integrationTestCassandraPermission' task
81+
run: ./gradlew integrationTestCassandraPermission
82+
83+
- name: Upload Gradle test reports
84+
if: always()
85+
uses: actions/upload-artifact@v4
86+
with:
87+
name: cassandra_3.11_permission_integration_test_reports
88+
path: core/build/reports/tests/integrationTestCassandraPermission

core/build.gradle

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ sourceSets {
2222
srcDir file('src/integration-test/java')
2323
include '**/com/scalar/db/common/*.java'
2424
include '**/com/scalar/db/storage/cassandra/*.java'
25+
exclude '**/com/scalar/db/storage/cassandra/CassandraPermissionTestUtils.java'
26+
exclude '**/com/scalar/db/storage/cassandra/CassandraPermissionIntegrationTest.java'
27+
exclude '**/com/scalar/db/storage/cassandra/CassandraAdminPermissionIntegrationTest.java'
2528
}
2629
resources.srcDir file('src/integration-test/resources')
2730
}
@@ -67,6 +70,20 @@ sourceSets {
6770
}
6871
resources.srcDir file('src/integration-test/resources')
6972
}
73+
integrationTestCassandraPermission {
74+
java {
75+
compileClasspath += main.output + test.output
76+
runtimeClasspath += main.output + test.output
77+
srcDir file('src/integration-test/java')
78+
include '**/com/scalar/db/common/*.java'
79+
include '**/com/scalar/db/storage/cassandra/CassandraPermissionTestUtils.java'
80+
include '**/com/scalar/db/storage/cassandra/CassandraAdminTestUtils.java'
81+
include '**/com/scalar/db/storage/cassandra/CassandraEnv.java'
82+
include '**/com/scalar/db/storage/cassandra/CassandraPermissionIntegrationTest.java'
83+
include '**/com/scalar/db/storage/cassandra/CassandraAdminPermissionIntegrationTest.java'
84+
}
85+
resources.srcDir file('src/integration-test/resources')
86+
}
7087
}
7188

7289
configurations {
@@ -88,6 +105,9 @@ configurations {
88105
integrationTestMultiStorageImplementation.extendsFrom testImplementation
89106
integrationTestMultiStorageRuntimeOnly.extendsFrom testRuntimeOnly
90107
integrationTestMultiStorageCompileOnly.extendsFrom testCompileOnly
108+
integrationTestCassandraPermissionImplementation.extendsFrom testImplementation
109+
integrationTestCassandraPermissionRuntimeOnly.extendsFrom testRuntimeOnly
110+
integrationTestCassandraPermissionCompileOnly.extendsFrom testCompileOnly
91111
}
92112

93113
dependencies {
@@ -200,6 +220,17 @@ task integrationTestMultiStorage(type: Test) {
200220
}
201221
}
202222

223+
task integrationTestCassandraPermission(type: Test) {
224+
description = 'Runs the integration tests for Cassandra permissions.'
225+
group = 'verification'
226+
testClassesDirs = sourceSets.integrationTestCassandraPermission.output.classesDirs
227+
classpath = sourceSets.integrationTestCassandraPermission.runtimeClasspath
228+
outputs.upToDateWhen { false } // ensures integration tests are run every time when called
229+
options {
230+
systemProperties(System.getProperties().findAll { it.key.toString().startsWith("scalardb") })
231+
}
232+
}
233+
203234
spotless {
204235
java {
205236
target 'src/*/java/**/*.java'
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.scalar.db.storage.cassandra;
2+
3+
import static com.scalar.db.storage.cassandra.CassandraPermissionTestUtils.MAX_RETRY_COUNT;
4+
import static com.scalar.db.storage.cassandra.CassandraPermissionTestUtils.SLEEP_BETWEEN_RETRIES_SECONDS;
5+
6+
import com.google.common.util.concurrent.Uninterruptibles;
7+
import com.scalar.db.api.DistributedStorageAdminPermissionIntegrationTestBase;
8+
import com.scalar.db.util.AdminTestUtils;
9+
import com.scalar.db.util.PermissionTestUtils;
10+
import java.util.Collections;
11+
import java.util.Map;
12+
import java.util.Properties;
13+
import org.junit.jupiter.api.Disabled;
14+
import org.junit.jupiter.api.Test;
15+
16+
public class CassandraAdminPermissionIntegrationTest
17+
extends DistributedStorageAdminPermissionIntegrationTestBase {
18+
@Override
19+
protected Properties getProperties(String testName) {
20+
return CassandraEnv.getProperties(testName);
21+
}
22+
23+
@Override
24+
protected Properties getPropertiesForNormalUser(String testName) {
25+
return CassandraEnv.getPropertiesForNormalUser(testName);
26+
}
27+
28+
@Override
29+
protected AdminTestUtils getAdminTestUtils(String testName) {
30+
return new CassandraAdminTestUtils(getProperties(testName));
31+
}
32+
33+
@Override
34+
protected PermissionTestUtils getPermissionTestUtils(String testName) {
35+
return new CassandraPermissionTestUtils(getProperties(testName));
36+
}
37+
38+
@Override
39+
protected Map<String, String> getCreationOptions() {
40+
return Collections.singletonMap(CassandraAdmin.REPLICATION_FACTOR, "1");
41+
}
42+
43+
@Override
44+
protected void waitForNamespaceCreation() {
45+
try {
46+
AdminTestUtils utils = getAdminTestUtils(TEST_NAME);
47+
int retryCount = 0;
48+
while (retryCount < MAX_RETRY_COUNT) {
49+
if (utils.namespaceExists(NAMESPACE)) {
50+
utils.close();
51+
return;
52+
}
53+
Uninterruptibles.sleepUninterruptibly(
54+
SLEEP_BETWEEN_RETRIES_SECONDS, java.util.concurrent.TimeUnit.SECONDS);
55+
retryCount++;
56+
}
57+
utils.close();
58+
throw new RuntimeException("Namespace was not created after " + MAX_RETRY_COUNT + " retries");
59+
} catch (Exception e) {
60+
throw new RuntimeException("Failed to wait for namespace creation", e);
61+
}
62+
}
63+
64+
@Override
65+
protected void waitForTableCreation() {
66+
try {
67+
AdminTestUtils utils = getAdminTestUtils(TEST_NAME);
68+
int retryCount = 0;
69+
while (retryCount < MAX_RETRY_COUNT) {
70+
if (utils.tableExists(NAMESPACE, TABLE)) {
71+
utils.close();
72+
return;
73+
}
74+
Uninterruptibles.sleepUninterruptibly(
75+
SLEEP_BETWEEN_RETRIES_SECONDS, java.util.concurrent.TimeUnit.SECONDS);
76+
retryCount++;
77+
}
78+
utils.close();
79+
throw new RuntimeException("Table was not created after " + MAX_RETRY_COUNT + " retries");
80+
} catch (Exception e) {
81+
throw new RuntimeException("Failed to wait for table creation", e);
82+
}
83+
}
84+
85+
@Override
86+
protected void waitForNamespaceDeletion() {
87+
try {
88+
AdminTestUtils utils = getAdminTestUtils(TEST_NAME);
89+
int retryCount = 0;
90+
while (retryCount < MAX_RETRY_COUNT) {
91+
if (!utils.namespaceExists(NAMESPACE)) {
92+
utils.close();
93+
return;
94+
}
95+
Uninterruptibles.sleepUninterruptibly(
96+
SLEEP_BETWEEN_RETRIES_SECONDS, java.util.concurrent.TimeUnit.SECONDS);
97+
retryCount++;
98+
}
99+
utils.close();
100+
throw new RuntimeException("Namespace was not deleted after " + MAX_RETRY_COUNT + " retries");
101+
} catch (Exception e) {
102+
throw new RuntimeException("Failed to wait for namespace deletion", e);
103+
}
104+
}
105+
106+
@Override
107+
protected void waitForTableDeletion() {
108+
try {
109+
AdminTestUtils utils = getAdminTestUtils(TEST_NAME);
110+
int retryCount = 0;
111+
while (retryCount < MAX_RETRY_COUNT) {
112+
if (!utils.tableExists(NAMESPACE, TABLE)) {
113+
utils.close();
114+
return;
115+
}
116+
Uninterruptibles.sleepUninterruptibly(
117+
SLEEP_BETWEEN_RETRIES_SECONDS, java.util.concurrent.TimeUnit.SECONDS);
118+
retryCount++;
119+
}
120+
utils.close();
121+
throw new RuntimeException("Table was not deleted after " + MAX_RETRY_COUNT + " retries");
122+
} catch (Exception e) {
123+
throw new RuntimeException("Failed to wait for table deletion", e);
124+
}
125+
}
126+
127+
@Test
128+
@Override
129+
@Disabled("Import-related functionality is not supported in Cassandra")
130+
public void getImportTableMetadata_WithSufficientPermission_ShouldSucceed() {}
131+
132+
@Test
133+
@Override
134+
@Disabled("Import-related functionality is not supported in Cassandra")
135+
public void addRawColumnToTable_WithSufficientPermission_ShouldSucceed() {}
136+
137+
@Test
138+
@Override
139+
@Disabled("Import-related functionality is not supported in Cassandra")
140+
public void importTable_WithSufficientPermission_ShouldSucceed() {}
141+
}

core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraAdminTestUtils.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package com.scalar.db.storage.cassandra;
22

3+
import com.scalar.db.config.DatabaseConfig;
34
import com.scalar.db.util.AdminTestUtils;
45
import java.util.Properties;
56

67
public class CassandraAdminTestUtils extends AdminTestUtils {
8+
private final ClusterManager clusterManager;
79

810
public CassandraAdminTestUtils(Properties properties) {
911
super(properties);
12+
DatabaseConfig databaseConfig = new DatabaseConfig(properties);
13+
clusterManager = new ClusterManager(databaseConfig);
1014
}
1115

1216
@Override
@@ -23,4 +27,19 @@ public void truncateMetadataTable() {
2327
public void corruptMetadata(String namespace, String table) {
2428
// Do nothing
2529
}
30+
31+
@Override
32+
public boolean namespaceExists(String namespace) {
33+
return clusterManager.getSession().getCluster().getMetadata().getKeyspace(namespace) != null;
34+
}
35+
36+
@Override
37+
public boolean tableExists(String namespace, String table) {
38+
return clusterManager.getMetadata(namespace, table) != null;
39+
}
40+
41+
@Override
42+
public void close() {
43+
clusterManager.close();
44+
}
2645
}

core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraEnv.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ public final class CassandraEnv {
77
private static final String PROP_CASSANDRA_CONTACT_POINTS = "scalardb.cassandra.contact_points";
88
private static final String PROP_CASSANDRA_USERNAME = "scalardb.cassandra.username";
99
private static final String PROP_CASSANDRA_PASSWORD = "scalardb.cassandra.password";
10+
private static final String PROP_CASSANDRA_NORMAL_USERNAME = "scalardb.cassandra.normal_username";
11+
private static final String PROP_CASSANDRA_NORMAL_PASSWORD = "scalardb.cassandra.normal_password";
1012

1113
private static final String DEFAULT_CASSANDRA_CONTACT_POINTS = "localhost";
1214
private static final String DEFAULT_CASSANDRA_USERNAME = "cassandra";
1315
private static final String DEFAULT_CASSANDRA_PASSWORD = "cassandra";
16+
private static final String DEFAULT_CASSANDRA_NORMAL_USERNAME = "test";
17+
private static final String DEFAULT_CASSANDRA_NORMAL_PASSWORD = "test";
1418

1519
private CassandraEnv() {}
1620

@@ -29,4 +33,17 @@ public static Properties getProperties(@SuppressWarnings("unused") String testNa
2933
props.setProperty(DatabaseConfig.CROSS_PARTITION_SCAN_ORDERING, "false");
3034
return props;
3135
}
36+
37+
public static Properties getPropertiesForNormalUser(String testName) {
38+
Properties properties = getProperties(testName);
39+
40+
String username =
41+
System.getProperty(PROP_CASSANDRA_NORMAL_USERNAME, DEFAULT_CASSANDRA_NORMAL_USERNAME);
42+
String password =
43+
System.getProperty(PROP_CASSANDRA_NORMAL_PASSWORD, DEFAULT_CASSANDRA_NORMAL_PASSWORD);
44+
properties.setProperty(DatabaseConfig.USERNAME, username);
45+
properties.setProperty(DatabaseConfig.PASSWORD, password);
46+
47+
return properties;
48+
}
3249
}

0 commit comments

Comments
 (0)