diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 00000000..af140c15 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,145 @@ +name: Build and test +on: [push] + +jobs: + build-and-check: + name: Build and check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + + - name: Generate and submit dependency graph + uses: gradle/actions/dependency-submission@v4 + if: ${{ github.ref == 'refs/heads/master' }} + + - name: Build, check and test + run: ./gradlew shadowJar annotation:jar check integrationTest + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: Jars + path: | + agent/build/libs/*.jar + annotation/build/libs/*.jar + + test-suite: + strategy: + matrix: + java: ['17', '11', '8'] + runs-on: ubuntu-latest + name: Run test suite with Java ${{ matrix.java }} + needs: build-and-check + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + name: Set up Java + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + + - name: Suid root tar + # Required for the bats libraries cache to restore properly + run: sudo chmod +s /bin/tar + + - name: Setup Bats and bats libs + id: setup-bats + uses: bats-core/bats-action@3.0.0 + + - name: Remove suid root tar + run: sudo chmod -s /bin/tar + + - uses: sbt/setup-sbt@v1 + + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: Jars + + - name: Clone test projects + shell: bash + env: + BATS_LIB_PATH: ${{ steps.setup-bats.outputs.lib-path }} + TERM: xterm + working-directory: ./agent + run: bin/test_projects + + - uses: actions/setup-java@v4 + name: Set up Gradle cache + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + cache: gradle + + - uses: actions/setup-java@v4 + name: Set up Maven cache + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + cache: maven + + - uses: actions/setup-java@v4 + name: Set up sbt cache + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + cache: sbt + + - name: Build test projects + shell: bash + env: + BATS_LIB_PATH: ${{ steps.setup-bats.outputs.lib-path }} + TERM: xterm + working-directory: ./agent + run: bin/test_install + + - name: Run tests + shell: bash + env: + BATS_LIB_PATH: ${{ steps.setup-bats.outputs.lib-path }} + TERM: xterm + working-directory: ./agent + run: bin/test_run + + release: + name: Release + runs-on: ubuntu-latest + needs: test-suite + if: ${{ github.ref == 'refs/heads/master' }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - uses: actions/download-artifact@v4 + with: + name: Jars + - name: Install semantic-release + run: | + npm i -g \ + semantic-release \ + @semantic-release/exec \ + @semantic-release/git \ + @semantic-release/changelog \ + @google/semantic-release-replace-plugin + - name: Run semantic-release + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD }} + ORG_GRADLE_PROJECT_ossrhUsername: ${{ secrets.ORG_GRADLE_PROJECT_OSSRHUSERNAME }} + ORG_GRADLE_PROJECT_ossrhPassword: ${{ secrets.ORG_GRADLE_PROJECT_OSSRHPASSWORD }} + run: semantic-release diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index a8652b86..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Build -on: - pull_request: - schedule: - - cron: "0 0 * * 0" - -jobs: - test: - strategy: - fail-fast: false - matrix: - os: [ ubuntu-latest, windows-latest, macos-latest ] - java: ['11', '17'] - exclude: - - os: windows-latest - java: 11 - - name: Test ${{ matrix.os }} ${{ matrix.java }} - runs-on: ${{ matrix.os }} - - # Java 11 on Windows is so slow it times out. At some point maybe we should - # investigate why.... - - timeout-minutes: 45 - steps: - - name: Fetch Sources - uses: actions/checkout@v4 - - - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1 - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: ${{ matrix.java }} - - - name: Install extras on macOS - if: runner.os == 'macOS' - run: brew install bash sbt - - - name: Run Tests - shell: bash - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - set -e - bin/disable-gradle-daemon - ./gradlew check integrationTest - bin/test \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8113ebfa..c8c96301 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ classes agent/bin/main agent/bin/test annotation/bin -pomupdater/bin runtime/bin # AppMap files diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d1776d58..00000000 --- a/.travis.yml +++ /dev/null @@ -1,93 +0,0 @@ -os: linux -dist: jammy -language: minimal - -# Only start one build for a push to a PR. -# https://github.com/travis-ci/travis-ci/issues/1147#issuecomment-441393807 -if: type != push OR branch = master OR branch =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/ - -before_cache: -- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock -- rm -fr $HOME/.gradle/caches/*/plugin-resolution/ - -cache: - directories: - - '$HOME/.gradle/caches/' - - '$HOME/.gradle/wrapper/' - - '$HOME/.m2/' - - '$HOME/.asdf/' - -before_install: -- | - if [ ! -d $HOME/.asdf/plugins ]; then - git clone https://github.com/asdf-vm/asdf.git $HOME/.asdf --branch v0.14.0 - source "$HOME/.asdf/asdf.sh" - asdf plugin add java - asdf plugin add sbt https://github.com/bram2000/asdf-sbt.git - asdf install sbt latest:1.9 - asdf plugin add prune https://github.com/apotterri/asdf-prune.git - fi - source "$HOME/.asdf/asdf.sh" - asdf update - asdf plugin update --all - asdf prune sbt 1.9 - asdf global sbt latest:1.9 - nvm install lts/* - -jobs: - include: - - name: jdk 8 - env: - - JDK=8 - install: - - | - source "$HOME/.asdf/asdf.sh" - asdf install java latest:adoptopenjdk-8 - asdf prune java adoptopenjdk-8 - asdf global java latest:adoptopenjdk-8 - - - name: jdk 11 - env: - - JDK=11 - install: - - | - source "$HOME/.asdf/asdf.sh" - asdf install java latest:adoptopenjdk-11 - asdf prune java adoptopenjdk-11 - asdf global java latest:adoptopenjdk-11 - - - name: jdk 17 - env: - - JDK=17 - install: - - | - source "$HOME/.asdf/asdf.sh" - asdf install java latest:adoptopenjdk-17 - asdf prune java adoptopenjdk-17 - asdf global java latest:adoptopenjdk-17 - -script: -- | - source "$HOME/.asdf/asdf.sh" - export JAVA_HOME="$(dirname $(dirname $(asdf which java)))" - export JDK_HOME="$JAVA_HOME" - java -version - ./gradlew check - ./gradlew integrationTest - ./bin/test - -before_deploy: - - | - npm i -g \ - semantic-release \ - @semantic-release/exec \ - @semantic-release/git \ - @semantic-release/changelog \ - @google/semantic-release-replace-plugin - -deploy: - - provider: script - script: semantic-release - on: - branch: master - condition: $JDK = 8 diff --git a/agent/bin/multiline_input_to_travis_env.py b/agent/bin/multiline_input_to_travis_env.py deleted file mode 100755 index 4f8a779c..00000000 --- a/agent/bin/multiline_input_to_travis_env.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python - -# converts multiline stdin into a form suitable for setting env vars in Travis UI -# see https://github.com/travis-ci/travis-ci/issues/7715#issuecomment-362536708 - -import sys - -body=sys.stdin.read() -body = body.replace('\n','\\n') -body = '"$( echo -e '+"'"+body+"'"+')"' -print(body) diff --git a/agent/bin/run_tests b/agent/bin/run_tests index 9ea6aa08..2106f63e 100755 --- a/agent/bin/run_tests +++ b/agent/bin/run_tests @@ -4,6 +4,8 @@ set -e java -version -source ./bin/test_install +./bin/test_projects + +./bin/test_install ./bin/test_run "$@" diff --git a/agent/bin/test_install b/agent/bin/test_install index 004012ae..878aed58 100755 --- a/agent/bin/test_install +++ b/agent/bin/test_install @@ -2,83 +2,12 @@ set -e -fixture_dir=$PWD/build/fixtures -mkdir -p build/fixtures +. test/helper.bash -source "test/helper.bash" -export ANNOTATION_JAR="$(find_annotation_jar)" +for d in build/fixtures/*; do + cd "$d" + ./mvnw package -quiet -DskipTests -Dcheckstyle.skip=true -Dspring-javaformat.skip=true + cd - +done -function install_petclinic ( - local repo="$1"; shift - local oldVersion="$1" - local pkg="$(basename $repo)" - - cd build/fixtures - - rm -rf "${pkg}" - git clone https://github.com/"${repo}".git - cd "${pkg}" - - echo "${JAVA_VERSION}" - if [[ ! -z $oldVersion ]]; then - case "${JAVA_VERSION}" in - 1.8*) - ;& - 11.*) - git checkout "${oldVersion}" - ;; - esac - ./mvnw --quiet package -DskipTests -Dcheckstyle.skip=true -Dspring-javaformat.skip=true - else - case "${JAVA_VERSION}" in - 1.8*) - ;& - 11.*) - echo "No old version, not packaging in ${pkg}" - ;; - 17.*) - ./mvnw --quiet package -DskipTests -Dcheckstyle.skip=true -Dspring-javaformat.skip=true - ;; - esac - fi -) - -# PetClinic now requires Java 17. When we're testing older JDKs, use the last -# version that supported 1.8 (and 11). Note that spring-projects/petclinic -# doesn't tag versions, so we just use the commit SHA. (We don't use the full -# hash, though, because Travis detects that as a secret. :( 8 digits should be -# enough to make a collision extremely unlikely.) -install_petclinic "spring-projects/spring-petclinic" 9cb8dde9 -../gradlew :pomupdater:run -PmainClass=com.appland.appmap.util.PomUpdater \ - -PpomFile="$PWD/build/fixtures/spring-petclinic/pom.xml" \ - -PannotationJar="${ANNOTATION_JAR}" - -install_petclinic "spring-petclinic/spring-framework-petclinic" - -export BATS_DIR="$PWD/build/bats" - -install_bats() ( - mkdir -p "$BATS_DIR" - cd "$BATS_DIR" - - - rm -rf bats-core bats-support bats-assert - git clone --depth 1 https://github.com/bats-core/bats-core.git \ - && git clone --depth 1 https://github.com/bats-core/bats-support.git \ - && git clone --depth 1 https://github.com/bats-core/bats-assert.git \ - && cd bats-core \ - && ./install.sh "$BATS_DIR" -) -if [[ ! -d "$BATS_DIR" ]]; then - install_bats -fi - -export BASHUNIT_DIR="$PWD/build/bashunit" -install_bashunit() ( - mkdir -p "$BASHUNIT_DIR" - curl -s https://bashunit.typeddevs.com/install.sh | bash -s "$BASHUNIT_DIR" - sed -ibak 's;#!/bin/bash;#!/usr/bin/env bash;' $BASHUNIT_DIR/bashunit -) -if [[ ! -d "$BASUNIT_DIR" ]]; then - install_bashunit -fi \ No newline at end of file +../gradlew testClasses diff --git a/agent/bin/test_projects b/agent/bin/test_projects new file mode 100755 index 00000000..00e56800 --- /dev/null +++ b/agent/bin/test_projects @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +fixture_dir=$PWD/build/fixtures +mkdir -p build/fixtures + +source "test/helper.bash" +export ANNOTATION_JAR="$(find_annotation_jar)" + +function is_old_java { + local version="$1" + [[ "$version" == 1.8* ]] || [[ "$version" == 11.* ]] +} + +function install_petclinic ( + local repo="$1"; shift + local branch=${1:-main} + local pkg="$(basename $repo)" + + if [[ -d "build/fixtures/${pkg}" ]]; then + echo "Fixture already exists: ${pkg}" + return + fi + + cd build/fixtures + + rm -rf "${pkg}" + git clone https://github.com/"${repo}".git --depth 1 --branch "${branch}" + cd "${pkg}" + + cd ../../.. +) + +function install_scala_test_app { + if [[ -d "test/scala/play-samples" ]]; then + echo "Fixture already exists: play-samples" + return + fi + cd test/scala + rm -rf play-samples + local branch=3.0.x + case "${JAVA_VERSION}" in + 1.8*) + branch=2.8.x + ;; + 11.*) + branch=2.9.x + ;; + esac + git clone --no-checkout https://github.com/playframework/play-samples.git --depth 1 --branch $branch + cd play-samples + git sparse-checkout set play-scala-rest-api-example + git checkout + cp ../logback-test.xml play-scala-rest-api-example/conf/. + cd ../../.. +} + +if is_old_java "$JAVA_VERSION"; then + install_petclinic "land-of-apps/spring-petclinic" old-java-support +else + install_petclinic "spring-projects/spring-petclinic" + install_petclinic "spring-petclinic/spring-framework-petclinic" +fi + +patch -N -p1 -d build/fixtures/spring-petclinic < test/petclinic/pom.patch + + +install_scala_test_app diff --git a/agent/bin/test_run b/agent/bin/test_run index 2f811a80..cf2cd954 100755 --- a/agent/bin/test_run +++ b/agent/bin/test_run @@ -1,8 +1,6 @@ #!/usr/bin/env bash set -e -export PATH="$BATS_DIR"/bin:"$BASHUNIT_DIR":$PATH - shopt -s extglob set -x @@ -19,5 +17,3 @@ set -x bats -r test/!(http_client) bats -r test/http_client - -bashunit 'test/**/*_test.sh' diff --git a/agent/test/access/access.bats b/agent/test/access/access.bats index a77a7e5f..abe6e730 100644 --- a/agent/test/access/access.bats +++ b/agent/test/access/access.bats @@ -1,7 +1,5 @@ #!/usr/bin/env bats -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' sep="$JAVA_PATH_SEPARATOR" diff --git a/agent/test/agent-cli/.gitignore b/agent/test/agent-cli/.gitignore deleted file mode 100644 index f133a2c8..00000000 --- a/agent/test/agent-cli/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -spring-petclinic - diff --git a/agent/test/agent_cli/agent_cli.bats b/agent/test/agent_cli/agent_cli.bats index 0e39b774..4a963709 100644 --- a/agent/test/agent_cli/agent_cli.bats +++ b/agent/test/agent_cli/agent_cli.bats @@ -1,7 +1,5 @@ #!/usr/bin/env bats -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' setup_file() { diff --git a/agent/test/bashunit-compat.sh b/agent/test/bashunit-compat.sh deleted file mode 100644 index 065401c3..00000000 --- a/agent/test/bashunit-compat.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -# This file is meant to contain any code required to use helper.bash functions -# in a bashunit script. - -assert_equal() { - [[ ! -z "$3" ]] && assert_equals "$2" "$1" "$3" || assert_equals "$2" "$1" -} diff --git a/agent/test/classloading/classloading.bats b/agent/test/classloading/classloading.bats index b5b29e60..7f9e517f 100644 --- a/agent/test/classloading/classloading.bats +++ b/agent/test/classloading/classloading.bats @@ -1,5 +1,3 @@ -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' setup_file() { diff --git a/agent/test/event/event.bats b/agent/test/event/event.bats index e512fb14..c5c501e7 100644 --- a/agent/test/event/event.bats +++ b/agent/test/event/event.bats @@ -1,7 +1,5 @@ #!/usr/bin/env bats -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' sep="$JAVA_PATH_SEPARATOR" diff --git a/agent/test/helper.bash b/agent/test/helper.bash index f9646626..a74a30f1 100644 --- a/agent/test/helper.bash +++ b/agent/test/helper.bash @@ -3,6 +3,8 @@ # Helper methods for tests export JAVA_PATH_SEPARATOR="$(java -XshowSettings:properties 2>&1 | awk '/path.separator/ {printf("%s", $3)}')" +[ -z "$JAVA_HOME" ] && export JAVA_HOME="$(java -XshowSettings:properties 2>&1 | awk '/java.home/ {printf("%s", $3)}')" +export JAVA_HOME source "$JAVA_HOME/release" export JAVA_VERSION @@ -24,6 +26,18 @@ start_recording() { _curl -sXPOST "${WS_URL}/_appmap/record" } +_tests_helper() { + export BATS_LIB_PATH=${BATS_LIB_PATH:-"/usr/lib"} + if type -t bats_load_library &>/dev/null; then + bats_load_library bats-support + bats_load_library bats-assert + fi +} + +_tests_helper + +export LC_ALL=C + stop_recording() { local out="${1:-$BATS_TEST_TMPDIR/stop_recording_output}" _curl -sXDELETE -o "$out" "${WS_URL}/_appmap/record" || true @@ -35,7 +49,7 @@ teardown() { if [[ -z "$BATS_TEST_COMPLETED" ]]; then # Letting output go to stdout is more helpful than redirecting to fd 3. echo "${BATS_TEST_NAME} failed" - cat "${FIXTURE_DIR}/appmap.log" + [[ -n "$FIXTURE_DIR" ]] && cat "${FIXTURE_DIR}/appmap.log" fi } @@ -108,13 +122,25 @@ _top_level() { find_agent_jar() { - find "$(_top_level)/agent/build/libs" -name 'appmap-[[:digit:]]*.jar' + if [[ -n "$AGENT_JAR" ]]; then + echo "$AGENT_JAR" + return + fi + find "$(_top_level)" -name 'appmap-[[:digit:]]*.jar' } +export AGENT_JAR="$(find_agent_jar)" + find_annotation_jar() { - find "$(_top_level)/annotation/build/libs" -name 'annotation-[[:digit:]]*.jar' + if [[ -n "$ANNOTATION_JAR" ]]; then + echo "$ANNOTATION_JAR" + return + fi + find "$(_top_level)" -name 'annotation-[[:digit:]]*.jar' } +export ANNOTATION_JAR="$(find_annotation_jar)" + check_ws_running() { printf 'checking for running web server\n' diff --git a/agent/test/http_client/httpclient/build.gradle b/agent/test/http_client/httpclient/build.gradle index c6833a35..e8320fb4 100644 --- a/agent/test/http_client/httpclient/build.gradle +++ b/agent/test/http_client/httpclient/build.gradle @@ -16,18 +16,8 @@ sourceSets { } } -// TODO: look at consolidating this with the gradle config in httpcore -def appmapJar = fileTree('../../../build/libs').matching { - include { - it.file.name ==~ /.*appmap-[0-9.]*(-SNAPSHOT)*.jar$/ - } - }.getFiles()[0] - -def annotationJar = fileTree('../../../../annotation/build/libs').matching { - include { - it.file.name ==~ /.*annotation-[0-9.]*(-SNAPSHOT)*.jar$/ - } - }.getFiles()[0] +def appmapJar = "$System.env.AGENT_JAR" +def annotationJar = "$System.env.ANNOTATION_JAR" if (!appmapJar || !annotationJar) { throw new GradleException("missing jars\n appmapJar: ${appmapJar}\n annotationJar: ${annotationJar}"); diff --git a/agent/test/http_client/httpclient/httpclient.bats b/agent/test/http_client/httpclient/httpclient.bats index 9c3dc06d..dfa0c546 100644 --- a/agent/test/http_client/httpclient/httpclient.bats +++ b/agent/test/http_client/httpclient/httpclient.bats @@ -1,7 +1,5 @@ #!/usr/bin/env bats -load '../../../build/bats/bats-support/load' -load '../../../build/bats/bats-assert/load' load '../../helper' load '../../petclinic-shared/shared-setup.bash' diff --git a/agent/test/http_client/setup_suite.bash b/agent/test/http_client/setup_suite.bash index ee5ba511..08ee1b25 100644 --- a/agent/test/http_client/setup_suite.bash +++ b/agent/test/http_client/setup_suite.bash @@ -1,7 +1,5 @@ #!/usr/bin/env bats -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' load '../petclinic-shared/shared-setup.bash' diff --git a/agent/test/http_client/springboot/springboot.bats b/agent/test/http_client/springboot/springboot.bats index ce172cee..ff2f93d4 100644 --- a/agent/test/http_client/springboot/springboot.bats +++ b/agent/test/http_client/springboot/springboot.bats @@ -1,7 +1,5 @@ #!/usr/bin/env bats -load '../../../build/bats/bats-support/load' -load '../../../build/bats/bats-assert/load' load '../../helper' setup_file() { diff --git a/agent/test/httpcore/build.gradle b/agent/test/httpcore/build.gradle index f7027468..4f5ec0e0 100644 --- a/agent/test/httpcore/build.gradle +++ b/agent/test/httpcore/build.gradle @@ -15,17 +15,8 @@ sourceSets { } } -def appmapJar = fileTree('../../build/libs').matching { - include { - it.file.name ==~ /.*appmap-[0-9.]*(-SNAPSHOT)*.jar$/ - } - }.getFiles()[0] - -def annotationJar = fileTree('../../../annotation/build/libs').matching { - include { - it.file.name ==~ /.*annotation-[0-9.]*(-SNAPSHOT)*.jar$/ - } - }.getFiles()[0] +def appmapJar = "$System.env.AGENT_JAR" +def annotationJar = "$System.env.ANNOTATION_JAR" if (!appmapJar || !annotationJar) { throw new GradleException("missing jars\n appmapJar: ${appmapJar}\n annotationJar: ${annotationJar}"); diff --git a/agent/test/httpcore/httpcore.bats b/agent/test/httpcore/httpcore.bats index 0925a93e..7a511d8c 100644 --- a/agent/test/httpcore/httpcore.bats +++ b/agent/test/httpcore/httpcore.bats @@ -5,8 +5,6 @@ # return the appropriate response. -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' setup_file() { diff --git a/agent/test/intellij/intellij.bats b/agent/test/intellij/intellij.bats index 97e6a50f..e2336bbd 100644 --- a/agent/test/intellij/intellij.bats +++ b/agent/test/intellij/intellij.bats @@ -1,5 +1,3 @@ -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' init_plugin() { @@ -26,7 +24,7 @@ setup() { rm -rf tmp/appmap ./gradlew clean - mkdir build + mkdir -p build cp "${AGENT_JAR}" build/appmap-agent.jar } diff --git a/agent/test/jdbc/build.gradle b/agent/test/jdbc/build.gradle index 9d578935..ea106d16 100644 --- a/agent/test/jdbc/build.gradle +++ b/agent/test/jdbc/build.gradle @@ -20,11 +20,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' } -def appmapJar = fileTree('../../build/libs').matching { - include { - it.file.name ==~ /.*appmap-[0-9.]*(-SNAPSHOT)*.jar$/ - } - }.getFiles()[0] +def appmapJar = "$System.env.AGENT_JAR" test { useJUnitPlatform() diff --git a/agent/test/jdbc/jdbc.bats b/agent/test/jdbc/jdbc.bats index fd27ce93..71bb7c26 100644 --- a/agent/test/jdbc/jdbc.bats +++ b/agent/test/jdbc/jdbc.bats @@ -1,7 +1,5 @@ #!/usr/bin/env bats -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' setup_file() { diff --git a/agent/test/petclinic-fw/petclinic-fw.bats b/agent/test/petclinic-fw/petclinic-fw.bats index e304abf1..5910b986 100644 --- a/agent/test/petclinic-fw/petclinic-fw.bats +++ b/agent/test/petclinic-fw/petclinic-fw.bats @@ -1,7 +1,5 @@ #!/usr/bin/env bats -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' load '../petclinic-shared/shared-setup.bash' diff --git a/agent/test/petclinic-shared/message-params.bash b/agent/test/petclinic-shared/message-params.bash index a94110e0..778baf2f 100644 --- a/agent/test/petclinic-shared/message-params.bash +++ b/agent/test/petclinic-shared/message-params.bash @@ -9,11 +9,9 @@ _test_form_data_is_recorded_as_message_parameters() { local out="$BATS_TEST_TMPDIR/stop_recording_output" stop_recording "${out}" - # run npx in a subshell so we can redirect stderr - run bash -c "npx --yes @appland/appmap@latest prune --output-data \"${out}\" 2>/dev/null" - assert_success - run jq -r '[.events[] | select(.http_server_request.normalized_path_info == "/owners/{ownerId}/edit") | .message[] | .name] | join(",")' <<< "${output}" + + run jq -r '[(.events[], .eventUpdates[]) | select(.http_server_request.normalized_path_info == "/owners/{ownerId}/edit") | .message[] | .name] | join(",")' <<< "${output}" assert_output 'firstName,lastName,address,city,telephone' } diff --git a/agent/test/petclinic/jetty.bats b/agent/test/petclinic/jetty.bats index ab25c9c7..7b655d72 100644 --- a/agent/test/petclinic/jetty.bats +++ b/agent/test/petclinic/jetty.bats @@ -1,5 +1,3 @@ -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' load '../petclinic-shared/shared-setup.bash' diff --git a/agent/test/petclinic/petclinic-no-requests.bats b/agent/test/petclinic/petclinic-no-requests.bats index 7ca79d73..f61ebb5c 100644 --- a/agent/test/petclinic/petclinic-no-requests.bats +++ b/agent/test/petclinic/petclinic-no-requests.bats @@ -6,8 +6,6 @@ # If running locally, keep in mind that this application will cache SQL results, # likely causing subsequent test runs to fail. -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' load '../petclinic-shared/shared-setup.bash' diff --git a/agent/test/petclinic/petclinic-tests.bats b/agent/test/petclinic/petclinic-tests.bats index acf000a6..0bd23257 100644 --- a/agent/test/petclinic/petclinic-tests.bats +++ b/agent/test/petclinic/petclinic-tests.bats @@ -1,5 +1,3 @@ -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' load '../petclinic-shared/shared-setup.bash' diff --git a/agent/test/petclinic/petclinic.bats b/agent/test/petclinic/petclinic.bats index 316090b4..31b956b9 100644 --- a/agent/test/petclinic/petclinic.bats +++ b/agent/test/petclinic/petclinic.bats @@ -6,8 +6,6 @@ # If running locally, keep in mind that this application will cache SQL results, # likely causing subsequent test runs to fail. -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' load '../petclinic-shared/shared-setup.bash' @@ -139,10 +137,16 @@ setup() { eval $(java -cp test/petclinic/classes petclinic.Props java.vm.version java.vm.name) assert_json '.metadata.name' assert_json_eq '.metadata.language.name' 'java' - assert_json_eq '.metadata.language.version' "${JAVA_VM_VERSION}" - assert_json_eq '.metadata.language.engine' "${JAVA_VM_NAME}" + if [[ -n "${JAVA_RUNTIME_VERSION}" ]]; then + assert_json_eq '.metadata.language.version' "${JAVA_RUNTIME_VERSION}" + fi + if [[ -n "${JAVA_VM_NAME}" ]]; then + assert_json_eq '.metadata.language.engine' "${JAVA_VM_NAME}" + fi + + assert_json_eq '.metadata.git.repository' 'https://github.com/spring-projects/spring-petclinic.git' \ + || assert_json_eq '.metadata.git.repository' 'https://github.com/land-of-apps/spring-petclinic.git' - assert_json_eq '.metadata.git.repository' 'https://github.com/spring-projects/spring-petclinic.git' assert_json '.metadata.git.branch' assert_json '.metadata.git.commit' } diff --git a/agent/test/petclinic/pom.patch b/agent/test/petclinic/pom.patch new file mode 100644 index 00000000..a9b7e093 --- /dev/null +++ b/agent/test/petclinic/pom.patch @@ -0,0 +1,51 @@ +diff --git a/pom.xml b/pom.xml +index 27fb9a6..d17781f 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -57,6 +57,19 @@ + + org.springframework.boot + spring-boot-starter-web ++ ++ ++ org.springframework.boot ++ spring-boot-starter-tomcat ++ ++ ++ ++ ++ com.appland ++ annotation ++ LATEST ++ system ++ ${env.ANNOTATION_JAR} + + + org.springframework.boot +@@ -451,5 +464,26 @@ + + + ++ ++ tomcat ++ ++ true ++ ++ ++ ++ org.springframework.boot ++ spring-boot-starter-tomcat ++ ++ ++ ++ ++ jetty ++ ++ ++ org.springframework.boot ++ spring-boot-starter-jetty ++ ++ ++ + + diff --git a/agent/test/scala/scala.bats b/agent/test/scala/scala.bats index 708938e1..f8d83ebb 100644 --- a/agent/test/scala/scala.bats +++ b/agent/test/scala/scala.bats @@ -1,24 +1,5 @@ -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' -init_example() ( - git clone --no-checkout https://github.com/playframework/play-samples.git - cd play-samples - git sparse-checkout set play-scala-rest-api-example - local branch=3.0.x - case "${JAVA_VERSION}" in - 1.8*) - branch=2.8.x - ;; - 11.*) - branch=2.9.x - ;; - esac - git checkout $branch - cp ../logback-test.xml play-scala-rest-api-example/conf/. -) - setup_file() { export AGENT_JAR="$(find_agent_jar)" export FIXTURE_DIR="play-samples/play-scala-rest-api-example" @@ -26,7 +7,8 @@ setup_file() { _configure_logging if [[ ! -d "${FIXTURE_DIR}" ]]; then - init_example + echo Run test_install first. + exit 1 fi } diff --git a/agent/test/spark/spark.bats b/agent/test/spark/spark.bats index 2dc92bf1..4db1defb 100644 --- a/agent/test/spark/spark.bats +++ b/agent/test/spark/spark.bats @@ -1,5 +1,3 @@ -load '../../build/bats/bats-support/load' -load '../../build/bats/bats-assert/load' load '../helper' recording_dir="app/tmp/appmap/request_recording" diff --git a/agent/test/test-frameworks/build.gradle b/agent/test/test-frameworks/build.gradle index a22ba5aa..0097825b 100644 --- a/agent/test/test-frameworks/build.gradle +++ b/agent/test/test-frameworks/build.gradle @@ -17,17 +17,8 @@ sourceSets { } } -def buildAppmapJar = fileTree('../../../agent/build/libs').matching { - include { - it.file.name ==~ /appmap-[0-9.]*(-SNAPSHOT)*.jar$/ - } - }.getFiles()[0] - -def buildAnnotationJar = fileTree('../../../annotation/build/libs').matching { - include { - it.file.name ==~ /annotation-[0-9.]*(-SNAPSHOT)*.jar$/ - } - }.getFiles()[0] +def buildAppmapJar = "$System.env.AGENT_JAR" +def buildAnnotationJar = "$System.env.ANNOTATION_JAR" def agentJar = findProperty("agentJar") ?: buildAppmapJar def annotationJar = findProperty("annotationJar") ?: buildAnnotationJar @@ -54,6 +45,10 @@ task test_junit(type: Test) { task test_testng(type: Test) { useTestNG() + testLogging { + showStandardStreams = true + } + jvmArgs += addAgentArgs } diff --git a/agent/test/test-frameworks/frameworks.bats b/agent/test/test-frameworks/frameworks.bats new file mode 100644 index 00000000..a217ab4c --- /dev/null +++ b/agent/test/test-frameworks/frameworks.bats @@ -0,0 +1,107 @@ +#!/usr/bin/env bats + +load ../helper + +setup_file() { + export AGENT_JAR="$(find_agent_jar)" + export ANNOTATION_JAR="$(find_annotation_jar)" + _configure_logging +} + +setup() { + cd "$(dirname "$BATS_TEST_FILENAME")" + rm -rf tmp/appmap +} + +# Helper function to run tests +run_framework_test() { + local framework=$1 + local test="$2" + run ./gradlew cleanTest test_${framework} --tests "$test" +} + +@test "metadata captured on success for junit" { + run_framework_test "junit" "JunitTests.testItPasses" + assert_success + + output="$(< tmp/appmap/junit/org_springframework_samples_petclinic_JunitTests_testItPasses.appmap.json)" + + assert_json_eq '.metadata.test_status' "succeeded" + assert_json_eq '.metadata.recorder.type' "tests" + assert_json_eq '.metadata.recorder.name' "junit" + assert_json_eq '.metadata.recording.defined_class' "org.springframework.samples.petclinic.JunitTests" +} + +@test "metadata captured on success for testng" { + run_framework_test "testng" "TestngTests.testItPasses" + assert_success + + output="$(< tmp/appmap/testng/org_springframework_samples_petclinic_TestngTests_testItPasses.appmap.json)" + + assert_json_eq '.metadata.test_status' "succeeded" + assert_json_eq '.metadata.recorder.type' "tests" + assert_json_eq '.metadata.recorder.name' "testng" + assert_json_eq '.metadata.recording.defined_class' "org.springframework.samples.petclinic.TestngTests" +} + +@test "test status set for failed test in junit" { + run_framework_test "junit" "JunitTests.testItFails" + assert_failure + + output="$(< tmp/appmap/junit/org_springframework_samples_petclinic_JunitTests_testItFails.appmap.json)" + + assert_json_eq '.metadata.test_status' "failed" + assert_json_contains '.metadata.test_failure.message' 'false is not true' + assert_json_eq '.metadata.test_failure.location' "src/test/java/org/springframework/samples/petclinic/JunitTests.java:20" +} + +@test "test status set for failed test in testng" { + run_framework_test "testng" "TestngTests.testItFails" + assert_failure + + output="$(< tmp/appmap/testng/org_springframework_samples_petclinic_TestngTests_testItFails.appmap.json)" + + assert_json_eq '.metadata.test_status' "failed" + assert_json_contains '.metadata.test_failure.message' 'false is not true' + assert_json_eq '.metadata.test_failure.location' "src/test/java/org/springframework/samples/petclinic/TestngTests.java:20" +} + +@test "NoAppMap on method disables recording for junit" { + run_framework_test "junit" "JunitTests.testAnnotatedMethodNotRecorded" + assert_success + assert_output --partial "passing annotated test, not recorded" + + [ ! -f tmp/appmap/junit/org_springframework_samples_petclinic_JunitTests_testItsNotRecorded.appmap.json ] +} + +@test "NoAppMap on method disables recording for testng" { + run_framework_test "testng" "TestngTests.testAnnotatedMethodNotRecorded" + assert_success + assert_output --partial "passing annotated test, not recorded" + + [ ! -f tmp/appmap/testng/org_springframework_samples_petclinic_TestngTests_testItsNotRecorded.appmap.json ] +} + +@test "NoAppMap on class disables recording for junit" { + run_framework_test "junit" "JunitTests\$TestClass.testAnnotatedClassNotRecorded" + assert_success + assert_output --partial "passing annotated class, not recorded" + + [ ! -f tmp/appmap/junit/org_springframework_samples_petclinic_JunitTests_TestClass_testAnnotatedClassNotRecorded.appmap.json ] +} + +@test "NoAppMap on class disables recording for testng" { + run_framework_test "testng" "TestngTests\$TestClass.testAnnotatedClassNotRecorded" + assert_success + assert_output --partial "passing annotated class, not recorded" + + [ ! -f tmp/appmap/testng/org_springframework_samples_petclinic_TestngTests_TestClass_testAnnotatedClassNotRecorded.appmap.json ] +} + +@test "TestNG expected exception" { + run_framework_test "testng" "TestngTests.testItThrows" + assert_success + + output="$(< tmp/appmap/testng/org_springframework_samples_petclinic_TestngTests_testItThrows.appmap.json)" + assert_json_eq '.metadata.test_status' "succeeded" +} \ No newline at end of file diff --git a/agent/test/test-frameworks/frameworks_test.sh b/agent/test/test-frameworks/frameworks_test.sh deleted file mode 100644 index 4267b8d5..00000000 --- a/agent/test/test-frameworks/frameworks_test.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash - -ROOT_DIR="$(dirname "${BASH_SOURCE[0]}")" - -source "$ROOT_DIR/../helper.bash" -source "$ROOT_DIR/../bashunit-compat.sh" - -set_up_before_script() { - export AGENT_JAR="$(find_agent_jar)" - export ANNOTATION_JAR="$(find_annotation_jar)" - - _configure_logging -} - -set_up() { - cd "$ROOT_DIR" - rm -rf tmp/appmap -} - -provider_framework() { - echo ${TEST_FRAMEWORK:-junit testng} -} - -run_tests() { - local framework=$1 - local test="$2" - ./gradlew -q clean test_${framework} --tests "$test" -} - -# data_provider provider_framework -function test_metadata_captured_on_success() { - local framework=$1 - local className="${framework^}" - - run_tests $framework "${className}Tests.testItPasses" - assert_successful_code - - output="$(< tmp/appmap/${framework}/org_springframework_samples_petclinic_"${className}"Tests_testItPasses.appmap.json)" - - assert_json_eq '.metadata.test_status' "succeeded" - - assert_json_eq '.metadata.recorder.type' "tests" - assert_json_eq '.metadata.recorder.name' "${framework}" - - assert_json_eq '.metadata.recording.defined_class' "org.springframework.samples.petclinic.${className}Tests" -} - -# data_provider provider_framework -function test_test_status_set_for_failed_test() { - local framework="$1" - local className="${framework^}" - run_tests $framework "${className}Tests.testItFails" - assert_general_error - - output="$(< tmp/appmap/${framework}/org_springframework_samples_petclinic_${className}Tests_testItFails.appmap.json)" - - assert_json_eq '.metadata.test_status' "failed" - assert_json_contains '.metadata.test_failure.message' 'false is not true' - assert_json_eq '.metadata.test_failure.location' "src/test/java/org/springframework/samples/petclinic/${className}Tests.java:20" -} - -# data_provider provider_framework -function test_NoAppMap_on_method_disables_recording() { - local framework="$1" - local className="${framework^}" - - output="$(run_tests $framework "${className}Tests.testAnnotatedMethodNotRecorded")" - assert_successful_code - assert_contains "$output" "passing annotated test, not recorded" - - assert_file_not_exists tmp/appmap/${framework}/org_springframework_samples_petclinic_${className}Tests_testItsNotRecorded.appmap.json -} - -# data_provider provider_framework -function test_NoAppMap_on_class_disables_recording() { - local framework="$1" - local className="${framework^}" - - output="$(run_tests $framework "${className}Tests\$TestClass.testAnnotatedClassNotRecorded")" - assert_successful_code - assert_contains "$output" "passing annotated class, not recorded" - - assert_file_not_exists tmp/appmap/${framework}/org_springframework_samples_petclinic_${className}Tests_TestClass_testAnnotatedClassNotRecorded.appmap.json -} - -function test_TestNG_expected_exception() { - run_tests testng "TestngTests.testItThrows" - assert_successful_code $? 'tests failed' - - output="$(< tmp/appmap/testng/org_springframework_samples_petclinic_TestngTests_testItThrows.appmap.json)" - - assert_json_eq '.metadata.test_status' "succeeded" -} diff --git a/pomupdater/build.gradle b/pomupdater/build.gradle deleted file mode 100644 index 6591dac0..00000000 --- a/pomupdater/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -plugins { - id 'application' - id 'java' -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.apache.maven:maven-model:3.9.5' -} - - -application { - mainClassName = 'com.appland.appmap.util.PomUpdater' -} - -run { - def pomFile = findProperty("pomFile") ?: "NULL" - def annotationJar = findProperty("annotationJar") ?: "NULL" - // Quoting multiple path arguments correctly from a shell script is a pain, so use properties instead. - args = [pomFile, annotationJar] -} \ No newline at end of file diff --git a/pomupdater/src/main/java/com/appland/appmap/util/PomUpdater.java b/pomupdater/src/main/java/com/appland/appmap/util/PomUpdater.java deleted file mode 100644 index def09a7d..00000000 --- a/pomupdater/src/main/java/com/appland/appmap/util/PomUpdater.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.appland.appmap.util; - -import java.io.FileReader; -import java.io.FileWriter; -import java.util.Arrays; - -import org.apache.maven.model.Activation; -import org.apache.maven.model.Dependency; -import org.apache.maven.model.Exclusion; -import org.apache.maven.model.Model; -import org.apache.maven.model.Profile; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; -import org.apache.maven.model.io.xpp3.MavenXpp3Writer; - -public class PomUpdater { - public static void main(String[] argv) { - String pomFilePath = argv[0]; - String annotationJarPath = argv[1]; - - MavenXpp3Reader reader = new MavenXpp3Reader(); - MavenXpp3Writer writer = new MavenXpp3Writer(); - - try { - Model model; - try (FileReader fileReader = new FileReader(pomFilePath)) { - model = reader.read(fileReader); - } - - long count = model.getDependencies().stream() - .filter(d -> d.getGroupId().equals("com.appland") && d.getArtifactId().equals("annotation")) - .count(); - - if (count != 0) { - System.err.println("PomUpdater: found existing dependency."); - System.exit(0); - } - - System.err.println("PomUpdater: updating " + argv[0]); - - addAnnotationJar(annotationJarPath, model); - - addProfiles(model); - - try (FileWriter fileWriter = new FileWriter(pomFilePath)) { - writer.write(fileWriter, model); - } - System.exit(0); - } catch (Exception e) { - e.printStackTrace(); - } - System.exit(1); - } - - private static void addProfiles(Model model) { - // Add profiles to allow the choice of embedded servlet container (Tomcat or Jetty) at runtime. - // Note that spring-boot-starter-web embeds spring-boot-start-tomcat and will always use it if - // present, so it must be explicictly excluded to allow the use of Jetty. - - Exclusion tomcatExclusion = new Exclusion(); - tomcatExclusion.setGroupId("org.springframework.boot"); - tomcatExclusion.setArtifactId("spring-boot-starter-tomcat"); - - model.getDependencies().stream() - .filter(d -> d.getArtifactId().equals("spring-boot-starter-web")).findFirst() - .ifPresent(d -> d.addExclusion(tomcatExclusion)); - - Dependency tomcatDependency = new Dependency(); - tomcatDependency.setGroupId("org.springframework.boot"); - tomcatDependency.setArtifactId("spring-boot-starter-tomcat"); - - Dependency jettyDependency = new Dependency(); - jettyDependency.setGroupId("org.springframework.boot"); - jettyDependency.setArtifactId("spring-boot-starter-jetty"); - - Profile tomcatProfile = new Profile(); - tomcatProfile.setId("tomcat"); - Activation activation = new Activation(); - activation.setActiveByDefault(true); - tomcatProfile.setActivation(activation); - tomcatProfile.setDependencies(Arrays.asList(tomcatDependency)); - - Profile jettyProfile = new Profile(); - jettyProfile.setId("jetty"); - jettyProfile.setDependencies(Arrays.asList(jettyDependency)); - - model.addProfile(tomcatProfile); - model.addProfile(jettyProfile); - } - - private static void addAnnotationJar(String annotationJar, Model model) { - Dependency newDependency = new Dependency(); - newDependency.setGroupId("com.appland"); - newDependency.setArtifactId("annotation"); - newDependency.setVersion("LATEST"); - newDependency.setScope("system"); - newDependency.setSystemPath(annotationJar); - - // Add the new dependency to the model - model.addDependency(newDependency); - } -} diff --git a/settings.gradle b/settings.gradle index 4594f067..d6567cfc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,4 +8,4 @@ */ rootProject.name = 'appmap-java' -include 'agent', 'annotation', 'pomupdater', 'runtime' +include 'agent', 'annotation', 'runtime'