Skip to content

Commit 60693bb

Browse files
authored
More robust sample testing ruby (#103)
environment security and more robust testing
1 parent 6c505c2 commit 60693bb

File tree

8 files changed

+261
-39
lines changed

8 files changed

+261
-39
lines changed

.github/dependabot.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ updates:
1010
directory: "/"
1111
open-pull-requests-limit: 2
1212
schedule:
13-
interval: "daily"
13+
interval: "weekly"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
3+
aws kinesis delete-stream --stream-name $STREAM_NAME || true
4+
5+
## Reset the values of checkpoint, leaseCounter, ownerSwitchesSinceCheckpoint, and leaseOwner in DynamoDB table
6+
echo "Resetting DDB table"
7+
aws dynamodb update-item \
8+
--table-name $APP_NAME \
9+
--key '{"leaseKey": {"S": "shardId-000000000000"}}' \
10+
--update-expression "SET checkpoint = :checkpoint, leaseCounter = :counter, ownerSwitchesSinceCheckpoint = :switches, leaseOwner = :owner" \
11+
--expression-attribute-values '{
12+
":checkpoint": {"S": "TRIM_HORIZON"},
13+
":counter": {"N": "0"},
14+
":switches": {"N": "0"},
15+
":owner": {"S": "AVAILABLE"}
16+
}' \
17+
--return-values NONE
18+
19+
# Delete all tables
20+
#for i in {1..5}; do
21+
# aws dynamodb delete-table --table-name $APP_NAME && break ||
22+
# echo "Retrying DynamoDB Table deletion in 10s" && sleep 10
23+
#done
24+
#for SUFFIX in "-CoordinatorState" "-WorkerMetricStats" "-LeaseManagement"; do
25+
# if aws dynamodb describe-table --table-name $APP_NAME$SUFFIX &>/dev/null; then
26+
# echo "Deleting table $APP_NAME$SUFFIX"
27+
# aws dynamodb delete-table --table-name $APP_NAME$SUFFIX || true
28+
# fi
29+
#done

.github/scripts/create_stream.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
set -e
3+
4+
for i in {1..10}; do
5+
if aws kinesis create-stream --stream-name $STREAM_NAME --shard-count 1; then
6+
break
7+
else
8+
echo "Stream creation failed, attempt $i/10. Waiting $((i * 3)) seconds..."
9+
sleep $((i * 3))
10+
fi
11+
done
12+
aws kinesis wait stream-exists --stream-name $STREAM_NAME
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Manipulate sample.properties file that the KCL application pulls properties from (ex: streamName, applicationName)
5+
# Depending on the OS, different properties need to be changed
6+
if [[ "$RUNNER_OS" == "macOS" ]]; then
7+
sed -i "" "s/kclrbsample/$STREAM_NAME/g" samples/sample.properties
8+
sed -i "" "s/RubyKCLSample/$APP_NAME/g" samples/sample.properties
9+
sed -i "" 's/us-east-5/us-east-1/g' samples/sample.properties
10+
grep -v "idleTimeBetweenReadsInMillis" samples/sample.properties > samples/temp.properties
11+
echo "idleTimeBetweenReadsInMillis = 250" >> samples/temp.properties
12+
mv samples/temp.properties samples/sample.properties
13+
elif [[ "$RUNNER_OS" == "Linux" ]]; then
14+
sed -i "s/kclrbsample/$STREAM_NAME/g" samples/sample.properties
15+
sed -i "s/RubyKCLSample/$APP_NAME/g" samples/sample.properties
16+
sed -i 's/us-east-5/us-east-1/g' samples/sample.properties
17+
sed -i "/idleTimeBetweenReadsInMillis/c\idleTimeBetweenReadsInMillis = 250" samples/sample.properties
18+
elif [[ "$RUNNER_OS" == "Windows" ]]; then
19+
sed -i "s/kclrbsample/$STREAM_NAME/g" samples/sample.properties
20+
sed -i "s/RubyKCLSample/$APP_NAME/g" samples/sample.properties
21+
sed -i 's/us-east-5/us-east-1/g' samples/sample.properties
22+
sed -i "/idleTimeBetweenReadsInMillis/c\idleTimeBetweenReadsInMillis = 250" samples/sample.properties
23+
24+
echo '@echo off' > samples/run_script.bat
25+
echo 'ruby %~dp0\sample_kcl.rb %*' >> samples/run_script.bat
26+
sed -i 's/executableName = sample_kcl.rb/executableName = run_script.bat/' samples/sample.properties
27+
else
28+
echo "Unknown OS: $RUNNER_OS"
29+
exit 1
30+
fi
31+
32+
cat samples/sample.properties
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
set -e
3+
4+
cd samples
5+
ruby sample_kcl_producer.rb -t 10 -d 1 --stream $STREAM_NAME
6+
7+
# Get records from stream to verify they exist before continuing
8+
SHARD_ITERATOR=$(aws kinesis get-shard-iterator --stream-name $STREAM_NAME --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON --query 'ShardIterator' --output text)
9+
INITIAL_RECORDS=$(aws kinesis get-records --shard-iterator $SHARD_ITERATOR)
10+
RECORD_COUNT_BEFORE=$(echo $INITIAL_RECORDS | jq '.Records | length')
11+
12+
if [ "$RECORD_COUNT_BEFORE" -eq 0 ]; then
13+
echo "No records found in stream. Test cannot proceed."
14+
exit 1
15+
fi
16+
echo "Found $RECORD_COUNT_BEFORE records in stream before KCL start"

