Skip to content
Merged
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
4 changes: 4 additions & 0 deletions argus-spring-boot-starter/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ dependencies {
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor:3.2.0")

testImplementation("org.junit.jupiter:junit-jupiter:${property("junitVersion")}")
testImplementation("org.springframework.boot:spring-boot-test:3.2.0")
testImplementation("org.springframework.boot:spring-boot-test-autoconfigure:3.2.0")
testImplementation("org.springframework:spring-test:6.1.0")
testImplementation("org.assertj:assertj-core:3.25.1")
}

tasks.withType<JavaCompile> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package io.argus.spring;

import io.argus.core.config.AgentConfig;

import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Real Spring context integration tests for the Argus Spring Boot starter.
*
* <p>Verifies that the auto-configuration's conditional wiring and the
* {@link ArgusProperties} binding mechanism actually work end-to-end through
* Spring, rather than just exercising the static property-to-config mapping
* (which is what {@link ArgusAutoConfigurationTest} does).
*
* <p>To avoid the side effects of {@code ArgusAutoConfiguration} (JFR streaming
* engine startup and {@code ArgusServer} thread spawn), the property-binding
* test uses a minimal {@code @EnableConfigurationProperties} configuration
* rather than loading the full auto-configuration.
*/
class ArgusAutoConfigurationIntegrationTest {

@Test
void argusPropertiesBindFromSpringPropertySources() {
new ApplicationContextRunner()
.withUserConfiguration(EnablePropsOnlyConfig.class)
.withPropertyValues(
"argus.buffer-size=131072",
"argus.server.port=9999",
"argus.server.enabled=false",
"argus.gc.enabled=true",
"argus.profiling.enabled=true",
"argus.profiling.interval-ms=10",
"argus.contention.threshold-ms=25",
"argus.metrics.prometheus.enabled=true"
)
.run(context -> {
assertThat(context).hasSingleBean(ArgusProperties.class);
ArgusProperties props = context.getBean(ArgusProperties.class);

assertThat(props.getBufferSize()).isEqualTo(131072);
assertThat(props.getServer().getPort()).isEqualTo(9999);
assertThat(props.getServer().isEnabled()).isFalse();
assertThat(props.getGc().isEnabled()).isTrue();
assertThat(props.getProfiling().isEnabled()).isTrue();
assertThat(props.getProfiling().getIntervalMs()).isEqualTo(10);
assertThat(props.getContention().getThresholdMs()).isEqualTo(25);
assertThat(props.getMetrics().getPrometheus().isEnabled()).isTrue();
});
}

@Test
void argusEnabledFalseShortCircuitsAutoConfiguration() {
new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ArgusAutoConfiguration.class))
.withPropertyValues("argus.enabled=false")
.run(context -> {
assertThat(context).doesNotHaveBean(ArgusAutoConfiguration.class);
assertThat(context).doesNotHaveBean(AgentConfig.class);
assertThat(context).doesNotHaveBean(ArgusProperties.class);
});
}

@Test
void argusEnabledMissingActivatesAutoConfigurationByDefault() {
// ArgusAutoConfiguration uses matchIfMissing=true; if the user does
// not set argus.enabled, the auto-config should activate. We assert
// ArgusProperties shows up — the bean graph beyond that is exercised
// by the dedicated mapping tests (ArgusAutoConfigurationTest) without
// booting the server thread.
new ApplicationContextRunner()
.withUserConfiguration(EnablePropsOnlyConfig.class)
.run(context -> assertThat(context).hasSingleBean(ArgusProperties.class));
}

@EnableConfigurationProperties(ArgusProperties.class)
static class EnablePropsOnlyConfig {
}
}
38 changes: 38 additions & 0 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,46 @@ New-Item -ItemType Directory -Path $BinDir -Force | Out-Null

$DownloadBase = "https://github.com/$Repo/releases/download/$Version"

# Try to fetch checksums.txt from the release. Releases before 1.3.0 do not
# publish it, so a 404 is non-fatal — we just skip integrity checks for those.
$ChecksumsFile = Join-Path $InstallDir ".checksums.txt"
$ChecksumsAvailable = $false
try {
Invoke-WebRequest "$DownloadBase/checksums.txt" -OutFile $ChecksumsFile -UseBasicParsing -ErrorAction Stop
$ChecksumsAvailable = $true
Write-Ok "Fetched checksums.txt for SHA-256 verification"
} catch {
if (Test-Path $ChecksumsFile) { Remove-Item $ChecksumsFile -Force }
Write-Warn "checksums.txt not published for $Version - skipping integrity check"
}

