Skip to content

Repro for flaky micrometer test #4340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 25 additions & 102 deletions .github/workflows/build-common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,18 @@ jobs:
matrix:
test-java-version:
- 8
- 11
- 17
- 21
- 23
vm:
- hotspot
# TODO (trask) enable once profiler supports OpenJ9
# - openj9
os:
- windows-2022
- ubuntu-latest
num:
- 1
- 2
- 3
- 4
- 5
fail-fast: false
steps:
- name: Support long paths
Expand Down Expand Up @@ -172,101 +173,23 @@ jobs:

- name: Test
# spotless is checked separately since it's a common source of failure
run: >
./gradlew
check
-x spotlessCheck
-PtestJavaVersion=${{ matrix.test-java-version }}
-PtestJavaVM=${{ matrix.vm }}
"-Porg.gradle.java.installations.paths=${{ steps.setup-test-java.outputs.path }}"
"-Porg.gradle.java.installations.auto-download=false"
${{ inputs.no-build-cache && ' --no-build-cache' || '' }}

setup-smoke-test-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4

- id: set-matrix
run: |
json_array=$(
for dir in smoke-tests/apps/*; do
# Convert directory path to module name (e.g., "smoke-tests/apps/MyApp" -> "smoke-tests:apps:MyApp")
module=$(echo "$dir" | sed 's|/|:|g')
# Extract just the app name from the module path (e.g., "smoke-tests:apps:MyApp" -> "MyApp")
module_short=$(echo "$module" | sed 's|.*:||')

find "${dir}/src/smokeTest/java" -name "*Test.java" | \
# Remove the base path to get relative path from smokeTest/java
sed "s|${dir}/src/smokeTest/java/||" | \
# Convert file name to class name (e.g., "com/example/MyTest.java" -> "com.example.MyTest")
sed 's|/|.|g' | sed 's|\.java$||' | \
# Process each fully qualified test class name
while read -r class_name; do
# Extract just the simple class name (e.g., "com.example.MyTest" -> "MyTest")
class_short=$(echo "$class_name" | sed 's/.*\.//')
echo "{\"display\":\"${module_short}:${class_short}\"," \
"\"module\":\"${module}\"," \
"\"test_class\":\"${class_name}\"}"
done
# Join all JSON objects with commas and remove trailing comma
done | tr '\n' ',' | sed 's/,$//'
)

# Output the matrix in GitHub Actions format
echo "matrix={\"include\":[$json_array]}" >> $GITHUB_OUTPUT

smoke-test:
name: ${{ matrix.display }}
needs: setup-smoke-test-matrix
runs-on: ubuntu-latest
strategy:
matrix: ${{fromJson(needs.setup-smoke-test-matrix.outputs.matrix)}}
fail-fast: false
steps:
- uses: actions/checkout@v4

- name: Set up Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Build and install local azure-monitor-opentelemetry-autoconfigure dependency
if: env.AZURE_MONITOR_OPENTELEMETRY_AUTOCONFIGURE_SNAPSHOT != ''
run: ./.github/scripts/build-azure-monitor-dependency.sh

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Test
run: ./gradlew ${{ matrix.module }}:smokeTest --tests "${{ matrix.test_class }}*"

- name: Create unique artifact name
if: failure()
run: |
# Create a unique name based on module and test class
artifact_name="${{ matrix.module }}:${{ matrix.test_class }}"
# Replace colons and dots with hyphens for valid artifact names
artifact_name=$(echo "$artifact_name" | sed 's/[:.]/\-/g')
echo "UPLOAD_ARTIFACT_NAME=$artifact_name" >> $GITHUB_ENV

- name: Upload smoke test reports
uses: actions/upload-artifact@v4
if: failure()
with:
name: ${{ env.UPLOAD_ARTIFACT_NAME }}
path: '**/build/reports/tests/smokeTest/**/*'

check-snapshot-dependency:
runs-on: ubuntu-latest
steps:
- name: Check for snapshot dependency
# running in a loop 1..50 to identify flaky test behavior
shell: bash
run: |
if [[ -n "$AZURE_MONITOR_OPENTELEMETRY_AUTOCONFIGURE_SNAPSHOT" ]]; then
echo "AZURE_MONITOR_OPENTELEMETRY_AUTOCONFIGURE_SNAPSHOT is set to '$AZURE_MONITOR_OPENTELEMETRY_AUTOCONFIGURE_SNAPSHOT'"
echo "PRs testing against a snapshot cannot be merged."
exit 1
fi
for i in {1..100}; do
echo "=== Test run $i/100 ==="
./gradlew \
test \
--rerun-tasks \
-PtestJavaVersion=${{ matrix.test-java-version }} \
-PtestJavaVM=${{ matrix.vm }} \
"-Porg.gradle.java.installations.paths=${{ steps.setup-test-java.outputs.path }}" \
"-Porg.gradle.java.installations.auto-download=false"
if [ $? -eq 0 ]; then
echo "Test run $i completed successfully"
else
echo "Test run $i failed"
exit 1
fi
done
echo "All 50 test runs completed successfully"
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ void shouldCaptureTimeGauge() {
TimeGauge.builder("test-time-gauge", "", MILLISECONDS, obj -> 11.0).register(registry);

// then
await().until(() -> getLastMeasurement("test-time-gauge") != null);
await()
.atMost(Duration.ofSeconds(20))
.until(() -> getLastMeasurement("test-time-gauge") != null);

AgentTestingMicrometerDelegate.Measurement measurement = getLastMeasurement("test-time-gauge");
assertThat(measurement.value).isEqualTo(11);
Expand All @@ -81,7 +83,7 @@ void shouldCaptureGauge() {
Gauge.builder("test-gauge", () -> 22.0).register(registry);

// then
await().until(() -> getLastMeasurement("test-gauge") != null);
await().atMost(Duration.ofSeconds(20)).until(() -> getLastMeasurement("test-gauge") != null);

AgentTestingMicrometerDelegate.Measurement measurement = getLastMeasurement("test-gauge");
assertThat(measurement.value).isEqualTo(22);
Expand All @@ -102,7 +104,7 @@ void shouldCaptureCounter() {
counter.increment(3.3);

// then
await().until(() -> getLastMeasurement("test-counter") != null);
await().atMost(Duration.ofSeconds(20)).until(() -> getLastMeasurement("test-counter") != null);

AgentTestingMicrometerDelegate.Measurement measurement = getLastMeasurement("test-counter");
assertThat(measurement.value).isEqualTo(3.3);
Expand All @@ -123,7 +125,7 @@ void shouldCaptureTimer() {
timer.record(Duration.ofMillis(55));

// then
await().until(() -> getLastMeasurement("test-timer") != null);
await().atMost(Duration.ofSeconds(20)).until(() -> getLastMeasurement("test-timer") != null);

AgentTestingMicrometerDelegate.Measurement measurement = getLastMeasurement("test-timer");
assertThat(measurement.value).isEqualTo(99);
Expand All @@ -146,7 +148,7 @@ void shouldCaptureDistributionSummary() {
distributionSummary.record(5.5);

// then
await().until(() -> getLastMeasurement("test-summary") != null);
await().atMost(Duration.ofSeconds(20)).until(() -> getLastMeasurement("test-summary") != null);

AgentTestingMicrometerDelegate.Measurement measurement = getLastMeasurement("test-summary");
assertThat(measurement.value).isEqualTo(9.9);
Expand Down Expand Up @@ -190,6 +192,7 @@ void shouldCaptureLongTaskTimer() {

// then
await()
.atMost(Duration.ofSeconds(20))
.untilAsserted(
() -> {
AgentTestingMicrometerDelegate.Measurement activeMeasurement =
Expand All @@ -207,6 +210,7 @@ void shouldCaptureLongTaskTimer() {
assertThat(activeMeasurement.namespace).isNull();

await()
.atMost(Duration.ofSeconds(20))
.untilAsserted(
() -> {
AgentTestingMicrometerDelegate.Measurement durationMeasurement =
Expand All @@ -233,7 +237,9 @@ void shouldCaptureFunctionCounter() {
FunctionCounter.builder("test-function-counter", "", obj -> 6.6).register(registry);

// then
await().until(() -> getLastMeasurement("test-function-counter") != null);
await()
.atMost(Duration.ofSeconds(20))
.until(() -> getLastMeasurement("test-function-counter") != null);

AgentTestingMicrometerDelegate.Measurement measurements =
getLastMeasurement("test-function-counter");
Expand All @@ -254,7 +260,9 @@ void shouldCaptureFunctionTimer() {
.register(registry);

// then
await().until(() -> getLastMeasurement("test-function-timer") != null);
await()
.atMost(Duration.ofSeconds(20))
.until(() -> getLastMeasurement("test-function-timer") != null);

AgentTestingMicrometerDelegate.Measurement measurement =
getLastMeasurement("test-function-timer");
Expand Down
Loading