Skip to content

Commit a9b563d

Browse files
CASSANALYTICS-106: Setup CI Pipeline with GitHub Actions
1 parent 59bd1d7 commit a9b563d

10 files changed

Lines changed: 322 additions & 3 deletions

File tree

.github/workflows/test.yaml

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
name: Test
19+
20+
on:
21+
push:
22+
branches: [ "trunk" ]
23+
pull_request:
24+
branches: [ "trunk" ]
25+
# Allows you to run this workflow manually from the Actions tab
26+
workflow_dispatch:
27+
28+
jobs:
29+
build:
30+
name: Compile and build
31+
runs-on: ubuntu-latest
32+
steps:
33+
- uses: actions/checkout@v4
34+
- name: Setup JDK
35+
uses: actions/setup-java@v4
36+
with:
37+
distribution: 'temurin'
38+
java-version: 11
39+
- run: |
40+
sudo apt-get update
41+
42+
if [ -f /etc/ssl/certs/java/cacerts/cacerts ]; then
43+
sudo mv /etc/ssl/certs/java/cacerts/ /etc/ssl/certs/java/cacerts-old
44+
sudo mv /etc/ssl/certs/java/cacerts-old/cacerts /etc/ssl/certs/java/
45+
sudo rmdir /etc/ssl/certs/java/cacerts-old
46+
fi
47+
48+
apt-get download ant ant-optional
49+
sudo dpkg --force-all -i ant*.deb
50+
rm ant*.deb
51+
52+
sudo bash -c 'for i in {2..20}; do echo 127.0.0.${i} localhost${i} >> /etc/hosts; done'
53+
54+
for i in {2..20}
55+
do
56+
sudo ip addr add "127.0.0.${i}" dev lo
57+
sudo route add -host "127.0.0.${i}" dev lo;
58+
done
59+
60+
CASSANDRA_USE_JDK11=true ./scripts/build-dependencies.sh
61+
62+
./gradlew codeCheckTasks
63+
- name: Cache Maven repository
64+
uses: actions/cache@v4
65+
with:
66+
path: ~/.m2
67+
key: maven-repo-${{ github.sha }}
68+
- name: Cache workspace
69+
id: cache-build-save
70+
uses: actions/cache/save@v4
71+
with:
72+
path: ${{ github.workspace }}
73+
key: build-${{ github.sha }}
74+
75+
unit-test:
76+
name: Unit test
77+
needs: build
78+
runs-on: ubuntu-latest
79+
strategy:
80+
matrix:
81+
scala: [ '2.12', '2.13' ]
82+
fail-fast: false
83+
steps:
84+
- name: Setup JDK
85+
uses: actions/setup-java@v4
86+
with:
87+
distribution: 'temurin'
88+
java-version: 11
89+
- run: |
90+
sudo bash -c 'for i in {2..20}; do echo 127.0.0.${i} localhost${i} >> /etc/hosts; done'
91+
for i in {2..20}
92+
do
93+
sudo ip addr add "127.0.0.${i}" dev lo
94+
sudo route add -host "127.0.0.${i}" dev lo;
95+
done
96+
- name: Cache Maven repository
97+
uses: actions/cache@v4
98+
with:
99+
path: ~/.m2
100+
key: maven-repo-${{ github.sha }}
101+
- name: Cache workspace
102+
id: cache-build-restore
103+
uses: actions/cache/restore@v4
104+
with:
105+
path: ${{ github.workspace }}
106+
key: build-${{ github.sha }}
107+
- run: |
108+
export SPARK_VERSION="3"
109+
export SCALA_VERSION="${{ matrix.scala }}"
110+
export JDK_VERSION="11"
111+
export INTEGRATION_MAX_PARALLEL_FORKS=1
112+
export INTEGRATION_MAX_HEAP_SIZE="1500M"
113+
export CASSANDRA_USE_JDK11=true
114+
115+
./gradlew --stacktrace clean assemble check -x cassandra-analytics-integration-tests:test
116+
117+
integration-test:
118+
name: Integration test
119+
needs: build
120+
runs-on: ubuntu-latest
121+
strategy:
122+
matrix:
123+
scala: [ '2.12', '2.13' ]
124+
cassandra: [ '4.0.17', '4.1.4', '5.0.5' ]
125+
job_index: [ 0, 1, 2, 3, 4 ]
126+
job_total: [ 5 ]
127+
exclude:
128+
- scala: "2.12"
129+
cassandra: "5.0.5"
130+
- scala: "2.12"
131+
cassandra: "4.1.4"
132+
- scala: "2.13"
133+
cassandra: "4.0.17"
134+
fail-fast: false
135+
steps:
136+
- name: Setup JDK
137+
uses: actions/setup-java@v4
138+
with:
139+
distribution: 'temurin'
140+
java-version: 11
141+
- run: |
142+
sudo bash -c 'for i in {2..20}; do echo 127.0.0.${i} localhost${i} >> /etc/hosts; done'
143+
for i in {2..20}
144+
do
145+
sudo ip addr add "127.0.0.${i}" dev lo
146+
sudo route add -host "127.0.0.${i}" dev lo;
147+
done
148+
- name: Cache Maven repository
149+
uses: actions/cache@v4
150+
with:
151+
path: ~/.m2
152+
key: maven-repo-${{ github.sha }}
153+
- name: Cache workspace
154+
id: cache-build-restore
155+
uses: actions/cache/restore@v4
156+
with:
157+
path: ${{ github.workspace }}
158+
key: build-${{ github.sha }}
159+
- run: |
160+
export SPARK_VERSION="3"
161+
export SCALA_VERSION="${{ matrix.scala }}"
162+
export JDK_VERSION="11"
163+
export INTEGRATION_MAX_PARALLEL_FORKS=1
164+
export INTEGRATION_MAX_HEAP_SIZE="4096M"
165+
export CASSANDRA_USE_JDK11=true
166+
167+
export DTEST_JAR="dtest-${{ matrix.cassandra }}.jar"
168+
export CASSANDRA_VERSION=$(echo ${{ matrix.cassandra }} | cut -d'.' -f 1,2)
169+
170+
./gradlew --stacktrace clean assemble
171+
172+
cd cassandra-analytics-integration-tests/src/test/java
173+
CLASSNAMES=$(find . -name '*Test.java' | sort | cut -c 3- | sed 's@/@.@g' | sed 's/.\{5\}$//' | awk 'NR % ${{ matrix.job_total }} == ${{ matrix.job_index }}')
174+
cd ../../../..
175+
176+
EXIT_STATUS=0
177+
# Execution of "gradle test --test $TEST_NAME" returns non-zero exit code when commend did not run any test
178+
# (e.g. when all tests are ignored). Currently there is no option to change Gradle behaviour.
179+
# Workaround the issue by explicitly skipping test classes that cannot be executed on Cassandra 4.0.
180+
C40_EXCLUSIONS=("org.apache.cassandra.analytics.BulkWriteDownInstanceMultipleTokensTest" "org.apache.cassandra.analytics.BulkWriteDownSidecarMultipleTokensTest" "org.apache.cassandra.analytics.CassandraAnalyticsSimpleMultipleTokensTest" "org.apache.cassandra.analytics.RandomPartitionerTest" "org.apache.cassandra.analytics.testcontainer.BulkWriteS3CompatModeSimpleMultipleTokensTest" "org.apache.cassandra.analytics.data.ClearSnapshotTest")
181+
for TEST_NAME in $CLASSNAMES; do
182+
SKIP="false"
183+
for C40_EXCLUSION in "${C40_EXCLUSIONS[@]}";
184+
do
185+
if [[ "$CASSANDRA_VERSION" == "4.0" && "$TEST_NAME" == ${C40_EXCLUSION} ]]; then
186+
SKIP="true"
187+
break
188+
fi
189+
done
190+
191+
test_id=$(date +%H%M%S)
192+
mkdir -p test-reports/$test_id
193+
194+
if [ $SKIP == "false" ]; then
195+
echo Executing test $TEST_NAME
196+
./gradlew --stacktrace cassandra-analytics-integration-tests:test --tests $TEST_NAME --no-daemon || EXIT_STATUS=$?;
197+
mv build/test-reports/* test-reports/$test_id
198+
else
199+
echo "Skipping test $TEST_NAME"
200+
fi
201+
done;
202+
203+
tar czf integration-tests.tar.gz test-reports/*
204+
205+
exit $EXIT_STATUS
206+
- name: Publish test results
207+
uses: actions/upload-artifact@v4
208+
if: (!cancelled())
209+
with:
210+
name: integration-tests-${{ matrix.scala }}-${{ matrix.cassandra }}-${{ matrix.job_index }}
211+
path: integration-tests.tar.gz

cassandra-analytics-core/src/main/java/org/apache/cassandra/spark/bulkwriter/SortedSSTableWriter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public int sstableCount()
170170
return sstableCount;
171171
}
172172

173-
public Map<Path, Digest> prepareSStablesToSend(@NotNull BulkWriterContext writerContext, Set<SSTableDescriptor> sstables) throws IOException
173+
public synchronized Map<Path, Digest> prepareSStablesToSend(@NotNull BulkWriterContext writerContext, Set<SSTableDescriptor> sstables) throws IOException
174174
{
175175
DirectoryStream.Filter<Path> sstableFilter = path -> {
176176
SSTableDescriptor baseName = SSTables.getSSTableDescriptor(path);
@@ -199,7 +199,7 @@ public Map<Path, Digest> prepareSStablesToSend(@NotNull BulkWriterContext writer
199199
return fileDigests;
200200
}
201201

202-
public void close(BulkWriterContext writerContext) throws IOException
202+
public synchronized void close(BulkWriterContext writerContext) throws IOException
203203
{
204204
if (isClosed)
205205
{
@@ -208,6 +208,7 @@ public void close(BulkWriterContext writerContext) throws IOException
208208
}
209209
isClosed = true;
210210
cqlSSTableWriter.close();
211+
Map<Path, Digest> lastFileDigests = new HashMap<>();
211212
for (Path dataFile : getDataFileStream())
212213
{
213214
// NOTE: We calculate file hashes before re-reading so that we know what we hashed
@@ -222,10 +223,11 @@ public void close(BulkWriterContext writerContext) throws IOException
222223
if (!alreadyHashed)
223224
{
224225
overallFileDigests.putAll(calculateFileDigestMap(dataFile));
226+
lastFileDigests.putAll(calculateFileDigestMap(dataFile));
225227
}
226228
sstableCount += 1;
227229
}
228-
bytesWritten += calculatedTotalSize(overallFileDigests.keySet());
230+
bytesWritten += calculatedTotalSize(lastFileDigests.keySet());
229231
validateSSTables(writerContext);
230232
}
231233

cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/distributed/impl/CassandraCluster.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
package org.apache.cassandra.distributed.impl;
2121

2222
import java.io.IOException;
23+
import java.lang.reflect.Field;
24+
import java.lang.reflect.Modifier;
2325
import java.net.InetSocketAddress;
2426
import java.util.Arrays;
2527
import java.util.Iterator;
@@ -94,6 +96,11 @@ public AbstractCluster<I> initializeCluster(String versionString,
9496
int originalNodeCount = nodesPerDc * dcCount;
9597
int finalNodeCount = dcCount * (nodesPerDc + newNodesPerDc);
9698

99+
if (requestedVersion.version.isLowerThan("4.1"))
100+
{
101+
updateCassandra40DTestSharedClasses();
102+
}
103+
97104
UpgradeableCluster.Builder clusterBuilder = UpgradeableCluster.build(originalNodeCount);
98105
clusterBuilder.withVersion(requestedVersion)
99106
.withDynamicPortAllocation(configuration.dynamicPortAllocation) // to allow parallel test runs
@@ -152,6 +159,27 @@ public AbstractCluster<I> initializeCluster(String versionString,
152159
return (AbstractCluster<I>) cluster;
153160
}
154161

162+
/**
163+
* CASSANDRA-16931 has not been backported to Cassandra 4.0, so we cannot
164+
* configure shared classes. Applying a workaround with reflection.
165+
*/
166+
private static void updateCassandra40DTestSharedClasses()
167+
{
168+
try
169+
{
170+
Field field = AbstractCluster.class.getDeclaredField("SHARED_PREDICATE");
171+
field.setAccessible(true);
172+
Field modifiersField = Field.class.getDeclaredField("modifiers");
173+
modifiersField.setAccessible(true);
174+
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
175+
field.set(null, ((Predicate<String>) field.get(null)).or(EXTRA));
176+
}
177+
catch (Exception e)
178+
{
179+
throw new IllegalStateException("Failed to adjust Cassandra 4.0 DTest shared classes", e);
180+
}
181+
}
182+
155183
// IClusterExtension methods
156184

