Skip to content

Commit b459c86

Browse files
author
Ariel Ben-Yehuda
committed
ci: add integration tests
1 parent 64752cb commit b459c86

File tree

9 files changed

+207
-44
lines changed

9 files changed

+207
-44
lines changed

.github/actions/rust-build/action.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ runs:
1616
- uses: Swatinem/rust-cache@v2
1717
- name: Build
1818
shell: bash
19-
run: if [ "${{ inputs.toolchain }}" != stable ]; then rm -fv Cargo.lock; fi && cargo build --all-features --verbose
19+
run: |
20+
if [ "${{ inputs.toolchain }}" != stable ]; then
21+
rm -fv Cargo.lock
22+
fi
23+
cargo build --all-features --verbose
2024
- name: Run tests
2125
shell: bash
2226
run: cargo test --all-features --verbose

.github/workflows/build-decoder.yml

Lines changed: 0 additions & 24 deletions
This file was deleted.

.github/workflows/build.yml

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ on: [pull_request]
33

44
jobs:
55
build:
6+
name: Build
67
runs-on: ubuntu-latest
78
strategy:
89
matrix:
@@ -17,5 +18,101 @@ jobs:
1718
uses: ./.github/actions/rust-build
1819
with:
1920
toolchain: ${{ matrix.toolchain }}
20-
21-
21+
- name: Upload artifact for testing
22+
uses: actions/upload-artifact@v4
23+
if: matrix.toolchain == 'stable'
24+
with:
25+
name: example-simple
26+
path: ./target/debug/examples/simple
27+
build-for-testing:
28+
name: Build For Testing
29+
runs-on: ubuntu-latest
30+
env:
31+
RUSTFLAGS: --cfg tokio_unstable
32+
steps:
33+
- uses: actions/checkout@v4
34+
- uses: dtolnay/rust-toolchain@master
35+
with:
36+
toolchain: stable
37+
- uses: Swatinem/rust-cache@v2
38+
- name: Build
39+
shell: bash
40+
run: cargo build --all-features --verbose --example simple
41+
- name: Upload artifact for testing
42+
uses: actions/upload-artifact@v4
43+
with:
44+
name: example-simple
45+
path: ./target/debug/examples/simple
46+
build-decoder:
47+
name: Build Decoder
48+
runs-on: ubuntu-latest
49+
env:
50+
RUST_BACKTRACE: 1
51+
steps:
52+
- uses: actions/checkout@v4
53+
- uses: dtolnay/rust-toolchain@master
54+
with:
55+
toolchain: stable
56+
- uses: Swatinem/rust-cache@v2
57+
with:
58+
cache-directories: decoder
59+
- name: Build
60+
working-directory: decoder
61+
shell: bash
62+
run: cargo build --all-features --verbose
63+
- name: Run tests
64+
working-directory: decoder
65+
shell: bash
66+
run: cargo test --all-features --verbose
67+
- name: Upload artifact for testing
68+
uses: actions/upload-artifact@v4
69+
with:
70+
name: pollcatch-decoder
71+
path: ./decoder/target/debug/pollcatch-decoder
72+
build-async-profiler:
73+
name: Build async-profiler
74+
runs-on: ubuntu-latest
75+
steps:
76+
- name: Checkout
77+
uses: actions/checkout@v4
78+
- name: Install async-profiler Dependencies
79+
run: sudo apt-get install -y sudo libicu-dev patchelf curl make g++ openjdk-11-jdk-headless gcovr
80+
- name: Build async-profiler
81+
working-directory: tests
82+
shell: bash
83+
run: ./build-async-profiler.sh
84+
- name: Upload artifact
85+
uses: actions/upload-artifact@v4
86+
with:
87+
name: libasyncProfiler
88+
path: ./tests/async-profiler/build/lib/libasyncProfiler.so
89+
test:
90+
name: Integration Test
91+
runs-on: ubuntu-latest
92+
needs: [build, build-for-testing, build-decoder, build-async-profiler]
93+
steps:
94+
- uses: actions/checkout@v4
95+
- name: Download pollcatch-decoder
96+
uses: actions/download-artifact@v4
97+
with:
98+
name: pollcatch-decoder
99+
path: ./tests
100+
- name: Download example-simple
101+
uses: actions/download-artifact@v4
102+
with:
103+
name: example-simple
104+
path: ./tests
105+
- name: Download libasyncProfiler
106+
uses: actions/download-artifact@v4
107+
with:
108+
name: libasyncProfiler
109+
path: ./tests
110+
- name: Run integration test
111+
shell: bash
112+
working-directory: tests
113+
run: chmod +x simple pollcatch-decoder && LD_LIBRARY_PATH=$PWD ./integration.sh
114+
- name: Upload profiles
115+
uses: actions/upload-artifact@v4
116+
with:
117+
name: profiles
118+
path: ./tests/profiles

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
/target
22
/decoder/target
3+
/tests/async-profiler
4+
/tests/profiles

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
3131
tokio = { version = "1", features = ["test-util", "full"] }
3232
test-case = "3"
3333
rand = "0.9"
34+
humantime = "2"
3435

3536
[[example]]
3637
name = 'simple'

examples/simple/main.rs

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use async_profiler_agent::{
5+
metadata::AgentMetadata,
56
profiler::ProfilerBuilder,
6-
reporter::s3::{S3Reporter, S3ReporterConfig},
7+
reporter::{
8+
local::LocalReporter,
9+
s3::{S3Reporter, S3ReporterConfig},
10+
},
711
};
812
use std::time::Duration;
913