.github/scripts/start_kcl.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/bash
2+
set -e
3+
set -o pipefail
4+
5+
chmod +x samples/sample_kcl.rb
6+
7+
# Reset the values of checkpoint, leaseCounter, ownerSwitchesSinceCheckpoint, and leaseOwner in DynamoDB table
8+
echo "Resetting checkpoint for shardId-000000000000"
9+
aws dynamodb update-item \
10+
--table-name $APP_NAME \
11+
--key '{"leaseKey": {"S": "shardId-000000000000"}}' \
12+
--update-expression "SET checkpoint = :checkpoint, leaseCounter = :counter, ownerSwitchesSinceCheckpoint = :switches, leaseOwner = :owner" \
13+
--expression-attribute-values '{
14+
":checkpoint": {"S": "TRIM_HORIZON"},
15+
":counter": {"N": "0"},
16+
":switches": {"N": "0"},
17+
":owner": {"S": "AVAILABLE"}
18+
}' \
19+
--return-values NONE 2>/dev/null || echo "DynamoDB table not found or update failed - KCL will create it"
20+
21+
# Get records from stream to verify they exist before continuing
22+
SHARD_ITERATOR=$(aws kinesis get-shard-iterator --stream-name $STREAM_NAME --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON --query 'ShardIterator' --output text)
23+
INITIAL_RECORDS=$(aws kinesis get-records --shard-iterator $SHARD_ITERATOR)
24+
RECORD_COUNT_BEFORE=$(echo $INITIAL_RECORDS | jq '.Records | length')
25+
26+
echo "Found $RECORD_COUNT_BEFORE records in stream before KCL start"
27+
28+
if [[ "$RUNNER_OS" == "macOS" ]]; then
29+
brew install coreutils
30+
(cd samples && gtimeout 300 rake run properties_file=sample.properties 2>&1 | tee ../kcl_output.log) || [ $? -eq 124 ]
31+
elif [[ "$RUNNER_OS" == "Linux" ]]; then
32+
(cd samples && timeout 300 rake run properties_file=sample.properties 2>&1 | tee ../kcl_output.log) || [ $? -eq 124 ]
33+
elif [[ "$RUNNER_OS" == "Windows" ]]; then
34+
(cd samples && timeout 300 rake run properties_file=sample.properties 2>&1 | tee ../kcl_output.log) || [ $? -eq 124 ]
35+
else
36+
echo "Unknown OS: $RUNNER_OS"
37+
exit 1
38+
fi
39+
40+
echo "---------ERROR LOGS HERE-------"
41+
grep -i error kcl_output.log || echo "No errors found in logs"

.github/scripts/verify_kcl.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash
2+
set -e
3+
4+
LEASE_EXISTS=$(aws dynamodb scan --table-name $APP_NAME --select "COUNT" --query "Count" --output text || echo "0")
5+
CHECKPOINT_EXISTS=$(aws dynamodb scan --table-name $APP_NAME --select "COUNT" --filter-expression "attribute_exists(checkpoint) AND checkpoint <> :trim_horizon" --expression-attribute-values '{":trim_horizon": {"S": "TRIM_HORIZON"}}' --query "Count" --output text || echo "0")
6+
7+
echo "Found $LEASE_EXISTS leases and $CHECKPOINT_EXISTS non-TRIM-HORIZON checkpoint in DynamoDB"
8+
9+
echo "Printing checkpoint values"
10+
aws dynamodb scan --table-name $APP_NAME --projection-expression "leaseKey,checkpoint" --output json
11+
12+
if [ "$LEASE_EXISTS" -gt 0 ] && [ "$CHECKPOINT_EXISTS" -gt 0 ]; then
13+
echo "Test passed: Found both leases and non-TRIM_HORIZON checkpoints in DDB (KCL is fully functional)"
14+
exit 0
15+
else
16+
echo "Test failed: KCL not fully functional"
17+
echo "Lease(s) found: $LEASE_EXISTS"
18+
echo "non-TRIM_HORIZON checkpoint(s) found: $CHECKPOINT_EXISTS"
19+
exit 1
20+
fi