157185
@Override

cassandra-analytics-integration-framework/src/main/java/org/apache/cassandra/testing/TestUtils.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
import com.google.common.collect.ImmutableMap;
2626

27+
import com.vdurmont.semver4j.Semver;
28+
import org.apache.cassandra.distributed.shared.Versions;
2729
import org.apache.cassandra.sidecar.testing.QualifiedName;
2830

2931
/**
@@ -130,4 +132,14 @@ public static void configureDefaultDTestJarProperties()
130132

131133
System.setProperty("cassandra.minimum_replication_factor", "1");
132134
}
135+
136+
/**
137+
* Utility method to know Cassandra cluster version before it is being initialized.
138+
*/
139+
public static Semver getDTestClusterVersion()
140+
{
141+
Versions versions = Versions.find();
142+
TestVersion testVersion = TestVersionSupplier.testVersions().findFirst().orElseThrow();
143+
return versions.getLatest(new Semver(testVersion.version(), Semver.SemverType.LOOSE)).version;
144+
}
133145
}

cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/BulkWriteDownInstanceMultipleTokensTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919
package org.apache.cassandra.analytics;
2020

21+
import com.vdurmont.semver4j.Semver;
2122
import org.apache.cassandra.testing.ClusterBuilderConfiguration;
23+
import org.apache.cassandra.testing.TestUtils;
24+
25+
import static org.assertj.core.api.Assumptions.assumeThat;
2226

