diff --git a/.gitignore b/.gitignore index 2874357d..9f677880 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,10 @@ node_modules .ruby-version /**/.ruby-version vendor/ + +# Cursor private rules +.cursor/rules/private-* + +# Integration Tests - Build Artifacts +archives/ +IntegrationTests/temp_artifacts/ diff --git a/IntegrationTests/Project.swift b/IntegrationTests/Project.swift index 5d222946..9646861d 100644 --- a/IntegrationTests/Project.swift +++ b/IntegrationTests/Project.swift @@ -2,9 +2,6 @@ import ProjectDescription let project = Project( name: "IntegrationTests", - packages: [ - .local(path: "../") - ], targets: [ .target( name: "IntegrationTests", @@ -14,7 +11,7 @@ let project = Project( deploymentTargets: .iOS("14.0"), sources: ["Sources/**"], dependencies: [ - .package(product: "mParticle-Apple-SDK", type: .runtime) + .xcframework(path: "temp_artifacts/mParticle_Apple_SDK.xcframework") ] ) ], diff --git a/IntegrationTests/README.md b/IntegrationTests/README.md index f69a4380..a4155211 100644 --- a/IntegrationTests/README.md +++ b/IntegrationTests/README.md @@ -37,12 +37,12 @@ tuist generate ## Overview This project provides tools for recording mParticle SDK API requests by: -- Generating a test iOS app using Tuist -- Linking directly to local SDK source code +- Building mParticle SDK as an xcframework for iOS Simulator +- Generating a test iOS app using Tuist that links to the built framework - Running the app in iOS Simulator - Recording all API traffic with WireMock for later use in testing -The project uses Tuist with `.local(path: "../")` package reference, which allows Xcode to resolve the local SDK package and use source files directly, automatically picking up your latest code changes. +The project builds the SDK into an xcframework stored in `temp_artifacts/` before each test run, ensuring tests always use your latest code changes. The framework is built for iOS Simulator only for faster compilation times during testing. ## Available Scripts @@ -55,22 +55,26 @@ Records all mParticle SDK API requests using WireMock for later use in integrati ``` **What it does:** -1. Generates Tuist project with local SDK sources -2. Builds the integration test application -3. Finds and resets iOS Simulators -4. Automatically selects available iPhone simulator (iPhone 17/16/15 priority) -5. Starts simulator -6. Installs test application -7. Starts WireMock in recording mode -8. Launches test application -9. Records all API traffic to mapping files -10. Waits for application completion -11. Stops WireMock and shows results +1. Builds mParticle SDK as xcframework for iOS Simulator +2. Generates Tuist project linked to the built framework +3. Builds the integration test application +4. Finds and resets iOS Simulators +5. Automatically selects available iPhone simulator (iPhone 17/16/15 priority) +6. Starts simulator +7. Installs test application +8. Starts WireMock in recording mode +9. Launches test application +10. Records all API traffic to mapping files +11. Waits for application completion +12. Stops WireMock and shows results **Recorded Files:** - `wiremock-recordings/mappings/*.json` - API request/response mappings - `wiremock-recordings/__files/*` - Response body files +**Build Artifacts:** +- `temp_artifacts/mParticle_Apple_SDK.xcframework` - Compiled SDK framework (auto-generated, not committed to git) + ### `extract_request_body.py` - Extract Request Body from WireMock Mapping Extracts JSON request body from a WireMock mapping file for easier editing and maintenance. @@ -115,11 +119,10 @@ python3 update_mapping_from_extracted.py wiremock-recordings/requests/identify_t - Reads the extracted request body from JSON file - Updates the source WireMock mapping file with the modified request body - Preserves all WireMock configuration (response, headers, etc.) -- Creates backup of original mapping file **Use case:** After extracting and editing a request body, use this script to apply changes back to the mapping. -**Note:** This script is automatically called by the test runner when executing integration tests with modified request bodies. +**Note:** This script is automatically called by `run_clean_integration_tests.sh` for all files in `wiremock-recordings/requests/` before starting WireMock, so manual execution is usually not needed during testing. ## Troubleshooting @@ -163,7 +166,7 @@ If another application is using the ports, terminate it before running the scrip ```bash ./run_wiremock_recorder.sh ``` - The script automatically uses your latest changes, runs the app, and records all API traffic + The script automatically builds the SDK as an xcframework with your latest changes, runs the app, and records all API traffic 3. **Review and filter recorded mappings:** - All recordings are saved to `wiremock-recordings/mappings/` @@ -215,8 +218,45 @@ After recording, you should update request bodies to make them more maintainable ### Running Integration Tests -When running integration tests, the test framework will: -1. Automatically look for extracted request bodies in `wiremock-recordings/requests/` -2. Apply any changes from extracted bodies to the mappings before starting WireMock -3. Run tests against the updated mappings +Use the verification script to run full end-to-end integration tests: + +```bash +./run_clean_integration_tests.sh +``` + +**What the verification script does:** + +1. **Rebuilds SDK:** Compiles mParticle SDK as xcframework for iOS Simulator from latest source code +2. **Regenerates project:** Runs Tuist to regenerate project linked to the new xcframework +3. **Resets environment:** Cleans simulators and builds test app +4. **๐Ÿ“ Applies user-friendly mappings:** Automatically converts all user-friendly request bodies from `wiremock-recordings/requests/` back to WireMock mappings +5. **Starts WireMock:** Launches WireMock container in verification mode with updated mappings +6. **Runs tests:** Executes test app in simulator +7. **Verifies results:** Checks that all requests matched mappings and all mappings were invoked +8. **Returns exit code:** Exits with code 1 if any verification fails (CI/CD compatible) + +**Note:** The SDK xcframework is built fresh on each run, stored in `temp_artifacts/mParticle_Apple_SDK.xcframework`. This ensures tests always use your latest code changes. + +**Automatic mapping application:** + +The script automatically looks for user-friendly request bodies in `wiremock-recordings/requests/` and applies them to the corresponding WireMock mappings before starting WireMock. This means you can: + +1. Edit request bodies in `wiremock-recordings/requests/*.json` +2. Run `./run_clean_integration_tests.sh` +3. Changes are automatically applied - no manual update step needed! + +**Example workflow:** + +```bash +# 1. Edit user-friendly mapping +vim wiremock-recordings/requests/.json + +# 2. Run verification (automatically applies changes) +./run_clean_integration_tests.sh + +# 3. If tests pass, commit both files +git add wiremock-recordings/requests/.json +git add wiremock-recordings/mappings/.json +git commit -m "Update request expectations" +``` diff --git a/IntegrationTests/common.sh b/IntegrationTests/common.sh new file mode 100755 index 00000000..1203edab --- /dev/null +++ b/IntegrationTests/common.sh @@ -0,0 +1,250 @@ +#!/bin/bash +# Common functions for WireMock integration testing scripts + +# === Common Configuration === +APP_NAME="IntegrationTests" +SCHEME="IntegrationTests" +BUNDLE_ID="com.mparticle.IntegrationTests" +CONFIGURATION="Debug" +DERIVED_DATA="$HOME/Library/Developer/Xcode/DerivedData" + +# WireMock configuration (can be overridden by scripts) +HTTP_PORT=${HTTP_PORT:-8080} +HTTPS_PORT=${HTTPS_PORT:-443} +MAPPINGS_DIR=${MAPPINGS_DIR:-"./wiremock-recordings"} + +# Global variables +DEVICE_NAME="" +DEVICE_ID="" +APP_PATH="" +APP_PID="" +TEMP_ARTIFACTS_DIR="$(pwd)/temp_artifacts" + +build_framework() { + echo "๐Ÿ—๏ธ Building mParticle SDK xcframework for iOS Simulator..." + + local SDK_DIR="$(cd .. && pwd)" + + # Clean previous builds + echo "๐Ÿงน Cleaning previous builds..." + rm -rf "$SDK_DIR/archives" "$TEMP_ARTIFACTS_DIR/mParticle_Apple_SDK.xcframework" + + # Build for iOS Simulator only (faster for integration tests) + echo "๐Ÿ“ฑ Building archive for iOS Simulator..." + xcodebuild archive \ + -project "$SDK_DIR/mParticle-Apple-SDK.xcodeproj" \ + -scheme mParticle-Apple-SDK \ + -destination "generic/platform=iOS Simulator" \ + -archivePath "$SDK_DIR/archives/mParticle-Apple-SDK-iOS_Simulator" \ + SKIP_INSTALL=NO \ + BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ + -quiet || { echo "โŒ Framework build error"; exit 1; } + + # Create xcframework from simulator archive only + echo "๐Ÿ“ฆ Creating xcframework..." + xcodebuild -create-xcframework \ + -archive "$SDK_DIR/archives/mParticle-Apple-SDK-iOS_Simulator.xcarchive" -framework mParticle_Apple_SDK.framework \ + -output "$SDK_DIR/mParticle_Apple_SDK.xcframework" \ + 2>&1 | grep -v "note:" || true + + # Move xcframework to temp artifacts directory + echo "๐Ÿ“ Moving xcframework to temp directory..." + mkdir -p "$TEMP_ARTIFACTS_DIR" + rm -rf "$TEMP_ARTIFACTS_DIR/mParticle_Apple_SDK.xcframework" + mv "$SDK_DIR/mParticle_Apple_SDK.xcframework" "$TEMP_ARTIFACTS_DIR/" + + # Clean up archives + rm -rf "$SDK_DIR/archives" + + echo "โœ… SDK built successfully at: $TEMP_ARTIFACTS_DIR/mParticle_Apple_SDK.xcframework" +} + +build_application() { + echo "๐Ÿ“ฆ Building application '$APP_NAME'..." + xcodebuild \ + -project IntegrationTests.xcodeproj \ + -scheme "$SCHEME" \ + -configuration "$CONFIGURATION" \ + -destination "generic/platform=iOS Simulator" \ + -derivedDataPath "$DERIVED_DATA" \ + -quiet \ + build || { echo "โŒ Build error"; exit 1; } + echo "โœ… Build completed." +} + +reset_simulators() { + echo "๐Ÿงน Resetting simulators..." + xcrun simctl shutdown all || true + xcrun simctl erase all || true + killall Simulator || true + echo "โœ… Simulators cleaned." +} + +find_available_device() { + echo "๐Ÿ” Searching for available iPhone simulator..." + + # Get list of available iPhone devices (excluding unavailable ones) + AVAILABLE_DEVICES=$(xcrun simctl list devices iPhone | grep -v "unavailable" | grep "iPhone" | grep -v "==" | head -5) + + if [ -z "$AVAILABLE_DEVICES" ]; then + echo "โŒ No iPhone simulators found. Please install iPhone simulators in Xcode." + exit 1 + fi + + # Try to find iPhone 17, 16, 15, or any available iPhone + for device_pattern in "iPhone 17" "iPhone 16" "iPhone 15" "iPhone"; do + DEVICE_NAME=$(echo "$AVAILABLE_DEVICES" | grep "$device_pattern" | head -1 | sed 's/^[[:space:]]*//' | sed 's/ (.*//') + if [ -n "$DEVICE_NAME" ]; then + echo "โœ… Selected device: $DEVICE_NAME" + break + fi + done + + if [ -z "$DEVICE_NAME" ]; then + echo "โŒ No suitable iPhone simulator found" + exit 1 + fi +} + +find_device() { + echo "๐Ÿ” Finding simulator device '$DEVICE_NAME'..." + DEVICE_ID=$(xcrun simctl list devices | grep "$DEVICE_NAME" | grep -v "unavailable" | awk -F '[()]' '{print $2}' | head -1) + + if [ -z "$DEVICE_ID" ]; then + echo "โŒ Simulator '$DEVICE_NAME' not found. Check Xcode > Devices & Simulators." + exit 1 + fi + echo "โœ… Found device: $DEVICE_ID" +} + +start_simulator() { + echo "๐Ÿ“ฑ Starting simulator $DEVICE_NAME..." + xcrun simctl boot "$DEVICE_ID" || true + open -a Simulator + + echo "โณ Waiting for simulator to start..." + xcrun simctl bootstatus "$DEVICE_ID" -b + echo "โœ… Simulator started." +} + +find_app_path() { + echo "๐Ÿ” Finding application path..." + APP_PATH=$(find "$DERIVED_DATA" -type d -name "${APP_NAME}.app" | head -1) + + if [ -z "$APP_PATH" ]; then + echo "โŒ Application not found in DerivedData" + exit 1 + fi + echo "โœ… Found app at: $APP_PATH" +} + +install_application() { + echo "๐Ÿ“ฒ Installing '$APP_NAME'..." + xcrun simctl install "$DEVICE_ID" "$APP_PATH" + + echo "โณ Waiting for app installation to complete..." + local MAX_WAIT=30 + local WAIT_COUNT=0 + while ! xcrun simctl get_app_container "$DEVICE_ID" "$BUNDLE_ID" &>/dev/null; do + sleep 1 + WAIT_COUNT=$((WAIT_COUNT + 1)) + if [ $WAIT_COUNT -ge $MAX_WAIT ]; then + echo "โŒ App installation timed out after ${MAX_WAIT} seconds" + exit 1 + fi + done + echo "โœ… App installed successfully" +} + +launch_application() { + echo "โ–ถ๏ธ Launching application..." + LAUNCH_OUTPUT=$(xcrun simctl launch "$DEVICE_ID" "$BUNDLE_ID") + APP_PID=$(echo "$LAUNCH_OUTPUT" | awk -F': ' '{print $2}') + + if [ -z "$APP_PID" ]; then + echo "โŒ Failed to get app PID" + exit 1 + fi + + echo "โœ… Application '$APP_NAME' started with PID: $APP_PID" +} + +wait_for_app_completion() { + echo "โณ Waiting for app to complete execution..." + local MAX_WAIT=60 + local WAIT_COUNT=0 + while kill -0 "$APP_PID" 2>/dev/null; do + sleep 1 + WAIT_COUNT=$((WAIT_COUNT + 1)) + if [ $WAIT_COUNT -ge $MAX_WAIT ]; then + echo "โš ๏ธ App still running after ${MAX_WAIT} seconds, proceeding anyway..." + break + fi + done + if [ $WAIT_COUNT -lt $MAX_WAIT ]; then + echo "โœ… App execution completed" + fi +} + +wait_for_wiremock() { + echo "โณ Waiting for WireMock to start..." + local MAX_RETRIES=30 + local RETRY_COUNT=0 + while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do + if curl -k -s -o /dev/null -w "%{http_code}" https://localhost:${HTTPS_PORT}/__admin/mappings | grep -q "200"; then + echo "โœ… WireMock is ready!" + break + fi + RETRY_COUNT=$((RETRY_COUNT + 1)) + echo "Waiting... ($RETRY_COUNT/$MAX_RETRIES)" + sleep 1 + done + + if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then + echo "โŒ WireMock failed to start within ${MAX_RETRIES} seconds" + exit 1 + fi + + echo "" +} + +start_wiremock() { + local mode=${1:-"verify"} # "record" or "verify" + + if [ "$mode" = "record" ]; then + echo "๐Ÿš€ Starting WireMock container in recording mode..." + else + echo "๐Ÿš€ Starting WireMock container in verification mode..." + fi + + stop_wiremock + + # Base docker command + local docker_cmd="docker run -d --name ${CONTAINER_NAME} \ + -p ${HTTP_PORT}:8080 \ + -p ${HTTPS_PORT}:8443 \ + -v \"$(pwd)/${MAPPINGS_DIR}\":/home/wiremock \ + wiremock/wiremock:3.9.1 \ + --https-port 8443" + + # Add mode-specific parameters + if [ "$mode" = "record" ]; then + docker_cmd="${docker_cmd} \ + --enable-browser-proxying \ + --preserve-host-header \ + --record-mappings \ + --proxy-all=\"${TARGET_URL}\"" + else + docker_cmd="${docker_cmd} \ + --verbose" + fi + + # Execute docker command + eval $docker_cmd +} + +stop_wiremock() { + docker stop ${CONTAINER_NAME} 2>/dev/null || true + docker rm ${CONTAINER_NAME} 2>/dev/null || true +} + diff --git a/IntegrationTests/extract_request_body.py b/IntegrationTests/extract_request_body.py index 6a6e5979..2b6f9a1c 100755 --- a/IntegrationTests/extract_request_body.py +++ b/IntegrationTests/extract_request_body.py @@ -136,7 +136,8 @@ def extract_request_body(mapping_file: str, test_name: str, replace_fields: bool try: request_data = mapping_data.get('request', {}) method = request_data.get('method', 'UNKNOWN') - url = request_data.get('url', 'UNKNOWN') + # Support both 'url' and 'urlPattern' fields + url = request_data.get('url') or request_data.get('urlPattern', 'UNKNOWN') body_patterns = request_data.get('bodyPatterns', []) diff --git a/IntegrationTests/run_clean_integration_tests.sh b/IntegrationTests/run_clean_integration_tests.sh new file mode 100755 index 00000000..bc0bcfca --- /dev/null +++ b/IntegrationTests/run_clean_integration_tests.sh @@ -0,0 +1,152 @@ +#!/bin/bash +set -e + +# === Parse script-specific arguments === +HTTP_PORT=${1:-8080} +HTTPS_PORT=${2:-443} +MAPPINGS_DIR=${3:-"./wiremock-recordings"} + +# Source common functions (will use HTTP_PORT, HTTPS_PORT, MAPPINGS_DIR if set) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/common.sh" + +# === Build framework and generate project === +build_framework + +echo "๐Ÿ”„ Generating project with Tuist..." +tuist generate --no-open + +# === Script-specific configuration === +CONTAINER_NAME="wiremock-verify" + +apply_user_friendly_mappings() { + echo "๐Ÿ”„ Applying user-friendly mappings to WireMock..." + local REQUESTS_DIR="${MAPPINGS_DIR}/requests" + + if [ -d "$REQUESTS_DIR" ] && [ "$(ls -A $REQUESTS_DIR/*.json 2>/dev/null)" ]; then + local APPLIED_COUNT=0 + for request_file in "$REQUESTS_DIR"/*.json; do + if [ -f "$request_file" ]; then + echo " ๐Ÿ“ Applying: $(basename $request_file)" + python3 update_mapping_from_extracted.py "$request_file" 2>/dev/null || { + echo " โš ๏ธ Failed to apply $(basename $request_file)" + } + APPLIED_COUNT=$((APPLIED_COUNT + 1)) + fi + done + echo "โœ… Applied $APPLIED_COUNT user-friendly mapping(s)" + else + echo "โš ๏ธ No user-friendly mappings found in $REQUESTS_DIR (skipping)" + fi +} + +verify_wiremock_results() { + echo "" + echo "๐Ÿ” Verifying WireMock results..." + echo "" + + local WIREMOCK_PORT=${HTTP_PORT} + + # Count all requests + local TOTAL=$(curl -s http://localhost:${WIREMOCK_PORT}/__admin/requests | jq '.requests | length') + local UNMATCHED=$(curl -s http://localhost:${WIREMOCK_PORT}/__admin/requests/unmatched | jq '.requests | length') + local MATCHED=$((TOTAL - UNMATCHED)) + + echo "๐Ÿ“Š WireMock summary:" + echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + echo " Total requests: $TOTAL" + echo " Matched requests: $MATCHED" + echo " Unmatched requests: $UNMATCHED" + echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + echo "" + + # Check for unmatched requests + if [ "$UNMATCHED" -gt 0 ]; then + echo "โŒ Found requests that did not match any mappings:" + curl -s http://localhost:${WIREMOCK_PORT}/__admin/requests/unmatched | \ + jq -r '.requests[] | " [\(.method)] \(.url)"' + stop_wiremock + exit 1 + else + echo "โœ… All incoming requests matched their mappings." + fi + + # Check for unused mappings by comparing URLs (not IDs, as WireMock generates new ones) + echo "" + echo "๐Ÿงฉ Checking: were all mappings invoked..." + + # Get all non-proxy mapping URLs from files + local EXPECTED_MAPPINGS=$(jq -r 'select(.response.proxyBaseUrl == null) | "\(.request.method // "ANY") \(.request.url // .request.urlPattern // .request.urlPath // .request.urlPathPattern)"' ${MAPPINGS_DIR}/mappings/*.json 2>/dev/null | sort) + + # Get all actual request URLs + local ACTUAL_REQUESTS=$(curl -s http://localhost:${WIREMOCK_PORT}/__admin/requests | \ + jq -r '.requests[] | "\(.request.method) \(.request.url)"' | sort | uniq) + + # Check each expected mapping + local UNUSED_FOUND=false + while IFS= read -r mapping; do + if [ -n "$mapping" ]; then + local method=$(echo "$mapping" | awk '{print $1}') + local url=$(echo "$mapping" | awk '{$1=""; print $0}' | sed 's/^ //') + + # Check if mapping was used + local matched=false + + # For patterns, check by comparing base structure + if echo "$url" | grep -q '\[' || echo "$url" | grep -q '\\'; then + # It's a pattern - extract the fixed parts + # /v2/us1-[a-f0-9]+/events -> /v2 and /events + # /v4/.../config\?... -> /v4 and /config + local url_start=$(echo "$url" | cut -d'[' -f1 | cut -d'\' -f1) + + # Check if there's a request with same method and starting path + if echo "$ACTUAL_REQUESTS" | grep -Fq "$method $url_start"; then + matched=true + fi + else + # Exact URL match + if echo "$ACTUAL_REQUESTS" | grep -Fq "$mapping"; then + matched=true + fi + fi + + if [ "$matched" = false ]; then + if [ "$UNUSED_FOUND" = false ]; then + echo "โš ๏ธ Some mappings were not invoked by the application:" + UNUSED_FOUND=true + fi + echo " $mapping" + fi + fi + done <<< "$EXPECTED_MAPPINGS" + + if [ "$UNUSED_FOUND" = false ]; then + echo "โœ… All recorded mappings were invoked by the application." + fi + + echo "" + echo "๐ŸŽ‰ Verification completed successfully!" +} + +# Trap to ensure cleanup on exit +trap stop_wiremock EXIT INT TERM + +# === Main execution flow === +build_application +find_app_path +reset_simulators +find_available_device +find_device +apply_user_friendly_mappings +start_wiremock "verify" +wait_for_wiremock +echo "๐Ÿ“ WireMock is running in verification mode" +echo "๐Ÿ”— Admin UI: http://localhost:${HTTP_PORT}/__admin" +echo "๐Ÿ”— HTTPS Endpoint: https://localhost:${HTTPS_PORT}" +echo "" +start_simulator +install_application +launch_application +wait_for_app_completion +verify_wiremock_results +stop_wiremock diff --git a/IntegrationTests/run_wiremock_recorder.sh b/IntegrationTests/run_wiremock_recorder.sh index f824e7ef..d17c8358 100755 --- a/IntegrationTests/run_wiremock_recorder.sh +++ b/IntegrationTests/run_wiremock_recorder.sh @@ -1,207 +1,29 @@ -echo "๐Ÿ”„ Generating project with Tuist..." -tuist generate --no-open - -# === Configuration === -APP_NAME="IntegrationTests" -SCHEME="IntegrationTests" -BUNDLE_ID="com.mparticle.IntegrationTests" -CONFIGURATION="Debug" -DERIVED_DATA="$HOME/Library/Developer/Xcode/DerivedData" +#!/bin/bash +# === Parse script-specific arguments === HTTP_PORT=${1:-8080} HTTPS_PORT=${2:-443} MAPPINGS_DIR=${3:-"./wiremock-recordings"} TARGET_URL=${4:-"https://config2.mparticle.com"} -CONTAINER_NAME="wiremock-recorder" - -# Global variables -DEVICE_NAME="" -DEVICE_ID="" -APP_PATH="" -APP_PID="" - -# === Prepare local directory for mappings === -mkdir -p "${MAPPINGS_DIR}/mappings" -mkdir -p "${MAPPINGS_DIR}/__files" - -build_application() { - echo "๐Ÿ“ฆ Building application '$APP_NAME'..." - xcodebuild \ - -project IntegrationTests.xcodeproj \ - -scheme "$SCHEME" \ - -configuration "$CONFIGURATION" \ - -destination "generic/platform=iOS Simulator" \ - -derivedDataPath "$DERIVED_DATA" \ - -quiet \ - build || { echo "โŒ Build error"; exit 1; } - echo "โœ… Build completed." -} - -reset_simulators() { - echo "๐Ÿงน Resetting simulators..." - xcrun simctl shutdown all || true - xcrun simctl erase all || true - killall Simulator || true - echo "โœ… Simulators cleaned." -} - -find_available_device() { - echo "๐Ÿ” Searching for available iPhone simulator..." - - # Get list of available iPhone devices (excluding unavailable ones) - AVAILABLE_DEVICES=$(xcrun simctl list devices iPhone | grep -v "unavailable" | grep "iPhone" | grep -v "==" | head -5) - - if [ -z "$AVAILABLE_DEVICES" ]; then - echo "โŒ No iPhone simulators found. Please install iPhone simulators in Xcode." - exit 1 - fi - - # Try to find iPhone 17, 16, 15, or any available iPhone - for device_pattern in "iPhone 17" "iPhone 16" "iPhone 15" "iPhone"; do - DEVICE_NAME=$(echo "$AVAILABLE_DEVICES" | grep "$device_pattern" | head -1 | sed 's/^[[:space:]]*//' | sed 's/ (.*//') - if [ -n "$DEVICE_NAME" ]; then - echo "โœ… Selected device: $DEVICE_NAME" - break - fi - done - - if [ -z "$DEVICE_NAME" ]; then - echo "โŒ No suitable iPhone simulator found" - exit 1 - fi -} - -find_device() { - echo "๐Ÿ” Finding simulator device '$DEVICE_NAME'..." - DEVICE_ID=$(xcrun simctl list devices | grep "$DEVICE_NAME" | grep -v "unavailable" | awk -F '[()]' '{print $2}' | head -1) - - if [ -z "$DEVICE_ID" ]; then - echo "โŒ Simulator '$DEVICE_NAME' not found. Check Xcode > Devices & Simulators." - exit 1 - fi - echo "โœ… Found device: $DEVICE_ID" -} - -start_simulator() { - echo "๐Ÿ“ฑ Starting simulator $DEVICE_NAME..." - xcrun simctl boot "$DEVICE_ID" || true - open -a Simulator - echo "โณ Waiting for simulator to start..." - xcrun simctl bootstatus "$DEVICE_ID" -b - echo "โœ… Simulator started." -} +# Source common functions (will use HTTP_PORT, HTTPS_PORT, MAPPINGS_DIR if set) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/common.sh" -install_application() { - echo "๐Ÿ“ฒ Installing '$APP_NAME'..." - xcrun simctl install "$DEVICE_ID" "$APP_PATH" +# === Build framework and generate project === +build_framework - echo "โณ Waiting for app installation to complete..." - local MAX_WAIT=30 - local WAIT_COUNT=0 - while ! xcrun simctl get_app_container "$DEVICE_ID" "$BUNDLE_ID" &>/dev/null; do - sleep 1 - WAIT_COUNT=$((WAIT_COUNT + 1)) - if [ $WAIT_COUNT -ge $MAX_WAIT ]; then - echo "โŒ App installation timed out after ${MAX_WAIT} seconds" - exit 1 - fi - done - echo "โœ… App installed successfully" -} - -launch_application() { - echo "โ–ถ๏ธ Launching application..." - LAUNCH_OUTPUT=$(xcrun simctl launch "$DEVICE_ID" "$BUNDLE_ID") - APP_PID=$(echo "$LAUNCH_OUTPUT" | awk -F': ' '{print $2}') - - if [ -z "$APP_PID" ]; then - echo "โŒ Failed to get app PID" - exit 1 - fi - - echo "โœ… Application '$APP_NAME' started with PID: $APP_PID" -} - -wait_for_app_completion() { - echo "โณ Waiting for app to complete execution..." - MAX_WAIT=60 - WAIT_COUNT=0 - while kill -0 "$APP_PID" 2>/dev/null; do - sleep 1 - WAIT_COUNT=$((WAIT_COUNT + 1)) - if [ $WAIT_COUNT -ge $MAX_WAIT ]; then - echo "โš ๏ธ App still running after ${MAX_WAIT} seconds, proceeding anyway..." - break - fi - done - if [ $WAIT_COUNT -lt $MAX_WAIT ]; then - echo "โœ… App execution completed" - fi -} - -find_app_path() { - echo "๐Ÿ” Finding application path..." - APP_PATH=$(find "$DERIVED_DATA" -type d -name "${APP_NAME}.app" | head -1) - - if [ -z "$APP_PATH" ]; then - echo "โŒ Application not found in DerivedData" - exit 1 - fi - echo "โœ… Found app at: $APP_PATH" -} - -start_wiremock() { - stop_wiremock - - docker run -d --name ${CONTAINER_NAME} \ - -p ${HTTP_PORT}:8080 \ - -p ${HTTPS_PORT}:8443 \ - -v "$(pwd)/${MAPPINGS_DIR}":/home/wiremock \ - wiremock/wiremock:3.9.1 \ - --enable-browser-proxying \ - --preserve-host-header \ - --record-mappings \ - --proxy-all="${TARGET_URL}" \ - --https-port 8443 -} - -wait_for_wiremock() { - echo "โณ Waiting for WireMock to start..." - MAX_RETRIES=30 - RETRY_COUNT=0 - while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do - if curl -k -s -o /dev/null -w "%{http_code}" https://localhost:${HTTPS_PORT}/__admin/mappings | grep -q "200"; then - echo "โœ… WireMock is ready!" - break - fi - RETRY_COUNT=$((RETRY_COUNT + 1)) - echo "Waiting... ($RETRY_COUNT/$MAX_RETRIES)" - sleep 1 - done - - if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then - echo "โŒ WireMock failed to start within ${MAX_RETRIES} seconds" - exit 1 - fi +echo "๐Ÿ”„ Generating project with Tuist..." +tuist generate --no-open - echo "" - echo "๐Ÿ“ WireMock is running and recording traffic to: ${MAPPINGS_DIR}" - echo "๐Ÿ”— Admin UI: http://localhost:${HTTP_PORT}/__admin" - echo "๐Ÿ”— HTTPS Proxy: https://localhost:${HTTPS_PORT}" - echo "" - echo "Press Ctrl+C to stop WireMock and exit..." - echo "" -} +# === Script-specific configuration === +CONTAINER_NAME="wiremock-recorder" -stop_wiremock() { - echo "" - echo "๐Ÿ›‘ Stopping WireMock container..." - docker stop ${CONTAINER_NAME} 2>/dev/null || true - docker rm ${CONTAINER_NAME} 2>/dev/null || true - echo "โœ… WireMock stopped" -} +# === Prepare local directory for mappings === +mkdir -p "${MAPPINGS_DIR}/mappings" +mkdir -p "${MAPPINGS_DIR}/__files" +# Trap to ensure cleanup on exit trap stop_wiremock EXIT INT TERM build_application @@ -209,8 +31,14 @@ find_app_path reset_simulators find_available_device find_device -start_wiremock +start_wiremock "record" wait_for_wiremock +echo "๐Ÿ“ WireMock is running and recording traffic to: ${MAPPINGS_DIR}" +echo "๐Ÿ”— Admin UI: http://localhost:${HTTP_PORT}/__admin" +echo "๐Ÿ”— HTTPS Proxy: https://localhost:${HTTPS_PORT}" +echo "" +echo "Press Ctrl+C to stop WireMock and exit..." +echo "" start_simulator install_application launch_application diff --git a/IntegrationTests/update_mapping_from_extracted.py b/IntegrationTests/update_mapping_from_extracted.py index 049f8efd..73982b07 100644 --- a/IntegrationTests/update_mapping_from_extracted.py +++ b/IntegrationTests/update_mapping_from_extracted.py @@ -88,6 +88,19 @@ def update_mapping(extracted_file: str) -> None: mapping_data['request']['bodyPatterns'][0]['equalToJson'] = escaped_json + # Update URL from extracted data (supports both url and urlPattern) + request_url = extracted_data.get('request_url') + if request_url: + # If URL contains regex pattern, use urlPattern, otherwise use url + if '[' in request_url or '\\' in request_url: + mapping_data['request']['urlPattern'] = request_url + # Remove old 'url' field if it exists + mapping_data['request'].pop('url', None) + else: + mapping_data['request']['url'] = request_url + # Remove old 'urlPattern' field if it exists + mapping_data['request'].pop('urlPattern', None) + except Exception as e: print(f"โŒ Error updating mapping: {e}") sys.exit(1) diff --git a/IntegrationTests/wiremock-recordings/mappings/mapping-v1-identify.json b/IntegrationTests/wiremock-recordings/mappings/mapping-v1-identify.json index 59b20aca..f2e86f48 100644 --- a/IntegrationTests/wiremock-recordings/mappings/mapping-v1-identify.json +++ b/IntegrationTests/wiremock-recordings/mappings/mapping-v1-identify.json @@ -1,35 +1,37 @@ { - "id" : "412faa99-da9a-3a2a-84f0-c05e3057d796", - "request" : { - "url" : "/v1/identify", - "method" : "POST", - "bodyPatterns" : [ { - "equalToJson" : "{\"client_sdk\":{\"platform\":\"ios\",\"sdk_version\":\"8.40.0\",\"sdk_vendor\":\"mparticle\"},\"environment\":\"development\",\"request_timestamp_ms\":1762457821120,\"request_id\":\"1F7C5D84-CDF2-4E68-9E4E-3D320ED84AF0\",\"known_identities\":{\"email\":\"foo@example.com\",\"customerid\":\"123456\",\"ios_idfv\":\"EE48E7EC-1EB3-468C-BAAC-2CC7DBFBDB34\",\"device_application_stamp\":\"24E78BF4-257D-440C-9C75-3B793CD41971\"}}", - "ignoreArrayOrder" : true, - "ignoreExtraElements" : true - } ] + "id": "412faa99-da9a-3a2a-84f0-c05e3057d796", + "request": { + "url": "/v1/identify", + "method": "POST", + "bodyPatterns": [ + { + "equalToJson": "{\"client_sdk\":{\"platform\":\"ios\",\"sdk_version\":\"8.40.0\",\"sdk_vendor\":\"mparticle\"},\"environment\":\"development\",\"request_timestamp_ms\":\"${json-unit.ignore}\",\"request_id\":\"${json-unit.ignore}\",\"known_identities\":{\"email\":\"foo@example.com\",\"customerid\":\"123456\",\"ios_idfv\":\"${json-unit.ignore}\",\"device_application_stamp\":\"${json-unit.ignore}\"}}", + "ignoreArrayOrder": true, + "ignoreExtraElements": true + } + ] }, - "response" : { - "status" : 200, - "bodyFileName" : "body-v1-identify-response.json", - "headers" : { - "X-Cache" : "MISS", - "X-MP-Trace-Id" : "690cf8ddafe953c59086638eb093dfd5", - "Server" : "Kestrel", - "X-Origin-Name" : "4PrgpUXX9K0sNAH1JImfyI--F_us1_origin", - "X-Fastly-Trace-Id" : "932181549", - "X-MP-Max-Age" : "86400", - "Date" : "Thu, 06 Nov 2025 19:37:01 GMT", - "X-Timer" : "S1762457821.273823,VS0,VE53", - "Via" : "1.1 varnish", - "Accept-Ranges" : "bytes", - "Strict-Transport-Security" : "max-age=900", - "Access-Control-Expose-Headers" : "X-MP-Max-Age", - "X-Served-By" : "cache-ewr-kewr1740068-EWR", - "Vary" : "Accept-Encoding", - "X-Cache-Hits" : "0", - "Content-Type" : "application/json; charset=utf-8" + "response": { + "status": 200, + "bodyFileName": "body-v1-identify-response.json", + "headers": { + "X-Cache": "MISS", + "X-MP-Trace-Id": "690cf8ddafe953c59086638eb093dfd5", + "Server": "Kestrel", + "X-Origin-Name": "4PrgpUXX9K0sNAH1JImfyI--F_us1_origin", + "X-Fastly-Trace-Id": "932181549", + "X-MP-Max-Age": "86400", + "Date": "Thu, 06 Nov 2025 19:37:01 GMT", + "X-Timer": "S1762457821.273823,VS0,VE53", + "Via": "1.1 varnish", + "Accept-Ranges": "bytes", + "Strict-Transport-Security": "max-age=900", + "Access-Control-Expose-Headers": "X-MP-Max-Age", + "X-Served-By": "cache-ewr-kewr1740068-EWR", + "Vary": "Accept-Encoding", + "X-Cache-Hits": "0", + "Content-Type": "application/json; charset=utf-8" } }, - "uuid" : "412faa99-da9a-3a2a-84f0-c05e3057d796" -} + "uuid": "412faa99-da9a-3a2a-84f0-c05e3057d796" +} \ No newline at end of file diff --git a/IntegrationTests/wiremock-recordings/mappings/mapping-v2-events-log-event.json b/IntegrationTests/wiremock-recordings/mappings/mapping-v2-events-log-event.json new file mode 100644 index 00000000..032b1997 --- /dev/null +++ b/IntegrationTests/wiremock-recordings/mappings/mapping-v2-events-log-event.json @@ -0,0 +1,33 @@ +{ + "id": "04cb059c-f069-30d2-bc49-99cbb469a6c3", + "request": { + "urlPattern": "/v2/us1-[a-f0-9]+/events", + "method": "POST", + "bodyPatterns": [ + { + "equalToJson": "{\"id\":\"${json-unit.ignore}\",\"ltv\":0,\"msgs\":[{\"vc\":\"off_thread\",\"ct\":\"${json-unit.ignore}\",\"psl\":0,\"id\":\"${json-unit.ignore}\",\"dt\":\"ss\",\"mt\":false},{\"sct\":\"${json-unit.ignore}\",\"id\":\"${json-unit.ignore}\",\"ct\":\"${json-unit.ignore}\",\"dt\":\"fr\",\"sid\":\"${json-unit.ignore}\",\"mt\":false,\"vc\":\"off_thread\"},{\"sct\":\"${json-unit.ignore}\",\"dt\":\"uic\",\"ct\":\"${json-unit.ignore}\",\"ni\":{\"dfs\":\"${json-unit.ignore}\",\"i\":\"123456\",\"n\":1,\"f\":true},\"id\":\"${json-unit.ignore}\",\"sid\":\"${json-unit.ignore}\",\"mt\":false,\"vc\":\"off_thread\"},{\"sct\":\"${json-unit.ignore}\",\"dt\":\"uic\",\"ct\":\"${json-unit.ignore}\",\"ni\":{\"dfs\":\"${json-unit.ignore}\",\"i\":\"foo@example.com\",\"n\":7,\"f\":true},\"id\":\"${json-unit.ignore}\",\"sid\":\"${json-unit.ignore}\",\"mt\":false,\"vc\":\"off_thread\"},{\"id\":\"${json-unit.ignore}\",\"vc\":\"off_thread\",\"sf\":true,\"dt\":\"ast\",\"ct\":\"${json-unit.ignore}\",\"sct\":\"${json-unit.ignore}\",\"sc\":true,\"sid\":\"${json-unit.ignore}\",\"t\":\"app_init\",\"ifr\":true,\"nsi\":0,\"mt\":false},{\"et\":\"Other\",\"id\":\"${json-unit.ignore}\",\"vc\":\"off_thread\",\"dt\":\"e\",\"el\":0,\"ct\":\"${json-unit.ignore}\",\"attrs\":{\"SimpleKey\":\"SimpleValue\"},\"sct\":\"${json-unit.ignore}\",\"sid\":\"${json-unit.ignore}\",\"en\":0,\"n\":\"Simple Event Name\",\"est\":\"${json-unit.ignore}\",\"mt\":false}],\"dt\":\"h\",\"a\":\"${json-unit.ignore}\",\"ai\":{\"av\":\"1.0\",\"sideloaded_kits_count\":0,\"bid\":\"${json-unit.ignore}\",\"pir\":false,\"fi\":false,\"lud\":\"${json-unit.ignore}\",\"arc\":\"arm64\",\"tsv\":\"90000\",\"apn\":\"com.mparticle.IntegrationTests\",\"env\":1,\"abn\":\"1\",\"bsv\":\"${json-unit.ignore}\",\"ict\":\"${json-unit.ignore}\"},\"ct\":\"${json-unit.ignore}\",\"das\":\"${json-unit.ignore}\",\"mpid\":6504934091054997508,\"ui\":[{\"i\":\"123456\",\"n\":1},{\"i\":\"foo@example.com\",\"n\":7}],\"uitl\":60,\"oo\":false,\"sdk\":\"8.40.0\",\"di\":{\"p\":\"arm64\",\"bid\":\"${json-unit.ignore}\",\"tz\":\"-5\",\"dn\":\"${json-unit.ignore}\",\"dll\":\"en\",\"dlc\":\"${json-unit.ignore}\",\"dsh\":\"1440\",\"dma\":\"Apple\",\"vid\":\"${json-unit.ignore}\",\"idst\":false,\"tzn\":\"America/New_York\",\"dp\":\"iOS\",\"dsw\":\"960\",\"dosv\":\"${json-unit.ignore}\",\"it\":false,\"dmdl\":\"arm64\",\"dr\":\"None\",\"jb\":{\"cydia\":false},\"lat\":false,\"arc\":\"arm64e\",\"b\":\"arm64\"},\"stl\":60}", + "ignoreArrayOrder": true, + "ignoreExtraElements": true + } + ] + }, + "response": { + "status": 202, + "bodyFileName": "body-v2-us1-log-event-response.json", + "headers": { + "X-Cache": "MISS, MISS", + "X-MP-Trace-Id": "690cf8e296a7a5c9974b078c5bdc6b95", + "Server": "Kestrel", + "X-Origin-Name": "fastlyshield--shield_ssl_cache_iad_kiad7000042_IAD", + "Date": "Thu, 06 Nov 2025 19:37:06 GMT", + "X-Timer": "S1762457827.775908,VS0,VE22", + "Via": "1.1 varnish, 1.1 varnish", + "Accept-Ranges": "bytes", + "X-Served-By": "cache-iad-kiad7000042-IAD, cache-ewr-kewr1740038-EWR", + "Vary": "Accept-Encoding", + "X-Cache-Hits": "0, 0", + "Content-Type": "application/json" + } + }, + "uuid": "04cb059c-f069-30d2-bc49-99cbb469a6c3" +} \ No newline at end of file diff --git a/IntegrationTests/wiremock-recordings/mappings/mapping-v2-us1-e5145d11865db44eb24cd5a9f194d654-events-log-event.json b/IntegrationTests/wiremock-recordings/mappings/mapping-v2-us1-e5145d11865db44eb24cd5a9f194d654-events-log-event.json deleted file mode 100644 index 0edb3db4..00000000 --- a/IntegrationTests/wiremock-recordings/mappings/mapping-v2-us1-e5145d11865db44eb24cd5a9f194d654-events-log-event.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "id" : "04cb059c-f069-30d2-bc49-99cbb469a6c3", - "request" : { - "url" : "/v2/us1-e5145d11865db44eb24cd5a9f194d654/events", - "method" : "POST", - "bodyPatterns" : [ { - "equalToJson" : "{\"id\":\"${json-unit.ignore}\",\"ltv\":0,\"msgs\":[{\"vc\":\"off_thread\",\"ct\":\"${json-unit.ignore}\",\"psl\":0,\"id\":\"${json-unit.ignore}\",\"dt\":\"ss\",\"mt\":false},{\"sct\":\"${json-unit.ignore}\",\"id\":\"${json-unit.ignore}\",\"ct\":\"${json-unit.ignore}\",\"dt\":\"fr\",\"sid\":\"${json-unit.ignore}\",\"mt\":false,\"vc\":\"off_thread\"},{\"sct\":\"${json-unit.ignore}\",\"dt\":\"uic\",\"ct\":\"${json-unit.ignore}\",\"ni\":{\"dfs\":\"${json-unit.ignore}\",\"i\":\"123456\",\"n\":1,\"f\":true},\"id\":\"${json-unit.ignore}\",\"sid\":\"${json-unit.ignore}\",\"mt\":false,\"vc\":\"off_thread\"},{\"sct\":\"${json-unit.ignore}\",\"dt\":\"uic\",\"ct\":\"${json-unit.ignore}\",\"ni\":{\"dfs\":\"${json-unit.ignore}\",\"i\":\"foo@example.com\",\"n\":7,\"f\":true},\"id\":\"${json-unit.ignore}\",\"sid\":\"${json-unit.ignore}\",\"mt\":false,\"vc\":\"off_thread\"},{\"id\":\"${json-unit.ignore}\",\"vc\":\"off_thread\",\"sf\":true,\"dt\":\"ast\",\"ct\":\"${json-unit.ignore}\",\"sct\":\"${json-unit.ignore}\",\"sc\":true,\"sid\":\"${json-unit.ignore}\",\"t\":\"app_init\",\"ifr\":true,\"nsi\":0,\"mt\":false},{\"et\":\"Other\",\"id\":\"${json-unit.ignore}\",\"vc\":\"off_thread\",\"dt\":\"e\",\"el\":0,\"ct\":\"${json-unit.ignore}\",\"attrs\":{\"SimpleKey\":\"SimpleValue\"},\"sct\":\"${json-unit.ignore}\",\"sid\":\"${json-unit.ignore}\",\"en\":0,\"n\":\"Simple Event Name\",\"est\":\"${json-unit.ignore}\",\"mt\":false}],\"dt\":\"h\",\"a\":\"${json-unit.ignore}\",\"ai\":{\"av\":\"1.0\",\"sideloaded_kits_count\":0,\"bid\":\"00000000-0000-0000-0000-000000000000\",\"pir\":false,\"fi\":false,\"lud\":\"${json-unit.ignore}\",\"arc\":\"arm64\",\"tsv\":\"90000\",\"apn\":\"com.mparticle.IntegrationTests\",\"env\":1,\"abn\":\"1\",\"bsv\":\"${json-unit.ignore}\",\"ict\":\"${json-unit.ignore}\"},\"ct\":\"${json-unit.ignore}\",\"das\":\"${json-unit.ignore}\",\"mpid\":6504934091054997508,\"ui\":[{\"i\":\"123456\",\"n\":1},{\"i\":\"foo@example.com\",\"n\":7}],\"uitl\":60,\"oo\":false,\"sdk\":\"8.40.0\",\"di\":{\"p\":\"arm64\",\"bid\":\"${json-unit.ignore}\",\"tz\":\"-5\",\"dn\":\"${json-unit.ignore}\",\"dll\":\"en\",\"dlc\":\"${json-unit.ignore}\",\"dsh\":\"1440\",\"dma\":\"Apple\",\"vid\":\"${json-unit.ignore}\",\"idst\":false,\"tzn\":\"America\\/New_York\",\"dp\":\"iOS\",\"dsw\":\"960\",\"dosv\":\"${json-unit.ignore}\",\"it\":false,\"dmdl\":\"arm64\",\"dr\":\"None\",\"jb\":{\"cydia\":false},\"lat\":false,\"arc\":\"arm64e\",\"b\":\"arm64\"},\"stl\":60}", - "ignoreArrayOrder" : true, - "ignoreExtraElements" : true - } ] - }, - "response" : { - "status" : 202, - "bodyFileName" : "body-v2-us1-log-event-response.json", - "headers" : { - "X-Cache" : "MISS, MISS", - "X-MP-Trace-Id" : "690cf8e296a7a5c9974b078c5bdc6b95", - "Server" : "Kestrel", - "X-Origin-Name" : "fastlyshield--shield_ssl_cache_iad_kiad7000042_IAD", - "Date" : "Thu, 06 Nov 2025 19:37:06 GMT", - "X-Timer" : "S1762457827.775908,VS0,VE22", - "Via" : "1.1 varnish, 1.1 varnish", - "Accept-Ranges" : "bytes", - "X-Served-By" : "cache-iad-kiad7000042-IAD, cache-ewr-kewr1740038-EWR", - "Vary" : "Accept-Encoding", - "X-Cache-Hits" : "0, 0", - "Content-Type" : "application/json" - } - }, - "uuid" : "04cb059c-f069-30d2-bc49-99cbb469a6c3" -} diff --git a/IntegrationTests/wiremock-recordings/mappings/mapping-v4-us1-e5145d11865db44eb24cd5a9f194d654-config-get-config.json b/IntegrationTests/wiremock-recordings/mappings/mapping-v4-config-get-config.json similarity index 91% rename from IntegrationTests/wiremock-recordings/mappings/mapping-v4-us1-e5145d11865db44eb24cd5a9f194d654-config-get-config.json rename to IntegrationTests/wiremock-recordings/mappings/mapping-v4-config-get-config.json index f6745ef4..1be2b310 100644 --- a/IntegrationTests/wiremock-recordings/mappings/mapping-v4-us1-e5145d11865db44eb24cd5a9f194d654-config-get-config.json +++ b/IntegrationTests/wiremock-recordings/mappings/mapping-v4-config-get-config.json @@ -1,7 +1,7 @@ { "id" : "a7d323f1-a729-39c6-86cd-4035c71f7d05", "request" : { - "url" : "/v4/us1-e5145d11865db44eb24cd5a9f194d654/config?av=1.0&sv=8.40.0", + "urlPattern" : "/v4/us1-[a-f0-9]+/config\\?av=1\\.0&sv=8\\.40\\.0", "method" : "GET" }, "response" : { diff --git a/IntegrationTests/wiremock-recordings/requests/identify.json b/IntegrationTests/wiremock-recordings/requests/identify.json index 6de21497..ba7300f8 100644 --- a/IntegrationTests/wiremock-recordings/requests/identify.json +++ b/IntegrationTests/wiremock-recordings/requests/identify.json @@ -10,13 +10,13 @@ "sdk_vendor": "mparticle" }, "environment": "development", - "request_timestamp_ms": 1762457821120, - "request_id": "1F7C5D84-CDF2-4E68-9E4E-3D320ED84AF0", + "request_timestamp_ms": "${json-unit.ignore}", + "request_id": "${json-unit.ignore}", "known_identities": { "email": "foo@example.com", "customerid": "123456", - "ios_idfv": "EE48E7EC-1EB3-468C-BAAC-2CC7DBFBDB34", - "device_application_stamp": "24E78BF4-257D-440C-9C75-3B793CD41971" + "ios_idfv": "${json-unit.ignore}", + "device_application_stamp": "${json-unit.ignore}" } } } \ No newline at end of file diff --git a/IntegrationTests/wiremock-recordings/requests/log_event.json b/IntegrationTests/wiremock-recordings/requests/log_event.json index dff825f5..3758cf0a 100644 --- a/IntegrationTests/wiremock-recordings/requests/log_event.json +++ b/IntegrationTests/wiremock-recordings/requests/log_event.json @@ -1,8 +1,8 @@ { "test_name": "log_event", - "source_mapping": "wiremock-recordings/mappings/mapping-v2-us1-e5145d11865db44eb24cd5a9f194d654-events-log-event.json", + "source_mapping": "wiremock-recordings/mappings/mapping-v2-events-log-event.json", "request_method": "POST", - "request_url": "/v2/us1-e5145d11865db44eb24cd5a9f194d654/events", + "request_url": "/v2/us1-[a-f0-9]+/events", "request_body": { "id": "${json-unit.ignore}", "ltv": 0,