1014
use aws_config::BehaviorVersion;
11-
use clap::Parser;
15+
use clap::{ArgGroup, Parser};
1216

1317
mod slow;
1418

@@ -27,13 +31,26 @@ pub fn set_up_tracing() {
2731

2832
/// Simple program to test the profiler agent
2933
#[derive(Parser, Debug)]
34+
#[command(group(
35+
ArgGroup::new("options")
36+
.required(true)
37+
.args(["local", "bucket"]),
38+
))]
3039
struct Args {
3140
#[arg(long)]
32-
profiling_group: String,
41+
profiling_group: Option<String>,
3342
#[arg(long)]
34-
bucket_owner: String,
43+
bucket_owner: Option<String>,
44+
#[arg(long, requires = "bucket_owner", requires = "profiling_group")]
45+
bucket: Option<String>,
3546
#[arg(long)]
36-
bucket: String,
47+
local: Option<String>,
48+
#[arg(long)]
49+
#[clap(value_parser = humantime::parse_duration)]
50+
duration: Option<Duration>,
51+
#[arg(long, default_value = "30s")]
52+
#[clap(value_parser = humantime::parse_duration)]
53+
reporting_interval: Duration,
3754
}
3855

3956
#[allow(unexpected_cfgs)]
@@ -56,23 +73,43 @@ async fn main_internal() -> Result<(), anyhow::Error> {
5673

5774
let args = Args::parse();
5875

59-
let sdk_config = aws_config::defaults(BehaviorVersion::latest()).load().await;
60-
let reporting_interval = Duration::from_secs(30);
61-
62-
let profiler = ProfilerBuilder::default()
63-
.with_reporter(S3Reporter::new(S3ReporterConfig {
64-
sdk_config: &sdk_config,
65-
bucket_owner: args.bucket_owner,
66-
bucket_name: args.bucket,
67-
profiling_group_name: args.profiling_group,
68-
}))
69-
.with_reporting_interval(reporting_interval)
76+
let profiler = ProfilerBuilder::default();
77+
78+
let profiler = match (
79+
args.local,
80+
args.bucket,
81+
args.bucket_owner,
82+
args.profiling_group,
83+
) {
84+
(Some(local), _, _, _) => profiler
85+
.with_reporter(LocalReporter::new(local))
86+
.with_custom_agent_metadata(AgentMetadata::Other),
87+
(_, Some(bucket), Some(bucket_owner), Some(profiling_group)) => {
88+
profiler.with_reporter(S3Reporter::new(S3ReporterConfig {
89+
sdk_config: &aws_config::defaults(BehaviorVersion::latest()).load().await,
90+
bucket_owner: bucket_owner,
91+
bucket_name: bucket,
92+
profiling_group_name: profiling_group,
93+
}))
94+
}
95+
_ => unreachable!(),
96+
};
97+
98+
let profiler = profiler
99+
.with_reporting_interval(args.reporting_interval)
70100
.build();
71101

72102
tracing::info!("starting profiler");
73103
profiler.spawn()?;
74104
tracing::info!("profiler started");
75105

76-
slow::run().await;
106+
if let Some(timeout) = args.duration {
107+
tokio::time::timeout(timeout, slow::run())
108+
.await
109+
.unwrap_err();
110+
} else {
111+
slow::run().await;
112+
}
113+
77114
Ok(())
78115
}

tests/build-async-profiler.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/bash
2+
3+
set -exuo pipefail
4+
5+
git clone https://github.com/async-profiler/async-profiler
6+
cd async-profiler
7+
git checkout 14c7e819b2054308da1bd980fe72137d2d0e0cf6
8+
make -j16

tests/integration.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/bash
2+
3+
set -exuo pipefail
4+
5+
mkdir -p profiles
6+
rm -f profiles/*.jfr
7+
./simple --local profiles --duration 30s --reporting-interval 5s
8+
for profile in profiles/*.jfr; do
9+
short_sleeps_100=$(./pollcatch-decoder longpolls --stack-depth=10 "$profile" 100us | ( grep -c short_sleep_2 || true ))
10+
short_sleeps_1000=$(./pollcatch-decoder longpolls --stack-depth=10 "$profile" 1000us | ( grep -c short_sleep_2 || true ))
11+
long_sleeps_100=$(./pollcatch-decoder longpolls --stack-depth=10 "$profile" 100us | ( grep -c accidentally_slow_2 || true ))
12+
long_sleeps_1000=$(./pollcatch-decoder longpolls --stack-depth=10 "$profile" 1000us | ( grep -c accidentally_slow_2 || true ))
13+
# Long sleeps should occur in both the 100us and 1000us filters
14+
if [ "$long_sleeps_100" -lt 1 ]; then
15+
echo "No long sleeps in 100us"
16+
exit 1
17+
fi
18+
if [ "$long_sleeps_1000" -lt 1 ]; then
19+
echo "No long sleeps in 1000us"
20+
exit 1
21+
fi
22+
# short sleeps should only occur in the 100us filter. Allow a small number of short sleeps if there was OS jank
23+
if [ "$short_sleeps_100" -lt 5 ]; then
24+
echo "No short sleeps in 100us"
25+
exit 1
26+
fi
27+
if [ "$short_sleeps_1000" -gt 5 ]; then
28+
echo "Too many short sleeps in 1000us"
29+
exit 1
30+
fi
31+
done

0 commit comments

Comments
 (0)