diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 000000000..a988178d6 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,173 @@ +on: + workflow_call: + inputs: + arch: + type: string + default: "64" + compiler: + type: string + default: "gcc" + coverage: + type: string + default: "OFF" + lib_msg_delivery: + type: string + default: "OFF" + lib_write_deadline: + type: string + default: "OFF" + repeat: + type: string + default: "1" + sanitize: + type: string + description: "sanitize option to use, 'address' or 'thread'" + server_version: + type: string + description: "nats-server version to test with" + default: "latest" + streaming: + type: string + default: "ON" + tls: + type: string + default: "ON" + type: + type: string + description: "Debug or Release." + default: "Release" + ubuntu_version: + type: string + description: "Ubuntu version to use, e.g. '20.04'" + default: "latest" + secrets: + CODECOV_TOKEN: + description: "Codecov repo token" + +permissions: + contents: write # to comment on coverage. + +defaults: + run: + shell: bash --noprofile --norc -x -eo pipefail {0} + +jobs: + do: + runs-on: ubuntu-${{ inputs.ubuntu_version }} + name: "ubuntu:${{ inputs.ubuntu_version }} ${{ inputs.compiler }} nats:${{ inputs.server_version }}" + steps: + - name: Checkout nats.c + uses: actions/checkout@v4 + + - name: "Checkout dependencies (nats.c.deps)" + uses: actions/checkout@v4 + with: + repository: nats-io/nats.c.deps + path: deps + + # configure the cmake flags and NATS_... environment variables + - id: cmake-flags + name: Configure cmake flags + env: + flags: -DNATS_BUILD_ARCH=${{ inputs.arch }} + -DCMAKE_BUILD_TYPE=${{ inputs.type }} + -DNATS_BUILD_STREAMING=${{ inputs.streaming }} + -DNATS_BUILD_WITH_TLS=${{ inputs.tls }} + -DNATS_PROTOBUF_DIR=${{ github.workspace}}/deps/pbuf + -DNATS_BUILD_USE_SODIUM=ON + -DNATS_SODIUM_DIR=${{ github.workspace}}/deps/sodium + run: | + if [[ -n "${{ inputs.sanitize }}" ]]; then + flags="$flags -DNATS_SANITIZE=ON -DCMAKE_C_FLAGS=-fsanitize=${{ inputs.sanitize }}" + fi + if [[ "${{ inputs.coverage }}" == "ON" ]]; then + flags="$flags -DNATS_COVERAGE=ON" + fi + echo "flags=$flags" >> $GITHUB_OUTPUT + + - id: nats-vars + name: Configure NATS_ environment variables + run: | + if [[ -n "${{ inputs.sanitize }}" ]]; then + echo "NATS_TEST_VALGRIND=yes" >> $GITHUB_ENV + fi + if [[ "${{ inputs.lib_msg_delivery }}" == "ON" ]]; then + echo "NATS_DEFAULT_TO_LIB_MSG_DELIVERY=yes" >> $GITHUB_ENV + fi + if [[ "${{ inputs.lib_write_deadline }}" == "ON" ]]; then + echo "NATS_DEFAULT_LIB_WRITE_DEADLINE=2000" >> $GITHUB_ENV + fi + echo "CC=${{ inputs.compiler }}" >> $GITHUB_ENV + + # install build dependencies + - name: Install ${{ inputs.compiler }} if needed + if: startsWith(inputs.compiler, 'clang-') || startsWith(inputs.compiler, 'gcc-') + run: | + sudo apt-get -q update + sudo apt-get -y install ${{ inputs.compiler }} + + # otherwise, configure cmake, build, archive and upload + - name: CMake + run: | + mkdir -p build + cd build + cmake .. ${{ steps.cmake-flags.outputs.flags }} + make rebuild_cache && make + + - name: "Rebuild the list of tests to match the compile flags" + working-directory: ./build + run: | + ./test/testsuite + if [[ $(diff list.txt ../test/list.txt; echo $?) != 0 ]]; then + mv list.txt ../test/list.txt + make rebuild_cache + fi + + # testing + + - name: "Download nats-server version ${{ inputs.server_version }}" + if: inputs.server_version + working-directory: ./build + run: | + rel=${{ inputs.server_version }} + if [ "$rel" = "latest" ]; then + rel=$(curl -s https://api.github.com/repos/nats-io/nats-server/releases/latest | jq -r '.tag_name') + fi + if [ "$rel" != "${rel#v}" ] && wget https://github.com/nats-io/nats-server/releases/download/$rel/nats-server-$rel-linux-amd64.tar.gz; then + tar -xzf nats-server-$rel-linux-amd64.tar.gz + cp nats-server-$rel-linux-amd64/nats-server ../deps/nats-server/nats-server + else + for c in 1 2 3 4 5 + do + echo "Attempt $c to download binary for main" + rm -f ./nats-server + curl -sf "https://binaries.nats.dev/nats-io/nats-server/v2@$rel" | PREFIX=. sh + # We are sometimes getting nats-server of size 0. Make sure we have a + # working nats-server by making sure we get a version number. + v="$(./nats-server -v)" + if [ "$v" != "" ]; then + break + fi + done + mv ./nats-server ../deps/nats-server/nats-server + fi + + - name: "Test" + working-directory: ./build + run: | + export PATH=../deps/nats-server:../deps/nats-streaming-server:$PATH + export NATS_TEST_SERVER_VERSION="$(nats-server -v)" + flags="" + ctest --timeout 60 --output-on-failure --repeat-until-fail ${{ inputs.repeat }} 2>&1 | tee /tmp/out.txt + if [[ $(grep -q 'ThreadSanitizer: ' /tmp/out.txt; echo $?) == 0 ]]; then + echo "!!! ThreadSanitizer detected WARNING(s) !!!" + exit 1 + fi + + - name: Upload coverage reports to Codecov + if: inputs.coverage == 'ON' + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + # verbose: true \ No newline at end of file diff --git a/.github/workflows/on-pr-debug.yml b/.github/workflows/on-pr-debug.yml new file mode 100644 index 000000000..ab0d17eef --- /dev/null +++ b/.github/workflows/on-pr-debug.yml @@ -0,0 +1,66 @@ +name: "Debug" +on: + pull_request: + +permissions: + contents: write # so it can comment + +defaults: + run: + shell: bash --noprofile --norc -x -eo pipefail {0} + +jobs: + default: + name: "DefaultD" + strategy: + fail-fast: false + matrix: + compiler: [gcc, clang] + uses: ./.github/workflows/build-test.yml + with: + compiler: ${{ matrix.compiler }} + server_version: main + type: Debug + repeat: 3 + + coverage: + name: "Coverage" + uses: ./.github/workflows/build-test.yml + with: + coverage: ON + server_version: main + type: Debug + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + sanitize-addr: + name: "Sanitize address" + uses: ./.github/workflows/build-test.yml + with: + sanitize: address + server_version: main + type: Debug + + sanitize-addr-lib-msg-delivery: + name: "Sanitize address (lib_msg_delivery)" + uses: ./.github/workflows/build-test.yml + with: + sanitize: address + server_version: main + lib_msg_delivery: ON + + san-addr: + name: "Sanitize address (lib_write_deadline)" + uses: ./.github/workflows/build-test.yml + with: + sanitize: address + server_version: main + lib_write_deadline: ON + + san-thread: + name: "Sanitize thread" + uses: ./.github/workflows/build-test.yml + with: + sanitize: thread + server_version: main + repeat: 3 \ No newline at end of file diff --git a/.github/workflows/on-push-release-extra.yml b/.github/workflows/on-push-release-extra.yml new file mode 100644 index 000000000..2ce47639c --- /dev/null +++ b/.github/workflows/on-push-release-extra.yml @@ -0,0 +1,62 @@ +name: "Release" +on: + push: + branches: + - main + - release_* + + +permissions: + contents: write # required by build-test to comment on coverage but not used here. + +defaults: + run: + shell: bash --noprofile --norc -x -eo pipefail {0} + +jobs: + server-versions: + strategy: + fail-fast: false + matrix: + server_version: [latest, v2.9.11] + uses: ./.github/workflows/build-test.yml + name: "Other servers" + with: + server_version: ${{ matrix.server_version }} + + TLS-OFF: + strategy: + fail-fast: false + matrix: + compiler: [gcc, clang] + uses: ./.github/workflows/build-test.yml + name: "No TLS" + with: + tls: OFF + + older-cc: + strategy: + fail-fast: false + matrix: + compiler: [gcc-7, gcc-8, clang-8] + uses: ./.github/workflows/build-test.yml + name: "Older compilers" + with: + ubuntu_version: 20.04 + compiler: ${{ matrix.compiler }} + + no-streaming: + uses: ./.github/workflows/build-test.yml + name: "No Streaming" + with: + streaming: OFF + + coverage: + name: "Coverage" + uses: ./.github/workflows/build-test.yml + with: + coverage: ON + server_version: main + type: Debug + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/on-push-release.yml b/.github/workflows/on-push-release.yml new file mode 100644 index 000000000..a42560e0d --- /dev/null +++ b/.github/workflows/on-push-release.yml @@ -0,0 +1,25 @@ +name: "Release" +on: + push: + +permissions: + contents: write # required by build-test to comment on coverage but not used here. + +defaults: + run: + shell: bash --noprofile --norc -x -eo pipefail {0} + +jobs: + quick: + name: "DefaultR" + strategy: + fail-fast: false + matrix: + compiler: [gcc, clang] + ubuntu_version: [latest, 20.04] + uses: ./.github/workflows/build-test.yml + with: + server_version: main + ubuntu_version: ${{ matrix.ubuntu_version }} + compiler: ${{ matrix.compiler }} + repeat: 3 diff --git a/.gitignore b/.gitignore index fdedaffa8..d68a2cc42 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ Compiled Object files, Static and Dynamic libs (Shared Objects) *.a *.so *.dylib +*.gcov # Folders build*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c2f60df7..0a5af371e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ include(CTest) include(FindPackageHandleStandardArgs) # Uncomment to have the build process verbose -#set(CMAKE_VERBOSE_MAKEFILE TRUE) +# set(CMAKE_VERBOSE_MAKEFILE TRUE) # Uncomment to have the executable moved to 'build' instead of their respective 'build/xxx' directories #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..a849fd986 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,19 @@ +ignore: + - "test/**" + - "examples/**" + - "src/win/**" + - "src/unix/**" + - "src/stan/protocol.pb-c.c" +coverage: + precision: 2 + round: down + range: "60...75" + status: + project: + default: + target: 65% + threshold: 1% +github_checks: + annotations: true +comment: + require_changes: false diff --git a/test/test.c b/test/test.c index 8e4c66d1a..ad8fa14d7 100644 --- a/test/test.c +++ b/test/test.c @@ -20,6 +20,7 @@ #else #include #include +#include #endif #include "buf.h" @@ -36344,6 +36345,18 @@ generateList(void) fclose(list); } +#ifndef _WIN32 +static void _sigsegv_handler(int sig) { + void *array[20]; + int size = backtrace(array, 20); + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); + exit(1); +} +#endif // _WIN32 + int main(int argc, char **argv) { const char *envStr; @@ -36372,6 +36385,10 @@ int main(int argc, char **argv) return 1; } +#ifndef _WIN32 + signal(SIGSEGV, _sigsegv_handler); +#endif // _WIN32 + envStr = getenv("NATS_TEST_TRAVIS"); if ((envStr != NULL) && (envStr[0] != '\0')) runOnTravis = true;