diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8eee471..0d14f50 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,16 +8,17 @@ jobs: runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v4 with: - java-version: "11.x" + distribution: "temurin" + java-version: "11" # -- Micro -- - name: Cache Micro id: cache-micro - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: micro.jar key: ${{ runner.os }}-micro @@ -47,16 +48,17 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v4 with: - java-version: "11.x" + distribution: "temurin" + java-version: "11" # -- Micro -- - name: Cache Micro id: cache-micro - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: micro.jar key: ${{ runner.os }}-micro @@ -66,13 +68,13 @@ jobs: run: curl -o micro.jar -L https://github.com/snowplow-incubator/snowplow-micro/releases/download/micro-1.1.2/snowplow-micro-1.1.2.jar - name: Setup MSBuild and add to PATH - uses: microsoft/setup-msbuild@v1.1 + uses: microsoft/setup-msbuild@v2 - name: cmake build run: cmake -D SNOWPLOW_BUILD_TESTS=1 -D SNOWPLOW_BUILD_EXAMPLE=1 -D SNOWPLOW_BUILD_PERFORMANCE=1 . - - name: Run MSBuild - run: msbuild .\snowplow.sln + - name: Build with CMake + run: cmake --build . --config Debug - name: Start Micro and run tests run: javaw -jar micro.jar --collector-config test/integration/micro.conf --iglu test/integration/iglu.json; sleep 15; .\Debug\snowplow-tests.exe @@ -81,16 +83,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - uses: actions/setup-java@v1 + - uses: actions/setup-java@v4 with: - java-version: "11.x" + distribution: "temurin" + java-version: "11" # -- Micro -- - name: Cache Micro id: cache-micro - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: micro.jar key: ${{ runner.os }}-micro diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c2b53ed..7112f10 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml index 99f3aa6..0911c8c 100644 --- a/.github/workflows/install.yml +++ b/.github/workflows/install.yml @@ -38,10 +38,9 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Install Conan - id: conan - uses: turtlebrowser/get-conan@main + run: pipx install conan - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Snowplow dependencies with apt-get run: sudo apt-get update && sudo apt-get install -y libcurl4-openssl-dev uuid-dev if: matrix.system_curl_uuid == 'True' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7ecb88..0dcf678 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,11 +11,11 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Get tag version id: version - run: echo ::set-output name=TAG_VERSION::${GITHUB_REF#refs/*/} + run: echo "TAG_VERSION=${GITHUB_REF#refs/*/}" >> "$GITHUB_OUTPUT" - name: Release uses: softprops/action-gh-release@v0.1.7 diff --git a/CMakeLists.txt b/CMakeLists.txt index c67a5ce..35d8b72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,7 @@ set_target_properties(snowplow PROPERTIES # add nlohmann/json library include(FetchContent) -set(NLOHMANN_JSON_VERSION 3.10.5) +set(NLOHMANN_JSON_VERSION 3.12.0) if(SNOWPLOW_USE_EXTERNAL_JSON) find_package(nlohmann_json ${NLOHMANN_JSON_VERSION} REQUIRED) else() @@ -85,10 +85,8 @@ if(SNOWPLOW_USE_EXTERNAL_SQLITE) find_package(SQLite3 REQUIRED) target_link_libraries(snowplow PRIVATE SQLite::SQLite3) else() - FetchContent_Declare(sqlite_amalgamation URL "https://www.sqlite.org/2022/sqlite-amalgamation-3380500.zip") - if (NOT sqlite_amalgamation_POPULATED) - FetchContent_Populate(sqlite_amalgamation) - endif() + FetchContent_Declare(sqlite_amalgamation URL "https://www.sqlite.org/2022/sqlite-amalgamation-3380500.zip" DOWNLOAD_EXTRACT_TIMESTAMP TRUE) + FetchContent_MakeAvailable(sqlite_amalgamation) target_include_directories(snowplow PRIVATE ${sqlite_amalgamation_SOURCE_DIR}) target_sources(snowplow PRIVATE ${sqlite_amalgamation_SOURCE_DIR}/sqlite3.c) endif() diff --git a/examples/conanfile.py b/examples/conanfile.py index ae9892b..646d00d 100644 --- a/examples/conanfile.py +++ b/examples/conanfile.py @@ -7,7 +7,7 @@ class LDDProDepsConan(ConanFile): default_options = {"system_curl_uuid": False} def requirements(self): - self.requires("nlohmann_json/3.11.2") + self.requires("nlohmann_json/3.12.0") self.requires("sqlite3/3.42.0") if not self.options.system_curl_uuid and self.settings.os != "Macos" and (self.settings.os != "Windows" or self.settings.os.subsystem == "cygwin" or self.settings.os.subsystem == "wsl"): self.requires("libcurl/8.0.1") diff --git a/test/integration/integration_test.cpp b/test/integration/integration_test.cpp index 03e18a0..b78c623 100644 --- a/test/integration/integration_test.cpp +++ b/test/integration/integration_test.cpp @@ -35,9 +35,8 @@ TEST_CASE("integration") { StructuredEvent sv("hello", "world"); string event_id = tracker->track(sv); tracker->flush(); - sleep_for(milliseconds(1000)); - auto counts = Micro::get_good_and_bad_count(); + auto counts = Micro::wait_for_good_and_bad_count(1, 0); REQUIRE(std::get<0>(counts) == 1); REQUIRE(std::get<1>(counts) == 0); @@ -72,9 +71,8 @@ TEST_CASE("integration") { string event_id = tracker->track(StructuredEvent("hello", "world1")); tracker->track(StructuredEvent("hello", "world2")); tracker->flush(); - sleep_for(milliseconds(1000)); - auto counts = Micro::get_good_and_bad_count(); + auto counts = Micro::wait_for_good_and_bad_count(2, 0); REQUIRE(std::get<0>(counts) == 2); REQUIRE(std::get<1>(counts) == 0); @@ -122,9 +120,8 @@ TEST_CASE("integration") { "{\"currentTime\": 0, \"duration\": 10, \"ended\": false, \"loop\": false, \"muted\": false, \"paused\": false, \"playbackRate\": 1, \"volume\": 100}"_json)}); string event_id = tracker->track(sde); tracker->flush(); - sleep_for(milliseconds(1000)); - auto counts = Micro::get_good_and_bad_count(); + auto counts = Micro::wait_for_good_and_bad_count(1, 0); REQUIRE(std::get<0>(counts) == 1); REQUIRE(std::get<1>(counts) == 0); @@ -152,9 +149,8 @@ TEST_CASE("integration") { string name = "screen"; event.name = &name; tracker->track(event); - sleep_for(milliseconds(1000)); - auto counts = Micro::get_good_and_bad_count(); + auto counts = Micro::wait_for_good_and_bad_count(1, 0); REQUIRE(std::get<0>(counts) == 1); REQUIRE(std::get<1>(counts) == 0); @@ -172,12 +168,12 @@ TEST_CASE("integration") { auto tracker = Snowplow::create_tracker(tracker_config, network_config, emitter_config); tracker->track(StructuredEvent("hello", "1")); + // Space the two events apart so they get distinct collector timestamps. sleep_for(milliseconds(500)); tracker->track(StructuredEvent("hello", "2")); tracker->flush(); - sleep_for(milliseconds(1000)); - auto counts = Micro::get_good_and_bad_count(); + auto counts = Micro::wait_for_good_and_bad_count(2, 0); REQUIRE(std::get<0>(counts) == 2); REQUIRE(std::get<1>(counts) == 0); diff --git a/test/integration/micro.cpp b/test/integration/micro.cpp index 420282b..b3b8a7b 100644 --- a/test/integration/micro.cpp +++ b/test/integration/micro.cpp @@ -13,6 +13,9 @@ See the Apache License Version 2.0 for the specific language governing permissio #include "micro.hpp" +#include +#include + using namespace snowplow; void Micro::clear() { @@ -27,6 +30,23 @@ tuple Micro::get_good_and_bad_count() { return std::make_tuple(good, bad); } +tuple Micro::wait_for_good_and_bad_count( + int expected_good, int expected_bad, int timeout_ms) { + using std::chrono::milliseconds; + using std::chrono::steady_clock; + + const milliseconds poll_interval(100); + auto deadline = steady_clock::now() + milliseconds(timeout_ms); + + tuple counts = get_good_and_bad_count(); + while (steady_clock::now() < deadline && + (std::get<0>(counts) < expected_good || std::get<1>(counts) < expected_bad)) { + std::this_thread::sleep_for(poll_interval); + counts = get_good_and_bad_count(); + } + return counts; +} + list Micro::get_good() { string response_str = request("/micro/good"); return json::parse(response_str).get>(); diff --git a/test/integration/micro.hpp b/test/integration/micro.hpp index abbc906..37a785e 100644 --- a/test/integration/micro.hpp +++ b/test/integration/micro.hpp @@ -34,6 +34,16 @@ class Micro { static tuple get_good_and_bad_count(); static list get_good(); + /** + * Polls Micro until it reports at least the expected number of good and bad + * events, or until the timeout elapses. Micro processes events + * asynchronously, so this avoids racing it with a fixed sleep on slow or + * busy CI runners. Returns the last observed counts either way, so callers + * keep asserting exact counts as before. + */ + static tuple wait_for_good_and_bad_count( + int expected_good, int expected_bad, int timeout_ms = 10000); + private: static string request(const string &path); };