.github/workflows/ruby.yml

Lines changed: 110 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,76 @@
55
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
66
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
77

8-
name: Sample Run and Dependabot Auto-merge
8+
name: Sample Run Tests and Dependabot
99
on:
1010
push:
1111
branches: [ master ]
12+
pull_request_target:
13+
branches: [ master ]
14+
types: [opened, synchronize, reopened, unlabeled]
1215

13-
permissions:
14-
id-token: write
15-
contents: write
16-
pull-requests: write
17-
statuses: write
16+
concurrency:
17+
group: ruby.yml
18+
cancel-in-progress: false
1819

1920
jobs:
21+
# Evaluates if the sample tests should run. If the workflow is triggered by a push OR
22+
# is triggered by a pull request without the 'skip-sample-tests' label, the sample tests should run.
23+
# Otherwise, the sample tests will be skipped
24+
check-if-should-run:
25+
runs-on: ubuntu-latest
26+
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request_target' && !contains(github.event.pull_request.labels.*.name, 'skip-sample-tests')) }}
27+
outputs:
28+
should_run: 'true'
29+
is_fork: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork }}
30+
steps:
31+
- run: echo "Evaluating workflow conditions"
32+
33+
# Workflow will pause and wait here if it is triggered by a fork PR. The workflow will continue to wait until
34+
# an approved member of the environment 'manual_approval' allows the workflow to run
35+
wait-for-approval:
36+
needs: [ check-if-should-run ]
37+
if: ${{ needs.check-if-should-run.outputs.is_fork == 'true' }}
38+
runs-on: ubuntu-latest
39+
environment: manual-approval
40+
steps:
41+
- run: echo "Fork PR approved by a team member."
42+
43+
# Sample run tests of the KCL
44+
# Runs only if (check-if-should-run allows AND (the PR is not from a fork OR it has been approved to run))
2045
sample-run:
21-
timeout-minutes: 8
46+
needs: [ check-if-should-run, wait-for-approval ]
47+
permissions:
48+
id-token: write
49+
if: ${{ always() && needs.check-if-should-run.outputs.should_run == 'true' && (needs.check-if-should-run.outputs.is_fork != 'true' || needs.wait-for-approval.result == 'success') }}
50+
timeout-minutes: 20
2251
runs-on: ${{ matrix.os }}
2352
defaults:
2453
run:
2554
shell: bash
2655

56+
# Initialize matrix based on PR labels (more-tests label runs more tests)
2757
strategy:
2858
fail-fast: false
2959
matrix:
30-
ruby-version: [ '3.0', '3.4' ]
31-
jdk-version: [ "8", "11", "17", "21", "24" ]
60+
ruby-version: ${{ github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'more-tests') && fromJSON('["3.0", "3.4"]') || fromJSON('["3.0"]') }}
61+
jdk-version: ${{ github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'more-tests') && fromJSON('["8", "11", "17", "21", "24"]') || fromJSON('["8", "11"]') }}
3262
os: [ ubuntu-latest, macOS-latest, windows-latest ]
3363

3464
steps:
35-
- name: Checkout working directory
65+
# For pull_request_target, checkout PR head instead of merge commit
66+
- name: Checkout
3667
uses: actions/checkout@v4
68+
with:
69+
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }}
3770

71+
# Configure AWS Credentials. Role session name is unique to avoid OIDC errors when running multiple tests concurrently
3872
- name: Configure AWS Credentials
3973
uses: aws-actions/configure-aws-credentials@v4
4074
with:
4175
aws-region: us-east-1
42-
role-to-assume: arn:aws:iam::751999266872:role/GitHubRuby
43-
role-session-name: myGitHubActionsRuby
76+
role-to-assume: ${{ secrets.AWS_ARN_GHA }}
77+
role-session-name: GHA-${{ github.run_id }}-${{ matrix.ruby-version }}-${{ matrix.jdk-version }}-${{ matrix.os }}
4478

4579
- name: Set up JDK ${{ matrix.jdk-version }}
4680
uses: actions/setup-java@v4
@@ -53,44 +87,82 @@ jobs:
5387
with:
5488
ruby-version: ${{ matrix.ruby-version }}
5589