# Verify-Sha256: aborts on mismatch, skips silently when checksums.txt is
# unavailable or has no entry for the artifact.
function Verify-Sha256 {
param([string]$LocalFile, [string]$ExpectedName)
if (-not $ChecksumsAvailable) { return }
$line = Select-String -Path $ChecksumsFile -Pattern " $([regex]::Escape($ExpectedName))$" -SimpleMatch:$false `
| Select-Object -First 1
if (-not $line) {
Write-Warn " no checksum entry for $ExpectedName - skipping"
return
}
$expected = ($line.Line -split '\s+')[0]
$actual = (Get-FileHash $LocalFile -Algorithm SHA256).Hash.ToLower()
if ($expected -ne $actual) {
Write-Err "SHA-256 mismatch for $ExpectedName"
Write-Err " expected: $expected"
Write-Err " actual: $actual"
Remove-Item $LocalFile -Force -ErrorAction SilentlyContinue
exit 1
}
Write-Ok " sha256 verified: $ExpectedName"
}

Write-Info "Downloading argus-agent-${VerNum}.jar ..."
try {
Invoke-WebRequest "$DownloadBase/argus-agent-${VerNum}.jar" -OutFile "$InstallDir\argus-agent.jar" -UseBasicParsing
Verify-Sha256 -LocalFile "$InstallDir\argus-agent.jar" -ExpectedName "argus-agent.jar"
Write-Ok "argus-agent.jar"
} catch {
Write-Err "Failed to download argus-agent. Check version: $Version"
Expand All @@ -87,6 +124,7 @@ try {
Write-Info "Downloading argus-cli-${VerNum}-all.jar ..."
try {
Invoke-WebRequest "$DownloadBase/argus-cli-${VerNum}-all.jar" -OutFile "$InstallDir\argus-cli.jar" -UseBasicParsing
Verify-Sha256 -LocalFile "$InstallDir\argus-cli.jar" -ExpectedName "argus-cli-${VerNum}-all.jar"
Write-Ok "argus-cli.jar"
} catch {
Write-Warn "argus-cli not found in release. CLI may not be available in $Version."
Expand Down
52 changes: 52 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,66 @@ mkdir -p "$INSTALL_DIR" "$BIN_DIR"

DOWNLOAD_BASE="https://github.com/$REPO/releases/download/$VERSION"

# Resolve which sha256 binary is available so we can verify release artifacts.
if command -v sha256sum &>/dev/null; then
SHA256_CMD="sha256sum"
elif command -v shasum &>/dev/null; then
SHA256_CMD="shasum -a 256"
else
SHA256_CMD=""
fi

# Try to fetch checksums.txt from the release. Releases before 1.3.0 do not
# publish it, so a 404 is non-fatal — we just skip integrity checks for those.
CHECKSUMS_FILE=""
if [ -n "$SHA256_CMD" ]; then
CHECKSUMS_FILE="$INSTALL_DIR/.checksums.txt"
if curl -fsSL "$DOWNLOAD_BASE/checksums.txt" -o "$CHECKSUMS_FILE" 2>/dev/null; then
ok "Fetched checksums.txt for SHA-256 verification"
else
rm -f "$CHECKSUMS_FILE"
CHECKSUMS_FILE=""
warn "checksums.txt not published for $VERSION — skipping integrity check"
fi
else
warn "No sha256sum/shasum on PATH — skipping integrity check"
fi

# verify_sha256 <local-path> <filename-in-checksums.txt>
# Aborts the install on mismatch. Skips silently if checksums.txt is unavailable
# or has no entry for the file (e.g. a legacy artifact).
verify_sha256() {
local local_file="$1"
local expected_name="$2"
[ -z "$CHECKSUMS_FILE" ] && return 0
local expected_hash
expected_hash=$(awk -v name="$expected_name" '$2 == name {print $1}' "$CHECKSUMS_FILE" | head -1)
if [ -z "$expected_hash" ]; then
warn " no checksum entry for $expected_name — skipping"
return 0
fi
local actual_hash
actual_hash=$($SHA256_CMD "$local_file" | awk '{print $1}')
if [ "$expected_hash" != "$actual_hash" ]; then
error "SHA-256 mismatch for $expected_name"
error " expected: $expected_hash"
error " actual: $actual_hash"
rm -f "$local_file"
exit 1
fi
ok " sha256 verified: $expected_name"
}

info "Downloading argus-agent-${VER_NUM}.jar ..."
curl -fSL "$DOWNLOAD_BASE/argus-agent-${VER_NUM}.jar" -o "$INSTALL_DIR/argus-agent.jar" \
|| { error "Failed to download argus-agent. Check version: $VERSION"; exit 1; }
verify_sha256 "$INSTALL_DIR/argus-agent.jar" "argus-agent.jar"
ok "argus-agent.jar"

info "Downloading argus-cli-${VER_NUM}-all.jar ..."
curl -fSL "$DOWNLOAD_BASE/argus-cli-${VER_NUM}-all.jar" -o "$INSTALL_DIR/argus-cli.jar" \
|| { warn "argus-cli not found in release. CLI may not be available in $VERSION."; }
verify_sha256 "$INSTALL_DIR/argus-cli.jar" "argus-cli-${VER_NUM}-all.jar"
ok "argus-cli.jar"

# --- Attempt native binary download (faster startup, no JVM required for launch) ---
Expand Down
Loading