2327
public class BulkWriteDownInstanceMultipleTokensTest extends BulkWriteDownInstanceTest
2428
{
@@ -28,4 +32,12 @@ protected ClusterBuilderConfiguration testClusterConfiguration()
2832
return super.testClusterConfiguration()
2933
.tokenCount(4);
3034
}
35+
36+
@Override
37+
protected void beforeClusterProvisioning()
38+
{
39+
assumeThat(TestUtils.getDTestClusterVersion().isGreaterThanOrEqualTo(new Semver("4.1", Semver.SemverType.LOOSE)))
40+
.describedAs("Cassandra 4.0 DTest does not support v-nodes")
41+
.isTrue();
42+
}
3143
}

cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/BulkWriteDownSidecarMultipleTokensTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919
package org.apache.cassandra.analytics;
2020

21+
import com.vdurmont.semver4j.Semver;
2122
import org.apache.cassandra.testing.ClusterBuilderConfiguration;
23+
import org.apache.cassandra.testing.TestUtils;
24+
25+
import static org.assertj.core.api.Assumptions.assumeThat;
2226

2327
public class BulkWriteDownSidecarMultipleTokensTest extends BulkWriteDownSidecarTest
2428
{
@@ -28,4 +32,12 @@ protected ClusterBuilderConfiguration testClusterConfiguration()
2832
return super.testClusterConfiguration()
2933
.tokenCount(4);
3034
}
35+
36+
@Override
37+
protected void beforeClusterProvisioning()
38+
{
39+
assumeThat(TestUtils.getDTestClusterVersion().isGreaterThanOrEqualTo(new Semver("4.1", Semver.SemverType.LOOSE)))
40+
.describedAs("Cassandra 4.0 DTest does not support v-nodes")
41+
.isTrue();
42+
}
3143
}

cassandra-analytics-integration-tests/src/test/java/org/apache/cassandra/analytics/CassandraAnalyticsSimpleMultipleTokensTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919
package org.apache.cassandra.analytics;
2020

21+
import com.vdurmont.semver4j.Semver;
2122
import org.apache.cassandra.testing.ClusterBuilderConfiguration;
23+
import org.apache.cassandra.testing.TestUtils;
24+
25+
import static org.assertj.core.api.Assumptions.assumeThat;
2226

2327
public class CassandraAnalyticsSimpleMultipleTokensTest extends CassandraAnalyticsSimpleTest
2428
{
@@ -28,4 +32,12 @@ protected ClusterBuilderConfiguration testClusterConfiguration()
2832
return super.testClusterConfiguration()
2933
.tokenCount(4);
3034
}
35+
36+
@Override
37+
protected void beforeClusterProvisioning()
38+
{
39+
assumeThat(TestUtils.getDTestClusterVersion().isGreaterThanOrEqualTo(new Semver("4.1", Semver.SemverType.LOOSE)))
40+
.describedAs("Cassandra 4.0 DTest does not support v-nodes")
41+
.isTrue();
42+
}
3143
}

0 commit comments

Comments
 (0)