56-
- name: Install Bundler and run tests
90+
- name: Install dependencies and run tests
5791
run: |
58-
gem install bundler
92+
gem install bundler aws-sdk-kinesis aws-kclrb
93+
if [ "${{ matrix.os }}" != "windows-latest" ]; then gem install rake; fi
5994
bundle install
6095
bundle update --bundler
6196
bundle exec rspec
6297
63-
- name: Install Rake (ubuntu and macOS)
64-
if: ${{ matrix.os != 'windows-latest' }}
98+
# Create unique identifiers for the stream name and application name
99+
- name: Set up unique identifiers
65100
run: |
66-
gem install rake
101+
STREAM_NAME="kclrbsample-${{ matrix.os }}-rb${{ matrix.ruby-version }}-jdk${{ matrix.jdk-version }}"
102+
APP_NAME="RubyKCLSample-${{ matrix.os }}-rb${{ matrix.ruby-version }}-jdk${{ matrix.jdk-version }}"
103+
echo "STREAM_NAME=$STREAM_NAME" >> $GITHUB_ENV
104+
echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV
67105
68-
- name: Install Kinesis SDK
106+
# Manipulate sample.properties file to use unique stream name, application name, and OS specific program changes
107+
- name: Manipulate sample.properties file
69108
run: |
70-
gem install aws-sdk-kinesis
71-
72-
- name: Running KCL producer
109+
chmod +x .github/scripts/manipulate_properties.sh
110+
.github/scripts/manipulate_properties.sh
111+
env:
112+
RUNNER_OS: ${{ matrix.os }}
113+
STREAM_NAME: ${{ env.STREAM_NAME }}
114+
APP_NAME: ${{ env.APP_NAME }}
115+
116+
# Create kinesis stream with unique name and wait for it to exist
117+
- name: Create and wait Kinesis stream
73118
run: |
74-
cd samples
75-
rake "run_producer[10]"
119+
chmod +x .github/scripts/create_stream.sh
120+
.github/scripts/create_stream.sh
121+
env:
122+
STREAM_NAME: ${{ env.STREAM_NAME }}
76123

77-
- name: Running KCL consumer (windows or ubuntu)
78-
if: ${{ matrix.os != 'macOS-latest'}}
124+
# Put words to sample stream with unique name based on run ID
125+
- name: Put words to sample stream
79126
run: |
80-
cd samples
81-
timeout 45 rake run properties_file=sample.properties || status="$?"; if (( status == 124 )); then exit 0; else exit 1; fi; exit "$status"
127+
chmod +x .github/scripts/put_words_to_stream.sh
128+
.github/scripts/put_words_to_stream.sh
129+
env:
130+
STREAM_NAME: ${{ env.STREAM_NAME }}
82131

83-
- name: Running KCL consumer (macOS)
84-
if: ${{ matrix.os == 'macOS-latest'}}
132+
# Run sample KCL application
133+
- name: Start KCL application
134+
run: |
135+
chmod +x .github/scripts/start_kcl.sh
136+
.github/scripts/start_kcl.sh
137+
env:
138+
RUNNER_OS: ${{ matrix.os }}
139+
STREAM_NAME: ${{ env.STREAM_NAME }}
140+
141+
# Check and verify results of KCL test
142+
- name: Verify KCL Functionality
85143
run: |
86-
brew install coreutils
87-
cd samples
88-
gtimeout 45 rake run properties_file=sample.properties || status="$?"; if (( status == 124 )); then exit 0; else exit 1; fi; exit "$status"
144+
chmod +x .github/scripts/verify_kcl.sh
145+
.github/scripts/verify_kcl.sh
146+
env:
147+
APP_NAME: ${{ env.APP_NAME }}
148+
149+
# Clean up all existing Streams and DDB tables
150+
- name: Clean up Kinesis Stream and DynamoDB table
151+
if: always()
152+
run: |
153+
chmod +x .github/scripts/clean_up_stream_table.sh
154+
.github/scripts/clean_up_stream_table.sh
155+
env:
156+
STREAM_NAME: ${{ env.STREAM_NAME }}
157+
APP_NAME: ${{ env.APP_NAME }}
89158

90159
auto-merge-dependabot:
91160
needs: [sample-run]
92161
runs-on: ubuntu-latest
93162
if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]'
163+
permissions:
164+
contents: read
165+
pull-requests: write
94166
steps:
95167
- name: Fetch Dependabot metadata
96168
id: metadata
@@ -99,12 +171,12 @@ jobs:
99171
alert-lookup: true
100172
github-token: "${{ secrets.GITHUB_TOKEN }}"
101173

102-
# - name: Approve PR
103-
# if: steps.metadata.outputs.update-type != 'version-update:semver-major'
104-
# run: gh pr review --approve "$PR_URL"
105-
# env:
106-
# PR_URL: ${{github.event.pull_request.html_url}}
107-
# GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
174+
- name: Approve PR
175+
if: steps.metadata.outputs.update-type != 'version-update:semver-major'
176+
run: gh pr review --approve "$PR_URL"
177+
env:
178+
PR_URL: ${{github.event.pull_request.html_url}}
179+
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
108180

109181
# - name: Enable auto-merge for Dependabot PRs
110182
# if: steps.metadata.outputs.update-type != 'version-update:semver-major'

0 commit comments

Comments
 (0)