diff --git a/.github/workflows/build-push-docker-image.yml b/.github/workflows/build-push-docker-image.yml index c7e59dce86..ba62e5d8d1 100644 --- a/.github/workflows/build-push-docker-image.yml +++ b/.github/workflows/build-push-docker-image.yml @@ -96,15 +96,15 @@ jobs: with: ref: ${{ needs.get_sha.outputs.sha }} fetch-depth: 1 - - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3.7.1 - + - name: Login to DockerHub uses: docker/login-action@v3.3.0 with: username: ${{ env.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} + password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3.7.1 - name: Build Docker Image uses: docker/build-push-action@v6.9.0 @@ -149,16 +149,16 @@ jobs: with: ref: ${{ needs.get_sha.outputs.sha }} fetch-depth: 1 - - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3.7.1 - + - name: Login to DockerHub uses: docker/login-action@v3.3.0 with: username: ${{ env.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3.7.1 + - name: Build Docker Image uses: docker/build-push-action@v6.9.0 with: @@ -198,15 +198,15 @@ jobs: needs: [build-transformer-image-amd64, build-transformer-image-arm64] steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.7.1 - - name: Login to DockerHub uses: docker/login-action@v3.3.0 with: username: ${{ env.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PROD_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.7.1 + - name: Create multi-arch manifest run: | docker buildx imagetools create -t ${{ inputs.push_tags }} ${{ inputs.push_tags }}-amd64 ${{ inputs.push_tags }}-arm64 diff --git a/.github/workflows/dt-test-and-report-code-coverage.yml b/.github/workflows/dt-test-and-report-code-coverage.yml index 2c76898882..12bd9ac78b 100644 --- a/.github/workflows/dt-test-and-report-code-coverage.yml +++ b/.github/workflows/dt-test-and-report-code-coverage.yml @@ -33,7 +33,7 @@ jobs: - name: Checkout uses: actions/checkout@v4.2.1 with: - fetch-depth: 1 + fetch-depth: 0 - name: Setup Node uses: actions/setup-node@v4.0.4 diff --git a/.github/workflows/prepare-for-prod-dt-deploy.yml b/.github/workflows/prepare-for-prod-dt-deploy.yml index 0a61a359bf..56fda56b70 100644 --- a/.github/workflows/prepare-for-prod-dt-deploy.yml +++ b/.github/workflows/prepare-for-prod-dt-deploy.yml @@ -159,7 +159,7 @@ jobs: cd customer-objects - declare -a enabled_ut_customers=() + declare -a enabled_dt_customers=() declare -a sub_directories=('enterprise-us' 'enterprise-eu') # identify the customers enabled in sub-directories @@ -167,21 +167,21 @@ jobs: for f in "./$directory"/*; do [[ -f $f ]] || continue - enabled="$(yq e '.spec.user_transformer.enabled' $f)" + enabled="$(yq e '.spec.transformer.enabled' $f)" if [ $enabled == "true" ]; then - enabled_ut_customers+=( $f ) + enabled_dt_customers+=( $f ) fi done done # bump up the customers version and repository information - for customer in "${enabled_ut_customers[@]}"; do - yq eval -i ".spec.user_transformer.image.version=\"$TAG_NAME\"" $customer - yq eval -i ".spec.user_transformer.image.repository=\"$TF_IMAGE_REPOSITORY\"" $customer + for customer in "${enabled_dt_customers[@]}"; do + yq eval -i ".spec.transformer.image.version=\"$TAG_NAME\"" $customer + yq eval -i ".spec.transformer.image.repository=\"$TF_IMAGE_REPOSITORY\"" $customer git add $customer done - git commit -m "chore: upgrade dedicated transformers to $TAG_NAME" + git commit -m "chore: upgrade dedicated dt transformers to $TAG_NAME" git push -u origin dedicated-transformer-$TAG_NAME gh pr create --fill diff --git a/.github/workflows/prepare-for-prod-ut-deploy.yml b/.github/workflows/prepare-for-prod-ut-deploy.yml index 3053979b3e..612dddc833 100644 --- a/.github/workflows/prepare-for-prod-ut-deploy.yml +++ b/.github/workflows/prepare-for-prod-ut-deploy.yml @@ -29,6 +29,7 @@ jobs: if: ((startsWith(github.event.pull_request.head.ref, 'release/') || startsWith(github.event.pull_request.head.ref, 'hotfix-release/')) && github.event.pull_request.merged == true) outputs: tag_name_ut: ${{ steps.gen_tag_names.outputs.tag_name_ut }} + tag_name: ${{ steps.gen_tag_names.outputs.tag_name }} steps: - name: Checkout uses: actions/checkout@v4.2.1 @@ -71,6 +72,7 @@ jobs: needs: [generate-tag-names, build-user-transformer-image] env: UT_TAG_NAME: ${{ needs.generate-tag-names.outputs.tag_name_ut }} + TAG_NAME: ${{ needs.generate-tag-names.outputs.tag_name }} TF_IMAGE_REPOSITORY: rudderstack/rudder-transformer steps: - name: Checkout @@ -134,3 +136,39 @@ jobs: git push -u origin hosted-user-transformer-$UT_TAG_NAME gh pr create --fill + + - name: Update helm charts and raise pull request for enterprise customers on dedicated transformers + env: + GITHUB_TOKEN: ${{ secrets.PAT }} + run: | + cd rudder-devops + git checkout -b dedicated-user-transformer-$TAG_NAME + + cd customer-objects + + declare -a enabled_ut_customers=() + declare -a sub_directories=('enterprise-us' 'enterprise-eu') + + # identify the customers enabled in sub-directories + for directory in "${sub_directories[@]}"; do + for f in "./$directory"/*; do + [[ -f $f ]] || continue + + enabled="$(yq e '.spec.user_transformer.enabled' $f)" + if [ $enabled == "true" ]; then + enabled_ut_customers+=( $f ) + fi + done + done + + # bump up the customers version and repository information + for customer in "${enabled_ut_customers[@]}"; do + yq eval -i ".spec.user_transformer.image.version=\"$TAG_NAME\"" $customer + yq eval -i ".spec.user_transformer.image.repository=\"$TF_IMAGE_REPOSITORY\"" $customer + git add $customer + done + + git commit -m "chore: upgrade dedicated user transformers to $TAG_NAME" + git push -u origin dedicated-user-transformer-$TAG_NAME + + gh pr create --fill \ No newline at end of file diff --git a/.github/workflows/prepare-for-staging-deploy.yml b/.github/workflows/prepare-for-staging-deploy.yml index 8eeafc376e..cdf27f7832 100644 --- a/.github/workflows/prepare-for-staging-deploy.yml +++ b/.github/workflows/prepare-for-staging-deploy.yml @@ -78,6 +78,7 @@ jobs: runs-on: ubuntu-latest needs: [generate-tag-names, build-transformer-image, build-user-transformer-image] env: + TF_IMAGE_REPOSITORY: rudderstack/rudder-transformer TAG_NAME: ${{ needs.generate-tag-names.outputs.tag_name }} UT_TAG_NAME: ${{ needs.generate-tag-names.outputs.tag_name_ut }} steps: @@ -113,6 +114,7 @@ jobs: git checkout -b $BRANCH_NAME cd helm-charts/shared-services/per-az/environment/staging + yq eval -i ".rudder-transformer.image.repository=\"$TF_IMAGE_REPOSITORY\"" staging.yaml yq eval -i ".rudder-transformer.image.tag=\"$TAG_NAME\"" staging.yaml yq eval -i ".user-transformer.image.tag=\"$TAG_NAME\"" staging.yaml git add staging.yaml diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 4bd66285bd..604ff1eaee 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -35,8 +35,8 @@ jobs: - name: Filter JS/TS Files run: | - echo "${{ steps.files.outputs.added_modified }}" | tr ' ' '\n' | grep -E '\.(js|ts|jsx|tsx)$' > changed_files.txt - if [ ! -s changed_files.txt ]; then + changed_files=$(echo "${{ steps.files.outputs.added_modified }}" | tr ' ' '\n' | grep -E '\.(js|ts|jsx|tsx)$' || true) + if [ -z "$changed_files" ]; then echo "No JS/TS files to format or lint." exit 0 fi diff --git a/.gitignore b/.gitignore index 84421f49d9..e52af90cc6 100644 --- a/.gitignore +++ b/.gitignore @@ -139,4 +139,8 @@ dist # component test report test_reports/ -temp/ \ No newline at end of file +temp/ + +# Allure +allure-results/ +allure-report/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c3c5528ff6..ee9dead590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,65 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.87.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.86.0...v1.87.0) (2024-12-13) + + +### Features + +* onboard topsort destination ([#3913](https://github.com/rudderlabs/rudder-transformer/issues/3913)) ([227419f](https://github.com/rudderlabs/rudder-transformer/commit/227419f1ff618f96aafa849862828e2315e4ac55)) + + +### Bug Fixes + +* handling partial error in a batch for reddit destination ([#3935](https://github.com/rudderlabs/rudder-transformer/issues/3935)) ([d40db6c](https://github.com/rudderlabs/rudder-transformer/commit/d40db6c1e7f71c5ab5fc3a3659d1fc51b6d527fa)) + +## [1.86.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.85.1...v1.86.0) (2024-12-09) + + +### Features + +* add support for getting anonymousId by note attributes array ([53d2bef](https://github.com/rudderlabs/rudder-transformer/commit/53d2bef38ad5d7bc5504111ec797b3c3973546dd)) +* add support for getting anonymousId by note attributes array ([#3893](https://github.com/rudderlabs/rudder-transformer/issues/3893)) ([d7f390c](https://github.com/rudderlabs/rudder-transformer/commit/d7f390cb471e44afb276484b8b804d1f257c539c)) + + +### Bug Fixes + +* braze subscription group fixes ([#3901](https://github.com/rudderlabs/rudder-transformer/issues/3901)) ([ebcf84e](https://github.com/rudderlabs/rudder-transformer/commit/ebcf84e07bf121d882c99df973af265a915a1ce1)) +* remove redundant ids and userIdentifier when gbraid or wbraid are there ([#3910](https://github.com/rudderlabs/rudder-transformer/issues/3910)) ([313710c](https://github.com/rudderlabs/rudder-transformer/commit/313710ca725538e5ffe357216d9c88e444f995c8)) +* skipping users events for snowpipe streaming ([#3836](https://github.com/rudderlabs/rudder-transformer/issues/3836)) ([12621c8](https://github.com/rudderlabs/rudder-transformer/commit/12621c8eee641f5a03a997e95ed016cff0eefde7)) + +### [1.85.1](https://github.com/rudderlabs/rudder-transformer/compare/v1.85.0...v1.85.1) (2024-11-21) + + +### Bug Fixes + +* braze subscription batch size ([#3897](https://github.com/rudderlabs/rudder-transformer/issues/3897)) ([ca71a31](https://github.com/rudderlabs/rudder-transformer/commit/ca71a318e4d8d098116fe539964b699254f58617)) +* stringifying session ID for airship ([#3896](https://github.com/rudderlabs/rudder-transformer/issues/3896)) ([bb0b9dc](https://github.com/rudderlabs/rudder-transformer/commit/bb0b9dc1e5a56e8141c6cb56e89835ba61ee7761)) + +## [1.85.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.84.0...v1.85.0) (2024-11-18) + + +### Features + +* added support to eu/us2 datacenter for gainsight px destination ([#3871](https://github.com/rudderlabs/rudder-transformer/issues/3871)) ([12ac3de](https://github.com/rudderlabs/rudder-transformer/commit/12ac3de6e7cc91a6cd52c33bc342f74bbaa8a631)) +* iterable EUDC ([#3828](https://github.com/rudderlabs/rudder-transformer/issues/3828)) ([1c134f8](https://github.com/rudderlabs/rudder-transformer/commit/1c134f84601aaea78581078137cb9955de576f9e)) +* iterable EUDC deleteUsers ([#3881](https://github.com/rudderlabs/rudder-transformer/issues/3881)) ([becb4fa](https://github.com/rudderlabs/rudder-transformer/commit/becb4fa54e9093ed69779f54c36864cb9d28d321)) +* moved userSchema to connection config in GARL vdmv2 ([#3870](https://github.com/rudderlabs/rudder-transformer/issues/3870)) ([640a11e](https://github.com/rudderlabs/rudder-transformer/commit/640a11eb3dca5735fed3ad9ad5bd058974b069d6)) +* now getting consent related fields from connection config from retl for GARL ([#3877](https://github.com/rudderlabs/rudder-transformer/issues/3877)) ([51bbc02](https://github.com/rudderlabs/rudder-transformer/commit/51bbc02d5b00ce1b8fe8c91b4a7041e926bae9bd)) +* onboard linkedin audience destination ([#3857](https://github.com/rudderlabs/rudder-transformer/issues/3857)) ([f3ff409](https://github.com/rudderlabs/rudder-transformer/commit/f3ff4092d455508dd3354ffb22d345fa97f4d1f2)) +* onboarding intercom v2 retl support ([#3843](https://github.com/rudderlabs/rudder-transformer/issues/3843)) ([3d7db73](https://github.com/rudderlabs/rudder-transformer/commit/3d7db7366e30df31c37cc473e344da82b49ed885)) +* sources v2 spec support along with adapters ([04c0694](https://github.com/rudderlabs/rudder-transformer/commit/04c069486bdd3c101906fa6c621e983090fcab25)) +* sources v2 spec support along with adapters ([#3810](https://github.com/rudderlabs/rudder-transformer/issues/3810)) ([c51cfbb](https://github.com/rudderlabs/rudder-transformer/commit/c51cfbb4664a8531dce23b2d06fe40997f95697e)) +* update pinterest_tag single product events with new mapping ([#3858](https://github.com/rudderlabs/rudder-transformer/issues/3858)) ([8520278](https://github.com/rudderlabs/rudder-transformer/commit/85202781de3464bd46fe910159d2b143cd4209e8)) + + +### Bug Fixes + +* adding logger for undefined source event ([#3879](https://github.com/rudderlabs/rudder-transformer/issues/3879)) ([79e5979](https://github.com/rudderlabs/rudder-transformer/commit/79e597907eee126b4187e4534b2aa2253d1431da)) +* adding uuid transformation for airship ([#3884](https://github.com/rudderlabs/rudder-transformer/issues/3884)) ([a80f874](https://github.com/rudderlabs/rudder-transformer/commit/a80f87486dc93b423e4fe6efbee6f4cb8330ba02)) +* handling invalid timestamp for adjust source ([#3866](https://github.com/rudderlabs/rudder-transformer/issues/3866)) ([d57f48e](https://github.com/rudderlabs/rudder-transformer/commit/d57f48e989d18d469bea0de94293bc685300945b)) +* revert gaec changes ([#3885](https://github.com/rudderlabs/rudder-transformer/issues/3885)) ([0aeaa39](https://github.com/rudderlabs/rudder-transformer/commit/0aeaa391b025fc68de6e3d63a6721f067c5be318)) + ## [1.84.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.83.2...v1.84.0) (2024-11-11) diff --git a/jest.config.typescript.js b/jest.config.typescript.js index 7350f1e19d..35997cb70c 100644 --- a/jest.config.typescript.js +++ b/jest.config.typescript.js @@ -128,7 +128,7 @@ module.exports = { // snapshotSerializers: [], // The test environment that will be used for testing - testEnvironment: 'node', + testEnvironment: 'allure-jest/node', // Options that will be passed to the testEnvironment // testEnvironmentOptions: {}, diff --git a/package-lock.json b/package-lock.json index d10997f143..6a7d4ce983 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.84.0", + "version": "1.87.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.84.0", + "version": "1.87.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", @@ -27,7 +27,7 @@ "ajv-draft-04": "^1.0.0", "ajv-formats": "^2.1.1", "amazon-dsp-formatter": "^1.0.2", - "axios": "^1.7.3", + "axios": "^1.7.9", "btoa": "^1.2.1", "component-each": "^0.2.6", "crypto-js": "^4.2.0", @@ -90,6 +90,7 @@ "@types/supertest": "^6.0.2", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.59.2", + "allure-jest": "^3.0.7", "axios-mock-adapter": "^1.22.0", "benchmark-suite": "^0.1.8", "commander": "^10.0.1", @@ -109,6 +110,8 @@ "http-terminator": "^3.2.0", "husky": "^9.1.6", "jest": "^29.5.0", + "jest-diff": "^29.7.0", + "jest-environment-node": "^29.7.0", "jest-sonar": "^0.2.16", "jest-when": "^3.5.2", "lint-staged": "^13.2.2", @@ -8201,6 +8204,56 @@ } } }, + "node_modules/allure-jest": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/allure-jest/-/allure-jest-3.0.7.tgz", + "integrity": "sha512-vOFLkjreMI0br1PoSNP8AyPY3ieTLdHcBz1c5kXSyWNIxx23EPJ/TxKgg1cYyQrkpm3z3TMCj3XS3iYhVwz0/g==", + "dev": true, + "dependencies": { + "allure-js-commons": "3.0.7" + }, + "peerDependencies": { + "jest": ">=24.8.0", + "jest-circus": ">=24.8.0", + "jest-cli": ">=24.8.0", + "jest-environment-jsdom": ">=24.8.0", + "jest-environment-node": ">=24.8.0" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + }, + "jest-circus": { + "optional": true + }, + "jest-cli": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "jest-environment-node": { + "optional": true + } + } + }, + "node_modules/allure-js-commons": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-3.0.7.tgz", + "integrity": "sha512-keHlPAtmzdtEK8FT5W0mOMYh9ZrdlhbrDyaaAKMNHipF/EsFak18XdbLiAKhnHbHiicE+n3BrmBU4rfQEoFHzA==", + "dev": true, + "dependencies": { + "md5": "^2.3.0" + }, + "peerDependencies": { + "allure-playwright": "3.0.7" + }, + "peerDependenciesMeta": { + "allure-playwright": { + "optional": true + } + } + }, "node_modules/amazon-dsp-formatter": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/amazon-dsp-formatter/-/amazon-dsp-formatter-1.0.2.tgz", @@ -8482,8 +8535,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.7.5", - "license": "MIT", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -10621,7 +10675,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -15026,8 +15082,9 @@ }, "node_modules/jest-diff": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -15194,8 +15251,9 @@ }, "node_modules/jest-environment-node": { "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", diff --git a/package.json b/package.json index 92ac9f0fb9..f7d7e44749 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.84.0", + "version": "1.87.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { @@ -36,11 +36,11 @@ "test": "jest -c jest.config.js --detectOpenHandles", "test:ci": "npm run test -- --coverage --expand --maxWorkers=50%", "test:js": "jest -c jest.default.config.js --detectOpenHandles", - "test:js:silent": "npm run test:js -- --silent", + "test:js:silent": "export LOG_LEVEL=silent && npm run test:js -- --silent", "test:js:ci": "npm run test:js -- --coverage --expand --maxWorkers=50%", "test:ts": "jest -c jest.config.typescript.js --detectOpenHandles", "test:ts:component:generateNwMocks": "npm run test:ts -- component --generate=true", - "test:ts:silent": "npm run test:ts -- --silent", + "test:ts:silent": "export LOG_LEVEL=silent && npm run test:ts -- --silent", "test:ts:ci": "npm run test:ts -- --coverage --expand --maxWorkers=50%", "test:ut:integration": "jest \"user_transformation.integration.test.js\" --detectOpenHandles --notify", "test:ut:integration:silent": "npm run test:ut:integration -- --silent", @@ -72,7 +72,7 @@ "ajv-draft-04": "^1.0.0", "ajv-formats": "^2.1.1", "amazon-dsp-formatter": "^1.0.2", - "axios": "^1.7.3", + "axios": "^1.7.9", "btoa": "^1.2.1", "component-each": "^0.2.6", "crypto-js": "^4.2.0", @@ -135,6 +135,7 @@ "@types/supertest": "^6.0.2", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.59.2", + "allure-jest": "^3.0.7", "axios-mock-adapter": "^1.22.0", "benchmark-suite": "^0.1.8", "commander": "^10.0.1", @@ -154,6 +155,8 @@ "http-terminator": "^3.2.0", "husky": "^9.1.6", "jest": "^29.5.0", + "jest-diff": "^29.7.0", + "jest-environment-node": "^29.7.0", "jest-sonar": "^0.2.16", "jest-when": "^3.5.2", "lint-staged": "^13.2.2", diff --git a/src/cdk/v2/destinations/pinterest_tag/utils.js b/src/cdk/v2/destinations/pinterest_tag/utils.js index 31a897f133..dbaeea9501 100644 --- a/src/cdk/v2/destinations/pinterest_tag/utils.js +++ b/src/cdk/v2/destinations/pinterest_tag/utils.js @@ -1,8 +1,8 @@ -/* eslint-disable no-param-reassign */ const sha256 = require('sha256'); const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib'); const { API_VERSION } = require('./config'); +const { CommonUtils } = require('../../../../util/common'); const VALID_ACTION_SOURCES = ['app_android', 'app_ios', 'web', 'offline']; @@ -21,9 +21,15 @@ const ecomEventMaps = [ }, ]; -const USER_NON_ARRAY_PROPERTIES = ['client_user_agent', 'client_ip_address']; +const USER_NON_ARRAY_PROPERTIES = [ + 'client_user_agent', + 'client_ip_address', + 'click_id', + 'partner_id', +]; -const getHashedValue = (key, value) => { +const transformValue = (key, value) => { + const arrayValue = CommonUtils.toArray(value); switch (key) { case 'em': case 'ct': @@ -32,33 +38,18 @@ const getHashedValue = (key, value) => { case 'ln': case 'fn': case 'ge': - value = Array.isArray(value) - ? value.map((val) => val.toString().trim().toLowerCase()) - : value.toString().trim().toLowerCase(); - break; + return arrayValue.map((val) => val.toString().trim().toLowerCase()); case 'ph': - // phone numbers should only contain digits & should not contain leading zeros - value = Array.isArray(value) - ? value.map((val) => val.toString().replace(/\D/g, '').replace(/^0+/, '')) - : value.toString().replace(/\D/g, '').replace(/^0+/, ''); - break; + return arrayValue.map((val) => val.toString().replace(/\D/g, '').replace(/^0+/, '')); case 'zp': - // zip fields should only contain digits - value = Array.isArray(value) - ? value.map((val) => val.toString().trim().replace(/\D/g, '')) - : value.toString().replace(/\D/g, ''); - break; - case 'hashed_maids': - case 'external_id': - case 'db': - // no action needed on value - break; + return arrayValue.map((val) => val.toString().trim().replace(/\D/g, '')); default: - return String(value); + return arrayValue; } - return Array.isArray(value) ? value.map((val) => sha256(val)) : [sha256(value)]; }; +const getHashedValue = (key, value) => transformValue(key, value).map((val) => sha256(val)); + /** * * @param {*} userPayload Payload mapped from user fields @@ -67,10 +58,15 @@ const getHashedValue = (key, value) => { * Ref: https://s.pinimg.com/ct/docs/conversions_api/dist/v3.html */ const processUserPayload = (userPayload) => { - Object.keys(userPayload).forEach((key) => { - userPayload[key] = getHashedValue(key, userPayload[key]); + const newPayload = { ...userPayload }; + Object.keys(newPayload).forEach((key) => { + if (USER_NON_ARRAY_PROPERTIES.includes(key)) { + newPayload[key] = String(newPayload[key]); + } else { + newPayload[key] = getHashedValue(key, newPayload[key]); + } }); - return userPayload; + return newPayload; }; /** @@ -99,11 +95,7 @@ const processHashedUserPayload = (userPayload, message) => { const processedHashedUserPayload = {}; Object.keys(userPayload).forEach((key) => { if (!USER_NON_ARRAY_PROPERTIES.includes(key)) { - if (Array.isArray(userPayload[key])) { - processedHashedUserPayload[key] = [...userPayload[key]]; - } else { - processedHashedUserPayload[key] = [userPayload[key]]; - } + processedHashedUserPayload[key] = CommonUtils.toArray(userPayload[key]); } else { processedHashedUserPayload[key] = userPayload[key]; } @@ -111,10 +103,8 @@ const processHashedUserPayload = (userPayload, message) => { // multiKeyMap will works on only specific values like m, male, MALE, f, F, Female // if hashed data is sent from the user, it is directly set over here const gender = message.traits?.gender || message.context?.traits?.gender; - if (gender && Array.isArray(gender)) { - processedHashedUserPayload.ge = [...gender]; - } else if (gender) { - processedHashedUserPayload.ge = [gender]; + if (gender) { + processedHashedUserPayload.ge = CommonUtils.toArray(gender); } return processedHashedUserPayload; }; diff --git a/src/cdk/v2/destinations/reddit/rtWorkflow.yaml b/src/cdk/v2/destinations/reddit/rtWorkflow.yaml index 937ff021f4..fd315b381a 100644 --- a/src/cdk/v2/destinations/reddit/rtWorkflow.yaml +++ b/src/cdk/v2/destinations/reddit/rtWorkflow.yaml @@ -36,7 +36,11 @@ steps: description: Batches the successfulEvents using endpoint condition: $.outputs.successfulEvents.length template: | - let batches = $.batchEvents($.outputs.successfulEvents); + const dontBatchTrueEvents = $.outputs.successfulEvents{.metadata.dontBatch}[]; + const dontBatchFalseEvents = $.outputs.successfulEvents{!.metadata.dontBatch}[]; + const dontBatchTrueEventsChunks = $.chunk(dontBatchTrueEvents, 1); + + let batches = [...$.batchEvents(dontBatchFalseEvents), ...$.batchEventChunks(dontBatchTrueEventsChunks)]; batches@batch.({ "batchedRequest": { "body": { diff --git a/src/cdk/v2/destinations/reddit/utils.js b/src/cdk/v2/destinations/reddit/utils.js index f562d31313..e51a72142a 100644 --- a/src/cdk/v2/destinations/reddit/utils.js +++ b/src/cdk/v2/destinations/reddit/utils.js @@ -81,6 +81,7 @@ const populateRevenueField = (eventType, properties) => { }; module.exports = { batchEvents, + batchEventChunks, populateRevenueField, calculateDefaultRevenue, }; diff --git a/src/controllers/bulkUpload.ts b/src/controllers/bulkUpload.ts deleted file mode 100644 index cb0bcfed3c..0000000000 --- a/src/controllers/bulkUpload.ts +++ /dev/null @@ -1,166 +0,0 @@ -/* eslint-disable global-require, import/no-dynamic-require, @typescript-eslint/no-unused-vars */ -import { client as errNotificationClient } from '../util/errorNotifier'; -import { - getDestFileUploadHandler, - getJobStatusHandler, - getPollStatusHandler, -} from '../util/fetchDestinationHandlers'; -import { CatchErr, ContextBodySimple } from '../util/types'; -import logger from '../logger'; -// TODO: To be refactored and redisgned - -const ERROR_MESSAGE_PROCESSOR_STRING = 'Error occurred while processing payload.'; - -const getCommonMetadata = (ctx) => - // TODO: Parse information such as - // cluster, namespace, etc information - // from the request - ({ - namespace: 'Unknown', - cluster: 'Unknown', - }); - -const getReqMetadata = (ctx) => { - try { - const reqBody = ctx.request.body; - return { destType: reqBody?.destType, importId: reqBody?.importId }; - } catch (error) { - // Do nothing - } - return {}; -}; - -export const fileUpload = async (ctx) => { - logger.debug('Native(Bulk-Upload): Request to transformer:: /fileUpload route', ctx.request.body); - const getReqMetadataFileUpload = () => { - try { - const reqBody = ctx.request.body; - return { destType: reqBody?.destType }; - } catch (error) { - // Do nothing - } - return {}; - }; - - const { destType }: ContextBodySimple = ctx.request.body; - const destFileUploadHandler = getDestFileUploadHandler('v0', destType.toLowerCase()); - - if (!destFileUploadHandler || !destFileUploadHandler.processFileData) { - ctx.status = 404; - ctx.body = `${destType} doesn't support bulk upload`; - return null; - } - let response; - try { - response = await destFileUploadHandler.processFileData(ctx.request.body); - } catch (error: CatchErr) { - response = { - statusCode: error?.response?.status || error?.status || 400, - error: error.message || ERROR_MESSAGE_PROCESSOR_STRING, - metadata: error.response ? error.response.metadata : null, - }; - errNotificationClient.notify(error, 'File Upload', { - ...response, - ...getCommonMetadata(ctx), - ...getReqMetadata(ctx), - }); - } - ctx.body = response; - logger.debug('Native(Bulk-Upload): Response from transformer:: /fileUpload route', ctx.body); - return ctx.body; -}; - -export const pollStatus = async (ctx) => { - logger.debug('Native(Bulk-Upload): Request to transformer:: /pollStatus route', ctx.request.body); - - const { destType }: ContextBodySimple = ctx.request.body; - const destFileUploadHandler = getPollStatusHandler('v0', destType.toLowerCase()); - let response; - if (!destFileUploadHandler || !destFileUploadHandler.processPolling) { - ctx.status = 404; - ctx.body = `${destType} doesn't support bulk upload`; - return null; - } - try { - response = await destFileUploadHandler.processPolling(ctx.request.body); - } catch (error: CatchErr) { - response = { - statusCode: error.response?.status || 400, - error: error.message || ERROR_MESSAGE_PROCESSOR_STRING, - }; - errNotificationClient.notify(error, 'Poll Status', { - ...response, - ...getCommonMetadata(ctx), - ...getReqMetadata(ctx), - }); - } - ctx.body = response; - logger.debug('Native(Bulk-Upload): Request from transformer:: /pollStatus route', ctx.body); - return ctx.body; -}; - -export const getWarnJobStatus = async (ctx) => { - logger.debug( - 'Native(Bulk-Upload): Request to transformer:: /getWarningJobs route', - ctx.request.body, - ); - - const { destType }: ContextBodySimple = ctx.request.body; - const destFileUploadHandler = getJobStatusHandler('v0', destType.toLowerCase()); - - if (!destFileUploadHandler || !destFileUploadHandler.processJobStatus) { - ctx.status = 404; - ctx.body = `${destType} doesn't support bulk upload`; - return null; - } - let response; - try { - response = await destFileUploadHandler.processJobStatus(ctx.request.body, 'warn'); - } catch (error: CatchErr) { - response = { - statusCode: error.response ? error.response.status : 400, - error: error.message || ERROR_MESSAGE_PROCESSOR_STRING, - }; - errNotificationClient.notify(error, 'Job Status', { - ...response, - ...getCommonMetadata(ctx), - ...getReqMetadata(ctx), - }); - } - ctx.body = response; - logger.debug('Native(Bulk-Upload): Request from transformer:: /getWarningJobs route', ctx.body); - return ctx.body; -}; - -export const getFailedJobStatus = async (ctx) => { - logger.debug( - 'Native(Bulk-Upload): Request to transformer:: /getFailedJobs route', - ctx.request.body, - ); - - const { destType }: ContextBodySimple = ctx.request.body; - const destFileUploadHandler = getJobStatusHandler('v0', destType.toLowerCase()); - - if (!destFileUploadHandler || !destFileUploadHandler.processJobStatus) { - ctx.status = 404; - ctx.body = `${destType} doesn't support bulk upload`; - return null; - } - let response; - try { - response = await destFileUploadHandler.processJobStatus(ctx.request.body, 'fail'); - } catch (error: CatchErr) { - response = { - statusCode: error.response ? error.response.status : 400, - error: error.message || ERROR_MESSAGE_PROCESSOR_STRING, - }; - errNotificationClient.notify(error, 'Job Status', { - ...response, - ...getCommonMetadata(ctx), - ...getReqMetadata(ctx), - }); - } - ctx.body = response; - logger.debug('Native(Bulk-Upload): Request from transformer:: /getFailedJobs route', ctx.body); - return ctx.body; -}; diff --git a/src/controllers/obs.delivery.js b/src/controllers/obs.delivery.js deleted file mode 100644 index 8e99650af6..0000000000 --- a/src/controllers/obs.delivery.js +++ /dev/null @@ -1,130 +0,0 @@ -/** - * -------------------------------------- - * -------------------------------------- - * ---------TO BE DEPRECATED------------- - * -------------------------------------- - * -------------------------------------- - */ - -const match = require('match-json'); -const jsonDiff = require('json-diff'); -const networkHandlerFactory = require('../adapters/networkHandlerFactory'); -const { getPayloadData } = require('../adapters/network'); -const { generateErrorObject } = require('../v0/util'); -const logger = require('../logger'); -const tags = require('../v0/util/tags'); -const stats = require('../util/stats'); - -const DestProxyController = { - /** - * Handler for testing the destination proxy - * @param {*} destination Destination name - * @param {*} ctx - * @returns - */ - async handleProxyTestRequest(destination, ctx) { - const { - deliveryPayload: routerDeliveryPayload, - destinationRequestPayload: routerDestReqPayload, - } = ctx.request.body; - let response; - try { - const destNetworkHandler = networkHandlerFactory.getNetworkHandler(destination); - - const proxyDestReqPayload = destNetworkHandler.prepareProxy(routerDeliveryPayload); - response = { - destinationRequestPayload: proxyDestReqPayload, - }; - - // Special handling required as Go and JavaScript encodes - // URL parameters differently - const { payloadFormat } = getPayloadData(routerDeliveryPayload.body); - if (payloadFormat === 'FORM') { - // This is to make sure we encode `~` in the data coming from the router. - // The data coming from the router is already a query parameter string - const routerDataVal = new URLSearchParams(routerDestReqPayload.data); - routerDestReqPayload.data = routerDataVal; - - const proxyDataVal = new URLSearchParams(); - proxyDestReqPayload.data.forEach((value, key) => { - const encodeAsterisk = (x) => x.replace(/\*/g, '%2A'); - // Router encodes `*` as well - proxyDataVal.append(encodeAsterisk(key), encodeAsterisk(value)); - }); - proxyDestReqPayload.data = proxyDataVal; - } - - // Compare the destination request payloads from router and proxy - if (!match(routerDestReqPayload, proxyDestReqPayload)) { - stats.counter('proxy_test_payload_mismatch', 1, { - destination, - }); - - logger.error(`[TransformerProxyTest] Destination request payload mismatch!`); - logger.error( - `[TransformerProxyTest] Delivery payload (router): ${JSON.stringify( - routerDeliveryPayload, - )}`, - ); - logger.error( - `[TransformerProxyTest] Destination request payload (router): ${JSON.stringify( - routerDestReqPayload, - )}`, - ); - logger.error( - `[TransformerProxyTest] Destination request payload (proxy): ${JSON.stringify( - proxyDestReqPayload, - )} `, - ); - - // Compute output difference - const outputDiff = jsonDiff.diffString(routerDestReqPayload, proxyDestReqPayload); - logger.error( - `[TransformerProxyTest] Destination request payload difference: ${outputDiff}`, - ); - response = { - outputDiff, - ...response, - }; - } else { - stats.counter('proxy_test_payload_match', 1, { - destination, - }); - } - } catch (err) { - stats.counter('proxy_test_error', 1, { - destination, - }); - - response = generateErrorObject( - err, - { - [tags.TAG_NAMES.DEST_TYPE]: destination.toUpperCase(), - [tags.TAG_NAMES.MODULE]: tags.MODULES.DESTINATION, - [tags.TAG_NAMES.FEATURE]: tags.FEATURES.DATA_DELIVERY, - }, - false, - ); - response.message = `[TransformerProxyTest] Error occurred while testing proxy for destination ("${destination}"): "${err.message}"`; - logger.error(response.message); - logger.error(err); - logger.error( - `[TransformerProxyTest] Delivery payload (router): ${JSON.stringify( - routerDeliveryPayload, - )}`, - ); - logger.error( - `[TransformerProxyTest] Destination request payload (router): ${JSON.stringify( - routerDestReqPayload, - )}`, - ); - } - - // Always return success as router doesn't care - ctx.status = 200; - ctx.body = { output: response }; - return ctx.body; - }, -}; - -module.exports = { DestProxyController }; diff --git a/src/features.ts b/src/features.ts index 4ff419a7fe..fb91ae2883 100644 --- a/src/features.ts +++ b/src/features.ts @@ -93,6 +93,7 @@ const defaultFeaturesConfig: FeaturesConfig = { AMAZON_AUDIENCE: true, INTERCOM_V2: true, LINKEDIN_AUDIENCE: true, + TOPSORT: true, }, regulations: [ 'BRAZE', diff --git a/src/legacy/delivery.js b/src/legacy/delivery.js deleted file mode 100644 index 8f7b092815..0000000000 --- a/src/legacy/delivery.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * -------------------------------------- - * -------------------------------------- - * ---------TO BE DEPRICIATED------------ - * -------------------------------------- - * -------------------------------------- - */ - -const path = require('path'); -const KoaRouter = require('@koa/router'); -const { DestProxyController } = require('../controllers/obs.delivery'); -const { getIntegrations } = require('../routes/utils'); -const { SUPPORTED_VERSIONS, API_VERSION } = require('../routes/utils/constants'); - -const router = new KoaRouter(); - -SUPPORTED_VERSIONS.forEach((version) => { - const destinations = getIntegrations(path.resolve(__dirname, `../${version}/destinations`)); - destinations.forEach((destination) => { - router.post(`/${version}/destinations/${destination}/proxyTest`, async (ctx) => { - ctx.set('apiVersion', API_VERSION); - await DestProxyController.handleProxyTestRequest(destination, ctx); - }); - }); -}); - -module.exports = router.routes(); diff --git a/src/legacy/router.js b/src/legacy/router.js deleted file mode 100644 index 60f786e225..0000000000 --- a/src/legacy/router.js +++ /dev/null @@ -1,1272 +0,0 @@ -// ============================================================================= -// DEPRECATION NOTICE: THIS FILE IS GETTING DEPRECATED AND WILL BE REMOVED IN FUTURE RELEASE -// ============================================================================= -/* eslint-disable import/no-dynamic-require */ -/* eslint-disable global-require */ -const Router = require('@koa/router'); -const lodash = require('lodash'); -const fs = require('fs'); -const path = require('path'); -const { PlatformError, getErrorRespEvents } = require('@rudderstack/integrations-lib'); -const logger = require('../logger'); -const stats = require('../util/stats'); -const { SUPPORTED_VERSIONS, API_VERSION } = require('../routes/utils/constants'); -const { client: errNotificationClient } = require('../util/errorNotifier'); -const tags = require('../v0/util/tags'); - -const { - isNonFuncObject, - getMetadata, - generateErrorObject, - checkAndCorrectUserId, -} = require('../v0/util'); -const { processDynamicConfig } = require('../util/dynamicConfig'); -const { DestHandlerMap } = require('../constants/destinationCanonicalNames'); -const { userTransformHandler } = require('../routerUtils'); -const networkHandlerFactory = require('../adapters/networkHandlerFactory'); -const destProxyRoutes = require('./delivery'); -const eventValidator = require('../util/eventValidation'); -const { getIntegrations } = require('../routes/utils'); -const { setupUserTransformHandler, validateCode } = require('../util/customTransformer'); -const { - RespStatusError, - RetryRequestError, - sendViolationMetrics, - constructValidationErrors, -} = require('../util/utils'); -const { extractLibraries } = require('../util/customTransformer'); -const { getCompatibleStatusCode } = require('../adapters/utils/networkUtils'); - -const transformerMode = process.env.TRANSFORMER_MODE; - -const startDestTransformer = transformerMode === 'destination' || !transformerMode; -const startSourceTransformer = transformerMode === 'source' || !transformerMode; -const transformerProxy = process.env.TRANSFORMER_PROXY || true; -const proxyTestModeEnabled = - process.env.TRANSFORMER_PROXY_TEST_ENABLED?.toLowerCase() === 'true' || false; -const transformerTestModeEnabled = process.env.TRANSFORMER_TEST_MODE - ? process.env.TRANSFORMER_TEST_MODE.toLowerCase() === 'true' - : false; - -const router = new Router(); - -const PAYLOAD_PROC_ERR_MSG = 'Error occurred while processing payload'; - -/** - * @deprecated this function is deprecated and will be removed in future release - */ -const getDestHandler = (version, dest) => { - if (Object.prototype.hasOwnProperty.call(DestHandlerMap, dest)) { - return require(`../${version}/destinations/${DestHandlerMap[dest]}/transform`); - } - return require(`../${version}/destinations/${dest}/transform`); -}; - -const getDestFileUploadHandler = (version, dest) => - require(`../${version}/destinations/${dest}/fileUpload`); - -const getPollStatusHandler = (version, dest) => require(`../${version}/destinations/${dest}/poll`); - -const getJobStatusHandler = (version, dest) => - require(`../${version}/destinations/${dest}/fetchJobStatus`); - -const getDeletionUserHandler = (version, dest) => - require(`../${version}/destinations/${dest}/deleteUsers`); - -const getSourceHandler = (version, source) => require(`../${version}/sources/${source}/transform`); - -let areFunctionsEnabled = -1; -const functionsEnabled = () => { - if (areFunctionsEnabled === -1) { - areFunctionsEnabled = process.env.ENABLE_FUNCTIONS === 'false' ? 0 : 1; - } - return areFunctionsEnabled === 1; -}; - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function getCommonMetadata(ctx) { - // TODO: Parse information such as - // cluster, namespace, etc information - // from the request - return { - namespace: 'Unknown', - cluster: 'Unknown', - }; -} - -/** - * Enriches the transformed event with more information - * - userId stringification - * - * @param {Object} transformedEvent - single transformed event - * @returns transformedEvent after enrichment - */ -const enrichTransformedEvent = (transformedEvent) => ({ - ...transformedEvent, - userId: checkAndCorrectUserId(transformedEvent.statusCode, transformedEvent?.userId), -}); - -/** - * @deprecated this function is deprecated and will be removed in future release - */ -function handleV0Destination(destHandler, inputArr) { - return destHandler(...inputArr); -} -/** - * @deprecated this function is deprecated and will be removed in future release - */ -async function handleDest(ctx, version, destination) { - const getReqMetadata = (event) => { - try { - return { - destType: destination, - destinationId: event?.destination?.ID, - destName: event?.destination?.Name, - metadata: event?.metadata, - }; - } catch (error) { - // Do nothing - } - return {}; - }; - - const events = ctx.request.body; - if (!Array.isArray(events) || events.length === 0) { - throw new PlatformError('Event is missing or in inappropriate format'); - } - const reqParams = ctx.request.query; - logger.debug(`[DT] Input events: ${JSON.stringify(events)}`); - - const metaTags = - events && events.length > 0 && events[0].metadata ? getMetadata(events[0].metadata) : {}; - stats.histogram('dest_transform_input_events', events.length, { - destination, - version, - ...metaTags, - }); - const executeStartTime = new Date(); - let destHandler = null; - const respList = await Promise.all( - events.map(async (event) => { - try { - let parsedEvent = event; - parsedEvent.request = { query: reqParams }; - parsedEvent = processDynamicConfig(parsedEvent); - let respEvents; - if (destHandler === null) { - destHandler = getDestHandler(version, destination); - } - respEvents = await handleV0Destination(destHandler.process, [parsedEvent]); - - if (respEvents) { - if (!Array.isArray(respEvents)) { - respEvents = [respEvents]; - } - return respEvents.map((ev) => ({ - output: enrichTransformedEvent(ev), - metadata: destHandler?.processMetadata - ? destHandler.processMetadata({ - metadata: event.metadata, - inputEvent: parsedEvent, - outputEvent: ev, - }) - : event.metadata, - statusCode: 200, - })); - } - return undefined; - } catch (error) { - logger.error(error); - - const implementation = tags.IMPLEMENTATIONS.NATIVE; - const errCtx = 'Processor Transformation'; - - const errObj = generateErrorObject(error, { - [tags.TAG_NAMES.DEST_TYPE]: destination.toUpperCase(), - [tags.TAG_NAMES.MODULE]: tags.MODULES.DESTINATION, - [tags.TAG_NAMES.IMPLEMENTATION]: implementation, - [tags.TAG_NAMES.FEATURE]: tags.FEATURES.PROCESSOR, - [tags.TAG_NAMES.DESTINATION_ID]: event.metadata?.destinationId, - [tags.TAG_NAMES.WORKSPACE_ID]: event.metadata?.workspaceId, - }); - - const resp = { - metadata: event.metadata, - destination: event.destination, - statusCode: errObj.status, - error: errObj.message, - statTags: errObj.statTags, - }; - - errNotificationClient.notify(error, errCtx, { - ...resp, - ...getCommonMetadata(ctx), - ...getReqMetadata(event), - }); - return resp; - } - }), - ); - stats.timing('cdk_events_latency', executeStartTime, { - destination, - ...metaTags, - }); - logger.debug(`[DT] Output events: ${JSON.stringify(respList)}`); - stats.histogram('dest_transform_output_events', respList.length, { - destination, - version, - ...metaTags, - }); - ctx.body = respList.flat(); - return ctx.body; -} - -async function handleValidation(ctx) { - const requestStartTime = new Date(); - const events = ctx.request.body; - const requestSize = Number(ctx.request.get('content-length')); - const reqParams = ctx.request.query; - const respList = []; - const metaTags = events[0].metadata ? getMetadata(events[0].metadata) : {}; - let ctxStatusCode = 200; - // eslint-disable-next-line no-restricted-syntax - for (const event of events) { - const eventStartTime = new Date(); - try { - const parsedEvent = event; - parsedEvent.request = { query: reqParams }; - // eslint-disable-next-line no-await-in-loop - const hv = await eventValidator.handleValidation(parsedEvent); - sendViolationMetrics(hv.validationErrors, hv.dropEvent, metaTags); - if (hv.dropEvent) { - respList.push({ - output: event.message, - metadata: event.metadata, - statusCode: 400, - validationErrors: hv.validationErrors, - error: JSON.stringify(constructValidationErrors(hv.validationErrors)), - }); - stats.counter('hv_violation_type', 1, { - violationType: hv.violationType, - ...metaTags, - }); - } else { - respList.push({ - output: event.message, - metadata: event.metadata, - statusCode: 200, - validationErrors: hv.validationErrors, - error: JSON.stringify(constructValidationErrors(hv.validationErrors)), - }); - stats.counter('hv_propagated_events', 1, { - ...metaTags, - }); - } - } catch (error) { - const errMessage = `Error occurred while validating : ${error}`; - logger.error(errMessage); - let status = 200; - if (error instanceof RetryRequestError) { - ctxStatusCode = error.statusCode; - } - if (error instanceof RespStatusError) { - status = error.statusCode; - } - respList.push({ - output: event.message, - metadata: event.metadata, - statusCode: status, - validationErrors: [], - error: errMessage, - }); - stats.counter('hv_errors', 1, { - ...metaTags, - }); - } finally { - stats.timing('hv_event_latency', eventStartTime, { - ...metaTags, - }); - } - } - ctx.body = respList; - ctx.status = ctxStatusCode; - ctx.set('apiVersion', API_VERSION); - - stats.counter('hv_events_count', events.length, { - ...metaTags, - }); - stats.histogram('hv_request_size', requestSize, { - ...metaTags, - }); - stats.timing('hv_request_latency', requestStartTime, { - ...metaTags, - }); -} - -async function isValidRouterDest(event, destType) { - try { - const routerDestHandler = getDestHandler('v0', destType); - return routerDestHandler?.processRouterDest !== undefined; - } catch (error) { - return false; - } -} -/** - * @deprecated this function is deprecated and will be removed in future release - */ -async function routerHandleDest(ctx) { - const getReqMetadata = () => { - try { - return { - destType: ctx.request?.body?.destType, - }; - } catch (error) { - // Do nothing - } - return {}; - }; - - const respEvents = []; - let destType; - let defTags; - try { - const { input } = ctx.request.body; - destType = ctx.request.body.destType; - defTags = { - [tags.TAG_NAMES.DEST_TYPE]: destType.toUpperCase(), - [tags.TAG_NAMES.MODULE]: tags.MODULES.DESTINATION, - [tags.TAG_NAMES.FEATURE]: tags.FEATURES.ROUTER, - [tags.TAG_NAMES.IMPLEMENTATION]: tags.IMPLEMENTATIONS.NATIVE, - }; - - const routerDestHandler = getDestHandler('v0', destType); - const isValidRTDest = await isValidRouterDest(input[0], destType); - if (!isValidRTDest) { - ctx.status = 404; - ctx.body = `${destType} doesn't support router transform`; - return null; - } - const allDestEvents = lodash.groupBy(input, (event) => event.destination.ID); - await Promise.all( - Object.values(allDestEvents).map(async (destInputArray) => { - const newDestInputArray = processDynamicConfig(destInputArray, 'router'); - const listOutput = await handleV0Destination(routerDestHandler.processRouterDest, [ - newDestInputArray, - { ...getCommonMetadata(ctx), ...getReqMetadata() }, - ]); - const hasProcMetadataForRouter = routerDestHandler.processMetadataForRouter; - // enriching transformed event - listOutput.forEach((listOut) => { - const { batchedRequest } = listOut; - if (Array.isArray(batchedRequest)) { - // eslint-disable-next-line no-param-reassign - listOut.batchedRequest = batchedRequest.map((batReq) => enrichTransformedEvent(batReq)); - } else if (batchedRequest && typeof batchedRequest === 'object') { - // eslint-disable-next-line no-param-reassign - listOut.batchedRequest = enrichTransformedEvent(batchedRequest); - } - - if (hasProcMetadataForRouter) { - // eslint-disable-next-line no-param-reassign - listOut.metadata = routerDestHandler.processMetadataForRouter(listOut); - } - }); - respEvents.push(...listOutput); - }), - ); - - // Add default stat tags - respEvents - .filter( - (resp) => - 'error' in resp && lodash.isObject(resp.statTags) && !lodash.isEmpty(resp.statTags), - ) - .forEach((resp) => { - // eslint-disable-next-line no-param-reassign - resp.statTags = { - ...resp.statTags, - ...defTags, - [tags.TAG_NAMES.DESTINATION_ID]: resp.metadata[0]?.destinationId, - [tags.TAG_NAMES.WORKSPACE_ID]: resp.metadata[0]?.workspaceId, - }; - }); - } catch (error) { - logger.error(error); - - const errObj = generateErrorObject(error, defTags); - - const resp = { - statusCode: errObj.status, - error: errObj.message, - statTags: errObj.statTags, - }; - - // Add support to perform refreshToken action for OAuth destinations - if (error?.authErrorCategory) { - resp.authErrorCategory = error.authErrorCategory; - } - - errNotificationClient.notify(error, 'Router Transformation', { - ...resp, - ...getCommonMetadata(ctx), - ...getReqMetadata(), - }); - - respEvents.push(resp); - } - ctx.body = { output: respEvents }; - return ctx.body; -} - -if (startDestTransformer) { - SUPPORTED_VERSIONS.forEach((version) => { - const destinations = getIntegrations(path.resolve(__dirname, `../${version}/destinations`)); - destinations.forEach((destination) => { - // eg. v0/destinations/ga - router.post(`/${version}/destinations/${destination}`, async (ctx) => { - const startTime = new Date(); - await handleDest(ctx, version, destination); - ctx.set('apiVersion', API_VERSION); - // Assuming that events are from one single source - - const metaTags = - ctx.request.body && ctx.request.body.length > 0 && ctx.request.body[0].metadata - ? getMetadata(ctx.request.body[0].metadata) - : {}; - - stats.timing('dest_transform_request_latency', startTime, { - destination, - version, - ...metaTags, - }); - stats.increment('dest_transform_requests', { - destination, - version, - ...metaTags, - }); - }); - // eg. v0/ga. will be deprecated in favor of v0/destinations/ga format - router.post(`/${version}/${destination}`, async (ctx) => { - const startTime = new Date(); - await handleDest(ctx, version, destination); - ctx.set('apiVersion', API_VERSION); - // Assuming that events are from one single source - - const metaTags = - ctx.request.body && ctx.request.body.length > 0 && ctx.request.body[0].metadata - ? getMetadata(ctx.request.body[0].metadata) - : {}; - - stats.timing('dest_transform_request_latency', startTime, { - destination, - ...metaTags, - }); - stats.increment('dest_transform_requests', { - destination, - version, - ...metaTags, - }); - }); - router.post('/routerTransform', async (ctx) => { - ctx.set('apiVersion', API_VERSION); - await routerHandleDest(ctx); - }); - }); - }); - - if (functionsEnabled()) { - router.post('/extractLibs', async (ctx) => { - try { - const { - code, - versionId, - validateImports = false, - additionalLibraries = [], - language = 'javascript', - testMode = false, - } = ctx.request.body; - - if (!code) { - throw new Error('Invalid request. Code is missing'); - } - - const obj = await extractLibraries( - code, - versionId, - validateImports, - additionalLibraries, - language, - testMode || versionId === 'testVersionId', - ); - ctx.body = obj; - } catch (err) { - ctx.status = 400; - ctx.body = { error: err.error || err.message }; - } - }); - - // eslint-disable-next-line sonarjs/cognitive-complexity - router.post('/customTransform', async (ctx) => { - const startTime = new Date(); - const events = ctx.request.body; - const { processSessions } = ctx.query; - logger.debug(`[CT] Input events: ${JSON.stringify(events)}`); - stats.histogram('user_transform_input_events', events.length, { - processSessions, - }); - let groupedEvents; - if (processSessions) { - groupedEvents = lodash.groupBy(events, (event) => { - // to have the backward-compatibility and being extra careful. We need to remove this (message.anonymousId) in next release. - const rudderId = event.metadata.rudderId || event.message.anonymousId; - return `${event.destination.ID}_${event.metadata.sourceId}_${rudderId}`; - }); - } else { - groupedEvents = lodash.groupBy( - events, - (event) => `${event.metadata.destinationId}_${event.metadata.sourceId}`, - ); - } - stats.counter('user_transform_function_group_size', Object.entries(groupedEvents).length, {}); - - let ctxStatusCode = 200; - const transformedEvents = []; - let librariesVersionIDs = []; - if (events[0].libraries) { - librariesVersionIDs = events[0].libraries.map((library) => library.VersionID); - } - await Promise.all( - Object.entries(groupedEvents).map(async ([dest, destEvents]) => { - logger.debug(`dest: ${dest}`); - const transformationVersionId = - destEvents[0] && - destEvents[0].destination && - destEvents[0].destination.Transformations && - destEvents[0].destination.Transformations[0] && - destEvents[0].destination.Transformations[0].VersionID; - const messageIds = destEvents.map((ev) => ev.metadata && ev.metadata.messageId); - const commonMetadata = { - sourceId: destEvents[0].metadata && destEvents[0].metadata.sourceId, - destinationId: destEvents[0].metadata && destEvents[0].metadata.destinationId, - destinationType: destEvents[0].metadata && destEvents[0].metadata.destinationType, - messageIds, - }; - - const metaTags = - destEvents.length > 0 && destEvents[0].metadata - ? getMetadata(destEvents[0].metadata) - : {}; - if (transformationVersionId) { - let destTransformedEvents; - try { - destTransformedEvents = await userTransformHandler()( - destEvents, - transformationVersionId, - librariesVersionIDs, - ); - transformedEvents.push( - ...destTransformedEvents.map((ev) => { - if (ev.error) { - return { - statusCode: 400, - error: ev.error, - metadata: lodash.isEmpty(ev.metadata) ? commonMetadata : ev.metadata, - }; - } - if (!isNonFuncObject(ev.transformedEvent)) { - return { - statusCode: 400, - error: `returned event in events from user transformation is not an object. transformationVersionId:${transformationVersionId} and returned event: ${JSON.stringify( - ev.transformedEvent, - )}`, - metadata: lodash.isEmpty(ev.metadata) ? commonMetadata : ev.metadata, - }; - } - return { - output: ev.transformedEvent, - metadata: lodash.isEmpty(ev.metadata) ? commonMetadata : ev.metadata, - statusCode: 200, - }; - }), - ); - } catch (error) { - logger.error(error); - let status = 400; - const errorString = error.toString(); - if (error instanceof RetryRequestError) { - ctxStatusCode = error.statusCode; - } - if (error instanceof RespStatusError) { - status = error.statusCode; - } - destTransformedEvents = destEvents.map((e) => ({ - statusCode: status, - metadata: e.metadata, - error: errorString, - })); - transformedEvents.push(...destTransformedEvents); - stats.counter('user_transform_errors', destEvents.length, { - transformationVersionId, - processSessions, - ...metaTags, - }); - } - } else { - const errorMessage = 'Transformation VersionID not found'; - logger.error(`[CT] ${errorMessage}`); - transformedEvents.push({ - statusCode: 400, - error: errorMessage, - metadata: commonMetadata, - }); - stats.counter('user_transform_errors', destEvents.length, { - transformationVersionId, - processSessions, - ...metaTags, - }); - } - }), - ); - logger.debug(`[CT] Output events: ${JSON.stringify(transformedEvents)}`); - ctx.body = transformedEvents; - ctx.status = ctxStatusCode; - ctx.set('apiVersion', API_VERSION); - - stats.timingSummary('user_transform_request_latency_summary', startTime, {}); - stats.increment('user_transform_requests', {}); - stats.histogram('user_transform_output_events', transformedEvents.length, {}); - }); - } -} - -if (transformerTestModeEnabled) { - router.post('/transformation/test', async (ctx) => { - try { - const { events, trRevCode, libraryVersionIDs = [] } = ctx.request.body; - if (!trRevCode || !trRevCode.code || !trRevCode.codeVersion) { - throw new Error('Invalid Request. Missing parameters in transformation code block'); - } - if (!events || events.length === 0) { - throw new Error('Invalid request. Missing events'); - } - - logger.debug(`[CT] Test Input Events: ${JSON.stringify(events)}`); - trRevCode.versionId = 'testVersionId'; - const res = await userTransformHandler()( - events, - trRevCode.versionId, - libraryVersionIDs, - trRevCode, - true, - ); - logger.debug(`[CT] Test Output Events: ${JSON.stringify(res.transformedEvents)}`); - ctx.body = res; - } catch (error) { - ctx.status = error.statusCode || 400; - ctx.body = { error: error.message }; - } - }); - - router.post('/transformationLibrary/test', async (ctx) => { - try { - const { code, language = 'javascript' } = ctx.request.body; - - if (!code) { - throw new Error('Invalid request. Missing code'); - } - - const res = await validateCode(code, language); - ctx.body = res; - } catch (error) { - ctx.body = { error: error.message }; - ctx.status = 400; - } - }); - /* *params - * code: transfromation code - * language - * name - */ - router.post('/transformation/sethandle', async (ctx) => { - try { - const { trRevCode, libraryVersionIDs = [] } = ctx.request.body; - const { code, versionId, language, testName } = trRevCode || {}; - if (!code || !language || !testName || (language === 'pythonfaas' && !versionId)) { - throw new Error('Invalid Request. Missing parameters in transformation code block'); - } - - logger.debug(`[CT] Setting up a transformation ${testName}`); - if (!trRevCode.versionId) { - trRevCode.versionId = 'testVersionId'; - } - if (!trRevCode.workspaceId) { - trRevCode.workspaceId = 'workspaceId'; - } - const res = await setupUserTransformHandler(libraryVersionIDs, trRevCode); - logger.debug(`[CT] Finished setting up transformation: ${testName}`); - ctx.body = res; - } catch (error) { - ctx.status = 400; - ctx.body = { error: error.message }; - } - }); -} - -async function handleSource(ctx, version, source) { - const getReqMetadata = () => { - try { - return { srcType: source }; - } catch (error) { - // Do nothing - } - return {}; - }; - - const sourceHandler = getSourceHandler(version, source); - const events = ctx.request.body; - logger.debug(`[ST] Input source events: ${JSON.stringify(events)}`); - stats.counter('source_transform_input_events', events.length, { - source, - version, - }); - const respList = []; - await Promise.all( - events.map(async (event) => { - try { - const respEvents = await sourceHandler.process(event); - - // We send response back to the source - // through outputToSource. This is not sent to gateway - if (Object.prototype.hasOwnProperty.call(respEvents, 'outputToSource')) { - respList.push(respEvents); - return; - } - - if (Array.isArray(respEvents)) { - respList.push({ output: { batch: respEvents } }); - } else { - respList.push({ output: { batch: [respEvents] } }); - } - } catch (error) { - logger.error(error); - - // TODO: Update the data contact for source transformation - // and then send the following additional information - // const errObj = generateErrorObject(error, { - // [tags.TAG_NAMES.SRC_TYPE]: source.toUpperCase(), - // [tags.TAG_NAMES.MODULE]: tags.MODULES.SOURCE, - // [tags.TAG_NAMES.IMPLEMENTATION]: tags.IMPLEMENTATIONS.NATIVE, - // [tags.TAG_NAMES.FEATURE]: tags.FEATURES.PROCESSOR - // [tags.TAG_NAMES.SOURCE_ID]: TBD - // }); - - // const resp = { - // statusCode: errObj.status, - // error: errObj.message, - // statTags: errObj.statTags - // }; - - const resp = { - statusCode: 400, - error: error.message || PAYLOAD_PROC_ERR_MSG, - }; - - respList.push(resp); - - stats.counter('source_transform_errors', events.length, { - source, - version, - }); - errNotificationClient.notify(error, 'Source Transformation', { - ...resp, - ...getCommonMetadata(ctx), - ...getReqMetadata(), - }); - } - }), - ); - logger.debug(`[ST] Output source events: ${JSON.stringify(respList)}`); - stats.increment('source_transform_output_events', respList.length, { - source, - version, - }); - ctx.body = respList; - ctx.set('apiVersion', API_VERSION); -} - -if (startSourceTransformer) { - SUPPORTED_VERSIONS.forEach((version) => { - const sources = getIntegrations(path.resolve(__dirname, `../${version}/sources`)); - sources.forEach((source) => { - // eg. v0/sources/customerio - router.post(`/${version}/sources/${source}`, async (ctx) => { - const startTime = new Date(); - await handleSource(ctx, version, source); - - stats.timing('source_transform_request_latency', startTime, { - source, - version, - }); - stats.increment('source_transform_requests', { source, version }); - }); - }); - }); -} -/** - * @deprecated this function is deprecated and will be removed in future release - */ -async function handleProxyRequest(destination, ctx) { - const getReqMetadata = () => { - try { - return { destType: destination }; - } catch (error) { - // Do nothing - } - return {}; - }; - - const { metadata, ...destinationRequest } = ctx.request.body; - const destNetworkHandler = networkHandlerFactory.getNetworkHandler(destination); - let response; - try { - stats.counter('tf_proxy_dest_req_count', 1, { - destination, - }); - const startTime = new Date(); - const rawProxyResponse = await destNetworkHandler.proxy(destinationRequest); - - stats.timing('transformer_proxy_time', startTime, { - destination, - }); - stats.counter('tf_proxy_dest_resp_count', 1, { - destination, - success: rawProxyResponse.success, - }); - - const processedProxyResponse = destNetworkHandler.processAxiosResponse(rawProxyResponse); - stats.counter('tf_proxy_proc_ax_response_count', 1, { - destination, - }); - response = destNetworkHandler.responseHandler( - { ...processedProxyResponse, rudderJobMetadata: metadata }, - destination, - ); - stats.counter('tf_proxy_resp_handler_count', 1, { - destination, - }); - } catch (err) { - logger.error('Error occurred while completing proxy request:'); - logger.error(err); - - const errObj = generateErrorObject( - err, - { - [tags.TAG_NAMES.DEST_TYPE]: destination.toUpperCase(), - [tags.TAG_NAMES.MODULE]: tags.MODULES.DESTINATION, - [tags.TAG_NAMES.IMPLEMENTATION]: tags.IMPLEMENTATIONS.NATIVE, - [tags.TAG_NAMES.FEATURE]: tags.FEATURES.DATA_DELIVERY, - [tags.TAG_NAMES.DESTINATION_ID]: metadata?.destinationId, - [tags.TAG_NAMES.WORKSPACE_ID]: metadata?.workspaceId, - }, - false, - ); - - response = { - status: errObj.status, - ...(errObj.authErrorCategory && { - authErrorCategory: errObj.authErrorCategory, - }), - destinationResponse: errObj.destinationResponse, - message: errObj.message, - statTags: errObj.statTags, - }; - - stats.counter('tf_proxy_err_count', 1, { - destination, - }); - - errNotificationClient.notify(err, 'Data Delivery', { - ...response, - ...getCommonMetadata(ctx), - ...getReqMetadata(), - }); - } - ctx.body = { output: response }; - // Sending `204` status(obtained from destination) is not working as expected - // Since this is success scenario, we'll be forcefully sending `200` status-code to server - ctx.status = getCompatibleStatusCode(response.status); - return ctx.body; -} - -if (transformerProxy) { - SUPPORTED_VERSIONS.forEach((version) => { - const destinations = getIntegrations(path.resolve(__dirname, `../${version}/destinations`)); - destinations.forEach((destination) => { - router.post(`/${version}/destinations/${destination}/proxy`, async (ctx) => { - const startTime = new Date(); - ctx.set('apiVersion', API_VERSION); - await handleProxyRequest(destination, ctx); - - stats.timing('transformer_total_proxy_latency', startTime, { - destination, - version, - }); - }); - }); - }); -} - -if (proxyTestModeEnabled) { - router.use(destProxyRoutes); -} - -router.get('/version', (ctx) => { - ctx.body = process.env.npm_package_version || 'Version Info not found'; -}); - -router.get('/transformerBuildVersion', (ctx) => { - ctx.body = process.env.transformer_build_version || 'Version Info not found'; -}); - -router.get('/health', (ctx) => { - const { git_commit_sha: gitCommitSha, transformer_build_version: imageVersion } = process.env; - ctx.body = { - service: 'UP', - ...(imageVersion && { version: imageVersion }), - ...(gitCommitSha && { gitCommitSha }), - }; -}); - -router.get('/features', (ctx) => { - const obj = JSON.parse(fs.readFileSync(path.resolve(__dirname, 'features.json'), 'utf8')); - ctx.body = JSON.stringify(obj); -}); -/** - * @deprecated this function is deprecated and will be removed in future release - */ -const batchHandler = (ctx) => { - const getReqMetadata = (destEvents) => { - try { - const reqBody = ctx.request.body; - const firstEvent = destEvents[0]; - return { - destType: reqBody?.destType, - destinationId: firstEvent?.destination?.ID, - destName: firstEvent?.destination?.Name, - metadata: firstEvent?.metadata, - }; - } catch (error) { - // Do nothing - } - return {}; - }; - - const { destType, input } = ctx.request.body; - const destHandler = getDestHandler('v0', destType); - if (!destHandler || !destHandler.batch) { - ctx.status = 404; - ctx.body = `${destType} doesn't support batching`; - return null; - } - const allDestEvents = lodash.groupBy(input, (event) => event.destination.ID); - - const response = { batchedRequests: [], errors: [] }; - Object.entries(allDestEvents).forEach(([, destEvents]) => { - try { - // eslint-disable-next-line no-param-reassign - destEvents = processDynamicConfig(destEvents, 'batch'); - const destBatchedRequests = destHandler.batch(destEvents); - response.batchedRequests.push(...destBatchedRequests); - } catch (error) { - const errorObj = generateErrorObject(error, { - [tags.TAG_NAMES.DEST_TYPE]: destType.toUpperCase(), - [tags.TAG_NAMES.MODULE]: tags.MODULES.DESTINATION, - [tags.TAG_NAMES.IMPLEMENTATION]: tags.IMPLEMENTATIONS.NATIVE, - [tags.TAG_NAMES.FEATURE]: tags.FEATURES.BATCH, - [tags.TAG_NAMES.DESTINATION_ID]: destEvents[0].metadata?.destinationId, - [tags.TAG_NAMES.WORKSPACE_ID]: destEvents[0].metadata?.workspaceId, - }); - const errResp = getErrorRespEvents( - destEvents.map((d) => d.metadata), - 500, // not using errorObj.status - errorObj.message, - errorObj.statTags, - ); - response.errors.push({ - ...errResp, - destination: destEvents[0].destination, - }); - errNotificationClient.notify(error, 'Batch Transformation', { - ...errResp, - ...getCommonMetadata(ctx), - ...getReqMetadata(destEvents), - }); - } - }); - if (response.errors.length > 0) { - ctx.status = 500; - ctx.body = response.errors; - return null; - } - ctx.body = response.batchedRequests; - return ctx.body; -}; -router.post('/batch', (ctx) => { - ctx.set('apiVersion', API_VERSION); - batchHandler(ctx); -}); - -/** - * @deprecated this function is deprecated and will be removed in future release - */ -const fileUpload = async (ctx) => { - const getReqMetadata = () => { - try { - const reqBody = ctx.request.body; - return { destType: reqBody?.destType }; - } catch (error) { - // Do nothing - } - return {}; - }; - - const { destType } = ctx.request.body; - const destFileUploadHandler = getDestFileUploadHandler('v0', destType.toLowerCase()); - - if (!destFileUploadHandler || !destFileUploadHandler.processFileData) { - ctx.status = 404; - ctx.body = `${destType} doesn't support bulk upload`; - return null; - } - let response; - try { - response = await destFileUploadHandler.processFileData(ctx.request.body); - } catch (error) { - response = { - statusCode: error.response ? error.response.status : 400, - error: error.message || PAYLOAD_PROC_ERR_MSG, - metadata: error.response ? error.response.metadata : null, - }; - errNotificationClient.notify(error, 'File Upload', { - ...response, - ...getCommonMetadata(ctx), - ...getReqMetadata(), - }); - } - ctx.body = response; - return ctx.body; -}; - -const jobAndPollStatusReqMetadata = (ctx) => { - try { - const reqBody = ctx.request.body; - return { destType: reqBody?.destType, importId: reqBody?.importId }; - } catch (error) { - // Do nothing - } - return {}; -}; - -/** - * @deprecated this function is deprecated and will be removed in future release - */ -const pollStatus = async (ctx) => { - const { destType } = ctx.request.body; - const destFileUploadHandler = getPollStatusHandler('v0', destType.toLowerCase()); - let response; - if (!destFileUploadHandler || !destFileUploadHandler.processPolling) { - ctx.status = 404; - ctx.body = `${destType} doesn't support bulk upload`; - return null; - } - try { - response = await destFileUploadHandler.processPolling(ctx.request.body); - } catch (error) { - response = { - statusCode: error.response ? error.response.status : 400, - error: error.message || PAYLOAD_PROC_ERR_MSG, - }; - errNotificationClient.notify(error, 'Poll Status', { - ...response, - ...getCommonMetadata(ctx), - ...jobAndPollStatusReqMetadata(ctx), - }); - } - ctx.body = response; - return ctx.body; -}; - -/** - * @deprecated this function is deprecated and will be removed in future release - */ -const getJobStatus = async (ctx, type) => { - const { destType } = ctx.request.body; - const destFileUploadHandler = getJobStatusHandler('v0', destType.toLowerCase()); - - if (!destFileUploadHandler || !destFileUploadHandler.processJobStatus) { - ctx.status = 404; - ctx.body = `${destType} doesn't support bulk upload`; - return null; - } - let response; - try { - response = await destFileUploadHandler.processJobStatus(ctx.request.body, type); - } catch (error) { - response = { - statusCode: error.response ? error.response.status : 400, - error: error.message || PAYLOAD_PROC_ERR_MSG, - }; - errNotificationClient.notify(error, 'Job Status', { - ...response, - ...getCommonMetadata(ctx), - ...jobAndPollStatusReqMetadata(ctx), - }); - } - ctx.body = response; - return ctx.body; -}; - -/** - * @deprecated this function is deprecated and will be removed in future release - */ -const handleDeletionOfUsers = async (ctx) => { - const getReqMetadata = () => { - try { - const reqBody = ctx.request.body; - return { - destType: reqBody[0]?.destType, - jobs: reqBody.map((req) => req.jobId), - }; - } catch (error) { - // Do nothing - } - return {}; - }; - - const getRudderDestInfo = () => { - try { - const rudderDestInfoHeader = ctx.get('x-rudder-dest-info'); - const destInfoHeader = JSON.parse(rudderDestInfoHeader); - if (!Array.isArray(destInfoHeader)) { - return destInfoHeader; - } - } catch (error) { - logger.error(`Error while getting rudderDestInfo header value: ${error}`); - } - return {}; - }; - - const { body } = ctx.request; - const respList = []; - const rudderDestInfo = getRudderDestInfo(); - let response; - await Promise.all( - body.map(async (reqBody) => { - const { destType } = reqBody; - const destUserDeletionHandler = getDeletionUserHandler('v0', destType.toLowerCase()); - if (!destUserDeletionHandler || !destUserDeletionHandler.processDeleteUsers) { - ctx.status = 404; - ctx.body = "Doesn't support deletion of users"; - return null; - } - - try { - response = await destUserDeletionHandler.processDeleteUsers({ - ...reqBody, - rudderDestInfo, - }); - if (response) { - respList.push(response); - } - } catch (error) { - const errObj = generateErrorObject( - error, - { - [tags.TAG_NAMES.DEST_TYPE]: destType.toUpperCase(), - [tags.TAG_NAMES.MODULE]: tags.MODULES.DESTINATION, - [tags.TAG_NAMES.IMPLEMENTATION]: tags.IMPLEMENTATIONS.NATIVE, - [tags.TAG_NAMES.FEATURE]: tags.FEATURES.USER_DELETION, - }, - false, - ); - - // adding the status to the request - ctx.status = errObj.status; - const resp = { - statusCode: errObj.status, - error: errObj.message, - ...(errObj.authErrorCategory && { - authErrorCategory: errObj.authErrorCategory, - }), - }; - - respList.push(resp); - logger.error(`Error Response List: ${JSON.stringify(respList, null, 2)}`); - - errNotificationClient.notify(error, 'User Deletion', { - ...resp, - ...getCommonMetadata(ctx), - ...getReqMetadata(), - }); - } - return undefined; - }), - ); - ctx.body = respList; - return ctx.body; - // const { destType } = ctx.request.body; -}; - -router.post('/fileUpload', async (ctx) => { - await fileUpload(ctx); -}); - -router.post('/pollStatus', async (ctx) => { - await pollStatus(ctx); -}); - -router.post('/getFailedJobs', async (ctx) => { - await getJobStatus(ctx, 'fail'); -}); - -router.post('/getWarningJobs', async (ctx) => { - await getJobStatus(ctx, 'warn'); -}); -// eg. v0/validate. will validate events as per respective tracking plans -router.post(`/v0/validate`, async (ctx) => { - await handleValidation(ctx); -}); - -// Api to handle deletion of users for data regulation -// { -// "destType": "dest name", -// "userAttributes": [ -// { -// "userId": "user_1" -// }, -// { -// "userId": "user_2" -// } -// ], -// "config": { -// "apiKey": "", -// "apiSecret": "" -// } -// } -router.post(`/deleteUsers`, async (ctx) => { - await handleDeletionOfUsers(ctx); -}); - -module.exports = { - router, - handleDest, - routerHandleDest, - batchHandler, - handleProxyRequest, - handleDeletionOfUsers, - fileUpload, - pollStatus, - getJobStatus, - handleV0Destination, - getDestHandler, -}; diff --git a/src/routes/bulkUpload.ts b/src/routes/bulkUpload.ts deleted file mode 100644 index efbd81c34e..0000000000 --- a/src/routes/bulkUpload.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Router from '@koa/router'; -import { - fileUpload, - pollStatus, - getFailedJobStatus, - getWarnJobStatus, -} from '../controllers/bulkUpload'; - -const router = new Router(); - -router.post('/fileUpload', fileUpload); -router.post('/pollStatus', pollStatus); -router.post('/getFailedJobs', getFailedJobStatus); -router.post('/getWarningJobs', getWarnJobStatus); -const bulkUploadRoutes = router.routes(); - -export default bulkUploadRoutes; diff --git a/src/routes/index.ts b/src/routes/index.ts index d77584bea3..9bd40b8e68 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -5,7 +5,6 @@ import dotenv from 'dotenv'; import { koaSwagger } from 'koa2-swagger-ui'; import path from 'path'; import userTransformRoutes from './userTransform'; -import bulkUploadRoutes from './bulkUpload'; import proxyRoutes from './delivery'; import destinationRoutes from './destination'; import miscRoutes from './misc'; @@ -17,11 +16,7 @@ import { isNotEmpty } from '../v0/util'; dotenv.config(); -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const enableSwagger = process.env.ENABLE_SWAGGER === 'true'; - export function applicationRoutes(app: Koa) { - app.use(bulkUploadRoutes); app.use(proxyRoutes); app.use(destinationRoutes); app.use(miscRoutes); diff --git a/src/util/prometheus.js b/src/util/prometheus.js index c8dd55068b..2a3a1fb22a 100644 --- a/src/util/prometheus.js +++ b/src/util/prometheus.js @@ -520,6 +520,24 @@ class Prometheus { type: 'counter', labelNames: ['destination_id'], }, + { + name: 'braze_batch_subscription_size', + help: 'braze_batch_subscription_size', + type: 'gauge', + labelNames: ['destination_id'], + }, + { + name: 'braze_batch_subscription_combined_size', + help: 'braze_batch_subscription_combined_size', + type: 'gauge', + labelNames: ['destination_id'], + }, + { + name: 'mailjet_packing_size', + help: 'mailjet_packing_size', + type: 'gauge', + labelNames: ['group'], + }, { name: 'hs_batch_size', help: 'hs_batch_size', diff --git a/src/v0/destinations/adobe_analytics/transform.js b/src/v0/destinations/adobe_analytics/transform.js index 5d3d6e7d00..ecc2fdd457 100644 --- a/src/v0/destinations/adobe_analytics/transform.js +++ b/src/v0/destinations/adobe_analytics/transform.js @@ -340,7 +340,9 @@ const processTrackEvent = (message, adobeEventName, destinationConfig, extras = return { ...extras, events: overrideEventString || adobeEventArr.join(','), - products: overrideProductString || prodString, + products: + overrideProductString || + (Array.isArray(prodString) && prodString.length > 0 ? prodString : undefined), }; }; diff --git a/src/v0/destinations/airship/data/airshipTrackConfig.json b/src/v0/destinations/airship/data/airshipTrackConfig.json index 1f280f756b..4b09fdb943 100644 --- a/src/v0/destinations/airship/data/airshipTrackConfig.json +++ b/src/v0/destinations/airship/data/airshipTrackConfig.json @@ -22,7 +22,10 @@ { "destKey": "session_id", "sourceKeys": ["properties.sessionId", "context.sessionId"], - "required": false + "required": false, + "metadata": { + "type": "toString" + } }, { "destKey": "transaction", diff --git a/src/v0/destinations/airship/transform.js b/src/v0/destinations/airship/transform.js index dc8543fbc5..18b7a87547 100644 --- a/src/v0/destinations/airship/transform.js +++ b/src/v0/destinations/airship/transform.js @@ -22,12 +22,20 @@ const { extractCustomFields, isEmptyObject, simpleProcessRouterDest, + convertToUuid, } = require('../../util'); const { JSON_MIME_TYPE } = require('../../util/constant'); -const { transformSessionId } = require('./utils'); const DEFAULT_ACCEPT_HEADER = 'application/vnd.urbanairship+json; version=3'; +const transformSessionId = (rawSessionId) => { + try { + return convertToUuid(rawSessionId); + } catch (error) { + throw new InstrumentationError(`Failed to transform session ID: ${error.message}`); + } +}; + const identifyResponseBuilder = (message, { Config }) => { const tagPayload = constructPayload(message, identifyMapping); const { apiKey, dataCenter } = Config; @@ -129,6 +137,8 @@ const trackResponseBuilder = async (message, { Config }) => { name = name.toLowerCase(); const payload = constructPayload(message, trackMapping); + + // ref : https://docs.airship.com/api/ua/#operation-api-custom-events-post if (isDefinedAndNotNullAndNotEmpty(payload.session_id)) { payload.session_id = transformSessionId(payload.session_id); } @@ -139,7 +149,7 @@ const trackResponseBuilder = async (message, { Config }) => { } payload.name = name.replace(/\s+/g, '_'); - if (payload.value) { + if (payload.value && typeof payload.value === 'string') { payload.value.replace(/\s+/g, '_'); } const { appKey, dataCenter, apiKey } = Config; diff --git a/src/v0/destinations/airship/utils.js b/src/v0/destinations/airship/utils.js deleted file mode 100644 index 0ef637245f..0000000000 --- a/src/v0/destinations/airship/utils.js +++ /dev/null @@ -1,12 +0,0 @@ -const { v5 } = require('uuid'); - -// ref : https://docs.airship.com/api/ua/#operation-api-custom-events-post -const transformSessionId = (rawSessionId) => { - const NAMESPACE = v5.DNS; - const uuidV5 = v5(rawSessionId, NAMESPACE); - return uuidV5; -}; - -module.exports = { - transformSessionId, -}; diff --git a/src/v0/destinations/am/deleteUsers.js b/src/v0/destinations/am/deleteUsers.js index 96c4f7b19c..1fde1c4142 100644 --- a/src/v0/destinations/am/deleteUsers.js +++ b/src/v0/destinations/am/deleteUsers.js @@ -16,7 +16,7 @@ const userDeletionHandler = async (userAttributes, config) => { if (!config) { throw new ConfigurationError('Config for deletion not present'); } - const { apiKey, apiSecret } = config; + const { apiKey, apiSecret, residencyServer } = config; if (!apiKey || !apiSecret) { throw new ConfigurationError('api key/secret for deletion not present'); } @@ -27,7 +27,10 @@ const userDeletionHandler = async (userAttributes, config) => { }; // Ref : https://www.docs.developers.amplitude.com/analytics/apis/user-privacy-api/#response const batchEvents = getUserIdBatches(userAttributes, DELETE_MAX_BATCH_SIZE); - const url = 'https://amplitude.com/api/2/deletions/users'; + const url = + residencyServer === 'EU' + ? 'https://analytics.eu.amplitude.com/api/2/deletions/users' + : 'https://amplitude.com/api/2/deletions/users'; const endpointPath = '/api/2/deletions/users'; await Promise.all( batchEvents.map(async (batch) => { diff --git a/src/v0/destinations/amazon_audience/utils.js b/src/v0/destinations/amazon_audience/utils.js index c25f301378..350d071a47 100644 --- a/src/v0/destinations/amazon_audience/utils.js +++ b/src/v0/destinations/amazon_audience/utils.js @@ -21,7 +21,8 @@ const buildResponseWithUsers = (users, action, config, jobIdList, secret) => { if (!secret?.clientId) { throw new OAuthSecretError('OAuth - Client Id not found'); } - const externalId = `Rudderstack_${sha256(`${jobIdList}`)}`; + const jobIdHash = sha256(String(jobIdList)); + const externalId = `Rudderstack_${jobIdHash}`; const response = defaultRequestConfig(); response.endpoint = ''; response.method = defaultPostRequestConfig.requestMethod; diff --git a/src/v0/destinations/branch/data/eventMapping.js b/src/v0/destinations/branch/data/eventMapping.js index 84ae1a07af..abab6a2993 100644 --- a/src/v0/destinations/branch/data/eventMapping.js +++ b/src/v0/destinations/branch/data/eventMapping.js @@ -40,6 +40,7 @@ const CommerceEventConfig = { 'Spend Credits': 'SPEND_CREDITS', 'Promotion Viewed': 'VIEW_AD', 'Promotion Clicked': 'CLICK_AD', + Purchase: 'PURCHASE', Reserve: 'RESERVE', }, event_data: ['transaction_id', 'currency', 'revenue', 'shipping', 'tax', 'coupon', 'description'], diff --git a/src/v0/destinations/branch/transform.js b/src/v0/destinations/branch/transform.js index 2626d8aa81..8362f10723 100644 --- a/src/v0/destinations/branch/transform.js +++ b/src/v0/destinations/branch/transform.js @@ -46,17 +46,16 @@ function getCategoryAndName(rudderEventName) { let requiredName = null; let requiredCategory = null; // eslint-disable-next-line array-callback-return, sonarjs/no-ignored-return - Object.keys(category.name).find((branchKey) => { + Object.keys(category.name).forEach((branchKey) => { if ( typeof branchKey === 'string' && typeof rudderEventName === 'string' && - branchKey.toLowerCase() === rudderEventName.toLowerCase() + (branchKey.toLowerCase() === rudderEventName.toLowerCase() || + category.name[branchKey].toLowerCase() === rudderEventName.toLowerCase()) ) { requiredName = category.name[branchKey]; requiredCategory = category; - return true; } - return false; }); if (requiredName != null && requiredCategory != null) { return { evName: requiredName, category: requiredCategory }; @@ -116,14 +115,12 @@ function mapPayload(category, rudderProperty, rudderPropertiesObj) { let valFound = false; if (category.content_items) { // eslint-disable-next-line sonarjs/no-ignored-return - Object.keys(category.content_items).find((branchMappingProperty) => { + Object.keys(category.content_items).forEach((branchMappingProperty) => { if (branchMappingProperty === rudderProperty) { const tmpKeyName = category.content_items[branchMappingProperty]; contentItems[tmpKeyName] = rudderPropertiesObj[rudderProperty]; valFound = true; - return true; } - return false; }); } @@ -217,16 +214,17 @@ function getCommonPayload(message, category, evName) { function processMessage(message, destination) { let evName; let category; + let updatedEventName = message.event; switch (message.type) { case EventType.TRACK: { if (!message.event) { throw new InstrumentationError('Event name is required'); } - ({ evName, category } = getCategoryAndName(message.event)); const eventNameFromConfig = getMappedEventNameFromConfig(message, destination); if (eventNameFromConfig) { - evName = eventNameFromConfig; + updatedEventName = eventNameFromConfig; } + ({ evName, category } = getCategoryAndName(updatedEventName)); break; } case EventType.IDENTIFY: diff --git a/src/v0/destinations/braze/braze.util.test.js b/src/v0/destinations/braze/braze.util.test.js index 71052f8d77..6fe4dbbb44 100644 --- a/src/v0/destinations/braze/braze.util.test.js +++ b/src/v0/destinations/braze/braze.util.test.js @@ -6,6 +6,7 @@ const { getPurchaseObjs, setAliasObject, handleReservedProperties, + combineSubscriptionGroups, } = require('./util'); const { processBatch } = require('./util'); const { @@ -254,7 +255,6 @@ describe('dedup utility tests', () => { enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'test-rest-api-key', supportDedup: true, trackAnonymousUser: true, @@ -958,7 +958,9 @@ describe('processBatch', () => { attributes: [{ id: i, name: 'test', xyz: 'abc' }], events: [{ id: i, event: 'test', xyz: 'abc' }], purchases: [{ id: i, purchase: 'test', xyz: 'abc' }], - subscription_groups: [{ id: i, group: 'test', xyz: 'abc' }], + subscription_groups: [ + { subscription_group_id: i, group: 'test', subscription_state: 'abc' }, + ], merge_updates: [{ id: i, alias: 'test', xyz: 'abc' }], }, }, @@ -972,7 +974,7 @@ describe('processBatch', () => { // Assert that the response is as expected expect(result.length).toBe(1); // One successful batched request and one failure response - expect(result[0].batchedRequest.length).toBe(6); // Two batched requests + expect(result[0].batchedRequest.length).toBe(8); // Two batched requests expect(result[0].batchedRequest[0].body.JSON.partner).toBe('RudderStack'); // Verify partner name expect(result[0].batchedRequest[0].body.JSON.attributes.length).toBe(75); // First batch contains 75 attributes expect(result[0].batchedRequest[0].body.JSON.events.length).toBe(75); // First batch contains 75 events @@ -981,10 +983,12 @@ describe('processBatch', () => { expect(result[0].batchedRequest[1].body.JSON.attributes.length).toBe(25); // Second batch contains remaining 25 attributes expect(result[0].batchedRequest[1].body.JSON.events.length).toBe(25); // Second batch contains remaining 25 events expect(result[0].batchedRequest[1].body.JSON.purchases.length).toBe(25); // Second batch contains remaining 25 purchases - expect(result[0].batchedRequest[2].body.JSON.subscription_groups.length).toBe(50); // First batch contains 50 subscription group - expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(50); // First batch contains 25 subscription group - expect(result[0].batchedRequest[4].body.JSON.merge_updates.length).toBe(50); // First batch contains 50 merge_updates - expect(result[0].batchedRequest[5].body.JSON.merge_updates.length).toBe(50); // First batch contains 25 merge_updates + expect(result[0].batchedRequest[2].body.JSON.subscription_groups.length).toBe(25); // First batch contains 25 subscription group + expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(25); // Second batch contains 25 subscription group + expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(25); // Third batch contains 25 subscription group + expect(result[0].batchedRequest[5].body.JSON.subscription_groups.length).toBe(25); // Fourth batch contains 25 subscription group + expect(result[0].batchedRequest[6].body.JSON.merge_updates.length).toBe(50); // First batch contains 50 merge_updates + expect(result[0].batchedRequest[7].body.JSON.merge_updates.length).toBe(50); // First batch contains 25 merge_updates }); test('processBatch handles more than 75 attributes, events, and purchases with non uniform distribution', () => { @@ -1055,7 +1059,9 @@ describe('processBatch', () => { batchedRequest: { body: { JSON: { - subscription_groups: [{ id: i, group: 'test', xyz: 'abc' }], + subscription_groups: [ + { subscription_group_id: i, group: 'test', subscription_state: 'abc' }, + ], }, }, }, @@ -1093,7 +1099,7 @@ describe('processBatch', () => { // Assert that the response is as expected expect(result.length).toBe(1); // One successful batched request and one failure response expect(result[0].metadata.length).toBe(490); // Check the total length is same as input jobs (120 + 160 + 100 + 70 +40) - expect(result[0].batchedRequest.length).toBe(6); // Two batched requests + expect(result[0].batchedRequest.length).toBe(7); // Two batched requests expect(result[0].batchedRequest[0].body.JSON.partner).toBe('RudderStack'); // Verify partner name expect(result[0].batchedRequest[0].body.JSON.attributes.length).toBe(75); // First batch contains 75 attributes expect(result[0].batchedRequest[0].body.JSON.events.length).toBe(75); // First batch contains 75 events @@ -1103,9 +1109,10 @@ describe('processBatch', () => { expect(result[0].batchedRequest[1].body.JSON.events.length).toBe(45); // Second batch contains remaining 45 events expect(result[0].batchedRequest[1].body.JSON.purchases.length).toBe(75); // Second batch contains remaining 75 purchases expect(result[0].batchedRequest[2].body.JSON.purchases.length).toBe(10); // Third batch contains remaining 10 purchases - expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(50); // First batch contains 50 subscription group - expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(20); // First batch contains 20 subscription group - expect(result[0].batchedRequest[5].body.JSON.merge_updates.length).toBe(40); // First batch contains 50 merge_updates + expect(result[0].batchedRequest[3].body.JSON.subscription_groups.length).toBe(25); // First batch contains 25 subscription group + expect(result[0].batchedRequest[4].body.JSON.subscription_groups.length).toBe(25); // Second batch contains 25 subscription group + expect(result[0].batchedRequest[5].body.JSON.subscription_groups.length).toBe(20); // Third batch contains 20 subscription group + expect(result[0].batchedRequest[6].body.JSON.merge_updates.length).toBe(40); // First batch contains 50 merge_updates }); test('check success and failure scenarios both for processBatch', () => { @@ -1751,3 +1758,124 @@ describe('handleReservedProperties', () => { }); }); }); + +describe('combineSubscriptionGroups', () => { + it('should merge external_ids, emails, and phones for the same subscription_group_id and subscription_state', () => { + const input = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1', 'id2'], + emails: ['email1@example.com', 'email2@example.com'], + phones: ['+1234567890', '+0987654321'], + }, + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id2', 'id3'], + emails: ['email2@example.com', 'email3@example.com'], + phones: ['+1234567890', '+1122334455'], + }, + ]; + + const expectedOutput = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1', 'id2', 'id3'], + emails: ['email1@example.com', 'email2@example.com', 'email3@example.com'], + phones: ['+1234567890', '+0987654321', '+1122334455'], + }, + ]; + + const result = combineSubscriptionGroups(input); + expect(result).toEqual(expectedOutput); + }); + + it('should handle groups with missing external_ids, emails, or phones', () => { + const input = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + emails: ['email1@example.com'], + }, + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + phones: ['+1234567890'], + }, + ]; + + const expectedOutput = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + emails: ['email1@example.com'], + phones: ['+1234567890'], + }, + ]; + + const result = combineSubscriptionGroups(input); + expect(result).toEqual(expectedOutput); + }); + + it('should handle multiple unique subscription groups', () => { + const input = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + { + subscription_group_id: 'group2', + subscription_state: 'Unsubscribed', + external_ids: ['id2'], + emails: ['email2@example.com'], + }, + ]; + + const expectedOutput = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + { + subscription_group_id: 'group2', + subscription_state: 'Unsubscribed', + external_ids: ['id2'], + emails: ['email2@example.com'], + }, + ]; + + const result = combineSubscriptionGroups(input); + expect(result).toEqual(expectedOutput); + }); + + it('should not include undefined fields in the output', () => { + const input = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + ]; + + const expectedOutput = [ + { + subscription_group_id: 'group1', + subscription_state: 'Subscribed', + external_ids: ['id1'], + }, + ]; + + const result = combineSubscriptionGroups(input); + expect(result).toEqual(expectedOutput); + }); +}); diff --git a/src/v0/destinations/braze/config.js b/src/v0/destinations/braze/config.js index 2bbade2754..8ccabbdb0a 100644 --- a/src/v0/destinations/braze/config.js +++ b/src/v0/destinations/braze/config.js @@ -36,7 +36,7 @@ const IDENTIFY_BRAZE_MAX_REQ_COUNT = 50; // https://www.braze.com/docs/api/endpoints/user_data/post_user_delete/ const ALIAS_BRAZE_MAX_REQ_COUNT = 50; -const SUBSCRIPTION_BRAZE_MAX_REQ_COUNT = 50; +const SUBSCRIPTION_BRAZE_MAX_REQ_COUNT = 25; const DEL_MAX_BATCH_SIZE = 50; const DESTINATION = 'braze'; diff --git a/src/v0/destinations/braze/transform.js b/src/v0/destinations/braze/transform.js index 09fb0205c5..2a9cb8e7dc 100644 --- a/src/v0/destinations/braze/transform.js +++ b/src/v0/destinations/braze/transform.js @@ -383,7 +383,7 @@ function processGroup(message, destination) { ); } subscriptionGroup.subscription_state = message.traits.subscriptionState; - subscriptionGroup.external_id = [message.userId]; + subscriptionGroup.external_ids = [message.userId]; const phone = getFieldValueFromMessage(message, 'phone'); const email = getFieldValueFromMessage(message, 'email'); if (phone) { diff --git a/src/v0/destinations/braze/util.js b/src/v0/destinations/braze/util.js index 6c8cf64265..74cb7fb953 100644 --- a/src/v0/destinations/braze/util.js +++ b/src/v0/destinations/braze/util.js @@ -45,6 +45,42 @@ const getEndpointFromConfig = (destination) => { return endpoint; }; +// Merges external_ids, emails, and phones for entries with the same subscription_group_id and subscription_state +const combineSubscriptionGroups = (subscriptionGroups) => { + const uniqueGroups = {}; + + subscriptionGroups.forEach((group) => { + const key = `${group.subscription_group_id}-${group.subscription_state}`; + if (!uniqueGroups[key]) { + uniqueGroups[key] = { + ...group, + external_ids: [...(group.external_ids || [])], + emails: [...(group.emails || [])], + phones: [...(group.phones || [])], + }; + } else { + uniqueGroups[key].external_ids.push(...(group.external_ids || [])); + uniqueGroups[key].emails.push(...(group.emails || [])); + uniqueGroups[key].phones.push(...(group.phones || [])); + } + }); + + return Object.values(uniqueGroups).map((group) => { + const result = { + subscription_group_id: group.subscription_group_id, + subscription_state: group.subscription_state, + external_ids: [...new Set(group.external_ids)], + }; + if (group.emails?.length) { + result.emails = [...new Set(group.emails)]; + } + if (group.phones?.length) { + result.phones = [...new Set(group.phones)]; + } + return result; + }); +}; + const CustomAttributeOperationUtil = { customAttributeUpdateOperation(key, data, traits, mergeObjectsUpdateOperation) { data[key] = {}; @@ -381,8 +417,22 @@ function prepareGroupAndAliasBatch(arrayChunks, responseArray, destination, type } else if (type === 'subscription') { response.endpoint = getSubscriptionGroupEndPoint(getEndpointFromConfig(destination)); const subscription_groups = chunk; + // maketool transformed event + logger.info(`braze subscription chunk ${JSON.stringify(subscription_groups)}`); + + stats.gauge('braze_batch_subscription_size', subscription_groups.length, { + destination_id: destination.ID, + }); + + // Deduplicate the subscription groups before constructing the response body + const deduplicatedSubscriptionGroups = combineSubscriptionGroups(subscription_groups); + + stats.gauge('braze_batch_subscription_combined_size', deduplicatedSubscriptionGroups.length, { + destination_id: destination.ID, + }); + response.body.JSON = removeUndefinedAndNullValues({ - subscription_groups, + subscription_groups: deduplicatedSubscriptionGroups, }); } responseArray.push({ @@ -756,4 +806,5 @@ module.exports = { collectStatsForAliasFailure, collectStatsForAliasMissConfigurations, handleReservedProperties, + combineSubscriptionGroups, }; diff --git a/src/v0/destinations/google_adwords_offline_conversions/transform.js b/src/v0/destinations/google_adwords_offline_conversions/transform.js index 76b12587cd..2648f03e8a 100644 --- a/src/v0/destinations/google_adwords_offline_conversions/transform.js +++ b/src/v0/destinations/google_adwords_offline_conversions/transform.js @@ -18,6 +18,7 @@ const { getClickConversionPayloadAndEndpoint, getConsentsDataFromIntegrationObj, getCallConversionPayload, + updateConversion, } = require('./utils'); const helper = require('./helper'); @@ -48,6 +49,9 @@ const getConversions = (message, metadata, { Config }, event, conversionType) => filteredCustomerId, eventLevelConsentsData, ); + convertedPayload.payload.conversions[0] = updateConversion( + convertedPayload.payload.conversions[0], + ); payload = convertedPayload.payload; endpoint = convertedPayload.endpoint; } else if (conversionType === 'store') { diff --git a/src/v0/destinations/google_adwords_offline_conversions/utils.js b/src/v0/destinations/google_adwords_offline_conversions/utils.js index 89fe609df9..2d47095eea 100644 --- a/src/v0/destinations/google_adwords_offline_conversions/utils.js +++ b/src/v0/destinations/google_adwords_offline_conversions/utils.js @@ -317,6 +317,35 @@ const getStoreConversionPayload = (message, Config, event) => { return payload; }; +const hasClickId = (conversion) => { + const { gbraid, wbraid, gclid } = conversion; + return gclid || wbraid || gbraid; +}; +const populateUserIdentifier = ({ email, phone, properties, payload, UserIdentifierSource }) => { + const copiedPayload = cloneDeep(payload); + // userIdentifierSource + // if userIdentifierSource doesn't exist in properties + // then it is taken from the webapp config + if (!properties.userIdentifierSource && UserIdentifierSource !== 'none') { + set( + copiedPayload, + 'conversions[0].userIdentifiers[0].userIdentifierSource', + UserIdentifierSource, + ); + // one of email or phone must be provided when none of gclid, wbraid and gbraid provided + } + if (!email && !phone) { + if (!hasClickId(copiedPayload.conversions[0])) { + throw new InstrumentationError( + `Either an email address or a phone number is required for user identification when none of gclid, wbraid, or gbraid is provided.`, + ); + } else { + // we are deleting userIdentifiers if any one of gclid, wbraid and gbraid is there but email or phone is not present + delete copiedPayload.conversions[0].userIdentifiers; + } + } + return copiedPayload; +}; const getClickConversionPayloadAndEndpoint = ( message, Config, @@ -335,7 +364,7 @@ const getClickConversionPayloadAndEndpoint = ( updatedClickMapping = removeHashToSha256TypeFromMappingJson(updatedClickMapping); } - const payload = constructPayload(message, updatedClickMapping); + let payload = constructPayload(message, updatedClickMapping); const endpoint = CLICK_CONVERSION.replace(':customerId', filteredCustomerId); @@ -353,17 +382,8 @@ const getClickConversionPayloadAndEndpoint = ( set(payload, 'conversions[0].cartData.items', itemList); } - // userIdentifierSource - // if userIdentifierSource doesn't exist in properties - // then it is taken from the webapp config - if (!properties.userIdentifierSource && UserIdentifierSource !== 'none') { - set(payload, 'conversions[0].userIdentifiers[0].userIdentifierSource', UserIdentifierSource); + payload = populateUserIdentifier({ email, phone, properties, payload, UserIdentifierSource }); - // one of email or phone must be provided - if (!email && !phone) { - throw new InstrumentationError(`Either of email or phone is required for user identifier`); - } - } // either of email or phone should be passed // defaultUserIdentifier depends on the webapp configuration // Ref - https://developers.google.com/google-ads/api/rest/reference/rest/v11/customers/uploadClickConversions#ClickConversion @@ -411,6 +431,25 @@ const getConsentsDataFromIntegrationObj = (message) => { return integrationObj?.consents || {}; }; +/** + * remove redundant ids + * @param {*} conversionCopy + */ +const updateConversion = (conversion) => { + const conversionCopy = cloneDeep(conversion); + if (conversionCopy.gclid) { + delete conversionCopy.wbraid; + delete conversionCopy.gbraid; + } + if (conversionCopy.wbraid && conversionCopy.gbraid) { + throw new InstrumentationError(`You can't use both wbraid and gbraid.`); + } + if (conversionCopy.wbraid || conversionCopy.gbraid) { + delete conversionCopy.userIdentifiers; + } + return conversionCopy; +}; + module.exports = { validateDestinationConfig, generateItemListFromProducts, @@ -423,4 +462,5 @@ module.exports = { getExisitingUserIdentifier, getConsentsDataFromIntegrationObj, getCallConversionPayload, + updateConversion, }; diff --git a/src/v0/destinations/google_adwords_offline_conversions/utils.test.js b/src/v0/destinations/google_adwords_offline_conversions/utils.test.js index 2d1863413c..b6c6653782 100644 --- a/src/v0/destinations/google_adwords_offline_conversions/utils.test.js +++ b/src/v0/destinations/google_adwords_offline_conversions/utils.test.js @@ -244,7 +244,9 @@ describe('getClickConversionPayloadAndEndpoint util tests', () => { }; expect(() => getClickConversionPayloadAndEndpoint(fittingPayload, config, '9625812972'), - ).toThrow('Either of email or phone is required for user identifier'); + ).toThrow( + 'Either an email address or a phone number is required for user identification when none of gclid, wbraid, or gbraid is provided.', + ); }); it('finaliseConsent', () => { diff --git a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js index 5866b66538..c3bf27a75d 100644 --- a/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js +++ b/src/v0/destinations/google_adwords_remarketing_lists/recordTransform.js @@ -1,4 +1,3 @@ -/* eslint-disable no-const-assign */ const lodash = require('lodash'); const { InstrumentationError } = require('@rudderstack/integrations-lib'); const { @@ -19,29 +18,22 @@ const { const { getErrorResponse, createFinalResponse } = require('../../util/recordUtils'); const { offlineDataJobsMapping, consentConfigMap } = require('./config'); -const processRecordEventArray = ( - records, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - operationType, -) => { - let outputPayloads = {}; - // ** only send it if identifier > 0 - - const fieldsArray = []; - const metadata = []; - records.forEach((record) => { - fieldsArray.push(record.message.fields); - metadata.push(record.metadata); - }); +const processRecordEventArray = (records, context, operationType) => { + const { + message, + destination, + accessToken, + developerToken, + audienceId, + typeOfList, + userSchema, + isHashRequired, + userDataConsent, + personalizationConsent, + } = context; + + const fieldsArray = records.map((record) => record.message.fields); + const metadata = records.map((record) => record.metadata); const userIdentifiersList = populateIdentifiersForRecordEvent( fieldsArray, @@ -51,131 +43,60 @@ const processRecordEventArray = ( ); const outputPayload = constructPayload(message, offlineDataJobsMapping); - outputPayload.operations = []; - // breaking the userIdentiFier array in chunks of 20 + const userIdentifierChunks = returnArrayOfSubarrays(userIdentifiersList, 20); - // putting each chunk in different create/remove operations - switch (operationType) { - case 'add': - // for add operation - userIdentifierChunks.forEach((element) => { - const operations = { - create: {}, - }; - operations.create.userIdentifiers = element; - outputPayload.operations.push(operations); - }); - outputPayloads = { ...outputPayloads, create: outputPayload }; - break; - case 'remove': - // for remove operation - userIdentifierChunks.forEach((element) => { - const operations = { - remove: {}, - }; - operations.remove.userIdentifiers = element; - outputPayload.operations.push(operations); - }); - outputPayloads = { ...outputPayloads, remove: outputPayload }; - break; - default: - } + outputPayload.operations = userIdentifierChunks.map((chunk) => ({ + [operationType]: { userIdentifiers: chunk }, + })); - const toSendEvents = []; - Object.values(outputPayloads).forEach((data) => { - const consentObj = populateConsentFromConfig( - { userDataConsent, personalizationConsent }, - consentConfigMap, - ); - toSendEvents.push( - responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj), - ); - }); + const consentObj = populateConsentFromConfig( + { userDataConsent, personalizationConsent }, + consentConfigMap, + ); - const successResponse = getSuccessRespEvents(toSendEvents, metadata, destination, true); + const toSendEvents = [outputPayload].map((data) => + responseBuilder(accessToken, developerToken, data, destination, audienceId, consentObj), + ); - return successResponse; + return getSuccessRespEvents(toSendEvents, metadata, destination, true); }; -function preparepayload(events, config) { +function preparePayload(events, config) { const { destination, message, metadata } = events[0]; const accessToken = getAccessToken(metadata, 'access_token'); const developerToken = getValueFromMessage(metadata, 'secret.developer_token'); - const { - audienceId, - typeOfList, - isHashRequired, - userSchema, - userDataConsent, - personalizationConsent, - } = config; + + const context = { + message, + destination, + accessToken, + developerToken, + ...config, + }; const groupedRecordsByAction = lodash.groupBy(events, (record) => record.message.action?.toLowerCase(), ); - let insertResponse; - let deleteResponse; - let updateResponse; - - if (groupedRecordsByAction.delete) { - deleteResponse = processRecordEventArray( - groupedRecordsByAction.delete, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'remove', - ); - } - - if (groupedRecordsByAction.insert) { - insertResponse = processRecordEventArray( - groupedRecordsByAction.insert, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'add', - ); - } - - if (groupedRecordsByAction.update) { - updateResponse = processRecordEventArray( - groupedRecordsByAction.update, - message, - destination, - accessToken, - developerToken, - audienceId, - typeOfList, - userSchema, - isHashRequired, - userDataConsent, - personalizationConsent, - 'add', - ); - } + const actionResponses = ['delete', 'insert', 'update'].reduce((responses, action) => { + const operationType = action === 'delete' ? 'remove' : 'create'; + if (groupedRecordsByAction[action]) { + return { + ...responses, + [action]: processRecordEventArray(groupedRecordsByAction[action], context, operationType), + }; + } + return responses; + }, {}); const errorResponse = getErrorResponse(groupedRecordsByAction); const finalResponse = createFinalResponse( - deleteResponse, - insertResponse, - updateResponse, + actionResponses.delete, + actionResponses.insert, + actionResponses.update, errorResponse, ); + if (finalResponse.length === 0) { throw new InstrumentationError( 'Missing valid parameters, unable to generate transformed payload', @@ -196,14 +117,16 @@ function processRecordInputsV0(groupedRecordInputs) { personalizationConsent, } = destination.Config; - return preparepayload(groupedRecordInputs, { + const config = { audienceId: getOperationAudienceId(audienceId, message), typeOfList, userSchema, isHashRequired, userDataConsent, personalizationConsent, - }); + }; + + return preparePayload(groupedRecordInputs, config); } function processRecordInputsV1(groupedRecordInputs) { @@ -211,11 +134,7 @@ function processRecordInputsV1(groupedRecordInputs) { const { audienceId, typeOfList, isHashRequired, userDataConsent, personalizationConsent } = connection.config.destination; - const identifiers = message?.identifiers; - let userSchema; - if (identifiers) { - userSchema = Object.keys(identifiers); - } + const userSchema = message?.identifiers ? Object.keys(message.identifiers) : undefined; const events = groupedRecordInputs.map((record) => ({ ...record, @@ -225,23 +144,23 @@ function processRecordInputsV1(groupedRecordInputs) { }, })); - return preparepayload(events, { + const config = { audienceId, typeOfList, userSchema, isHashRequired, userDataConsent, personalizationConsent, - }); + }; + + return preparePayload(events, config); } function processRecordInputs(groupedRecordInputs) { const event = groupedRecordInputs[0]; - // First check for rETL flow and second check for ES flow - if (isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event)) { - return processRecordInputsV0(groupedRecordInputs); - } - return processRecordInputsV1(groupedRecordInputs); + return isEventSentByVDMV1Flow(event) || !isEventSentByVDMV2Flow(event) + ? processRecordInputsV0(groupedRecordInputs) + : processRecordInputsV1(groupedRecordInputs); } module.exports = { diff --git a/src/v0/destinations/iterable/config.js b/src/v0/destinations/iterable/config.js index 125367875f..e60e444c18 100644 --- a/src/v0/destinations/iterable/config.js +++ b/src/v0/destinations/iterable/config.js @@ -76,11 +76,31 @@ const constructEndpoint = (dataCenter, category) => { return `${baseUrl}${category.endpoint}`; }; +const BULK_ENDPOINTS = ['/api/users/bulkUpdate', '/api/events/trackBulk']; + const IDENTIFY_MAX_BATCH_SIZE = 1000; const IDENTIFY_MAX_BODY_SIZE_IN_BYTES = 4000000; const TRACK_MAX_BATCH_SIZE = 8000; +const ITERABLE_RESPONSE_USER_ID_PATHS = [ + 'invalidUserIds', + 'failedUpdates.invalidUserIds', + 'failedUpdates.notFoundUserIds', + 'failedUpdates.forgottenUserIds', + 'failedUpdates.conflictUserIds', + 'failedUpdates.invalidDataUserIds', +]; + +const ITERABLE_RESPONSE_EMAIL_PATHS = [ + 'invalidEmails', + 'failedUpdates.invalidEmails', + 'failedUpdates.notFoundEmails', + 'failedUpdates.forgottenEmails', + 'failedUpdates.conflictEmails', + 'failedUpdates.invalidDataEmails', +]; + module.exports = { mappingConfig, ConfigCategory, @@ -88,4 +108,7 @@ module.exports = { TRACK_MAX_BATCH_SIZE, IDENTIFY_MAX_BATCH_SIZE, IDENTIFY_MAX_BODY_SIZE_IN_BYTES, + ITERABLE_RESPONSE_USER_ID_PATHS, + ITERABLE_RESPONSE_EMAIL_PATHS, + BULK_ENDPOINTS, }; diff --git a/src/v0/destinations/iterable/util.js b/src/v0/destinations/iterable/util.js index b918600253..764d76f882 100644 --- a/src/v0/destinations/iterable/util.js +++ b/src/v0/destinations/iterable/util.js @@ -483,6 +483,7 @@ const batchUpdateUserEvents = (updateUserEvents, registerDeviceOrBrowserTokenEve /** * Processes chunks of catalog events, extracts the necessary data, and prepares batched requests for further processing + * ref : https://api.iterable.com/api/docs#catalogs_bulkUpdateCatalogItems * @param {*} catalogEventsChunks * @returns */ @@ -600,12 +601,12 @@ const batchTrackEvents = (trackEvents) => { */ const prepareBatchRequests = (filteredEvents) => { const { - trackEvents, - catalogEvents, - errorRespList, - updateUserEvents, - eventResponseList, - registerDeviceOrBrowserTokenEvents, + trackEvents, // track + catalogEvents, // identify + errorRespList, // track + updateUserEvents, // identify + eventResponseList, // track + registerDeviceOrBrowserTokenEvents, // identify } = filteredEvents; const updateUserBatchedResponseList = diff --git a/src/v0/destinations/iterable/util.test.js b/src/v0/destinations/iterable/util.test.js index 098960ac77..6bbf00ba08 100644 --- a/src/v0/destinations/iterable/util.test.js +++ b/src/v0/destinations/iterable/util.test.js @@ -8,7 +8,6 @@ const { registerDeviceTokenEventPayloadBuilder, registerBrowserTokenEventPayloadBuilder, } = require('./util'); - const { ConfigCategory } = require('./config'); const getTestMessage = () => { diff --git a/src/v0/destinations/mailjet/transform.js b/src/v0/destinations/mailjet/transform.js index 78b4f766d1..0a742b4cf7 100644 --- a/src/v0/destinations/mailjet/transform.js +++ b/src/v0/destinations/mailjet/transform.js @@ -1,5 +1,6 @@ const lodash = require('lodash'); const { TransformationError, InstrumentationError } = require('@rudderstack/integrations-lib'); +const stats = require('../../../util/stats'); const { getSuccessRespEvents, defaultRequestConfig, @@ -105,6 +106,9 @@ const batchEvents = (successRespList) => { const eventChunks = lodash.chunk(eventGroups[combination], MAX_BATCH_SIZE); // eventChunks = [[e1,e2,e3,..batchSize],[e1,e2,e3,..batchSize]..] eventChunks.forEach((chunk) => { + stats.gauge('mailjet_packing_size', chunk.length, { + group: combination, + }); const batchEventResponse = generateBatchedPaylaodForArray(chunk, combination); batchedResponseList.push( getSuccessRespEvents( diff --git a/src/v0/destinations/moengage/transform.js b/src/v0/destinations/moengage/transform.js index 8a16d9c7a7..2df921cb60 100644 --- a/src/v0/destinations/moengage/transform.js +++ b/src/v0/destinations/moengage/transform.js @@ -49,7 +49,7 @@ function responseBuilderSimple(message, category, destination) { // using base64 and prepends it with the string 'Basic '. Authorization: `Basic ${btoa(`${apiId}:${apiKey}`)}`, }; - response.userId = message.anonymousId || message.userId; + response.userId = message.userId || message.anonymousId; if (payload) { switch (category.type) { case 'identify': diff --git a/src/v0/destinations/snowpipe_streaming/transform.js b/src/v0/destinations/snowpipe_streaming/transform.js index 3b0a6e1a93..36fe19ceff 100644 --- a/src/v0/destinations/snowpipe_streaming/transform.js +++ b/src/v0/destinations/snowpipe_streaming/transform.js @@ -1 +1,26 @@ -module.exports = require('../snowflake/transform'); +const transform = require('../snowflake/transform'); +const { processWarehouseMessage } = require('../../../warehouse'); + +const provider = 'snowpipe_streaming'; + +function process(event) { + const whSchemaVersion = event.request.query.whSchemaVersion || 'v1'; + const whStoreEvent = event.destination.Config.storeFullEvent === true; + const destJsonPaths = event.destination?.Config?.jsonPaths || ''; + return processWarehouseMessage(event.message, { + metadata: event.metadata, + whSchemaVersion, + whStoreEvent, + getDataTypeOverride: transform.getDataTypeOverride, + provider, + sourceCategory: event.metadata ? event.metadata.sourceCategory : null, + destJsonPaths, + destConfig: event.destination?.Config, + }); +} + +module.exports = { + provider, + process, + getDataTypeOverride: transform.getDataTypeOverride, +}; diff --git a/src/v0/destinations/topsort/config.js b/src/v0/destinations/topsort/config.js new file mode 100644 index 0000000000..5d4060f526 --- /dev/null +++ b/src/v0/destinations/topsort/config.js @@ -0,0 +1,31 @@ +const { getMappingConfig } = require('../../util'); + +const ENDPOINT = 'https://api.topsort.com/v2/events'; + +const ConfigCategory = { + TRACK: { + type: 'track', + name: 'TopsortTrackConfig', + }, + PLACEMENT: { name: 'TopsortPlacementConfig' }, + ITEM: { name: 'TopsortItemConfig' }, + PURCHASE_ITEM: { name: 'TopSortPurchaseProductConfig' }, +}; + +const ECOMM_EVENTS_WITH_PRODUCT_ARRAY = [ + 'Cart Viewed', + 'Checkout Started', + 'Order Updated', + 'Order Completed', + 'Order Refunded', + 'Order Cancelled', +]; + +const mappingConfig = getMappingConfig(ConfigCategory, __dirname); + +module.exports = { + mappingConfig, + ConfigCategory, + ENDPOINT, + ECOMM_EVENTS_WITH_PRODUCT_ARRAY, +}; diff --git a/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json b/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json new file mode 100644 index 0000000000..f3f9d877a9 --- /dev/null +++ b/src/v0/destinations/topsort/data/TopSortPurchaseProductConfig.json @@ -0,0 +1,24 @@ +[ + { + "destKey": "productId", + "sourceKeys": ["product_id", "properties.product_id"] + }, + { + "destKey": "unitPrice", + "sourceKeys": ["price", "properties.price"], + "metadata": { + "type": "toNumber" + } + }, + { + "destKey": "quantity", + "sourceKeys": ["quantity", "properties.quantity"], + "metadata": { + "toInt": true + } + }, + { + "destKey": "vendorId", + "sourceKeys": "properties.vendorId" + } +] diff --git a/src/v0/destinations/topsort/data/TopsortItemConfig.json b/src/v0/destinations/topsort/data/TopsortItemConfig.json new file mode 100644 index 0000000000..ff8c77a7ac --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortItemConfig.json @@ -0,0 +1,15 @@ +[ + { + "destKey": "position", + "sourceKeys": ["properties.position", "position"], + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "productId", + "sourceKeys": ["properties.product_id", "product_id"], + "required": false + } +] diff --git a/src/v0/destinations/topsort/data/TopsortPlacementConfig.json b/src/v0/destinations/topsort/data/TopsortPlacementConfig.json new file mode 100644 index 0000000000..7c67bb183d --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortPlacementConfig.json @@ -0,0 +1,36 @@ +[ + { + "destKey": "path", + "sourceKeys": "context.page.path", + "required": false + }, + { + "destKey": "searchQuery", + "sourceKeys": "properties.query", + "required": false + }, + { + "destKey": "page", + "sourceKeys": "properties.pageNumber", + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "pageSize", + "sourceKeys": "properties.pageSize", + "metadata": { + "toInt": true + }, + "required": false + }, + { + "destKey": "categoryIds", + "sourceKeys": "properties.category_id", + "required": false, + "metadata": { + "toArray": true + } + } +] diff --git a/src/v0/destinations/topsort/data/TopsortTrackConfig.json b/src/v0/destinations/topsort/data/TopsortTrackConfig.json new file mode 100644 index 0000000000..fcc9c57d1b --- /dev/null +++ b/src/v0/destinations/topsort/data/TopsortTrackConfig.json @@ -0,0 +1,27 @@ +[ + { + "destKey": "occurredAt", + "sourceKeys": ["timestamp", "originalTimestamp"], + "required": true + }, + { + "destKey": "opaqueUserId", + "sourceKeys": "anonymousId", + "required": true + }, + { + "destKey": "resolvedBidId", + "sourceKeys": "properties.resolvedBidId", + "required": false + }, + { + "destKey": "entity", + "sourceKeys": "properties.entity", + "required": false + }, + { + "destKey": "additionalAttribution", + "sourceKeys": "properties.additionalAttribution", + "required": false + } +] diff --git a/src/v0/destinations/topsort/impressions-and-clicks.js b/src/v0/destinations/topsort/impressions-and-clicks.js new file mode 100644 index 0000000000..ca3c6ad860 --- /dev/null +++ b/src/v0/destinations/topsort/impressions-and-clicks.js @@ -0,0 +1,95 @@ +const { ConfigCategory, mappingConfig } = require('./config'); +const { getItemPayloads, addFinalPayload } = require('./utils'); +const { constructPayload, generateUUID } = require('../../util'); + +const processImpressionsAndClicksUtility = { + // Create event data object + createEventData(basePayload, placementPayload, itemPayload, event) { + return { + topsortPayload: { + ...basePayload, + placement: { + ...placementPayload, + ...itemPayload, + }, + id: generateUUID(), + }, + event, + }; + }, + + // Process events with a product array + processProductArray({ + products, + basePayload, + placementPayload, + topsortEventName, + finalPayloads, + }) { + const itemPayloads = getItemPayloads(products, mappingConfig[ConfigCategory.ITEM.name]); + itemPayloads.forEach((itemPayload) => { + const eventData = this.createEventData( + basePayload, + placementPayload, + itemPayload, + topsortEventName, + ); + addFinalPayload(eventData, finalPayloads); + }); + }, + + // Process events with a single product + processSingleProduct({ + basePayload, + placementPayload, + message, + topsortEventName, + finalPayloads, + }) { + const itemPayload = constructPayload(message, mappingConfig[ConfigCategory.ITEM.name]); + const eventData = this.createEventData( + basePayload, + placementPayload, + itemPayload, + topsortEventName, + ); + + // Ensure messageId is used instead of generating a UUID for single product events + eventData.topsortPayload.id = message.messageId; + + // Add final payload with appropriate ID and other headers + addFinalPayload(eventData, finalPayloads); + }, + + processImpressionsAndClicks({ + isProductArrayAvailable, + basePayload, + topsortEventName, + finalPayloads, + products, + message, + placementPayload, + }) { + if (isProductArrayAvailable) { + // If product array is available, process the event with multiple products + this.processProductArray({ + basePayload, + topsortEventName, + finalPayloads, + products, + placementPayload, + }); + } else { + // Otherwise, process the event with a single product + this.processSingleProduct({ + basePayload, + topsortEventName, + finalPayloads, + message, + placementPayload, + }); + } + }, +}; + +module.exports = { processImpressionsAndClicksUtility }; diff --git a/src/v0/destinations/topsort/purchase.js b/src/v0/destinations/topsort/purchase.js new file mode 100644 index 0000000000..497188cb10 --- /dev/null +++ b/src/v0/destinations/topsort/purchase.js @@ -0,0 +1,56 @@ +const { ConfigCategory, mappingConfig } = require('./config'); +const { getItemPayloads, addFinalPayload } = require('./utils'); +const { constructPayload, generateUUID } = require('../../util'); + +const processPurchaseEventUtility = { + // Create event data object for purchase events + createEventData(basePayload, items, event) { + return { + topsortPayload: { + ...basePayload, + items, + id: generateUUID(), + }, + event, + }; + }, + + // Function to process events with a product array for purchase events + processProductArray(args) { + const { products, basePayload, topsortEventName, finalPayloads } = args; + const itemPayloads = getItemPayloads( + products, + mappingConfig[ConfigCategory.PURCHASE_ITEM.name], + ); + const eventData = this.createEventData(basePayload, itemPayloads, topsortEventName); + addFinalPayload(eventData, finalPayloads); + }, + + // Function to process events with a single product for purchase events + processSingleProduct(args) { + const { basePayload, message, topsortEventName, finalPayloads } = args; + const itemPayload = constructPayload(message, mappingConfig[ConfigCategory.PURCHASE_ITEM.name]); + const eventData = this.createEventData(basePayload, [itemPayload], topsortEventName); + + // Ensure messageId is used instead of generating a UUID for single product events + eventData.topsortPayload.id = message.messageId; + + // Add final payload with appropriate ID and other headers + addFinalPayload(eventData, finalPayloads); + }, + + // Function to process purchase events (either with a product array or single product) + processPurchaseEvent(args) { + if (args.isProductArrayAvailable) { + // Process the event with multiple products (product array) + this.processProductArray(args); + } else { + // Process the event with a single product + this.processSingleProduct(args); + } + }, +}; + +module.exports = { + processPurchaseEventUtility, +}; diff --git a/src/v0/destinations/topsort/transform.js b/src/v0/destinations/topsort/transform.js new file mode 100644 index 0000000000..e5997ab37d --- /dev/null +++ b/src/v0/destinations/topsort/transform.js @@ -0,0 +1,158 @@ +const { + InstrumentationError, + ConfigurationError, + getHashFromArray, +} = require('@rudderstack/integrations-lib'); +const { + mappingConfig, + ECOMM_EVENTS_WITH_PRODUCT_ARRAY, + ConfigCategory, + ENDPOINT, +} = require('./config'); +const { + constructPayload, + handleRtTfSingleEventError, + defaultRequestConfig, + defaultPostRequestConfig, + getSuccessRespEvents, +} = require('../../util'); +const { isProductArrayValid, getMappedEventName } = require('./utils'); +const { JSON_MIME_TYPE } = require('../../util/constant'); +const { processPurchaseEventUtility } = require('./purchase'); +const { processImpressionsAndClicksUtility } = require('./impressions-and-clicks'); + +const processTopsortEvents = (message, { Config }, finalPayloads) => { + const { topsortEvents } = Config; + const { event, properties } = message; + const { products } = properties; + + // Parse Topsort event mappings + const mappedEventName = getMappedEventName(getHashFromArray(topsortEvents), event); + + if (!mappedEventName) { + throw new InstrumentationError("Event not mapped in 'topsortEvents'. Dropping the event."); + } + + const topsortEventName = mappedEventName; + + // Construct base and placement payloads + const basePayload = constructPayload(message, mappingConfig[ConfigCategory.TRACK.name]); + + const commonArgs = { + basePayload, + topsortEventName, + finalPayloads, + products, + message, + isProductArrayAvailable: + ECOMM_EVENTS_WITH_PRODUCT_ARRAY.includes(event) && isProductArrayValid(event, properties), + }; + + // Process events based on type and construct payload within each logic block + if (topsortEventName === 'impressions' || topsortEventName === 'clicks') { + const placementPayload = constructPayload( + message, + mappingConfig[ConfigCategory.PLACEMENT.name], + ); + processImpressionsAndClicksUtility.processImpressionsAndClicks({ + ...commonArgs, + placementPayload, // Only pass placementPayload for impressions and clicks + }); + } else if (topsortEventName === 'purchases') { + processPurchaseEventUtility.processPurchaseEvent({ + ...commonArgs, + }); + } else { + throw new InstrumentationError(`Event not mapped: ${topsortEventName}`); + } + + return finalPayloads; +}; + +const processEvent = (message, destination, finalPayloads) => { + // Check for missing API Key or missing Advertiser ID + if (!destination.Config.apiKey) { + throw new ConfigurationError('API Key is missing. Aborting message.', 400); + } + if (!message.type) { + throw new InstrumentationError('Message Type is missing. Aborting message.', 400); + } + + const messageType = message.type.toLowerCase(); + + // Handle 'track' event type + if (messageType !== 'track') { + throw new InstrumentationError('Only "track" events are supported. Dropping event.', 400); + } + + processTopsortEvents(message, destination, finalPayloads); +}; + +// Process function that is called per event +const process = (event) => { + const finalPayloads = { + impressions: [], + clicks: [], + purchases: [], + }; + + processEvent(event.message, event.destination, finalPayloads); + + const response = defaultRequestConfig(); + const { apiKey } = event.destination.Config; + + response.method = defaultPostRequestConfig.requestMethod; + response.body.JSON = finalPayloads; + response.headers = { + 'content-type': JSON_MIME_TYPE, + Authorization: `Bearer ${apiKey}`, + }; + + response.endpoint = ENDPOINT; + + return response; +}; + +// Router destination handler to process a batch of events +const processRouterDest = async (inputs, reqMetadata) => { + const finalPayloads = { + impressions: [], + clicks: [], + purchases: [], + }; + + const failureResponses = []; + const successMetadatas = []; + + inputs.forEach((input) => { + try { + // Process the event + processEvent(input.message, input.destination, finalPayloads); + // Add to successMetadatas array + successMetadatas.push(input.metadata); + } catch (error) { + // Handle error and store the error details + const failureResponse = handleRtTfSingleEventError(input, error, reqMetadata); + failureResponses.push(failureResponse); + } + }); + + const response = defaultRequestConfig(); + const { destination } = inputs[0]; + const { apiKey } = destination.Config; + + response.method = defaultPostRequestConfig.requestMethod; + response.body.JSON = finalPayloads; + response.headers = { + 'content-type': JSON_MIME_TYPE, + Authorization: `Bearer ${apiKey}`, + }; + + response.endpoint = ENDPOINT; + + const successResponses = getSuccessRespEvents(response, successMetadatas, destination, true); + + return [successResponses, ...failureResponses]; +}; + +module.exports = { process, processRouterDest }; diff --git a/src/v0/destinations/topsort/utils.js b/src/v0/destinations/topsort/utils.js new file mode 100644 index 0000000000..ca9edfbcea --- /dev/null +++ b/src/v0/destinations/topsort/utils.js @@ -0,0 +1,53 @@ +const { ConfigurationError } = require('@rudderstack/integrations-lib'); +const { constructPayload } = require('../../util'); + +// Function to check if a product array is valid +const isProductArrayValid = (event, properties) => + Array.isArray(properties?.products) && properties?.products.length > 0; + +// Function to construct item payloads for each product +const getItemPayloads = (products, mappingConfigs) => + products.map((product) => constructPayload(product, mappingConfigs)); + +// Function to add the structured event data to the final payloads array +const addFinalPayload = (eventData, finalPayloads) => { + switch (eventData.event) { + case 'impressions': + finalPayloads.impressions.push(eventData.topsortPayload); + break; + case 'clicks': + finalPayloads.clicks.push(eventData.topsortPayload); + break; + case 'purchases': + finalPayloads.purchases.push(eventData.topsortPayload); + break; + default: + throw new ConfigurationError('Invalid event mapping'); + } +}; + +// Function to retrieve mapped event name from Topsort event mappings. +const getMappedEventName = (parsedTopsortEventMappings, event) => { + const eventName = event.toLowerCase(); + + const mappedEventNames = parsedTopsortEventMappings[eventName]; + + // Check if mapping exists + if (!mappedEventNames) { + throw new ConfigurationError(`Event '${eventName}' not found in Topsort event mappings`); + } + + // If there are multiple mappings, pick the first one or apply your logic + if (Array.isArray(mappedEventNames)) { + return mappedEventNames[0]; // Return the first mapping + } + + return mappedEventNames; // Return the single mapping if not an array +}; + +module.exports = { + isProductArrayValid, + getItemPayloads, + addFinalPayload, + getMappedEventName, +}; diff --git a/src/v0/util/facebookUtils/networkHandler.js b/src/v0/util/facebookUtils/networkHandler.js index fbb7899efe..46ac59a07a 100644 --- a/src/v0/util/facebookUtils/networkHandler.js +++ b/src/v0/util/facebookUtils/networkHandler.js @@ -85,7 +85,10 @@ const errorDetailsMap = { "Object with ID 'PIXEL_ID' / 'DATASET_ID' / 'AUDIENCE_ID' does not exist, cannot be loaded due to missing permissions, or does not support this operation", ) .build(), - default: new ErrorDetailsExtractorBuilder().setStatus(400).setMessageField('message').build(), + default: new ErrorDetailsExtractorBuilder() + .setStatus(400) + .setMessageField('error_user_msg') + .build(), }, 1: { // An unknown error occurred. @@ -107,9 +110,7 @@ const errorDetailsMap = { .setStat({ [TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH, }) - .setMessage( - 'The session has been invalidated because the user changed their password or Facebook has changed the session for security reasons', - ) + .setMessageField('error_user_msg') .build(), 463: new ErrorDetailsExtractorBuilder() @@ -117,56 +118,56 @@ const errorDetailsMap = { .setStat({ [TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH, }) - .setMessageField('message') + .setMessageField('error_user_msg') .build(), default: new ErrorDetailsExtractorBuilder() .setStatus(400) .setStat({ [TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH, }) - .setMessage('Invalid OAuth 2.0 access token') + .setMessageField('error_user_msg') .build(), }, 3: { default: new ErrorDetailsExtractorBuilder() .setStatus(400) - .setMessage('Capability or permissions issue.') + .setMessageField('error_user_msg') .build(), }, 2: { default: new ErrorDetailsExtractorBuilder() .setStatus(500) - .setMessage('Temporary issue due to downtime.') + .setMessageField('error_user_msg') .build(), }, 341: { default: new ErrorDetailsExtractorBuilder() .setStatus(500) - .setMessage('Application limit reached: Temporary issue due to downtime or throttling') + .setMessageField('error_user_msg') .build(), }, 368: { default: new ErrorDetailsExtractorBuilder() .setStatus(500) - .setMessage('Temporarily blocked for policies violations.') + .setMessageField('error_user_msg') .build(), }, 5000: { default: new ErrorDetailsExtractorBuilder() .setStatus(500) - .setMessage('Unknown Error Code') + .setMessageField('error_user_msg') .build(), }, 4: { default: new ErrorDetailsExtractorBuilder() .setStatus(429) - .setMessage('API Too Many Calls') + .setMessageField('error_user_msg') .build(), }, 17: { default: new ErrorDetailsExtractorBuilder() .setStatus(429) - .setMessage('API User Too Many Calls') + .setMessageField('error_user_msg') .build(), }, // facebook custom audience related error codes @@ -176,9 +177,7 @@ const errorDetailsMap = { 294: { default: new ErrorDetailsExtractorBuilder() .setStatus(400) - .setMessage( - 'Missing permission. Please make sure you have ads_management permission and the application is included in the allowlist', - ) + .setMessageField('error_user_msg') .build(), }, 1487301: { @@ -214,7 +213,10 @@ const errorDetailsMap = { .build(), }, 200: { - default: new ErrorDetailsExtractorBuilder().setStatus(403).setMessageField('message').build(), + default: new ErrorDetailsExtractorBuilder() + .setStatus(403) + .setMessageField('error_user_msg') + .build(), }, 21009: { default: new ErrorDetailsExtractorBuilder().setStatus(500).setMessageField('message').build(), @@ -236,9 +238,11 @@ const getStatus = (error) => { const isErrorDetailEmpty = isEmpty(errorDetail); if (isErrorDetailEmpty) { // Unhandled error response + const errorMessage = get(error?.error || error, 'error_user_msg'); return { status: errorStatus, stats: { [TAG_NAMES.META]: METADATA.UNHANDLED_STATUS_CODE }, + errorMessage: errorMessage || JSON.stringify(error), }; } errorStatus = errorDetail.status; diff --git a/src/v0/util/index.js b/src/v0/util/index.js index 1676498fdb..0f9abfb040 100644 --- a/src/v0/util/index.js +++ b/src/v0/util/index.js @@ -16,6 +16,7 @@ const uaParser = require('ua-parser-js'); const moment = require('moment-timezone'); const sha256 = require('sha256'); const crypto = require('crypto'); +const { v5 } = require('uuid'); const { InstrumentationError, BaseError, @@ -969,6 +970,7 @@ const handleMetadataForValue = (value, metadata, destKey, integrationsObj = null strictMultiMap, validateTimestamp, allowedKeyCheck, + toArray, } = metadata; // if value is null and defaultValue is supplied - use that @@ -1036,6 +1038,13 @@ const handleMetadataForValue = (value, metadata, destKey, integrationsObj = null } } + if (toArray) { + if (Array.isArray(formattedVal)) { + return formattedVal; + } + return [formattedVal]; + } + return formattedVal; }; @@ -2330,6 +2339,29 @@ const isEventSentByVDMV1Flow = (event) => event?.message?.context?.mappedToDesti const isEventSentByVDMV2Flow = (event) => event?.connection?.config?.destination?.schemaVersion === VDM_V2_SCHEMA_VERSION; + +const convertToUuid = (input) => { + const NAMESPACE = v5.DNS; + + if (!isDefinedAndNotNull(input)) { + throw new InstrumentationError('Input is undefined or null.'); + } + + try { + // Stringify and trim the input + const trimmedInput = String(input).trim(); + + // Check for empty input after trimming + if (!trimmedInput) { + throw new InstrumentationError('Input is empty or invalid.'); + } + // Generate and return UUID + return v5(trimmedInput, NAMESPACE); + } catch (error) { + const errorMessage = `Failed to transform input to uuid: ${error.message}`; + throw new InstrumentationError(errorMessage); + } +}; // ======================================================================== // EXPORTS // ======================================================================== @@ -2456,4 +2488,5 @@ module.exports = { getRelativePathFromURL, removeEmptyKey, isAxiosError, + convertToUuid, }; diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js index 0b05b6f2d6..cfdfefddee 100644 --- a/src/v0/util/index.test.js +++ b/src/v0/util/index.test.js @@ -2,6 +2,7 @@ const { InstrumentationError } = require('@rudderstack/integrations-lib'); const utilities = require('.'); const { getFuncTestData } = require('../../../test/testHelper'); const { FilteredEventsError } = require('./errorTypes'); +const { v5 } = require('uuid'); const { hasCircularReference, flattenJson, @@ -11,6 +12,7 @@ const { groupRouterTransformEvents, isAxiosError, removeHyphens, + convertToUuid, } = require('./index'); const exp = require('constants'); @@ -985,3 +987,65 @@ describe('removeHyphens', () => { }); }); }); + +describe('convertToUuid', () => { + const NAMESPACE = v5.DNS; + + test('should generate UUID for valid string input', () => { + const input = 'testInput'; + const expectedUuid = '7ba1e88f-acf9-5528-9c1c-0c897ed80e1e'; + const result = convertToUuid(input); + expect(result).toBe(expectedUuid); + }); + + test('should generate UUID for valid numeric input', () => { + const input = 123456; + const expectedUuid = 'a52b2702-9bcf-5701-852a-2f4edc640fe1'; + const result = convertToUuid(input); + expect(result).toBe(expectedUuid); + }); + + test('should trim spaces and generate UUID', () => { + const input = ' testInput '; + const expectedUuid = '7ba1e88f-acf9-5528-9c1c-0c897ed80e1e'; + const result = convertToUuid(input); + expect(result).toBe(expectedUuid); + }); + + test('should throw an error for empty input', () => { + const input = ''; + expect(() => convertToUuid(input)).toThrow(InstrumentationError); + expect(() => convertToUuid(input)).toThrow('Input is empty or invalid.'); + }); + + test('to throw an error for null input', () => { + const input = null; + expect(() => convertToUuid(input)).toThrow(InstrumentationError); + expect(() => convertToUuid(input)).toThrow('Input is undefined or null'); + }); + + test('to throw an error for undefined input', () => { + const input = undefined; + expect(() => convertToUuid(input)).toThrow(InstrumentationError); + expect(() => convertToUuid(input)).toThrow('Input is undefined or null'); + }); + + test('should throw an error for input that is whitespace only', () => { + const input = ' '; + expect(() => convertToUuid(input)).toThrow(InstrumentationError); + expect(() => convertToUuid(input)).toThrow('Input is empty or invalid.'); + }); + + test('should handle long string input gracefully', () => { + const input = 'a'.repeat(1000); + const expectedUuid = v5(input, NAMESPACE); + const result = convertToUuid(input); + expect(result).toBe(expectedUuid); + }); + + test('any invalid input if stringified does not throw error', () => { + const input = {}; + const result = convertToUuid(input); + expect(result).toBe('672ca00c-37f4-5d71-b8c3-6ae0848080ec'); + }); +}); diff --git a/src/v1/destinations/iterable/networkHandler.ts b/src/v1/destinations/iterable/networkHandler.ts new file mode 100644 index 0000000000..e3edb5daab --- /dev/null +++ b/src/v1/destinations/iterable/networkHandler.ts @@ -0,0 +1,33 @@ +import { prepareProxyRequest, proxyRequest } from '../../../adapters/network'; +import { processAxiosResponse } from '../../../adapters/utils/networkUtils'; +import { BULK_ENDPOINTS } from '../../../v0/destinations/iterable/config'; +import { GenericStrategy } from './strategies/generic'; +import { TrackIdentifyStrategy } from './strategies/track-identify'; +import { GenericProxyHandlerInput } from './types'; + +const strategyRegistry: { [key: string]: any } = { + [TrackIdentifyStrategy.name]: new TrackIdentifyStrategy(), + [GenericStrategy.name]: new GenericStrategy(), +}; + +const getResponseStrategy = (endpoint: string) => { + if (BULK_ENDPOINTS.some((path) => endpoint.includes(path))) { + return strategyRegistry[TrackIdentifyStrategy.name]; + } + return strategyRegistry[GenericStrategy.name]; +}; + +const responseHandler = (responseParams: GenericProxyHandlerInput) => { + const { destinationRequest } = responseParams; + const strategy = getResponseStrategy(destinationRequest.endpoint); + return strategy.handleResponse(responseParams); +}; + +function networkHandler(this: any) { + this.prepareProxy = prepareProxyRequest; + this.proxy = proxyRequest; + this.processAxiosResponse = processAxiosResponse; + this.responseHandler = responseHandler; +} + +export { networkHandler }; diff --git a/src/v1/destinations/iterable/strategies/base.ts b/src/v1/destinations/iterable/strategies/base.ts new file mode 100644 index 0000000000..dfde1e9225 --- /dev/null +++ b/src/v1/destinations/iterable/strategies/base.ts @@ -0,0 +1,22 @@ +import { isHttpStatusSuccess } from '../../../../v0/util'; +import { GenericProxyHandlerInput } from '../types'; + +// Base strategy is the base class for all strategies in Iterable destination +abstract class BaseStrategy { + handleResponse(responseParams: GenericProxyHandlerInput): void { + const { destinationResponse } = responseParams; + const { status } = destinationResponse; + + if (!isHttpStatusSuccess(status)) { + return this.handleError(responseParams); + } + + return this.handleSuccess(responseParams); + } + + abstract handleError(responseParams: GenericProxyHandlerInput): void; + + abstract handleSuccess(responseParams: any): void; +} + +export { BaseStrategy }; diff --git a/src/v1/destinations/iterable/strategies/generic.ts b/src/v1/destinations/iterable/strategies/generic.ts new file mode 100644 index 0000000000..e43eb7623b --- /dev/null +++ b/src/v1/destinations/iterable/strategies/generic.ts @@ -0,0 +1,57 @@ +import { BaseStrategy } from './base'; +import { + GenericProxyHandlerInput, + IterableBulkApiResponse, + IterableSuccessResponse, +} from '../types'; +import { ProxyMetdata } from '../../../../types'; +import { TransformerProxyError } from '../../../../v0/util/errorTypes'; +import { TAG_NAMES } from '../../../../v0/util/tags'; +import { getDynamicErrorType } from '../../../../adapters/utils/networkUtils'; + +class GenericStrategy extends BaseStrategy { + handleSuccess(responseParams: { + destinationResponse: IterableBulkApiResponse; + rudderJobMetadata: ProxyMetdata[]; + }): IterableSuccessResponse { + const { destinationResponse, rudderJobMetadata } = responseParams; + const { status } = destinationResponse; + + const responseWithIndividualEvents = rudderJobMetadata.map((metadata) => ({ + statusCode: status, + metadata, + error: 'success', + })); + + return { + status, + message: '[ITERABLE Response Handler] - Request Processed Successfully', + destinationResponse, + response: responseWithIndividualEvents, + }; + } + + handleError(responseParams: GenericProxyHandlerInput): void { + const { destinationResponse, rudderJobMetadata } = responseParams; + const { response, status } = destinationResponse; + const responseMessage = response.params || response.msg || response.message; + const errorMessage = JSON.stringify(responseMessage) || 'unknown error format'; + + const responseWithIndividualEvents = rudderJobMetadata.map((metadata) => ({ + statusCode: status, + metadata, + error: errorMessage, + })); + + throw new TransformerProxyError( + `ITERABLE: Error transformer proxy during ITERABLE response transformation. ${errorMessage}`, + status, + { [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status) }, + destinationResponse, + '', + responseWithIndividualEvents, + ); + } +} + +export { GenericStrategy }; diff --git a/src/v1/destinations/iterable/strategies/track-identify.ts b/src/v1/destinations/iterable/strategies/track-identify.ts new file mode 100644 index 0000000000..a8a0868251 --- /dev/null +++ b/src/v1/destinations/iterable/strategies/track-identify.ts @@ -0,0 +1,69 @@ +import { BaseStrategy } from './base'; +import { GenericProxyHandlerInput, IterableBulkProxyInput } from '../types'; +import { checkIfEventIsAbortableAndExtractErrorMessage } from '../utils'; +import { DeliveryJobState, DeliveryV1Response } from '../../../../types'; +import { TransformerProxyError } from '../../../../v0/util/errorTypes'; +import { getDynamicErrorType } from '../../../../adapters/utils/networkUtils'; +import { TAG_NAMES } from '../../../../v0/util/tags'; + +class TrackIdentifyStrategy extends BaseStrategy { + handleSuccess(responseParams: IterableBulkProxyInput): DeliveryV1Response { + const { destinationResponse, rudderJobMetadata, destinationRequest } = responseParams; + const { status } = destinationResponse; + const responseWithIndividualEvents: DeliveryJobState[] = []; + + const { events, users } = destinationRequest?.body.JSON || {}; + const finalData = events || users; + + if (finalData) { + finalData.forEach((event, idx) => { + const parsedOutput = { + statusCode: 200, + metadata: rudderJobMetadata[idx], + error: 'success', + }; + + const { isAbortable, errorMsg } = checkIfEventIsAbortableAndExtractErrorMessage( + event, + destinationResponse, + ); + if (isAbortable) { + parsedOutput.statusCode = 400; + parsedOutput.error = errorMsg; + } + responseWithIndividualEvents.push(parsedOutput); + }); + } + + return { + status, + message: '[ITERABLE Response Handler] - Request Processed Successfully', + destinationResponse, + response: responseWithIndividualEvents, + }; + } + + handleError(responseParams: GenericProxyHandlerInput): void { + const { destinationResponse, rudderJobMetadata } = responseParams; + const { response, status } = destinationResponse; + const responseMessage = response.params || response.msg || response.message; + const errorMessage = JSON.stringify(responseMessage) || 'unknown error format'; + + const responseWithIndividualEvents = rudderJobMetadata.map((metadata) => ({ + statusCode: status, + metadata, + error: errorMessage, + })); + + throw new TransformerProxyError( + `ITERABLE: Error transformer proxy during ITERABLE response transformation. ${errorMessage}`, + status, + { [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status) }, + destinationResponse, + '', + responseWithIndividualEvents, + ); + } +} + +export { TrackIdentifyStrategy }; diff --git a/src/v1/destinations/iterable/types.ts b/src/v1/destinations/iterable/types.ts new file mode 100644 index 0000000000..f0875494ed --- /dev/null +++ b/src/v1/destinations/iterable/types.ts @@ -0,0 +1,69 @@ +import { ProxyMetdata, ProxyV1Request } from '../../../types'; + +type FailedUpdates = { + invalidEmails?: string[]; + invalidUserIds?: string[]; + notFoundEmails?: string[]; + notFoundUserIds?: string[]; + invalidDataEmails?: string[]; + invalidDataUserIds?: string[]; + conflictEmails?: string[]; + conflictUserIds?: string[]; + forgottenEmails?: string[]; + forgottenUserIds?: string[]; +}; + +export type GeneralApiResponse = { + msg?: string; + code?: string; + params?: Record; + successCount?: number; + failCount?: number; + invalidEmails?: string[]; + invalidUserIds?: string[]; + filteredOutFields?: string[]; + createdFields?: string[]; + disallowedEventNames?: string[]; + failedUpdates?: FailedUpdates; +}; + +export type IterableBulkApiResponse = { + status: number; + response: GeneralApiResponse; +}; + +type IterableBulkRequestBody = { + events?: any[]; + users?: any[]; +}; + +export type IterableBulkProxyInput = { + destinationResponse: IterableBulkApiResponse; + rudderJobMetadata: ProxyMetdata[]; + destType: string; + destinationRequest?: { + body: { + JSON: IterableBulkRequestBody; + }; + }; +}; + +export type GenericProxyHandlerInput = { + destinationResponse: any; + rudderJobMetadata: ProxyMetdata[]; + destType: string; + destinationRequest: ProxyV1Request; +}; + +export type Response = { + statusCode: number; + metadata: any; + error: string; +}; + +export type IterableSuccessResponse = { + status: number; + message: string; + destinationResponse: IterableBulkApiResponse; + response: Response[]; +}; diff --git a/src/v1/destinations/iterable/utils.test.ts b/src/v1/destinations/iterable/utils.test.ts new file mode 100644 index 0000000000..a556e3704f --- /dev/null +++ b/src/v1/destinations/iterable/utils.test.ts @@ -0,0 +1,184 @@ +import { checkIfEventIsAbortableAndExtractErrorMessage } from './utils'; +describe('checkIfEventIsAbortableAndExtractErrorMessage', () => { + // Returns non-abortable and empty error message when failCount is 0 + it('should return non-abortable and empty error message when failCount is 0', () => { + const event = { + email: 'test@example.com', + userId: 'user123', + eventName: 'testEvent', + }; + const destinationResponse = { + status: 200, + response: { + failCount: 0, + }, + }; + + const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse); + expect(result).toEqual({ isAbortable: false, errorMsg: '' }); + }); + + // Handles undefined or null event fields gracefully + it('should handle undefined or null event fields gracefully', () => { + const event = { + email: null, + userId: undefined, + eventName: 'testEvent', + }; + const destinationResponse = { + status: 200, + response: { + failCount: 1, + invalidEmails: ['test@example.com'], + }, + }; + const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse); + expect(result).toEqual({ isAbortable: false, errorMsg: '' }); + }); + + // Handles events with all expected fields present + it('should handle events with all expected fields present and return non-abortable when no match', () => { + const event = { + email: 'test@example.com', + userId: 'user123', + eventName: 'purchase', + id: 'event123', + createdAt: '2023-10-01T00:00:00Z', + campaignId: 'campaign123', + templateId: 'template123', + createNewFields: true, + dataFields: { field1: 'value1' }, + }; + + const destinationResponse = { + status: 200, + response: { + failCount: 1, + invalidEmails: ['another@example.com'], + }, + }; + + const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse); + + expect(result.isAbortable).toBe(false); + expect(result.errorMsg).toBe(''); + }); + + // Returns appropriate error message for abortable event + + it('should find the right value for which it should fail and passes otherwise for emails', () => { + const event = { + email: 'test', + userId: 'user123', + eventName: 'purchase', + dataFields: { customField1: 'value1', customField2: 'value2' }, + }; + const destinationResponse = { + status: 200, + response: { + failCount: 1, + failedUpdates: { + invalidEmails: ['test'], + }, + }, + }; + const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse); + expect(result).toEqual({ + isAbortable: true, + errorMsg: 'email error:"test" in "failedUpdates.invalidEmails".', + }); + }); + + it('should find the right value for which it should fail', () => { + const event = { + email: 'test@gmail.com', + userId: 'user123', + eventName: 'purchase', + dataFields: { customField1: 'test', customField2: 'value2' }, + }; + const destinationResponse = { + status: 200, + response: { + failCount: 1, + failedUpdates: { + invalidEmails: ['test'], + }, + }, + }; + const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse); + expect(result.isAbortable).toBe(false); + expect(result.errorMsg).toBe(''); + }); + + it('should find all the matching paths it failed for and curate error message', () => { + const event = { + email: 'test', + userId: 'user123', + eventName: 'purchase', + dataFields: { customField1: 'test', customField2: 'value2' }, + }; + const destinationResponse = { + status: 200, + response: { + failCount: 1, + invalidEmails: ['test'], + failedUpdates: { + invalidEmails: ['test'], + conflictEmails: ['test'], + }, + }, + }; + const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse); + expect(result.isAbortable).toBe(true); + expect(result.errorMsg).toBe( + 'email error:"test" in "invalidEmails,failedUpdates.invalidEmails,failedUpdates.conflictEmails".', + ); + }); + + it('should find the right value for which it should fail and passes otherwise for userIds', () => { + const event = { + email: 'test', + userId: 'user123', + eventName: 'purchase', + dataFields: { customField1: 'value1', customField2: 'value2' }, + }; + const destinationResponse = { + status: 200, + response: { + failCount: 1, + failedUpdates: { + invalidUserIds: ['user123'], + }, + }, + }; + const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse); + expect(result).toEqual({ + isAbortable: true, + errorMsg: 'userId error:"user123" in "failedUpdates.invalidUserIds".', + }); + }); + + it('should find the right value for which it should fail and passes otherwise for disallowed events', () => { + const event = { + email: 'test', + userId: 'user123', + eventName: 'purchase', + dataFields: { customField1: 'value1', customField2: 'value2' }, + }; + const destinationResponse = { + status: 200, + response: { + failCount: 1, + disallowedEventNames: ['purchase'], + failedUpdates: { + invalidUserIds: [], + }, + }, + }; + const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse); + expect(result).toEqual({ + isAbortable: true, + errorMsg: 'eventName error:"purchase" in "disallowedEventNames".', + }); + }); +}); diff --git a/src/v1/destinations/iterable/utils.ts b/src/v1/destinations/iterable/utils.ts new file mode 100644 index 0000000000..90985a8e94 --- /dev/null +++ b/src/v1/destinations/iterable/utils.ts @@ -0,0 +1,92 @@ +import { + ITERABLE_RESPONSE_EMAIL_PATHS, + ITERABLE_RESPONSE_USER_ID_PATHS, +} from '../../../v0/destinations/iterable/config'; +import { IterableBulkApiResponse } from './types'; + +const get = require('get-value'); + +/** + * Checks if a value is present in a response array based on a given path. + * @param {Object} response - The response object to search within. + * @param {string} path - The path to the response array. + * @param {any} value - The value to check for in the array. + * @returns {boolean} - True if the value is in the array, otherwise false. + */ +const isValueInResponseArray = (destinationResponse, path, value) => { + const respArr = get(destinationResponse, path); + return Array.isArray(respArr) && respArr.includes(value); +}; + +/** + * Determines if an event should be aborted based on the response from a destination + * and extracts an error message if applicable. + * ref: + * 1) https://api.iterable.com/api/docs#users_updateEmail + * 2) https://api.iterable.com/api/docs#events_track + * 3) https://api.iterable.com/api/docs#users_bulkUpdateUser + * 4) https://api.iterable.com/api/docs#events_trackBulk + * 5) https://api.iterable.com/api/docs#catalogs_bulkUpdateCatalogItems + * 6) https://api.iterable.com/api/docs#users_registerDeviceToken + * 7) https://api.iterable.com/api/docs#users_registerBrowserToken + * 8) https://api.iterable.com/api/docs#commerce_trackPurchase + * 9) https://api.iterable.com/api/docs#commerce_updateCart + * + * @param {Object} event - The event object containing various event properties. + * @param {Object} destinationResponse - The response object from the destination. + * @returns {Object} An object containing a boolean `isAbortable` indicating if the event + * should be aborted, and an `errorMsg` string with the error message if applicable. + */ + +export const checkIfEventIsAbortableAndExtractErrorMessage = ( + event: any, + destinationResponse: IterableBulkApiResponse, +): { + isAbortable: boolean; + errorMsg: string; +} => { + const { failCount } = destinationResponse.response; + + if (failCount === 0) { + return { isAbortable: false, errorMsg: '' }; + } + + const eventValues = { + email: event.email, + userId: event.userId, + eventName: event.eventName, + }; + + let errorMsg = ''; + const userIdMatchPath = ITERABLE_RESPONSE_USER_ID_PATHS.filter((userIdPath) => + isValueInResponseArray(destinationResponse.response, userIdPath, eventValues.userId), + ); + if (userIdMatchPath.length > 0) { + errorMsg += `userId error:"${eventValues.userId}" in "${userIdMatchPath}".`; + } + + const emailMatchPath = ITERABLE_RESPONSE_EMAIL_PATHS.filter((emailPath) => + isValueInResponseArray(destinationResponse.response, emailPath, eventValues.email), + ); + + if (emailMatchPath.length > 0) { + errorMsg += `email error:"${eventValues.email}" in "${emailMatchPath}".`; + } + + const eventNameMatchPath = ['disallowedEventNames'].filter((eventNamePath) => + isValueInResponseArray(destinationResponse.response, eventNamePath, eventValues.eventName), + ); + + if (eventNameMatchPath.length > 0) { + errorMsg += `eventName error:"${eventValues.eventName}" in "${eventNameMatchPath}".`; + } + + if (errorMsg) { + return { + isAbortable: true, + errorMsg, + }; + } + + return { isAbortable: false, errorMsg: '' }; +}; diff --git a/src/v0/destinations/reddit/networkHandler.js b/src/v1/destinations/reddit/networkHandler.js similarity index 52% rename from src/v0/destinations/reddit/networkHandler.js rename to src/v1/destinations/reddit/networkHandler.js index 7c9b32eaa4..608408a7fb 100644 --- a/src/v0/destinations/reddit/networkHandler.js +++ b/src/v1/destinations/reddit/networkHandler.js @@ -1,16 +1,31 @@ const { RetryableError, TAG_NAMES, NetworkError } = require('@rudderstack/integrations-lib'); const isString = require('lodash/isString'); const { prepareProxyRequest, proxyRequest } = require('../../../adapters/network'); -const { isHttpStatusSuccess } = require('../../util/index'); +const { isHttpStatusSuccess } = require('../../../v0/util/index'); const { REFRESH_TOKEN } = require('../../../adapters/networkhandler/authConstants'); const { processAxiosResponse, getDynamicErrorType, } = require('../../../adapters/utils/networkUtils'); +const { TransformerProxyError } = require('../../../v0/util/errorTypes'); -const redditRespHandler = (destResponse) => { - const { status, response } = destResponse; +const populateResponseWithDontBatch = (rudderJobMetadata, response) => { + const errorMessage = JSON.stringify(response); + return rudderJobMetadata.map((metadata) => { + // eslint-disable-next-line no-param-reassign + metadata.dontBatch = true; + return { + statusCode: 500, + metadata, + error: errorMessage, + }; + }); +}; + +const redditRespHandler = (responseParams) => { + const { destinationResponse, rudderJobMetadata } = responseParams; + const { status, response } = destinationResponse; // to handle the case when authorization-token is invalid if (status === 401) { @@ -28,26 +43,41 @@ const redditRespHandler = (destResponse) => { throw new RetryableError( `${errorMessage} during reddit response transformation`, status, - destResponse, + destinationResponse, authErrorCategory, ); } + if (status === 400 && Array.isArray(rudderJobMetadata) && rudderJobMetadata.length > 1) { + // sending back 500 for retry only when events came in a batch + const responseWithDontBatch = populateResponseWithDontBatch(rudderJobMetadata, response); + throw new TransformerProxyError( + `REDDIT: Error transformer proxy during REDDIT response transformation`, + 500, + { + [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(500), + }, + destinationResponse, + '', + responseWithDontBatch, + ); + } + throw new NetworkError( `${JSON.stringify(response)} during reddit response transformation`, status, { [TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status), }, - destResponse, + destinationResponse, ); }; const responseHandler = (responseParams) => { - const { destinationResponse } = responseParams; + const { destinationResponse, rudderJobMetadata } = responseParams; const message = `Request Processed Successfully`; const { status } = destinationResponse; if (!isHttpStatusSuccess(status)) { // if error, successfully return status, message and original destination response - redditRespHandler(destinationResponse); + redditRespHandler(responseParams); } const { response } = destinationResponse; const errorMessage = @@ -55,20 +85,23 @@ const responseHandler = (responseParams) => { ? response?.invalid_events[0]?.error_message : null; const destResp = errorMessage || destinationResponse; + const responseWithIndividualEvents = rudderJobMetadata.map((metadata) => ({ + statusCode: 200, + metadata, + error: 'success', + })); // Mostly any error will not have a status of 2xx return { status, message, - destResp, + destinationResponse: destResp, + response: responseWithIndividualEvents, }; }; -// eslint-disable-next-line @typescript-eslint/naming-convention -class networkHandler { - constructor() { - this.responseHandler = responseHandler; - this.proxy = proxyRequest; - this.prepareProxy = prepareProxyRequest; - this.processAxiosResponse = processAxiosResponse; - } +function networkHandler() { + this.proxy = proxyRequest; + this.processAxiosResponse = processAxiosResponse; + this.prepareProxy = prepareProxyRequest; + this.responseHandler = responseHandler; } module.exports = { networkHandler }; diff --git a/src/v1/sources/shopify/config.js b/src/v1/sources/shopify/config.js index 5d88353d60..9cb11e471f 100644 --- a/src/v1/sources/shopify/config.js +++ b/src/v1/sources/shopify/config.js @@ -31,10 +31,17 @@ const PIXEL_EVENT_MAPPING = { checkout_address_info_submitted: 'Checkout Address Info Submitted', checkout_contact_info_submitted: 'Checkout Contact Info Submitted', checkout_shipping_info_submitted: 'Checkout Shipping Info Submitted', - payment_info_submitted: 'Payment Info Submitted', + payment_info_submitted: 'Payment Info Entered', search_submitted: 'Search Submitted', }; +const RUDDER_ECOM_MAP = { + checkouts_create: 'Checkout Started - Webhook', + checkouts_update: 'Checkout Updated', + orders_updated: 'Order Updated', + orders_create: 'Order Created', +}; + const contextualFieldMappingJSON = JSON.parse( fs.readFileSync(path.resolve(__dirname, 'pixelEventsMappings', 'contextualFieldMapping.json')), ); @@ -63,6 +70,14 @@ const checkoutStartedCompletedEventMappingJSON = JSON.parse( ), ); +const productMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'webhookEventsMapping', 'productMapping.json')), +); + +const lineItemsMappingJSON = JSON.parse( + fs.readFileSync(path.resolve(__dirname, 'webhookEventsMapping', 'lineItemsMapping.json')), +); + const pixelEventToCartTokenLocationMapping = { cart_viewed: 'properties.cart_id', checkout_address_info_submitted: commonCartTokenLocation, @@ -79,6 +94,7 @@ module.exports = { INTEGERATION, PIXEL_EVENT_TOPICS, PIXEL_EVENT_MAPPING, + RUDDER_ECOM_MAP, contextualFieldMappingJSON, cartViewedEventMappingJSON, productListViewedEventMappingJSON, @@ -86,4 +102,6 @@ module.exports = { productToCartEventMappingJSON, checkoutStartedCompletedEventMappingJSON, pixelEventToCartTokenLocationMapping, + productMappingJSON, + lineItemsMappingJSON, }; diff --git a/src/v1/sources/shopify/webhookEventsMapping/identifyMapping.json b/src/v1/sources/shopify/webhookEventsMapping/identifyMapping.json new file mode 100644 index 0000000000..0367267502 --- /dev/null +++ b/src/v1/sources/shopify/webhookEventsMapping/identifyMapping.json @@ -0,0 +1,112 @@ +[ + { + "sourceKeys": "id", + "destKeys": "userId" + }, + { + "sourceKeys": "email", + "destKeys": "traits.email" + }, + + { + "sourceKeys": "first_name", + "destKeys": "traits.firstName" + }, + + { + "sourceKeys": "last_name", + "destKeys": "traits.lastName" + }, + + { + "sourceKeys": "phone", + "destKeys": "traits.phone" + }, + + { + "sourceKeys": "addresses", + "destKeys": "traits.addressList" + }, + + { + "sourceKeys": "default_address", + "destKeys": "traits.address" + }, + + { + "sourceKeys": "shipping_address", + "destKeys": "traits.shippingAddress" + }, + + { + "sourceKeys": "billing_address", + "destKeys": "traits.billingAddress" + }, + + { + "sourceKeys": "accepts_marketing", + "destKeys": "traits.acceptsMarketing" + }, + + { + "sourceKeys": "orders_count", + "destKeys": "traits.orderCount" + }, + + { + "sourceKeys": "state", + "destKeys": "traits.state" + }, + { + "sourceKeys": "total_spent", + "destKeys": "traits.totalSpent" + }, + { + "sourceKeys": "note", + "destKeys": "traits.note" + }, + { + "sourceKeys": "verified_email", + "destKeys": "traits.verifiedEmail" + }, + { + "sourceKeys": "multipass_identifier", + "destKeys": "traits.multipassIdentifier" + }, + { + "sourceKeys": "tax_exempt", + "destKeys": "traits.taxExempt" + }, + { + "sourceKeys": "tags", + "destKeys": "traits.tags" + }, + { + "sourceKeys": "last_order_name", + "destKeys": "traits.lastOrderName" + }, + { + "sourceKeys": "currency", + "destKeys": "traits.currency" + }, + { + "sourceKeys": "marketing_opt_in_level", + "destKeys": "traits.marketingOptInLevel" + }, + { + "sourceKeys": "tax_exemptions", + "destKeys": "traits.taxExemptions" + }, + { + "sourceKeys": "sms_marketing_consent", + "destKeys": "traits.smsMarketingConsent" + }, + { + "sourceKeys": "admin_graphql_api_id", + "destKeys": "traits.adminGraphqlApiId" + }, + { + "sourceKeys": "accepts_marketing_updated_at", + "destKeys": "traits.acceptsMarketingUpdatedAt" + } +] diff --git a/src/v1/sources/shopify/webhookEventsMapping/lineItemsMapping.json b/src/v1/sources/shopify/webhookEventsMapping/lineItemsMapping.json new file mode 100644 index 0000000000..3bcef331b0 --- /dev/null +++ b/src/v1/sources/shopify/webhookEventsMapping/lineItemsMapping.json @@ -0,0 +1,32 @@ +[ + { + "sourceKeys": "product_id", + "destKey": "product_id", + "metadata": { + "type": "toString" + } + }, + { + "sourceKeys": "sku", + "destKey": "sku" + }, + { + "sourceKeys": "name", + "destKey": "title" + }, + { + "sourceKeys": "price", + "destKey": "price", + "metadata": { + "type": "toNumber" + } + }, + { + "sourceKeys": "vendor", + "destKey": "brand" + }, + { + "sourceKeys": "quantity", + "destKey": "quantity" + } +] diff --git a/src/v1/sources/shopify/webhookEventsMapping/mapping.json b/src/v1/sources/shopify/webhookEventsMapping/mapping.json new file mode 100644 index 0000000000..6c268ef13c --- /dev/null +++ b/src/v1/sources/shopify/webhookEventsMapping/mapping.json @@ -0,0 +1,10 @@ +[ + { + "sourceKeys": "line_items", + "destKeys": "products" + }, + { + "sourceKeys": "id", + "destKeys": "properties.order_id" + } +] diff --git a/src/v1/sources/shopify/webhookEventsMapping/productMapping.json b/src/v1/sources/shopify/webhookEventsMapping/productMapping.json new file mode 100644 index 0000000000..e78ed50dfc --- /dev/null +++ b/src/v1/sources/shopify/webhookEventsMapping/productMapping.json @@ -0,0 +1,24 @@ +[ + { + "sourceKeys": "id", + "destKey": "order_id", + "metadata": { + "type": "toString" + } + }, + { + "sourceKeys": "total_price", + "destKey": "value" + }, + { + "sourceKeys": "total_tax", + "destKey": "tax", + "metadata": { + "type": "toNumber" + } + }, + { + "sourceKeys": "currency", + "destKey": "currency" + } +] diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js index c31bc74bf1..d0221f6950 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideTransform.js @@ -1,18 +1,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ const lodash = require('lodash'); const get = require('get-value'); -// const { RedisError } = require('@rudderstack/integrations-lib'); const stats = require('../../../../util/stats'); -const { - getShopifyTopic, - // createPropertiesForEcomEvent, - extractEmailFromPayload, - getAnonymousIdAndSessionId, - // getHashLineItems, -} = require('../../../../v0/sources/shopify/util'); -// const logger = require('../../../logger'); +const { getShopifyTopic, extractEmailFromPayload } = require('../../../../v0/sources/shopify/util'); const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../../../v0/util'); -// const { RedisDB } = require('../../../util/redis/redisConnector'); const Message = require('../../../../v0/sources/message'); const { EventType } = require('../../../../constants'); const { @@ -20,14 +11,15 @@ const { MAPPING_CATEGORIES, IDENTIFY_TOPICS, ECOM_TOPICS, - RUDDER_ECOM_MAP, SUPPORTED_TRACK_EVENTS, SHOPIFY_TRACK_MAP, lineItemsMappingJSON, } = require('../../../../v0/sources/shopify/config'); +const { RUDDER_ECOM_MAP } = require('../config'); const { createPropertiesForEcomEventFromWebhook, getProductsFromLineItems, + getAnonymousIdFromAttributes, } = require('./serverSideUtlis'); const NO_OPERATION_SUCCESS = { @@ -54,7 +46,7 @@ const ecomPayloadBuilder = (event, shopifyTopic) => { message.setEventType(EventType.TRACK); message.setEventName(RUDDER_ECOM_MAP[shopifyTopic]); - const properties = createPropertiesForEcomEventFromWebhook(event); + const properties = createPropertiesForEcomEventFromWebhook(event, shopifyTopic); message.properties = removeUndefinedAndNullValues(properties); // Map Customer details if present const customerDetails = get(event, 'customer'); @@ -128,12 +120,9 @@ const processEvent = async (inputEvent, metricMetadata) => { message.setProperty('traits.email', email); } } + // attach anonymousId if the event is track event using note_attributes if (message.type !== EventType.IDENTIFY) { - const { anonymousId } = await getAnonymousIdAndSessionId( - message, - { shopifyTopic, ...metricMetadata }, - null, - ); + const anonymousId = getAnonymousIdFromAttributes(event); if (isDefinedAndNotNull(anonymousId)) { message.setProperty('anonymousId', anonymousId); } diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js index a611d1d8dc..b94ec9c3dd 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtils.test.js @@ -1,6 +1,7 @@ const { getProductsFromLineItems, createPropertiesForEcomEventFromWebhook, + getAnonymousIdFromAttributes, } = require('./serverSideUtlis'); const { constructPayload } = require('../../../../v0/util'); @@ -97,11 +98,11 @@ describe('serverSideUtils.js', () => { const result = createPropertiesForEcomEventFromWebhook(message); expect(result).toEqual({ products: [ - { brand: 'Hydrogen Vendor', price: '600.00', product_id: 7234590408818, quantity: 1 }, + { brand: 'Hydrogen Vendor', price: 600.0, product_id: '7234590408818', quantity: 1 }, { brand: 'Hydrogen Vendor', - price: '600.00', - product_id: 7234590408817, + price: 600.0, + product_id: '7234590408817', quantity: 1, title: 'The Collection Snowboard: Nitrogen', }, @@ -109,4 +110,21 @@ describe('serverSideUtils.js', () => { }); }); }); + + describe('getAnonymousIdFromAttributes', () => { + // Handles empty note_attributes array gracefully + it('should return null when note_attributes is an empty array', async () => { + const event = { note_attributes: [] }; + const result = await getAnonymousIdFromAttributes(event); + expect(result).toBeNull(); + }); + + it('get anonymousId from noteAttributes', async () => { + const event = { + note_attributes: [{ name: 'rudderAnonymousId', value: '123456' }], + }; + const result = await getAnonymousIdFromAttributes(event); + expect(result).toEqual('123456'); + }); + }); }); diff --git a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js index eed03de71f..df33d7a347 100644 --- a/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js +++ b/src/v1/sources/shopify/webhookTransformations/serverSideUtlis.js @@ -1,9 +1,6 @@ +const { isDefinedAndNotNull } = require('@rudderstack/integrations-lib'); const { constructPayload } = require('../../../../v0/util'); - -const { - lineItemsMappingJSON, - productMappingJSON, -} = require('../../../../v0/sources/shopify/config'); +const { lineItemsMappingJSON, productMappingJSON } = require('../config'); /** * Returns an array of products from the lineItems array received from the webhook event @@ -17,7 +14,6 @@ const getProductsFromLineItems = (lineItems, mapping) => { } const products = []; lineItems.forEach((lineItem) => { - // const product = constructPayload(lineItem, lineItemsMappingJSON); const product = constructPayload(lineItem, mapping); products.push(product); }); @@ -29,17 +25,37 @@ const getProductsFromLineItems = (lineItems, mapping) => { * @param {Object} message * @returns {Object} properties */ -const createPropertiesForEcomEventFromWebhook = (message) => { +const createPropertiesForEcomEventFromWebhook = (message, shopifyTopic) => { const { line_items: lineItems } = message; if (!lineItems || lineItems.length === 0) { return []; } const mappedPayload = constructPayload(message, productMappingJSON); + if (shopifyTopic === 'orders_updated' || shopifyTopic === 'checkouts_update') { + delete mappedPayload.value; + } mappedPayload.products = getProductsFromLineItems(lineItems, lineItemsMappingJSON); return mappedPayload; }; +/** + * Returns the anonymousId from the noteAttributes array in the webhook event + * @param {Object} event + * @returns {String} anonymousId + */ +const getAnonymousIdFromAttributes = (event) => { + if (!isDefinedAndNotNull(event) || !isDefinedAndNotNull(event.note_attributes)) { + return null; // Return early if event or note_attributes is invalid + } + + const noteAttributes = event.note_attributes; + const rudderAnonymousIdObject = noteAttributes.find((attr) => attr.name === 'rudderAnonymousId'); + + return rudderAnonymousIdObject ? rudderAnonymousIdObject.value : null; +}; + module.exports = { createPropertiesForEcomEventFromWebhook, getProductsFromLineItems, + getAnonymousIdFromAttributes, }; diff --git a/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js index 0c1007f311..46ae59e0cf 100644 --- a/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js +++ b/src/v1/sources/shopify/webpixelTransformations/pixelUtils.js @@ -14,7 +14,7 @@ const { function getNestedValue(object, path) { const keys = path.split('.'); - return keys.reduce((nestedObject, key) => nestedObject && nestedObject[key], object); + return keys.reduce((nestedObject, key) => nestedObject?.[key], object); } function setNestedValue(object, path, value) { diff --git a/src/warehouse/config/ReservedKeywords.json b/src/warehouse/config/ReservedKeywords.json index 3c383d24bf..53b8738e1d 100644 --- a/src/warehouse/config/ReservedKeywords.json +++ b/src/warehouse/config/ReservedKeywords.json @@ -1519,6 +1519,99 @@ "WHERE": true, "WITH": true }, + "SNOWPIPE_STREAMING": { + "ACCOUNT": true, + "ALL": true, + "ALTER": true, + "AND": true, + "ANY": true, + "AS": true, + "BETWEEN": true, + "BY": true, + "CASE": true, + "CAST": true, + "CHECK": true, + "COLUMN": true, + "CONNECT": true, + "CONNECTION": true, + "CONSTRAINT": true, + "CREATE": true, + "CROSS": true, + "CURRENT": true, + "CURRENT_DATE": true, + "CURRENT_TIME": true, + "CURRENT_TIMESTAMP": true, + "CURRENT_USER": true, + "DATABASE": true, + "DELETE": true, + "DISTINCT": true, + "DROP": true, + "ELSE": true, + "EXISTS": true, + "FALSE": true, + "FOLLOWING": true, + "FOR": true, + "FROM": true, + "FULL": true, + "GRANT": true, + "GROUP": true, + "GSCLUSTER": true, + "HAVING": true, + "ILIKE": true, + "IN": true, + "INCREMENT": true, + "INNER": true, + "INSERT": true, + "INTERSECT": true, + "INTO": true, + "IS": true, + "ISSUE": true, + "JOIN": true, + "LATERAL": true, + "LEFT": true, + "LIKE": true, + "LOCALTIME": true, + "LOCALTIMESTAMP": true, + "MINUS": true, + "NATURAL": true, + "NOT": true, + "NULL": true, + "OF": true, + "ON": true, + "OR": true, + "ORDER": true, + "ORGANIZATION": true, + "QUALIFY": true, + "REGEXP": true, + "REVOKE": true, + "RIGHT": true, + "RLIKE": true, + "ROW": true, + "ROWS": true, + "SAMPLE": true, + "SCHEMA": true, + "SELECT": true, + "SET": true, + "SOME": true, + "START": true, + "TABLE": true, + "TABLESAMPLE": true, + "THEN": true, + "TO": true, + "TRIGGER": true, + "TRUE": true, + "TRY_CAST": true, + "UNION": true, + "UNIQUE": true, + "UPDATE": true, + "USING": true, + "VALUES": true, + "VIEW": true, + "WHEN": true, + "WHENEVER": true, + "WHERE": true, + "WITH": true + }, "CLICKHOUSE": {}, "S3_DATALAKE": { "ALL": true, diff --git a/src/warehouse/index.js b/src/warehouse/index.js index 3491a257da..ea663c9b2f 100644 --- a/src/warehouse/index.js +++ b/src/warehouse/index.js @@ -349,7 +349,10 @@ function stringLikeObjectToString(obj) { */ function getColumns(options, event, columnTypes) { const columns = {}; - const uuidTS = options.provider === 'snowflake' ? 'UUID_TS' : 'uuid_ts'; + const uuidTS = + options.provider === 'snowflake' || options.provider === 'snowpipe_streaming' + ? 'UUID_TS' + : 'uuid_ts'; columns[uuidTS] = 'datetime'; // add loaded_at for bq to be segment compatible if (options.provider === 'bq') { @@ -377,6 +380,7 @@ function getColumns(options, event, columnTypes) { const fullEventColumnTypeByProvider = { snowflake: 'json', + snowpipe_streaming: 'json', rs: 'text', bq: 'string', postgres: 'json', @@ -613,6 +617,15 @@ function enhanceContextWithSourceDestInfo(message, metadata) { message.context = context; } +function shouldSkipUsersTable(options) { + return ( + options.provider === 'snowpipe_streaming' || + options.destConfig?.skipUsersTable || + options.integrationOptions?.skipUsersTable || + false + ); +} + function processWarehouseMessage(message, options) { const utils = getVersionedUtils(options.whSchemaVersion); options.utils = utils; @@ -638,8 +651,7 @@ function processWarehouseMessage(message, options) { const eventType = message.type?.toLowerCase(); const skipTracksTable = options.destConfig?.skipTracksTable || options.integrationOptions.skipTracksTable || false; - const skipUsersTable = - options.destConfig?.skipUsersTable || options.integrationOptions.skipUsersTable || false; + const skipUsersTable = shouldSkipUsersTable(options); const skipReservedKeywordsEscaping = options.integrationOptions.skipReservedKeywordsEscaping || false; diff --git a/src/warehouse/v1/util.js b/src/warehouse/v1/util.js index d1289bc674..95dd59b030 100644 --- a/src/warehouse/v1/util.js +++ b/src/warehouse/v1/util.js @@ -11,7 +11,7 @@ function safeTableName(options, name = '') { if (tableName === '') { throw new TransformationError('Table name cannot be empty.'); } - if (provider === 'snowflake') { + if (provider === 'snowflake' || provider === 'snowpipe_streaming') { tableName = tableName.toUpperCase(); } else if (provider === 'postgres') { tableName = tableName.substr(0, 63); @@ -41,7 +41,7 @@ function safeColumnName(options, name = '') { if (columnName === '') { throw new TransformationError('Column name cannot be empty.'); } - if (provider === 'snowflake') { + if (provider === 'snowflake' || provider === 'snowpipe_streaming') { columnName = columnName.toUpperCase(); } else if (provider === 'postgres') { columnName = columnName.substr(0, 63); diff --git a/test/__tests__/data/warehouse/events.js b/test/__tests__/data/warehouse/events.js index bca6f776be..99343e43e1 100644 --- a/test/__tests__/data/warehouse/events.js +++ b/test/__tests__/data/warehouse/events.js @@ -368,6 +368,146 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "TRACKS", + columns: { + UUID_TS: "datetime", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USER_AGENT: "string", + EVENT_TEXT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string", + EVENT: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + EVENT_TEXT: "button clicked", + ID: "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.364Z", + TIMESTAMP: "2020-01-24T06:29:02.403Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.364Z", + CHANNEL: "web", + EVENT: "button_clicked" + } + }, + { + metadata: { + table: "BUTTON_CLICKED", + columns: { + UUID_TS: "datetime", + CURRENCY: "string", + REVENUE: "int", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USER_AGENT: "string", + EVENT_TEXT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string", + EVENT: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CURRENCY: "USD", + REVENUE: 50, + STACK_HISTORY_ERROR_DETAILS: [ + { + "message": "Cannot set headers after they are sent to the client", + "toString": "[function]" + } + ], + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + EVENT_TEXT: "button clicked", + ID: "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.364Z", + TIMESTAMP: "2020-01-24T06:29:02.403Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.364Z", + CHANNEL: "web", + EVENT: "button_clicked", + } + } + ], s3_datalake: [ { metadata: { @@ -845,6 +985,78 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "IDENTIFIES", + columns: { + UUID_TS: "datetime", + CITY: "string", + COUNTRY: "string", + EMAIL: "string", + FIRSTNAME: "string", + LASTNAME: "string", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USER_AGENT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CITY: "Disney", + COUNTRY: "UK", + EMAIL: "mickey@disney.com", + FIRSTNAME: "Mickey", + LASTNAME: "Mouse", + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + ID: "2536eda4-d638-4c93-8014-8ffe3f083214", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.363Z", + TIMESTAMP: "2020-01-24T06:29:02.402Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.362Z", + CHANNEL: "web" + } + }, + ], s3_datalake: [ { metadata: { @@ -1170,6 +1382,66 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "PAGES", + columns: { + UUID_TS: "datetime", + PATH: "string", + URL: "string", + NAME: "string", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_USER_AGENT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + PATH: "/tests/html/index2.html", + URL: "http://localhost/tests/html/index2.html", + NAME: "sample title", + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + ID: "dd266c67-9199-4a52-ba32-f46ddde67312", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.359Z", + TIMESTAMP: "2020-01-24T06:29:02.402Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.358Z", + CHANNEL: "web" + } + } + ], s3_datalake: [ { metadata: { @@ -1424,6 +1696,67 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "SCREENS", + columns: { + UUID_TS: "datetime", + PATH: "string", + CATEGORY: "string", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_USER_AGENT: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + TIMESTAMP: "datetime", + CHANNEL: "string", + NAME: "string" + } + }, + data: { + PATH: "/abc", + CATEGORY: "test-category", + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.0", + CONTEXT_TRAITS_EMAIL: "test@rudderstack.com", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.0", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", + CONTEXT_LOCALE: "en-US", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + ID: "5e10d13a-bf9a-44bf-b884-43a9e591ea71", + ANONYMOUS_ID: "00000000000000000000000000", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2019-10-14T11:15:53.296Z", + ORIGINAL_TIMESTAMP: "2019-10-14T11:15:18.299Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + TIMESTAMP: "2020-01-24T06:29:02.402Z", + CHANNEL: "web", + NAME: "ApplicationLoaded" + } + } + ], s3_datalake: [ { metadata: { @@ -1687,6 +2020,73 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "GROUPS", + columns: { + UUID_TS: "datetime", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_USER_AGENT: "string", + CONTEXT_LOCALE: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + CONTEXT_OS_ID: "string", + CONTEXT_OS_MANUFACTURER: "string", + CONTEXT_OS_MODEL: "string", + CONTEXT_OS_TYPE: "string", + CONTEXT_SCREEN_DENSITY: "int", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + GROUP_ID: "string", + SENT_AT: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + TIMESTAMP: "datetime", + CHANNEL: "string" + } + }, + data: { + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.0", + CONTEXT_TRAITS_EMAIL: "test@rudderstack.com", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.0", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", + CONTEXT_LOCALE: "en-US", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_OS_ID: "72e528f869711c3d", + CONTEXT_OS_MANUFACTURER: "Google", + CONTEXT_OS_MODEL: "sdk_gphone_x86", + CONTEXT_OS_NAME: "", + CONTEXT_OS_TOKEN: "", + CONTEXT_OS_TYPE: "android", + CONTEXT_SCREEN_DENSITY: 2, + ID: "84e26acc-56a5-4835-8233-591137fca468", + ANONYMOUS_ID: "00000000000000000000000000", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + GROUP_ID: "g1", + SENT_AT: "2019-10-14T09:03:22.563Z", + ORIGINAL_TIMESTAMP: "2019-10-14T09:03:17.562Z", + TIMESTAMP: "2020-01-24T11:59:02.403Z", + RECEIVED_AT: "2020-01-24T11:59:02.403Z", + CHANNEL: "web" + } + } + ], s3_datalake: [ { metadata: { @@ -1956,6 +2356,70 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "ALIASES", + columns: { + UUID_TS: "datetime", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USER_AGENT: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string", + PREVIOUS_ID: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USER_AGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + ID: "79313729-7fe5-4204-963a-dc46f4205e4e", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "1234abc", + SENT_AT: "2020-01-24T06:29:02.366Z", + TIMESTAMP: "2020-01-24T06:29:02.403Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.366Z", + CHANNEL: "web", + PREVIOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca" + } + } + ], s3_datalake: [ { metadata: { @@ -2147,6 +2611,40 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "EXTRACT_EVENT", + columns: { + DATE_PROPERTY: "datetime", + DATE_PROPERTY_2: "datetime", + CONTEXT_SOURCES_JOB_ID: "string", + CONTEXT_SOURCES_JOB_RUN_ID: "string", + CONTEXT_SOURCES_TASK_RUN_ID: "string", + CONTEXT_SOURCES_VERSION: "string", + EVENT: "string", + ID: "string", + USER_ID: "string", + RECEIVED_AT: "datetime", + BOOLEAN_PROPERTY: "boolean", + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + DATE_PROPERTY: "2023-02-01T07:53:31.430Z", + DATE_PROPERTY_2: "2023-01-31T07:39:10.002Z", + CONTEXT_SOURCES_JOB_ID: "2JABSy1nq89H7xeJimBL2pCtOOp", + CONTEXT_SOURCES_JOB_RUN_ID: "cfd6705nsevh5p2l77ag", + CONTEXT_SOURCES_TASK_RUN_ID: "cfd6705nsevh5p2l77b0", + CONTEXT_SOURCES_VERSION: "version", + ID: "some-uuid", + USER_ID: "dummy-user-id-inside-properties", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + EVENT: "extract_event", + BOOLEAN_PROPERTY: true, + } + } + ], s3_datalake: [ { metadata: { @@ -2193,6 +2691,9 @@ function output(eventType, provider) { if (provider === "snowflake") { return _.cloneDeep(sampleEvents[eventType].output.snowflake); } + if (provider === "snowpipe_streaming") { + return _.cloneDeep(sampleEvents[eventType].output.snowpipe_streaming); + } if (provider === "s3_datalake") { return _.cloneDeep(sampleEvents[eventType].output.s3_datalake); } diff --git a/test/__tests__/data/warehouse/integration_options_events.js b/test/__tests__/data/warehouse/integration_options_events.js index 35eafb6a9b..b3f076851b 100644 --- a/test/__tests__/data/warehouse/integration_options_events.js +++ b/test/__tests__/data/warehouse/integration_options_events.js @@ -74,6 +74,13 @@ const sampleEvents = { jsonPaths: ["tMap"] } }, + SNOWPIPE_STREAMING: { + options: { + skipTracksTable: true, + useBlendoCasing: true, + jsonPaths: ["tMap"] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -432,6 +439,88 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + metadata: { + table: "_GROUPS", + columns: { + UUID_TS: "datetime", + CURRENCY: "string", + REVENUE: "int", + PATH_TO_$1_000_000: "string", + _9OMEGA: "boolean", + CAMELCASE123KEY: "string", + TESTMAP_NESTEDMAP: "json", + TMAP: "json", + TESTARRAY: "json", + CONTEXT_APP_BUILD: "string", + CONTEXT_APP_NAME: "string", + CONTEXT_APP_NAMESPACE: "string", + CONTEXT_APP_VERSION: "string", + CONTEXT_LIBRARY_NAME: "string", + CONTEXT_LIBRARY_VERSION: "string", + CONTEXT_LOCALE: "string", + CONTEXT_SCREEN_DENSITY: "int", + CONTEXT_TRAITS_CITY: "string", + CONTEXT_TRAITS_COUNTRY: "string", + CONTEXT_TRAITS_EMAIL: "string", + CONTEXT_TRAITS_FIRSTNAME: "string", + CONTEXT_USERAGENT: "string", + EVENT_TEXT: "string", + ID: "string", + ANONYMOUS_ID: "string", + USER_ID: "string", + SENT_AT: "datetime", + TIMESTAMP: "datetime", + RECEIVED_AT: "datetime", + ORIGINAL_TIMESTAMP: "datetime", + CHANNEL: "string", + CONTEXT_IP: "string", + CONTEXT_REQUEST_IP: "string", + CONTEXT_PASSED_IP: "string", + EVENT: "string" + }, + receivedAt: "2020-01-24T11:59:02.403+05:30" + }, + data: { + CURRENCY: "USD", + REVENUE: 50, + PATH_TO_$1_000_000: "None", + _9OMEGA: true, + CAMELCASE123KEY: "camel case", + TESTMAP_NESTEDMAP: '{"n1":"nested prop 1"}', + TMAP: '{"t1":10,"t2":20}', + TESTARRAY: '["This is","an","array"]', + CONTEXT_APP_BUILD: "1.0.0", + CONTEXT_APP_NAME: "RudderLabs JavaScript SDK", + CONTEXT_APP_NAMESPACE: "com.rudderlabs.javascript", + CONTEXT_APP_VERSION: "1.0.5", + CONTEXT_LIBRARY_NAME: "RudderLabs JavaScript SDK", + CONTEXT_LIBRARY_VERSION: "1.0.5", + CONTEXT_LOCALE: "en-GB", + CONTEXT_SCREEN_DENSITY: 2, + CONTEXT_TRAITS_CITY: "Disney", + CONTEXT_TRAITS_COUNTRY: "USA", + CONTEXT_TRAITS_EMAIL: "mickey@disney.com", + CONTEXT_TRAITS_FIRSTNAME: "Mickey", + CONTEXT_USERAGENT: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + EVENT_TEXT: "groups", + ID: "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + ANONYMOUS_ID: "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + USER_ID: "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33", + SENT_AT: "2020-01-24T06:29:02.364Z", + TIMESTAMP: "2020-01-24T06:29:02.403Z", + RECEIVED_AT: "2020-01-24T06:29:02.403Z", + ORIGINAL_TIMESTAMP: "2020-01-24T06:29:02.364Z", + CHANNEL: "web", + CONTEXT_IP: "0.0.0.0", + CONTEXT_REQUEST_IP: "[::1]:53708", + CONTEXT_PASSED_IP: "0.0.0.0", + EVENT: "groups" + } + } + ], s3_datalake: [ { metadata: { @@ -730,7 +819,7 @@ const sampleEvents = { ] } }, - users: { + identify: { input: { destination: { Config: { @@ -1255,6 +1344,75 @@ const sampleEvents = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "97c46c81-3140-456d-b2a9-690d70aaca35", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.1.11", + "CONTEXT_DEVICE_ID": "id", + "CONTEXT_DEVICE_TOKEN": "token", + "CONTEXT_DEVICE_TYPE": "ios", + "CONTEXT_IP": "[::1]:53708", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.1.11", + "CONTEXT_LOCALE": "en-US", + "CONTEXT_OS_NAME": "android", + "CONTEXT_OS_VERSION": "1.12.3", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_TRAITS_EMAIL": "user123@email.com", + "CONTEXT_TRAITS_PHONE": "+917836362334", + "CONTEXT_TRAITS_USER_ID": "user123", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "EMAIL": "user123@email.com", + "ID": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "PHONE": "+917836362334", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "user123" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_DEVICE_ID": "string", + "CONTEXT_DEVICE_TOKEN": "string", + "CONTEXT_DEVICE_TYPE": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_OS_NAME": "string", + "CONTEXT_OS_VERSION": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_PHONE": "string", + "CONTEXT_TRAITS_USER_ID": "string", + "CONTEXT_USER_AGENT": "string", + "EMAIL": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "PHONE": "string", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "IDENTIFIES" + } + }, + ], s3_datalake: [ { "data": { @@ -1639,6 +1797,8 @@ function opOutput(eventType, provider) { switch (provider) { case "snowflake": return _.cloneDeep(sampleEvents[eventType].output.snowflake); + case "snowpipe_streaming": + return _.cloneDeep(sampleEvents[eventType].output.snowpipe_streaming); case "s3_datalake": return _.cloneDeep(sampleEvents[eventType].output.s3_datalake); case "rs": @@ -1646,13 +1806,13 @@ function opOutput(eventType, provider) { case "bq": return _.cloneDeep(sampleEvents[eventType].output.bq); case "gcs_datalake": - if (eventType === 'users') { + if (eventType === 'identify') { return _.cloneDeep(sampleEvents[eventType].output.gcs_datalake); } else { return _.cloneDeep(sampleEvents[eventType].output.default); } case "azure_datalake": - if (eventType === 'users') { + if (eventType === 'identify') { return _.cloneDeep(sampleEvents[eventType].output.azure_datalake); } else { return _.cloneDeep(sampleEvents[eventType].output.default); diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js index 30cce51fb7..7615abe5e1 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/aliases.js @@ -78,6 +78,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "testMap.nestedMap", + "ctestMap.cnestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -426,5 +434,70 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CITY": "Disney", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "COUNTRY": "USA", + "EMAIL": "mickey@disney.com", + "FIRSTNAME": "Mickey", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP_N_1": "nested prop 1", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CITY": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "COUNTRY": "string", + "EMAIL": "string", + "FIRSTNAME": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP_N_1": "string", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "ALIASES" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js index 9d38ecc292..b28b3a161e 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/extract.js @@ -59,6 +59,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "PMap.nestedMap", + "CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -276,6 +284,43 @@ module.exports = { "table": "PRODUCT_ADDED" } } + ], + snowpipe_streaming: [ + { + "data": { + "CONTEXT_C_MAP_NESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_SOURCES_JOB_ID": "djfhksdjhfkjdhfkjahkf", + "CONTEXT_SOURCES_JOB_RUN_ID": "job_run_id", + "CONTEXT_SOURCES_TASK_RUN_ID": "task_run_id", + "CONTEXT_SOURCES_VERSION": "1169/merge", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "EVENT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "P_MAP_NESTED_MAP_N_1": "nested prop 1", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50 + }, + "metadata": { + "columns": { + "CONTEXT_C_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_SOURCES_JOB_ID": "string", + "CONTEXT_SOURCES_JOB_RUN_ID": "string", + "CONTEXT_SOURCES_TASK_RUN_ID": "string", + "CONTEXT_SOURCES_VERSION": "string", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "EVENT": "string", + "ID": "string", + "P_MAP_NESTED_MAP_N_1": "string", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PRODUCT_ADDED" + } + } ] } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js index bbae993b27..457d251a74 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/groups.js @@ -78,6 +78,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "testMap.nestedMap", + "ctestMap.cnestedMap", + ] + } + }, GCS_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -431,5 +439,70 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CITY": "Disney", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "COUNTRY": "USA", + "EMAIL": "mickey@disney.com", + "FIRSTNAME": "Mickey", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP_N_1": "nested prop 1", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CITY": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "COUNTRY": "string", + "EMAIL": "string", + "FIRSTNAME": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP_N_1": "string", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "GROUPS" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js index 42f5cccf49..d91ef5f44b 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/identifies.js @@ -53,6 +53,16 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "UPMap.nestedMap", + "CTMap.nestedMap", + "TMap.nestedMap", + "CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -879,6 +889,85 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "97c46c81-3140-456d-b2a9-690d70aaca35", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.1.11", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_DEVICE_ID": "id", + "CONTEXT_DEVICE_TOKEN": "token", + "CONTEXT_DEVICE_TYPE": "ios", + "CONTEXT_IP": "[::1]:53708", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.1.11", + "CONTEXT_LOCALE": "en-US", + "CONTEXT_OS_NAME": "android", + "CONTEXT_OS_VERSION": "1.12.3", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_TRAITS_CT_MAP_NESTED_MAP_N_1": "nested prop 1", + "CONTEXT_TRAITS_EMAIL": "user123@email.com", + "CONTEXT_TRAITS_PHONE": "+917836362334", + "CONTEXT_TRAITS_USER_ID": "user123", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "CT_MAP_NESTED_MAP_N_1": "nested prop 1", + "EMAIL": "user123@email.com", + "ID": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "PHONE": "+917836362334", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "T_MAP_NESTED_MAP_N_1": "nested prop 1", + "UP_MAP_NESTED_MAP_N_1": "nested prop 1", + "USER_ID": "user123" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_DEVICE_ID": "string", + "CONTEXT_DEVICE_TOKEN": "string", + "CONTEXT_DEVICE_TYPE": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_OS_NAME": "string", + "CONTEXT_OS_VERSION": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_TRAITS_CT_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_PHONE": "string", + "CONTEXT_TRAITS_USER_ID": "string", + "CONTEXT_USER_AGENT": "string", + "CT_MAP_NESTED_MAP_N_1": "string", + "EMAIL": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "PHONE": "string", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "T_MAP_NESTED_MAP_N_1": "string", + "UP_MAP_NESTED_MAP_N_1": "string", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "IDENTIFIES" + } + }, + ], datalake: [ { "data": { diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js index dc2d3a3318..322ee8f3e6 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/pages.js @@ -67,6 +67,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "testMap.nestedMap", + "ctestMap.cnestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -404,5 +412,66 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP_N_1": "nested prop 1", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP_N_1": "string", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PAGES" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js index 9b789d2747..27d7b9a69b 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/screens.js @@ -67,6 +67,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "testMap.nestedMap", + ".ctestMap.cnestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -404,5 +412,66 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP_N_1": "nested prop 1", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP_N_1": "string", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "SCREENS" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js index 691ce57ca1..aabfce149b 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/legacy/tracks.js @@ -78,6 +78,15 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "UPMap.nestedMap", + "PMap.nestedMap", + "CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -828,6 +837,148 @@ module.exports = { "table": "PRODUCT_ADDED" } } + ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_TRAITS_CITY": "Disney", + "CONTEXT_TRAITS_COUNTRY": "USA", + "CONTEXT_TRAITS_EMAIL": "mickey@disney.com", + "CONTEXT_TRAITS_FIRSTNAME": "Mickey", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "EVENT": "product_added", + "EVENT_TEXT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_TRAITS_CITY": "string", + "CONTEXT_TRAITS_COUNTRY": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_FIRSTNAME": "string", + "CONTEXT_USER_AGENT": "string", + "EVENT": "string", + "EVENT_TEXT": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "TRACKS" + } + }, + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "context nested prop 1", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_TRAITS_CITY": "Disney", + "CONTEXT_TRAITS_COUNTRY": "USA", + "CONTEXT_TRAITS_EMAIL": "mickey@disney.com", + "CONTEXT_TRAITS_FIRSTNAME": "Mickey", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "EMAIL": "test@gmail.com", + "EVENT": "product_added", + "EVENT_TEXT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "P_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "UP_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP_N_1": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_TRAITS_CITY": "string", + "CONTEXT_TRAITS_COUNTRY": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_FIRSTNAME": "string", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "EMAIL": "string", + "EVENT": "string", + "EVENT_TEXT": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "P_MAP_NESTED_MAP": "json", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "UP_MAP_NESTED_MAP": "json", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PRODUCT_ADDED" + } + } ] } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js index d5d57f85b9..4b74fd3768 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/aliases.js @@ -66,6 +66,11 @@ module.exports = { jsonPaths: ["alias.traits.testMap.nestedMap", "alias.context.ctestMap.cnestedMap"] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: ["alias.traits.testMap.nestedMap", "alias.context.ctestMap.cnestedMap"] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -414,5 +419,70 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CITY": "Disney", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "COUNTRY": "USA", + "EMAIL": "mickey@disney.com", + "FIRSTNAME": "Mickey", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CITY": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "COUNTRY": "string", + "EMAIL": "string", + "FIRSTNAME": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP": "json", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "ALIASES" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js index a950b7f526..03745c0502 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/extract.js @@ -59,6 +59,14 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "extract.properties.PMap.nestedMap", + "extract.context.CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -276,6 +284,43 @@ module.exports = { "table": "PRODUCT_ADDED" } } + ], + snowpipe_streaming: [ + { + "data": { + "CONTEXT_C_MAP_NESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_SOURCES_JOB_ID": "djfhksdjhfkjdhfkjahkf", + "CONTEXT_SOURCES_JOB_RUN_ID": "job_run_id", + "CONTEXT_SOURCES_TASK_RUN_ID": "task_run_id", + "CONTEXT_SOURCES_VERSION": "1169/merge", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "EVENT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "P_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50 + }, + "metadata": { + "columns": { + "CONTEXT_C_MAP_NESTED_MAP": "json", + "CONTEXT_SOURCES_JOB_ID": "string", + "CONTEXT_SOURCES_JOB_RUN_ID": "string", + "CONTEXT_SOURCES_TASK_RUN_ID": "string", + "CONTEXT_SOURCES_VERSION": "string", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "EVENT": "string", + "ID": "string", + "P_MAP_NESTED_MAP": "json", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PRODUCT_ADDED" + } + } ] } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js index 6979aa1100..1e7c8110da 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/groups.js @@ -66,6 +66,11 @@ module.exports = { jsonPaths: ["group.traits.testMap.nestedMap", "group.context.ctestMap.cnestedMap"] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: ["group.traits.testMap.nestedMap", "group.context.ctestMap.cnestedMap"] + } + }, GCS_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -419,5 +424,70 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CITY": "Disney", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "COUNTRY": "USA", + "EMAIL": "mickey@disney.com", + "FIRSTNAME": "Mickey", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CITY": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "COUNTRY": "string", + "EMAIL": "string", + "FIRSTNAME": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP": "json", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "GROUPS" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js index 89fcc23cd5..d9c3b80df3 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/identifies.js @@ -53,6 +53,16 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "identify.userProperties.UPMap.nestedMap", + "identify.context.traits.CTMap.nestedMap", + "identify.traits.TMap.nestedMap", + "identify.context.CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -879,6 +889,85 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "97c46c81-3140-456d-b2a9-690d70aaca35", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.1.11", + "CONTEXT_C_MAP_NESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_DEVICE_ID": "id", + "CONTEXT_DEVICE_TOKEN": "token", + "CONTEXT_DEVICE_TYPE": "ios", + "CONTEXT_IP": "[::1]:53708", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.1.11", + "CONTEXT_LOCALE": "en-US", + "CONTEXT_OS_NAME": "android", + "CONTEXT_OS_VERSION": "1.12.3", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_TRAITS_CT_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "CONTEXT_TRAITS_EMAIL": "user123@email.com", + "CONTEXT_TRAITS_PHONE": "+917836362334", + "CONTEXT_TRAITS_USER_ID": "user123", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0", + "CT_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "EMAIL": "user123@email.com", + "ID": "2116ef8c-efc3-4ca4-851b-02ee60dad6ff", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "PHONE": "+917836362334", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2021-01-03T17:02:53.195Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "T_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "UP_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "USER_ID": "user123" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP": "json", + "CONTEXT_DEVICE_ID": "string", + "CONTEXT_DEVICE_TOKEN": "string", + "CONTEXT_DEVICE_TYPE": "string", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_OS_NAME": "string", + "CONTEXT_OS_VERSION": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_TRAITS_CT_MAP_NESTED_MAP": "json", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_PHONE": "string", + "CONTEXT_TRAITS_USER_ID": "string", + "CONTEXT_USER_AGENT": "string", + "CT_MAP_NESTED_MAP": "json", + "EMAIL": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "PHONE": "string", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "T_MAP_NESTED_MAP": "json", + "UP_MAP_NESTED_MAP": "json", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "IDENTIFIES" + } + }, + ], datalake: [ { "data": { diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js index d5282c1cfd..1f72ec31cf 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/pages.js @@ -55,6 +55,11 @@ module.exports = { jsonPaths: ["page.properties.testMap.nestedMap", "page.context.ctestMap.cnestedMap"] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: ["page.properties.testMap.nestedMap", "page.context.ctestMap.cnestedMap"] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -392,5 +397,66 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP": "json", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PAGES" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js index 3eec47b89d..68b5aafcb5 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/screens.js @@ -55,6 +55,11 @@ module.exports = { jsonPaths: ["screen.properties.testMap.nestedMap", "screen.context.ctestMap.cnestedMap"] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: ["screen.properties.testMap.nestedMap", "screen.context.ctestMap.cnestedMap"] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -392,5 +397,66 @@ module.exports = { } } ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TEST_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_CTEST_MAP_CNESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TEST_MAP_NESTED_MAP": "json", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "SCREENS" + } + } + ], } } diff --git a/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js b/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js index 6b411835db..70c20b8b8e 100644 --- a/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js +++ b/test/__tests__/data/warehouse/integrations/jsonpaths/new/tracks.js @@ -78,6 +78,15 @@ module.exports = { ] } }, + SNOWPIPE_STREAMING: { + options: { + jsonPaths: [ + "track.userProperties.UPMap.nestedMap", + "track.properties.PMap.nestedMap", + "track.context.CMap.nestedMap", + ] + } + }, S3_DATALAKE: { options: { skipReservedKeywordsEscaping: true @@ -828,6 +837,148 @@ module.exports = { "table": "PRODUCT_ADDED" } } + ], + snowpipe_streaming: [ + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_C_MAP_NESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_TRAITS_CITY": "Disney", + "CONTEXT_TRAITS_COUNTRY": "USA", + "CONTEXT_TRAITS_EMAIL": "mickey@disney.com", + "CONTEXT_TRAITS_FIRSTNAME": "Mickey", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "EVENT": "product_added", + "EVENT_TEXT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_TRAITS_CITY": "string", + "CONTEXT_TRAITS_COUNTRY": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_FIRSTNAME": "string", + "CONTEXT_USER_AGENT": "string", + "EVENT": "string", + "EVENT_TEXT": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "RECEIVED_AT": "datetime", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "TRACKS" + } + }, + { + "data": { + "ANONYMOUS_ID": "e6ab2c5e-2cda-44a9-a962-e2f67df78bca", + "CHANNEL": "web", + "CONTEXT_APP_BUILD": "1.0.0", + "CONTEXT_APP_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_APP_NAMESPACE": "com.rudderlabs.javascript", + "CONTEXT_APP_VERSION": "1.0.5", + "CONTEXT_C_MAP_NESTED_MAP": "{\"n1\":\"context nested prop 1\"}", + "CONTEXT_IP": "0.0.0.0", + "CONTEXT_LIBRARY_NAME": "RudderLabs JavaScript SDK", + "CONTEXT_LIBRARY_VERSION": "1.0.5", + "CONTEXT_LOCALE": "en-GB", + "CONTEXT_PASSED_IP": "0.0.0.0", + "CONTEXT_REQUEST_IP": "[::1]:53708", + "CONTEXT_SCREEN_DENSITY": 2, + "CONTEXT_TRAITS_CITY": "Disney", + "CONTEXT_TRAITS_COUNTRY": "USA", + "CONTEXT_TRAITS_EMAIL": "mickey@disney.com", + "CONTEXT_TRAITS_FIRSTNAME": "Mickey", + "CONTEXT_USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36", + "CURRENCY": "USD", + "EMAIL": "test@gmail.com", + "EVENT": "product_added", + "EVENT_TEXT": "Product Added", + "ID": "a6a0ad5a-bd26-4f19-8f75-38484e580fc7", + "ORIGINAL_TIMESTAMP": "2020-01-24T06:29:02.364Z", + "P_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "RECEIVED_AT": "2020-01-24T06:29:02.403Z", + "REVENUE": 50, + "SENT_AT": "2020-01-24T06:29:02.364Z", + "TIMESTAMP": "2020-01-24T06:29:02.403Z", + "UP_MAP_NESTED_MAP": "{\"n1\":\"nested prop 1\"}", + "USER_ID": "9bb5d4c2-a7aa-4a36-9efb-dd2b1aec5d33" + }, + "metadata": { + "columns": { + "ANONYMOUS_ID": "string", + "CHANNEL": "string", + "CONTEXT_APP_BUILD": "string", + "CONTEXT_APP_NAME": "string", + "CONTEXT_APP_NAMESPACE": "string", + "CONTEXT_APP_VERSION": "string", + "CONTEXT_C_MAP_NESTED_MAP": "json", + "CONTEXT_IP": "string", + "CONTEXT_LIBRARY_NAME": "string", + "CONTEXT_LIBRARY_VERSION": "string", + "CONTEXT_LOCALE": "string", + "CONTEXT_PASSED_IP": "string", + "CONTEXT_REQUEST_IP": "string", + "CONTEXT_SCREEN_DENSITY": "int", + "CONTEXT_TRAITS_CITY": "string", + "CONTEXT_TRAITS_COUNTRY": "string", + "CONTEXT_TRAITS_EMAIL": "string", + "CONTEXT_TRAITS_FIRSTNAME": "string", + "CONTEXT_USER_AGENT": "string", + "CURRENCY": "string", + "EMAIL": "string", + "EVENT": "string", + "EVENT_TEXT": "string", + "ID": "string", + "ORIGINAL_TIMESTAMP": "datetime", + "P_MAP_NESTED_MAP": "json", + "RECEIVED_AT": "datetime", + "REVENUE": "int", + "SENT_AT": "datetime", + "TIMESTAMP": "datetime", + "UP_MAP_NESTED_MAP": "json", + "USER_ID": "string", + "UUID_TS": "datetime" + }, + "receivedAt": "2020-01-24T11:59:02.403+05:30", + "table": "PRODUCT_ADDED" + } + } ] } } diff --git a/test/__tests__/data/warehouse/names.js b/test/__tests__/data/warehouse/names.js index b0380dc06d..e6015cef2c 100644 --- a/test/__tests__/data/warehouse/names.js +++ b/test/__tests__/data/warehouse/names.js @@ -41,6 +41,19 @@ const names = { C_Z: "string", CAMEL_CASE_123_KEY: "string", _1_C_COMEGA: "string" + }, + snowpipe_streaming: { + OMEGA: "string", + OMEGA_V_2: "string", + _9_MEGA: "string", + MEGA: "string", + OME_GA: "string", + ALPHA: "string", + OME_GA: "string", + _9_MEGA_90: "string", + C_Z: "string", + CAMEL_CASE_123_KEY: "string", + _1_C_COMEGA: "string" } }, data: { @@ -69,6 +82,19 @@ const names = { C_Z: "test", CAMEL_CASE_123_KEY: "test", _1_C_COMEGA: "test" + }, + snowpipe_streaming: { + OMEGA: "test", + OMEGA_V_2: "test", + _9_MEGA: "test", + MEGA: "test", + OME_GA: "test", + ALPHA: "test", + OME_GA: "test", + _9_MEGA_90: "test", + C_Z: "test", + CAMEL_CASE_123_KEY: "test", + _1_C_COMEGA: "test" } }, namesMap: { @@ -97,6 +123,19 @@ const names = { Cízǔ: "C_Z", CamelCase123Key: "CAMEL_CASE_123_KEY", "1CComega": "_1_C_COMEGA" + }, + snowpipe_streaming: { + omega: "OMEGA", + "omega v2": "OMEGA_V_2", + "9mega": "_9_MEGA", + "mega&": "MEGA", + ome$ga: "OME_GA", + alpha$: "ALPHA", + "ome_ ga": "OME_GA", + "9mega________-________90": "_9_MEGA_90", + Cízǔ: "C_Z", + CamelCase123Key: "CAMEL_CASE_123_KEY", + "1CComega": "_1_C_COMEGA" } } } diff --git a/test/__tests__/legacyRouter.test.ts b/test/__tests__/legacyRouter.test.ts deleted file mode 100644 index 926f6e76d4..0000000000 --- a/test/__tests__/legacyRouter.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import { DestinationController } from '../../src/controllers/destination'; -const destArg = process.argv.filter((x) => x.startsWith('--destName='))[0]; // send arguments on which destination -const typeArg = process.argv.filter((x) => x.startsWith('--type='))[0]; // send argument on which function - -// To invoke CDK live compare: -// router: CDK_LIVE_TEST=1 npx jest versionedRouter --destName=algolia --type=router -// processor: CDK_LIVE_TEST=1 npx jest versionedRouter --destName=algolia --type=processor - -let destination; -if (typeArg) { - destination = destArg ? destArg.split('=')[1] : 'heap'; // default - const type = typeArg.split('=')[1]; - let reqBody; - let respBody; - if (type !== 'all') { - try { - reqBody = JSON.parse( - fs - .readFileSync( - path.resolve(__dirname, `./data/versioned_${type}_${destination}_input.json`), - ) - .toString(), - ); - respBody = JSON.parse( - fs - .readFileSync( - path.resolve(__dirname, `./data/versioned_${type}_${destination}_output.json`), - ) - .toString(), - ); - } catch (error) { - throw new Error('destination/type not valid' + error); - } - } - if (type === 'router') { - it(`Testing: routerHandleDest`, async () => { - const output = await DestinationController.destinationTransformAtRouter(reqBody); - expect(output).toEqual(respBody); - }); - } else if (type === 'processor') { - it(`Testing: handleDest`, async () => { - const output = await DestinationController.destinationTransformAtProcessor(reqBody); - expect(output).toEqual(respBody); - }); - } else if (type === 'batch') { - it(`Testing: batchHandler`, async () => { - const output = await DestinationController.batchProcess(reqBody); - expect(output).toEqual(respBody); - }); - } else if (type === 'all') { - it(`Testing: routerHandleDest`, async () => { - const reqBody = JSON.parse( - fs - .readFileSync( - path.resolve(__dirname, `./data/versioned_router_${destination}_input.json`), - ) - .toString(), - ); - const respBody = JSON.parse( - fs - .readFileSync( - path.resolve(__dirname, `./data/versioned_router_${destination}_output.json`), - ) - .toString(), - ); - const output = await DestinationController.destinationTransformAtRouter(reqBody); - expect(output).toEqual(respBody); - }); - it(`Testing: handleDest`, async () => { - const reqBody = JSON.parse( - fs - .readFileSync( - path.resolve(__dirname, `./data/versioned_processor_${destination}_input.json`), - ) - .toString(), - ); - const respBody = JSON.parse( - fs - .readFileSync( - path.resolve(__dirname, `./data/versioned_processor_${destination}_output.json`), - ) - .toString(), - ); - destination = destination || 'heap'; // default - const output = await DestinationController.destinationTransformAtProcessor(reqBody); - expect(output).toEqual(respBody); - }); - it(`Testing: batchHandler`, async () => { - const reqBody = JSON.parse( - fs - .readFileSync(path.resolve(__dirname, `./data/versioned_batch_braze_input.json`)) - .toString(), - ); - const respBody = JSON.parse( - fs - .readFileSync(path.resolve(__dirname, `./data/versioned_batch_braze_output.json`)) - .toString(), - ); - }); - } else { - it(`Type is not all/router/batch/processor`, () => { - expect('Type is not all/router/batch/processor').toEqual( - 'Type is not all/router/batch/processor', - ); - }); - } -} else { - it(`No type and destination mentioned for testing versionedRouter`, () => { - expect('no command line argument provided').toEqual('no command line argument provided'); - }); -} diff --git a/test/__tests__/warehouse.test.js b/test/__tests__/warehouse.test.js index 7fdecbd7cf..44d1d33ff8 100644 --- a/test/__tests__/warehouse.test.js +++ b/test/__tests__/warehouse.test.js @@ -37,14 +37,6 @@ const integrations = [ "s3_datalake", "gcs_datalake", ]; - -const integration = (index ) => { - const it = integrations[index]; - if (it === "snowflake" || it === "snowpipe_streaming") { - return "snowflake"; - } - return it; -} const transformers = integrations.map(integration => require(`../../src/${version}/destinations/${integration}/transform`) ); @@ -62,7 +54,7 @@ const propsKeyMap = { }; const integrationCasedString = (integration, str) => { - if (integration === "snowflake") { + if (integration === "snowflake" || integration === "snowpipe_streaming") { return str.toUpperCase(); } return str; @@ -74,7 +66,7 @@ describe("event types", () => { const i = input("track"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("track", integration(index))); + expect(received).toMatchObject(output("track", integrations[index])); }); }); }); @@ -85,7 +77,7 @@ describe("event types", () => { // also verfies priority order between traits and context.traits transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("identify", integration(index))); + expect(received).toMatchObject(output("identify", integrations[index])); }); }); }); @@ -95,7 +87,7 @@ describe("event types", () => { const i = input("page"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("page", integration(index))); + expect(received).toMatchObject(output("page", integrations[index])); }); }); it("should take name from properties if top-level name is missing", () => { @@ -104,7 +96,7 @@ describe("event types", () => { delete i.message.name; transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("page", integration(index))); + expect(received).toMatchObject(output("page", integrations[index])); }); }); }); @@ -114,7 +106,7 @@ describe("event types", () => { const i = input("screen"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("screen", integration(index))); + expect(received).toMatchObject(output("screen", integrations[index])); }); }); it("should take name from properties if top-level name is missing", () => { @@ -123,7 +115,7 @@ describe("event types", () => { delete i.message.name; transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("screen", integration(index))); + expect(received).toMatchObject(output("screen", integrations[index])); }); }); }); @@ -133,7 +125,7 @@ describe("event types", () => { const i = input("alias"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("alias", integration(index))); + expect(received).toMatchObject(output("alias", integrations[index])); }); }); }); @@ -143,7 +135,7 @@ describe("event types", () => { const i = input("extract"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toMatchObject(output("extract", integration(index))); + expect(received).toMatchObject(output("extract", integrations[index])); }); }); }); @@ -161,8 +153,9 @@ describe("column & table names", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); - const provider = - (integration(index) === "snowflake" || integration(index) == "snowpipe_streaming") ? "snowflake" : "default"; + const provider = ["snowflake", "snowpipe_streaming"].includes(integrations[index]) + ? integrations[index] + : "default"; expect(received[1].metadata.columns).toMatchObject( names.output.columns[provider] @@ -195,7 +188,7 @@ describe("column & table names", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); - if (integration(index) === "postgres") { + if (integrations[index] === "postgres") { expect(received[1].metadata).toHaveProperty( "table", "a_1_a_2_a_3_a_4_a_5_b_1_b_2_b_3_b_4_b_5_c_1_c_2_c_3_c_4_c_5_d_1" @@ -219,7 +212,7 @@ describe("column & table names", () => { //KEY should be trimmed to 63 return; } - if (integration(index) === "snowflake") { + if (integrations[index] === "snowflake" || integrations[index] === "snowpipe_streaming") { expect(received[1].metadata).toHaveProperty( "table", "A_1_A_2_A_3_A_4_A_5_B_1_B_2_B_3_B_4_B_5_C_1_C_2_C_3_C_4_C_5_D_1_D_2_D_3_D_4_D_5_E_1_E_2_E_3_E_4_E_5_F_1_F_2_F_3_F_4_F_5_G_1_G_2" @@ -242,7 +235,7 @@ describe("column & table names", () => { ); return; } - if (integration(index) === "s3_datalake" || integration(index) === "gcs_datalake" || integration(index) === "azure_datalake") { + if (integrations[index] === "s3_datalake" || integrations[index] === "gcs_datalake" || integrations[index] === "azure_datalake") { expect(received[1].metadata).toHaveProperty( "table", "a_1_a_2_a_3_a_4_a_5_b_1_b_2_b_3_b_4_b_5_c_1_c_2_c_3_c_4_c_5_d_1_d_2_d_3_d_4_d_5_e_1_e_2_e_3_e_4_e_5_f_1_f_2_f_3_f_4_f_5_g_1_g_2_g_3_g_4_g_5" @@ -325,7 +318,7 @@ describe("conflict between rudder set props and user set props", () => { const propsKey = propsKeyMap[evType]; transformers.forEach((transformer, index) => { let sampleRudderPropKey = "id"; - if (integration(index) === "snowflake") { + if (integrations[index] === "snowflake" || integrations[index] === "snowpipe_streaming") { sampleRudderPropKey = "ID"; } @@ -363,7 +356,7 @@ describe("handle reserved words", () => { const propsKey = propsKeyMap[evType]; transformers.forEach((transformer, index) => { const reserverdKeywordsMap = - reservedANSIKeywordsMap[integration(index).toUpperCase()]; + reservedANSIKeywordsMap[integrations[index].toUpperCase()]; i.message[propsKey] = Object.assign( i.message[propsKey] || {}, @@ -373,7 +366,7 @@ describe("handle reserved words", () => { const received = transformer.process(i); const out = - evType === "track" || evType === "identify" + evType === "track" || (evType === "identify" && integrations[index] !== 'snowpipe_streaming') ? received[1] : received[0]; @@ -386,7 +379,7 @@ describe("handle reserved words", () => { } else { k = snakeCasedKey; } - if (integration(index) === "snowflake") { + if (integrations[index] === "snowflake" || integrations[index] === "snowpipe_streaming") { expect(out.metadata.columns).toHaveProperty(k); } else { expect(out.metadata.columns).toHaveProperty(k.toLowerCase()); @@ -470,24 +463,24 @@ describe("context ip", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toBe("string"); expect( received[0].data[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toEqual("new_ip"); if (received[1]) { expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toBe("string"); expect( received[1].data[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toEqual("new_ip"); } @@ -505,23 +498,23 @@ describe("context ip", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toBe("string"); expect( received[0].data[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toEqual("requested_ip"); if (received[1]) { expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toBe("string"); expect( received[1].data[ - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ] ).toEqual("requested_ip"); } @@ -542,10 +535,10 @@ describe("remove rudder property if rudder property is null", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "context_ip") + integrationCasedString(integrations[index], "context_ip") ); }); }); @@ -560,29 +553,29 @@ describe("remove any property if event is object ", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "channel") + integrationCasedString(integrations[index], "channel") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "channel") + integrationCasedString(integrations[index], "channel") ); }); transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "event_text") + integrationCasedString(integrations[index], "event_text") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "event_text") + integrationCasedString(integrations[index], "event_text") ); }); i.message.channel = { channel: "android" }; transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "channel") + integrationCasedString(integrations[index], "channel") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "channel") + integrationCasedString(integrations[index], "channel") ); }); }); @@ -598,13 +591,13 @@ describe("store full rudder event", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); const columnName = integrationCasedString( - integration(index), + integrations[index], "rudder_event" ); expect(received[0].metadata.columns).toHaveProperty(columnName); expect(received[0].metadata.columns[columnName]).toEqual( - fullEventColumnTypeByProvider[integration(index)] + fullEventColumnTypeByProvider[integrations[index]] ); expect(received[0].data[columnName]).toEqual(JSON.stringify(i.message)); @@ -644,7 +637,7 @@ describe("rudder reserved columns", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); checkProps.forEach(k => { - k = integrationCasedString(integration(index), k); + k = integrationCasedString(integrations[index], k); expect(received[0].metadata.columns).not.toHaveProperty(k); expect(received[0].data).not.toHaveProperty(k); if (received[1]) { @@ -664,14 +657,25 @@ describe("id column datatype for users table", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); + if (integrations[index] === 'snowpipe_streaming') { + expect(received).toHaveLength(1); + expect( + received[0].metadata.columns[ + integrationCasedString(integrations[index], "user_id") + ] + ).toEqual("int"); + return; + } + + expect(received).toHaveLength(2); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "user_id") + integrationCasedString(integrations[index], "user_id") ] ).toEqual("int"); expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("int"); }); @@ -681,14 +685,25 @@ describe("id column datatype for users table", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); + if (integrations[index] === 'snowpipe_streaming') { + expect(received).toHaveLength(1); + expect( + received[0].metadata.columns[ + integrationCasedString(integrations[index], "user_id") + ] + ).toEqual("float"); + return; + } + + expect(received).toHaveLength(2); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "user_id") + integrationCasedString(integrations[index], "user_id") ] ).toEqual("float"); expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("float"); }); @@ -707,22 +722,22 @@ describe("handle leading underscores in properties", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "_timestamp") + integrationCasedString(integrations[index], "_timestamp") ); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "__timestamp") + integrationCasedString(integrations[index], "__timestamp") ); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "__timestamp_new") + integrationCasedString(integrations[index], "__timestamp_new") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integration(index), "_timestamp") + integrationCasedString(integrations[index], "_timestamp") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integration(index), "__timestamp") + integrationCasedString(integrations[index], "__timestamp") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integration(index), "__timestamp_new") + integrationCasedString(integrations[index], "__timestamp_new") ); }); }); @@ -736,22 +751,22 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[0].data[integrationCasedString(integration(index), "id")] + received[0].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[1].data[integrationCasedString(integration(index), "id")] + received[1].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); }); }); @@ -764,22 +779,22 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[0].data[integrationCasedString(integration(index), "id")] + received[0].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[1].data[integrationCasedString(integration(index), "id")] + received[1].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); }); }); @@ -792,17 +807,17 @@ describe("handle recordId from cloud sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[0].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect( - received[0].data[integrationCasedString(integration(index), "id")] + received[0].data[integrationCasedString(integrations[index], "id")] ).toEqual(i.message.messageId); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("string"); }); @@ -818,28 +833,28 @@ describe("handle recordId from cloud sources", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ] ).toEqual("string"); expect( received[0].data[ - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ] ).toBe("42"); expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("int"); expect( - received[1].data[integrationCasedString(integration(index), "id")] + received[1].data[integrationCasedString(integrations[index], "id")] ).toBe(42); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); }); }); @@ -854,28 +869,28 @@ describe("handle recordId from cloud sources", () => { const received = transformer.process(i); expect( received[0].metadata.columns[ - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ] ).toEqual("string"); expect( received[0].data[ - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ] ).toBe("42"); expect( received[1].metadata.columns[ - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ] ).toEqual("int"); expect( - received[1].data[integrationCasedString(integration(index), "id")] + received[1].data[integrationCasedString(integrations[index], "id")] ).toBe(42); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "record_id") + integrationCasedString(integrations[index], "record_id") ); }); }); @@ -915,10 +930,10 @@ describe("handle level three nested events from sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).not.toHaveProperty( - integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") ); expect(received[1].data).not.toHaveProperty( - integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") ); }); }); @@ -943,10 +958,10 @@ describe("handle level three nested events from sources", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[1].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") ); expect(received[1].data).toHaveProperty( - integrationCasedString(integration(index), "n_0_n_1_n_2_n_3_prop_3") + integrationCasedString(integrations[index], "n_0_n_1_n_2_n_3_prop_3") ); }); }); @@ -956,7 +971,7 @@ describe("Handle no of columns in an event", () => { it("should throw an error if no of columns are more than 200", () => { const i = input("track"); transformers - .filter((transformer, index) => integration(index) !== "s3_datalake" && integration(index) !== "gcs_datalake" && integration(index) !== "azure_datalake") + .filter((transformer, index) => integrations[index] !== "s3_datalake" && integrations[index] !== "gcs_datalake" && integrations[index] !== "azure_datalake") .forEach((transformer, index) => { i.message.properties = largeNoOfColumnsevent; expect(() => transformer.process(i)).toThrow( @@ -984,13 +999,13 @@ describe("Add auto generated messageId for events missing it", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ); expect(received[0].data).toHaveProperty( - integrationCasedString(integration(index), "id") + integrationCasedString(integrations[index], "id") ); expect( - received[0].data[integrationCasedString(integration(index), "id")] + received[0].data[integrationCasedString(integrations[index], "id")] ).toMatch(/auto-.*/); }); }); @@ -1007,10 +1022,10 @@ describe("Add receivedAt for events missing it", () => { transformers.forEach((transformer, index) => { const received = transformer.process(i); expect(received[0].metadata.columns).toHaveProperty( - integrationCasedString(integration(index), "received_at") + integrationCasedString(integrations[index], "received_at") ); expect(received[0].data).toHaveProperty( - integrationCasedString(integration(index), "received_at") + integrationCasedString(integrations[index], "received_at") ); }); }); @@ -1023,22 +1038,22 @@ describe("Integration options", () => { const i = opInput("track"); transformers.forEach((transformer, index) => { const {jsonPaths} = i.destination.Config; - if (integration(index) === "postgres") { + if (integrations[index] === "postgres") { delete i.destination.Config.jsonPaths; } const received = transformer.process(i); i.destination.Config.jsonPaths = jsonPaths; - expect(received).toEqual(opOutput("track", integration(index))); + expect(received).toEqual(opOutput("track", integrations[index])); }); }); }); describe("users", () => { it("should skip users when skipUsersTable is set", () => { - const i = opInput("users"); + const i = opInput("identify"); transformers.forEach((transformer, index) => { const received = transformer.process(i); - expect(received).toEqual(opOutput("users", integration(index))); + expect(received).toEqual(opOutput("identify", integrations[index])); }); }); }); @@ -1054,6 +1069,8 @@ describe("Integration options", () => { return _.cloneDeep(config.output.postgres); case "snowflake": return _.cloneDeep(config.output.snowflake); + case "snowpipe_streaming": + return _.cloneDeep(config.output.snowpipe_streaming); case "s3_datalake": case "gcs_datalake": case "azure_datalake": @@ -1093,18 +1110,18 @@ describe("Integration options", () => { for (const testCase of testCases) { transformers.forEach((transformer, index) => { - it(`new ${testCase.eventType} for ${integration(index)}`, () => { + it(`new ${testCase.eventType} for ${integrations[index]}`, () => { const config = require("./data/warehouse/integrations/jsonpaths/new/" + testCase.eventType); const input = _.cloneDeep(config.input); const received = transformer.process(input); - expect(received).toEqual(output(testCase.eventType, config, integration(index))); + expect(received).toEqual(output(testCase.eventType, config, integrations[index])); }) - it(`legacy ${testCase.eventType} for ${integration(index)}`, () => { + it(`legacy ${testCase.eventType} for ${integrations[index]}`, () => { const config = require("./data/warehouse/integrations/jsonpaths/legacy/" + testCase.eventType); const input = _.cloneDeep(config.input); const received = transformer.process(input); - expect(received).toEqual(output(testCase.eventType, config, integration(index))); + expect(received).toEqual(output(testCase.eventType, config, integrations[index])); }) }); } @@ -1242,7 +1259,10 @@ describe("Destination config", () => { transformers.forEach((transformer, index) => { const received = transformer.process(scenario.event); - expect(received).toHaveLength(scenario.expected.length); + const expectedLength = integrations[index] === "snowpipe_streaming" && scenario.event.message.type === "identify" + ? 1 + : scenario.expected.length; + expect(received).toHaveLength(expectedLength); for (const i in received) { const evt = received[i]; expect(evt.data.id ? evt.data.id : evt.data.ID).toEqual(scenario.expected[i].id); @@ -1285,7 +1305,9 @@ describe("Destination config", () => { } } const output = transformer.process(event); - const events = [output[0], output[1]]; // identifies and users event + const events = integrations[index] === "snowpipe_streaming" + ? [output[0]] + : [output[0], output[1]]; const traitsToCheck = { 'city': 'Disney', 'country': 'USA', @@ -1294,10 +1316,10 @@ describe("Destination config", () => { }; events.forEach(event => { Object.entries(traitsToCheck).forEach(([trait, value]) => { - expect(event.data[integrationCasedString(integration(index), trait)]).toEqual(value); - expect(event.data[integrationCasedString(integration(index), `context_traits_${trait}`)]).toEqual(value); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), trait)); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_traits_${trait}`)); + expect(event.data[integrationCasedString(integrations[index], trait)]).toEqual(value); + expect(event.data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); }); }); }); @@ -1325,13 +1347,13 @@ describe("Destination config", () => { } } const output = transformer.process(event); - expect(output[0].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v_2'); - expect(output[0].data[integrationCasedString(integration(index), `context_attribute_v_3`)]).toEqual('some-value'); - expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v_3`)); - expect(output[1].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v_2'); - expect(output[1].data[integrationCasedString(integration(index), `context_attribute_v_3`)]).toEqual('some-value'); - expect(output[1].metadata.table).toEqual(integrationCasedString(integration(index), 'button_clicked_v_2')); - expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v_3`)); + expect(output[0].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v_2'); + expect(output[0].data[integrationCasedString(integrations[index], `context_attribute_v_3`)]).toEqual('some-value'); + expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v_3`)); + expect(output[1].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v_2'); + expect(output[1].data[integrationCasedString(integrations[index], `context_attribute_v_3`)]).toEqual('some-value'); + expect(output[1].metadata.table).toEqual(integrationCasedString(integrations[index], 'button_clicked_v_2')); + expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v_3`)); }); }); }); @@ -1364,7 +1386,10 @@ describe("Destination config", () => { } } const received = transformer.process(event); - const events = [received[0], received[1]]; // identifies and users event + const events = integrations[index] === "snowpipe_streaming" + ? [received[0]] + : [received[0], received[1]]; + // identifies and users event const traitsToCheck = { 'city': 'Disney', 'country': 'USA', @@ -1373,10 +1398,10 @@ describe("Destination config", () => { }; events.forEach(event => { Object.entries(traitsToCheck).forEach(([trait, value]) => { - expect(event.data).not.toHaveProperty(integrationCasedString(integration(index), trait)); - expect(event.data[integrationCasedString(integration(index), `context_traits_${trait}`)]).toEqual(value); - expect(event.metadata.columns).not.toHaveProperty(integrationCasedString(integration(index), trait)); - expect(event.metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_traits_${trait}`)); + expect(event.data).not.toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.data[integrationCasedString(integrations[index], `context_traits_${trait}`)]).toEqual(value); + expect(event.metadata.columns).not.toHaveProperty(integrationCasedString(integrations[index], trait)); + expect(event.metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_traits_${trait}`)); }); }); }); @@ -1402,13 +1427,13 @@ describe("Destination config", () => { } } const output = transformer.process(event); - expect(output[0].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v2'); - expect(output[0].data[integrationCasedString(integration(index), `context_attribute_v3`)]).toEqual('some-value'); - expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v3`)); - expect(output[1].data[integrationCasedString(integration(index), `event`)]).toEqual('button_clicked_v2'); - expect(output[1].data[integrationCasedString(integration(index), `context_attribute_v3`)]).toEqual('some-value'); - expect(output[1].metadata.table).toEqual(integrationCasedString(integration(index), 'button_clicked_v2')); - expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integration(index), `context_attribute_v3`)); + expect(output[0].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v2'); + expect(output[0].data[integrationCasedString(integrations[index], `context_attribute_v3`)]).toEqual('some-value'); + expect(output[0].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v3`)); + expect(output[1].data[integrationCasedString(integrations[index], `event`)]).toEqual('button_clicked_v2'); + expect(output[1].data[integrationCasedString(integrations[index], `context_attribute_v3`)]).toEqual('some-value'); + expect(output[1].metadata.table).toEqual(integrationCasedString(integrations[index], 'button_clicked_v2')); + expect(output[1].metadata.columns).toHaveProperty(integrationCasedString(integrations[index], `context_attribute_v3`)); }); }); }); @@ -1615,8 +1640,8 @@ describe("context traits", () => { expect(Object.keys(received[0].data).join()).not.toMatch(/context_traits/g); } for (const column of t.expectedColumns) { - expect(received[0].metadata.columns[integrationCasedString(integration(index), column)]).toEqual(t.expectedMetadata); - expect(received[0].data[integrationCasedString(integration(index), column)]).toEqual(t.expectedData); + expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); } }); } @@ -1708,8 +1733,8 @@ describe("group traits", () => { expect(Object.keys(received[0].data).join()).not.toMatch(/group_traits/g); } for (const column of t.expectedColumns) { - expect(received[0].metadata.columns[integrationCasedString(integration(index), column)]).toEqual(t.expectedMetadata); - expect(received[0].data[integrationCasedString(integration(index), column)]).toEqual(t.expectedData); + expect(received[0].metadata.columns[integrationCasedString(integrations[index], column)]).toEqual(t.expectedMetadata); + expect(received[0].data[integrationCasedString(integrations[index], column)]).toEqual(t.expectedData); } }); }); diff --git a/test/apitests/data_scenarios/cdk_v2/failure.json b/test/apitests/data_scenarios/cdk_v2/failure.json index 154d24481d..c252761e88 100644 --- a/test/apitests/data_scenarios/cdk_v2/failure.json +++ b/test/apitests/data_scenarios/cdk_v2/failure.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -448,7 +446,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -462,7 +460,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/cdk_v2/success.json b/test/apitests/data_scenarios/cdk_v2/success.json index 88f430dd7c..ce819c3f80 100644 --- a/test/apitests/data_scenarios/cdk_v2/success.json +++ b/test/apitests/data_scenarios/cdk_v2/success.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -448,7 +446,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -462,7 +460,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/batch/failure_batch.json b/test/apitests/data_scenarios/destination/batch/failure_batch.json index 6352ca1a11..80595e44f4 100644 --- a/test/apitests/data_scenarios/destination/batch/failure_batch.json +++ b/test/apitests/data_scenarios/destination/batch/failure_batch.json @@ -221,8 +221,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -257,7 +256,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -576,8 +574,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -612,7 +609,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -933,8 +929,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -969,7 +964,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1247,8 +1241,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1283,7 +1276,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1722,8 +1714,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1758,7 +1749,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], diff --git a/test/apitests/data_scenarios/destination/batch/successful_batch.json b/test/apitests/data_scenarios/destination/batch/successful_batch.json index 32745f49d5..45ceb1a545 100644 --- a/test/apitests/data_scenarios/destination/batch/successful_batch.json +++ b/test/apitests/data_scenarios/destination/batch/successful_batch.json @@ -221,8 +221,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -257,7 +256,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -578,8 +576,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -614,7 +611,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -935,8 +931,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -971,7 +966,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], @@ -1557,8 +1551,7 @@ "unsetParamsReferrerOnNewSession", "batchEvents", "eventUploadPeriodMillis", - "eventUploadThreshold", - "oneTrustCookieCategories" + "eventUploadThreshold" ] }, "excludeKeys": [], @@ -1593,7 +1586,6 @@ "useIdfaAsDeviceId", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption", "mapDeviceBrand" ], diff --git a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json index 3deb7d4b8b..c24dd08e8d 100644 --- a/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json +++ b/test/apitests/data_scenarios/destination/proc/batch_input_multiplex.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_failure.json index 68c7fc3baa..d08949ffb6 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_failure.json @@ -93,7 +93,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -107,7 +107,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json index a2652855d5..78e067e84b 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_partial_failure.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -271,7 +270,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -285,7 +284,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/proc/multiplex_success.json b/test/apitests/data_scenarios/destination/proc/multiplex_success.json index ba4d5266f3..2b05a2fad8 100644 --- a/test/apitests/data_scenarios/destination/proc/multiplex_success.json +++ b/test/apitests/data_scenarios/destination/proc/multiplex_success.json @@ -94,7 +94,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -108,7 +108,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/apitests/data_scenarios/destination/router/failure_test.json b/test/apitests/data_scenarios/destination/router/failure_test.json index 197456f66a..4b341142e9 100644 --- a/test/apitests/data_scenarios/destination/router/failure_test.json +++ b/test/apitests/data_scenarios/destination/router/failure_test.json @@ -157,7 +157,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -171,7 +171,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -395,7 +394,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -409,7 +408,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -633,7 +631,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -647,7 +645,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -1018,7 +1015,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -1032,7 +1029,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, @@ -1234,7 +1230,7 @@ "whitelistedEvents", "eventFilteringOption" ], - "web": ["useNativeSDK", "oneTrustCookieCategories"] + "web": ["useNativeSDK"] }, "excludeKeys": [], "includeKeys": [ @@ -1248,7 +1244,6 @@ "deduplicationKey", "blacklistedEvents", "whitelistedEvents", - "oneTrustCookieCategories", "eventFilteringOption" ], "saveDestinationResponse": false, diff --git a/test/integrations/component.test.ts b/test/integrations/component.test.ts index baad6813df..85c2eac2cd 100644 --- a/test/integrations/component.test.ts +++ b/test/integrations/component.test.ts @@ -24,6 +24,7 @@ import { appendFileSync } from 'fs'; import { assertRouterOutput, responses } from '../testHelper'; import { generateTestReport, initaliseReport } from '../test_reporter/reporter'; import _ from 'lodash'; +import { enhancedTestUtils } from '../test_reporter/allureReporter'; // To run single destination test cases // npm run test:ts -- component --destination=adobe_analytics @@ -55,7 +56,13 @@ if (opts.generate === 'true') { let server: Server; -const INTEGRATIONS_WITH_UPDATED_TEST_STRUCTURE = ['klaviyo', 'campaign_manager', 'criteo_audience']; +const INTEGRATIONS_WITH_UPDATED_TEST_STRUCTURE = [ + 'active_campaign', + 'klaviyo', + 'campaign_manager', + 'criteo_audience', + 'branch', +]; beforeAll(async () => { initaliseReport(); @@ -153,13 +160,8 @@ const testRoute = async (route, tcData: TestCaseData) => { if (INTEGRATIONS_WITH_UPDATED_TEST_STRUCTURE.includes(tcData.name?.toLocaleLowerCase())) { expect(validateTestWithZOD(tcData, response)).toEqual(true); - const bodyMatched = _.isEqual(response.body, outputResp.body); - const statusMatched = response.status === outputResp.status; - if (bodyMatched && statusMatched) { - generateTestReport(tcData, response.body, 'passed'); - } else { - generateTestReport(tcData, response.body, 'failed'); - } + enhancedTestUtils.beforeTestRun(tcData); + enhancedTestUtils.afterTestRun(tcData, response.body); } if (outputResp?.body) { diff --git a/test/integrations/destinations/active_campaign/processor/data.ts b/test/integrations/destinations/active_campaign/processor/data.ts index cef8c2a3a8..56bb3892b9 100644 --- a/test/integrations/destinations/active_campaign/processor/data.ts +++ b/test/integrations/destinations/active_campaign/processor/data.ts @@ -1,25 +1,63 @@ +/** + * Auto-migrated and optimized test cases + * Generated on: 2024-12-10T06:45:10.187Z + */ + +import { ProcessorTestData } from '../../../testTypes'; +import { Metadata } from '../../../../../src/types'; import MockAdapter from 'axios-mock-adapter'; import { isMatch } from 'lodash'; -export const data = [ +const baseMetadata: Metadata = { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-10T06:45:09.572Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, +}; + +export const data: ProcessorTestData[] = [ { + id: 'processor-1733813110185', name: 'active_campaign', - description: 'Test 0', + description: 'Test 0: Indetify scenario which tests the happy path of creating a contact', + scenario: + 'The contact is created successfully with all the fields info , a test tag is also added and the contact is subscribe to to list 2 and unsubscribed from list 3 and an invalid operation is performed on list 3', + successCriteria: 'Processor test should pass successfully, and the contact should be created', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.rudder.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { channel: 'web', messageId: '84e26acc-56a5-4835-8233-591137fca468', @@ -42,9 +80,18 @@ export const data = [ Random: 'random', }, lists: [ - { id: 2, status: 'subscribe' }, - { id: 3, status: 'unsubscribe' }, - { id: 3, status: 'unsubscribexyz' }, + { + id: 2, + status: 'subscribe', + }, + { + id: 3, + status: 'unsubscribe', + }, + { + id: 3, + status: 'unsubscribexyz', + }, ], address: { city: 'kolkata', @@ -54,12 +101,36 @@ export const data = [ street: '', }, }, - integrations: { All: true }, + integrations: { + All: true, + }, sentAt: '2019-10-14T09:03:22.563Z', }, + metadata: baseMetadata, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiKey', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], - method: 'POST', }, }, output: { @@ -85,10 +156,22 @@ export const data = [ firstName: 'James', lastName: 'Doe', fieldValues: [ - { field: '0', value: 'Trastkiv' }, - { field: '1', value: 'Russia' }, - { field: '3', value: '||Potato||Onion||' }, - { field: '4', value: 'random' }, + { + field: '0', + value: 'Trastkiv', + }, + { + field: '1', + value: 'Russia', + }, + { + field: '3', + value: '||Potato||Onion||', + }, + { + field: '4', + value: 'random', + }, ], }, }, @@ -99,6 +182,7 @@ export const data = [ files: {}, userId: '', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -106,23 +190,21 @@ export const data = [ }, }, { + id: 'processor-1733813110186', name: 'active_campaign', - description: 'Test 0', + description: + 'Test 1: Identify scenario which tests the happy path of creating a contact with multiple tags', + scenario: + 'Identify scenario which tests the happy path of creating a contact with all fields info and multiple tags and the contact is subscribed to list 2 and unsubscribed from list 3 and an invalid operation is performed on list 3', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.rudder.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { channel: 'web', messageId: '84e26acc-56a5-4835-8233-591137fca468', @@ -145,9 +227,18 @@ export const data = [ Random: 'random', }, lists: [ - { id: 2, status: 'subscribe' }, - { id: 3, status: 'unsubscribe' }, - { id: 3, status: 'unsubscribexyz' }, + { + id: 2, + status: 'subscribe', + }, + { + id: 3, + status: 'unsubscribe', + }, + { + id: 3, + status: 'unsubscribexyz', + }, ], address: { city: 'kolkata', @@ -157,12 +248,36 @@ export const data = [ street: '', }, }, - integrations: { All: true }, + integrations: { + All: true, + }, sentAt: '2019-10-14T09:03:22.563Z', }, + metadata: baseMetadata, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiKey', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], - method: 'POST', }, }, output: { @@ -188,10 +303,22 @@ export const data = [ firstName: 'James', lastName: 'Doe', fieldValues: [ - { field: '0', value: 'Trastkiv' }, - { field: '1', value: 'Russia' }, - { field: '3', value: '||Potato||Onion||' }, - { field: '4', value: 'random' }, + { + field: '0', + value: 'Trastkiv', + }, + { + field: '1', + value: 'Russia', + }, + { + field: '3', + value: '||Potato||Onion||', + }, + { + field: '4', + value: 'random', + }, ], }, }, @@ -202,6 +329,7 @@ export const data = [ files: {}, userId: '', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -209,40 +337,49 @@ export const data = [ }, }, { + id: 'processor-1733813110186', name: 'active_campaign', - description: 'Test 1', + description: 'Test 2: Page scenario which tests the happy path of tracking a page view', + scenario: 'Scenario which tests the happy path of tracking a page view', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.rudder.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { channel: 'web', context: { - page: { referring_domain: 'https://www.rudderlabs.com' }, + page: { + referring_domain: 'https://www.rudderlabs.com', + }, app: { build: '1.0.0', name: 'RudderLabs JavaScript SDK', namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - traits: { email: 'jamesDoe@gmail.com', anonymousId: '12345' }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + traits: { + email: 'jamesDoe@gmail.com', + anonymousId: '12345', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, request_ip: '1.1.1.1', type: 'page', @@ -259,100 +396,36 @@ export const data = [ title: 'Test Page', url: 'https://www.rudderlabs.com', }, - integrations: { All: true }, - sentAt: '2019-10-14T11:15:53.296Z', - }, - }, - ], - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - body: { - XML: {}, - FORM: {}, - JSON_ARRAY: {}, - JSON: { siteTrackingDomain: { name: 'rudderlabs.com' } }, - }, - type: 'REST', - files: {}, - method: 'POST', - params: {}, - headers: { - 'Api-Token': 'dummyApiKey', - 'Content-Type': 'application/json', + integrations: { + All: true, }, - version: '1', - endpoint: 'https://active.campaigns.rudder.com/api/3/siteTrackingDomains', - userId: '', + sentAt: '2019-10-14T11:15:53.296Z', }, - statusCode: 200, - }, - ], - }, - }, - }, - { - name: 'active_campaign', - description: 'Test 2', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { + metadata: baseMetadata, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: 'dummyApiKey', apiUrl: 'https://active.campaigns.rudder.com', actid: '476550467', eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', }, - }, - message: { - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - traits: { email: 'jamesDoe@gmail.com', anonymousId: '12345' }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - locale: 'en-US', - os: { name: '', version: '' }, - screen: { density: 2 }, - }, - request_ip: '1.1.1.1', - type: 'page', - messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', - session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', - originalTimestamp: '2019-10-14T11:15:18.299Z', - anonymousId: '00000000000000000000000000', - userId: '12345', - properties: { - name: 'ApplicationLoaded', - path: '/test', - referrer: 'Rudder', - search: 'abc', - title: 'Test Page', - url: 'https://www.rudderlabs.com', - }, - integrations: { All: true }, - sentAt: '2019-10-14T11:15:53.296Z', + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, ], - method: 'POST', }, }, output: { @@ -365,7 +438,11 @@ export const data = [ XML: {}, FORM: {}, JSON_ARRAY: {}, - JSON: { siteTrackingDomain: { name: 'rudderlabs.com' } }, + JSON: { + siteTrackingDomain: { + name: 'rudderlabs.com', + }, + }, }, type: 'REST', files: {}, @@ -379,6 +456,7 @@ export const data = [ endpoint: 'https://active.campaigns.rudder.com/api/3/siteTrackingDomains', userId: '', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -386,23 +464,21 @@ export const data = [ }, }, { + id: 'processor-1733813110186', name: 'active_campaign', - description: 'Test 3', + description: + 'Test 3: Screen event scenario which tests the happy path of tracking a screen view', + scenario: + 'Screen event scenario which tests the happy path of tracking a screen viewn the email field is passed in the visit field for the destination and the properties name is passed in the eventdata field the event is ScreenViewed', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.rudder.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { channel: 'web', context: { @@ -412,125 +488,71 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - traits: { email: 'jamesDoe@gmail.com', anonymousId: '12345' }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + traits: { + email: 'jamesDoe@gmail.com', + anonymousId: '12345', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, request_ip: '1.1.1.1', - type: 'page', + type: 'screen', messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', originalTimestamp: '2019-10-14T11:15:18.299Z', anonymousId: '00000000000000000000000000', userId: '12345', properties: { - name: 'ApplicationLoaded', path: '/test', referrer: 'Rudder', - referring_domain: 'https://www.rudderlabs.com', search: 'abc', title: 'Test Page', - url: 'https://www.rudderlabs.com', - }, - integrations: { All: true }, - sentAt: '2019-10-14T11:15:53.296Z', - }, - }, - ], - method: 'POST', - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - body: { - XML: {}, - FORM: {}, - JSON_ARRAY: {}, - JSON: { siteTrackingDomain: { name: 'rudderlabs.com' } }, + url: 'www.rudderlabs.com', + name: 'Rudder_Event_Screen_Test', }, - type: 'REST', - files: {}, - method: 'POST', - params: {}, - headers: { - 'Api-Token': 'dummyApiKey', - 'Content-Type': 'application/json', + event: 'ScreenViewed', + integrations: { + All: true, }, - version: '1', - endpoint: 'https://active.campaigns.rudder.com/api/3/siteTrackingDomains', - userId: '', + sentAt: '2019-10-14T11:15:53.296Z', }, - statusCode: 200, - }, - ], - }, - }, - }, - { - name: 'active_campaign', - description: 'Test 4', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { + metadata: baseMetadata, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: 'dummyApiKey', apiUrl: 'https://active.campaigns.rudder.com', actid: '476550467', eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', }, - }, - message: { - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - traits: { email: 'jamesDoe@gmail.com', anonymousId: '12345' }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', - locale: 'en-US', - os: { name: '', version: '' }, - screen: { density: 2 }, - }, - request_ip: '1.1.1.1', - type: 'screen', - messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', - session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', - originalTimestamp: '2019-10-14T11:15:18.299Z', - anonymousId: '00000000000000000000000000', - userId: '12345', - properties: { - path: '/test', - referrer: 'Rudder', - search: 'abc', - title: 'Test Page', - url: 'www.rudderlabs.com', - name: 'Rudder_Event_Screen_Test', - }, - event: 'ScreenViewed', - integrations: { All: true }, - sentAt: '2019-10-14T11:15:53.296Z', + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, ], - method: 'POST', }, }, output: { @@ -563,6 +585,7 @@ export const data = [ endpoint: 'https://trackcmp.net/event', userId: '', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -570,23 +593,20 @@ export const data = [ }, }, { + id: 'processor-1733813110186', name: 'active_campaign', - description: 'Test 5', + description: 'Test 4: Track event scenario which tests the happy path of tracking an event', + scenario: + 'Track event scenraio where the event name is Tracking Action and the properties name is Rudder_Event_Track_Test', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.rudder.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { anonymousId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', context: { @@ -596,26 +616,60 @@ export const data = [ model: 'Redmi 6', name: 'xiaomi', }, - network: { carrier: 'Banglalink' }, - os: { name: 'android', version: '8.1.0' }, + network: { + carrier: 'Banglalink', + }, + os: { + name: 'android', + version: '8.1.0', + }, traits: { email: 'jamesDoe@gmail.com', - address: { city: 'Dhaka', country: 'Bangladesh' }, + address: { + city: 'Dhaka', + country: 'Bangladesh', + }, anonymousId: 'c82cbdff-e5be-4009-ac78-cdeea09ab4b1', }, }, event: 'Tracking Action', - integrations: { All: true }, + integrations: { + All: true, + }, message_id: 'a80f82be-9bdc-4a9f-b2a5-15621ee41df8', - properties: { name: 'Rudder_Event_Track_Test' }, + properties: { + name: 'Rudder_Event_Track_Test', + }, userId: 'test_user_id', timestamp: '2019-09-01T15:46:51.693Z', originalTimestamp: '2019-09-01T15:46:51.693Z', type: 'track', }, + metadata: baseMetadata, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiKey', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], - method: 'POST', }, }, output: { @@ -648,6 +702,7 @@ export const data = [ endpoint: 'https://trackcmp.net/event', userId: '', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -655,23 +710,20 @@ export const data = [ }, }, { + id: 'processor-1733813110186', name: 'active_campaign', - description: 'Test 6', + description: + 'Test 5: Identify scenario which tests the happy path of creating/updating a contact with all fields info', + scenario: 'Scneario is exactly same as Test 0', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.rudder.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { channel: 'web', context: { @@ -681,13 +733,21 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, messageId: '84e26acc-56a5-4835-8233-591137fca468', session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', @@ -707,9 +767,18 @@ export const data = [ Random: 'random', }, lists: [ - { id: 2, status: 'subscribe' }, - { id: 3, status: 'unsubscribe' }, - { id: 3, status: 'unsubscribexyz' }, + { + id: 2, + status: 'subscribe', + }, + { + id: 3, + status: 'unsubscribe', + }, + { + id: 3, + status: 'unsubscribexyz', + }, ], address: { city: 'kolkata', @@ -719,12 +788,36 @@ export const data = [ street: '', }, }, - integrations: { All: true }, + integrations: { + All: true, + }, sentAt: '2019-10-14T09:03:22.563Z', }, + metadata: baseMetadata, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiKey', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], - method: 'POST', }, }, output: { @@ -742,10 +835,22 @@ export const data = [ email: 'jamesDoe@gmail.com', phone: '92374162212', fieldValues: [ - { field: '0', value: 'Trastkiv' }, - { field: '1', value: 'Russia' }, - { field: '3', value: '||Potato||Onion||' }, - { field: '4', value: 'random' }, + { + field: '0', + value: 'Trastkiv', + }, + { + field: '1', + value: 'Russia', + }, + { + field: '3', + value: '||Potato||Onion||', + }, + { + field: '4', + value: 'random', + }, ], }, }, @@ -762,32 +867,29 @@ export const data = [ endpoint: 'https://active.campaigns.rudder.com/api/3/contact/sync', userId: '', }, + metadata: baseMetadata, statusCode: 200, }, ], }, }, }, - { + id: 'processor-1733813110186', name: 'active_campaign', description: - 'Test 7: node error(ECONNABORTED) where there is no response coming from dest. server', + 'Test 6: node error(ECONNABORTED) where there is no response coming from dest. server', + scenario: + 'Scenario which tests the failure case where there is no response from the destination server', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.dumber.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { channel: 'web', context: { @@ -797,13 +899,21 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, messageId: '84e26acc-56a5-4835-8233-591137fca468', session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', @@ -823,9 +933,18 @@ export const data = [ Random: 'random', }, lists: [ - { id: 2, status: 'subscribe' }, - { id: 3, status: 'unsubscribe' }, - { id: 3, status: 'unsubscribexyz' }, + { + id: 2, + status: 'subscribe', + }, + { + id: 3, + status: 'unsubscribe', + }, + { + id: 3, + status: 'unsubscribexyz', + }, ], address: { city: 'kolkata', @@ -835,12 +954,36 @@ export const data = [ street: '', }, }, - integrations: { All: true }, + integrations: { + All: true, + }, sentAt: '2019-10-14T09:03:22.563Z', }, + metadata: baseMetadata, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiKey', + apiUrl: 'https://active.campaigns.dumber.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], - method: 'POST', }, }, output: { @@ -848,17 +991,20 @@ export const data = [ status: 200, body: [ { + metadata: baseMetadata, + statusCode: 500, error: '{"message":"Failed to create new contact (undefined,\\"[ECONNABORTED] :: Connection aborted\\")","destinationResponse":"[ECONNABORTED] :: Connection aborted"}', statTags: { destType: 'ACTIVE_CAMPAIGN', + destinationId: 'default-destination', errorCategory: 'network', errorType: 'retryable', feature: 'processor', implementation: 'native', module: 'destination', + workspaceId: 'default-workspace', }, - statusCode: 500, }, ], }, @@ -890,23 +1036,20 @@ export const data = [ }, }, { + id: 'processor-1733813110186', name: 'active_campaign', - description: 'Test 8: erreneous response from active_campaign server(5xx)', + description: 'Test 7: erreneous response from active_campaign server(5xx)', + scenario: + 'Scenario which tests the failure case where the destination server returns a 5xx error', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.dumber2.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { channel: 'web', context: { @@ -916,13 +1059,21 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, messageId: '84e26acc-56a5-4835-8233-591137fca468', session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', @@ -942,9 +1093,18 @@ export const data = [ Random: 'random', }, lists: [ - { id: 2, status: 'subscribe' }, - { id: 3, status: 'unsubscribe' }, - { id: 3, status: 'unsubscribexyz' }, + { + id: 2, + status: 'subscribe', + }, + { + id: 3, + status: 'unsubscribe', + }, + { + id: 3, + status: 'unsubscribexyz', + }, ], address: { city: 'kolkata', @@ -954,12 +1114,36 @@ export const data = [ street: '', }, }, - integrations: { All: true }, + integrations: { + All: true, + }, sentAt: '2019-10-14T09:03:22.563Z', }, + metadata: baseMetadata, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiKey', + apiUrl: 'https://active.campaigns.dumber2.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], - method: 'POST', }, }, output: { @@ -967,17 +1151,20 @@ export const data = [ status: 200, body: [ { + metadata: baseMetadata, + statusCode: 504, error: '{"message":"Failed to create new contact (undefined,\\"\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n \\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\naccurx.api-us1.com | 504: Gateway time-out\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\\\n
\\\\\\\\n
\\\\\\\\n
\\\\\\\\n

\\\\\\\\n Gateway time-out\\\\\\\\n Error code 504\\\\\\\\n

\\\\\\\\n
\\\\\\\\n Visit cloudflare.com for more information.\\\\\\\\n
\\\\\\\\n
2023-12-06 10:33:27 UTC
\\\\\\\\n
\\\\\\\\n
\\\\\\\\n
\\\\\\\\n
\\\\\\\\n \\\\\\\\n
\\\\\\\\n
\\\\\\\\n \\\\\\\\n \\\\\\\\n \\\\\\\\n \\\\\\\\n
\\\\\\\\n You\\\\\\\\n

\\\\\\\\n \\\\\\\\n Browser\\\\\\\\n \\\\\\\\n

\\\\\\\\n Working\\\\\\\\n
\\\\\\\\n\\\\\\\\n
\\\\\\\\n
\\\\\\\\n \\\\\\\\n \\\\\\\\n \\\\\\\\n \\\\\\\\n
\\\\\\\\n Frankfurt\\\\\\\\n

\\\\\\\\n \\\\\\\\n Cloudflare\\\\\\\\n \\\\\\\\n

\\\\\\\\n Working\\\\\\\\n
\\\\\\\\n\\\\\\\\n
\\\\\\\\n
\\\\\\\\n \\\\\\\\n \\\\\\\\n \\\\\\\\n \\\\\\\\n
\\\\\\\\n accurx.api-us1.com\\\\\\\\n

\\\\\\\\n \\\\\\\\n Host\\\\\\\\n \\\\\\\\n

\\\\\\\\n Error\\\\\\\\n
\\\\\\\\n\\\\\\\\n
\\\\\\\\n
\\\\\\\\n
\\\\\\\\n\\\\\\\\n
\\\\\\\\n
\\\\\\\\n
\\\\\\\\n

What happened?

\\\\\\\\n

The web server reported a gateway time-out error.

\\\\\\\\n
\\\\\\\\n
\\\\\\\\n

What can I do?

\\\\\\\\n

Please try again in a few minutes.

\\\\\\\\n
\\\\\\\\n
\\\\\\\\n
\\\\\\\\n\\\\\\\\n \\\\\\\\n\\\\\\\\n\\\\\\\\n
\\\\\\\\n
\\\\\\\\n\\\\\\\\n\\\\\\\\n\\\\\\")\\")","destinationResponse":"\\\\n\\\\n\\\\n\\\\n \\\\n\\\\n\\\\n\\\\naccurx.api-us1.com | 504: Gateway time-out\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n
\\\\n
\\\\n
\\\\n

\\\\n Gateway time-out\\\\n Error code 504\\\\n

\\\\n
\\\\n Visit cloudflare.com for more information.\\\\n
\\\\n
2023-12-06 10:33:27 UTC
\\\\n
\\\\n
\\\\n
\\\\n
\\\\n \\\\n
\\\\n
\\\\n \\\\n \\\\n \\\\n \\\\n
\\\\n You\\\\n

\\\\n \\\\n Browser\\\\n \\\\n

\\\\n Working\\\\n
\\\\n\\\\n
\\\\n
\\\\n \\\\n \\\\n \\\\n \\\\n
\\\\n Frankfurt\\\\n

\\\\n \\\\n Cloudflare\\\\n \\\\n

\\\\n Working\\\\n
\\\\n\\\\n
\\\\n
\\\\n \\\\n \\\\n \\\\n \\\\n
\\\\n accurx.api-us1.com\\\\n

\\\\n \\\\n Host\\\\n \\\\n

\\\\n Error\\\\n
\\\\n\\\\n
\\\\n
\\\\n
\\\\n\\\\n
\\\\n
\\\\n
\\\\n

What happened?

\\\\n

The web server reported a gateway time-out error.

\\\\n
\\\\n
\\\\n

What can I do?

\\\\n

Please try again in a few minutes.

\\\\n
\\\\n
\\\\n
\\\\n\\\\n \\\\n\\\\n\\\\n
\\\\n
\\\\n\\\\n\\\\n\\")"}', statTags: { destType: 'ACTIVE_CAMPAIGN', + destinationId: 'default-destination', errorCategory: 'network', errorType: 'retryable', feature: 'processor', implementation: 'native', module: 'destination', + workspaceId: 'default-workspace', }, - statusCode: 504, }, ], }, @@ -1016,23 +1203,19 @@ export const data = [ }, }, { + id: 'processor-1733813110186', name: 'active_campaign', - description: 'Test 9: erreneous response from active_campaign server(4xx)', + description: 'Test 8: erreneous response from active_campaign server(4xx)', + scenario: 'Scenrio which tests the processor when the active_campaign server returns 4xx error', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - apiKey: 'dummyApiKey', - apiUrl: 'https://active.campaigns.dumber2.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, message: { channel: 'web', context: { @@ -1042,13 +1225,21 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, messageId: '84e26acc-56a5-4835-8233-591137fca468', session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', @@ -1068,9 +1259,18 @@ export const data = [ Random: 'random', }, lists: [ - { id: 2, status: 'subscribe' }, - { id: 3, status: 'unsubscribe' }, - { id: 3, status: 'unsubscribexyz' }, + { + id: 2, + status: 'subscribe', + }, + { + id: 3, + status: 'unsubscribe', + }, + { + id: 3, + status: 'unsubscribexyz', + }, ], address: { city: 'kolkata', @@ -1080,12 +1280,36 @@ export const data = [ street: '', }, }, - integrations: { All: true }, + integrations: { + All: true, + }, sentAt: '2019-10-14T09:03:22.563Z', }, + metadata: baseMetadata, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiKey', + apiUrl: 'https://active.campaigns.dumber2.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], - method: 'POST', }, }, output: { @@ -1093,17 +1317,20 @@ export const data = [ status: 200, body: [ { + metadata: baseMetadata, + statusCode: 422, error: '{"message":"Failed to create new contact (undefined,{\\"errors\\":[{\\"title\\":\\"Contact Email Address is not valid.\\",\\"detail\\":\\"\\",\\"code\\":\\"email_invalid\\",\\"error\\":\\"must_be_valid_email_address\\",\\"source\\":{\\"pointer\\":\\"/data/attributes/email\\"}}]})","destinationResponse":{"errors":[{"title":"Contact Email Address is not valid.","detail":"","code":"email_invalid","error":"must_be_valid_email_address","source":{"pointer":"/data/attributes/email"}}]}}', statTags: { destType: 'ACTIVE_CAMPAIGN', + destinationId: 'default-destination', errorCategory: 'network', errorType: 'aborted', feature: 'processor', implementation: 'native', module: 'destination', + workspaceId: 'default-workspace', }, - statusCode: 422, }, ], }, diff --git a/test/integrations/destinations/active_campaign/router/data.ts b/test/integrations/destinations/active_campaign/router/data.ts index a73140c161..148e330b18 100644 --- a/test/integrations/destinations/active_campaign/router/data.ts +++ b/test/integrations/destinations/active_campaign/router/data.ts @@ -1,7 +1,18 @@ -export const data = [ +/** + * Auto-migrated and optimized test cases + * Generated on: 2024-12-06T12:28:59.200Z + */ + +import { RouterTestData } from '../../../testTypes'; +import {} from '../../../../../src/types'; + +export const data: RouterTestData[] = [ { + id: 'router-1733488139199', name: 'active_campaign', - description: 'Test 0', + description: 'Test 0: Successful identify event', + scenario: 'Scenario which tests for a successful identify event', + successCriteria: 'Router test should pass successfully', feature: 'router', module: 'destination', version: 'v0', @@ -10,15 +21,6 @@ export const data = [ body: { input: [ { - destination: { - Config: { - apiKey: 'dummyApiToken', - apiUrl: 'https://active.campaigns.rudder.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, - metadata: { jobId: 2, userId: 'u1' }, message: { channel: 'web', context: { @@ -28,13 +30,21 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, messageId: '84e26acc-56a5-4835-8233-591137fca468', session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', @@ -56,9 +66,18 @@ export const data = [ Random: 'random', }, lists: [ - { id: 2, status: 'subscribe' }, - { id: 3, status: 'unsubscribe' }, - { id: 3, status: 'unsubscribexyz' }, + { + id: 2, + status: 'subscribe', + }, + { + id: 3, + status: 'unsubscribe', + }, + { + id: 3, + status: 'unsubscribexyz', + }, ], address: { city: 'kolkata', @@ -68,9 +87,66 @@ export const data = [ street: '', }, }, - integrations: { All: true }, + integrations: { + All: true, + }, sentAt: '2019-10-14T09:03:22.563Z', }, + metadata: { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 2, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-06T12:28:58.577Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiToken', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], destType: 'active_campaign', @@ -96,10 +172,22 @@ export const data = [ lastName: 'Doe', phone: '92374162212', fieldValues: [ - { field: '0', value: 'Trastkiv' }, - { field: '1', value: 'Russia' }, - { field: '3', value: '||Potato||Onion||' }, - { field: '4', value: 'random' }, + { + field: '0', + value: 'Trastkiv', + }, + { + field: '1', + value: 'Russia', + }, + { + field: '3', + value: '||Potato||Onion||', + }, + { + field: '4', + value: 'random', + }, ], }, }, @@ -108,21 +196,72 @@ export const data = [ files: {}, method: 'POST', params: {}, - headers: { 'Api-Token': 'dummyApiToken', 'Content-Type': 'application/json' }, + headers: { + 'Api-Token': 'dummyApiToken', + 'Content-Type': 'application/json', + }, version: '1', endpoint: 'https://active.campaigns.rudder.com/api/3/contact/sync', }, - metadata: [{ jobId: 2, userId: 'u1' }], - batched: false, + metadata: [ + { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 2, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-06T12:28:58.577Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, + ], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: 'dummyApiToken', apiUrl: 'https://active.campaigns.rudder.com', actid: '476550467', eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: false, }, ], }, @@ -130,8 +269,11 @@ export const data = [ }, }, { + id: 'router-1733488139199', name: 'active_campaign', - description: 'Test 1', + description: 'Test 1: Test case for a successful page event', + scenario: 'Scenario which tests for a successful page event', + successCriteria: 'Router test should pass successfully', feature: 'router', module: 'destination', version: 'v0', @@ -140,15 +282,6 @@ export const data = [ body: { input: [ { - destination: { - Config: { - apiKey: 'dummyApiToken', - apiUrl: 'https://active.campaigns.rudder.com', - actid: '476550467', - eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', - }, - }, - metadata: { jobId: 2, userId: 'u1' }, message: { channel: 'web', context: { @@ -158,13 +291,24 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - traits: { email: 'jamesDoe@gmail.com', anonymousId: '12345' }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + traits: { + email: 'jamesDoe@gmail.com', + anonymousId: '12345', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, request_ip: '1.1.1.1', type: 'page', @@ -181,9 +325,66 @@ export const data = [ title: 'Test Page', url: 'https://www.rudderlabs.com', }, - integrations: { All: true }, + integrations: { + All: true, + }, sentAt: '2019-10-14T11:15:53.296Z', }, + metadata: { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 2, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-06T12:28:58.577Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, + destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: 'dummyApiToken', + apiUrl: 'https://active.campaigns.rudder.com', + actid: '476550467', + eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], destType: 'active_campaign', @@ -202,27 +403,82 @@ export const data = [ XML: {}, FORM: {}, JSON_ARRAY: {}, - JSON: { siteTrackingDomain: { name: 'rudderlabs.com' } }, + JSON: { + siteTrackingDomain: { + name: 'rudderlabs.com', + }, + }, }, type: 'REST', files: {}, method: 'POST', params: {}, - headers: { 'Api-Token': 'dummyApiToken', 'Content-Type': 'application/json' }, + headers: { + 'Api-Token': 'dummyApiToken', + 'Content-Type': 'application/json', + }, version: '1', endpoint: 'https://active.campaigns.rudder.com/api/3/siteTrackingDomains', }, - metadata: [{ jobId: 2, userId: 'u1' }], - batched: false, + metadata: [ + { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 2, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-06T12:28:58.577Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, + ], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: 'dummyApiToken', apiUrl: 'https://active.campaigns.rudder.com', actid: '476550467', eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: false, }, ], }, @@ -230,8 +486,11 @@ export const data = [ }, }, { + id: 'router-1733488139199', name: 'active_campaign', - description: 'Test 2', + description: 'Test 2: Page event with invalid URL', + scenario: 'Scenario which tests for a page event with invalid URL', + successCriteria: 'Router test should pass successfully', feature: 'router', module: 'destination', version: 'v0', @@ -246,7 +505,10 @@ export const data = [ sentAt: '2023-01-10T22:31:10.954Z', channel: 'web', context: { - os: { name: '', version: '' }, + os: { + name: '', + version: '', + }, app: { name: 'RudderLabs JavaScript SDK', build: '1.0.0', @@ -273,7 +535,10 @@ export const data = [ innerHeight: 782, }, traits: {}, - library: { name: 'RudderLabs JavaScript SDK', version: '2.20.0' }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '2.20.0', + }, campaign: {}, sessionId: 1673389635049, userAgent: @@ -297,18 +562,66 @@ export const data = [ receivedAt: '2023-01-10T22:31:11.612Z', request_ip: '0.0.0.20', anonymousId: '878e8f5f-9b6c-4aef-b5d3-1b970a13f17a', - integrations: { All: true }, + integrations: { + All: true, + }, originalTimestamp: '2023-01-10T22:31:10.943Z', }, + metadata: { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 5, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-06T12:28:58.577Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: 'dummyApiToken', apiUrl: 'https://active.campaigns.rudder.com', actid: '476550467', eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: { jobId: 5, userId: 'u1' }, }, ], destType: 'active_campaign', @@ -322,25 +635,75 @@ export const data = [ body: { output: [ { - error: 'Invalid URL: url', - statTags: { - destType: 'ACTIVE_CAMPAIGN', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - feature: 'router', - implementation: 'native', - module: 'destination', - }, + metadata: [ + { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 5, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-06T12:28:58.577Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, + ], statusCode: 400, - metadata: [{ jobId: 5, userId: 'u1' }], - batched: false, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: 'dummyApiToken', apiUrl: 'https://active.campaigns.rudder.com', actid: '476550467', eventKey: 'f8a866fddc721350fdc2fbbd2e5c43a6dddaaa03', }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, + batched: false, + error: 'Invalid URL: url', + statTags: { + destType: 'ACTIVE_CAMPAIGN', + destinationId: 'default-destination', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'router', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspace', }, }, ], diff --git a/test/integrations/destinations/adobe_analytics/processor/data.ts b/test/integrations/destinations/adobe_analytics/processor/data.ts index fa050897c9..2ace5bed4b 100644 --- a/test/integrations/destinations/adobe_analytics/processor/data.ts +++ b/test/integrations/destinations/adobe_analytics/processor/data.ts @@ -1412,7 +1412,7 @@ export const data = [ JSON_ARRAY: {}, XML: { payload: - '17941080sales campaignweb127.0.0.1en-USDalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)https://www.google.com/search?q=estore+bestsellerroottval001RudderLabs JavaScript SDK <Custom>TEDxGROWTH&MARKETINGoWatched Videohttps://www.estore.com/best-seller/1growth2020-01-09T10:01:53.558Zmktcloudid001event1footlockerrudderstackpoc', + '17941080sales campaignweb127.0.0.1en-USDalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)https://www.google.com/search?q=estore+bestsellerroottval001RudderLabs JavaScript SDK <Custom>TEDxGROWTH&MARKETINGoWatched Videohttps://www.estore.com/best-seller/1growth2020-01-09T10:01:53.558Zmktcloudid001event1footlockerrudderstackpoc', }, FORM: {}, }, @@ -1582,7 +1582,7 @@ export const data = [ JSON_ARRAY: {}, XML: { payload: - '17941080sales campaignweb127.0.0.1en-USDalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)https://www.google.com/search?q=estore+bestsellerroottval001Kolkata9935400932RudderLabs JavaScript SDKopage viewhttps://www.estore.com/best-seller/1r15,faze90Rciaz,hummer,tharcustompropval1custompropval22020-01-09T10:01:53.558Zmktcloudid001event2footlockerrudderstackpoc', + '17941080sales campaignweb127.0.0.1en-USDalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)https://www.google.com/search?q=estore+bestsellerroottval001Kolkata9935400932RudderLabs JavaScript SDKopage viewhttps://www.estore.com/best-seller/1r15,faze90Rciaz,hummer,tharcustompropval1custompropval22020-01-09T10:01:53.558Zmktcloudid001event2footlockerrudderstackpoc', }, FORM: {}, }, @@ -3044,7 +3044,7 @@ export const data = [ JSON_ARRAY: {}, XML: { payload: - '17941080sales campaignweb127.0.0.1en-USDalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)https://www.google.com/search?q=estore+bestsellerroottval001RudderLabs JavaScript SDKorandom unmapped eventhttps://www.estore.com/best-seller/12020-01-09T10:01:53.558Zmktcloudid001override eventfootlockerrudderstackpoc', + '17941080sales campaignweb127.0.0.1en-USDalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)https://www.google.com/search?q=estore+bestsellerroottval001RudderLabs JavaScript SDKorandom unmapped eventhttps://www.estore.com/best-seller/12020-01-09T10:01:53.558Zmktcloudid001override eventfootlockerrudderstackpoc', }, FORM: {}, }, diff --git a/test/integrations/destinations/af/processor/validation.ts b/test/integrations/destinations/af/processor/validation.ts index 8042570c7d..b36cd7d15d 100644 --- a/test/integrations/destinations/af/processor/validation.ts +++ b/test/integrations/destinations/af/processor/validation.ts @@ -1786,6 +1786,7 @@ export const newConfigValidationTests: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1843,6 +1844,7 @@ export const newConfigValidationTests: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1900,6 +1902,7 @@ export const newConfigValidationTests: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1956,6 +1959,7 @@ export const newConfigValidationTests: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2016,6 +2020,7 @@ export const newConfigValidationTests: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/airship/processor/data.ts b/test/integrations/destinations/airship/processor/data.ts index a72495d23d..973a6be0ec 100644 --- a/test/integrations/destinations/airship/processor/data.ts +++ b/test/integrations/destinations/airship/processor/data.ts @@ -1934,6 +1934,77 @@ export const data = [ }, }, }, + { + name: 'airship', + description: 'Test 16', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'track', + messageId: '84e26acc-56a5-4835-8233-591137fca468', + session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22', + originalTimestamp: '2019-10-14T09:03:17.562Z', + anonymousId: '123456', + event: 'Product Clicked', + userId: 'testuserId1', + properties: { value: 55 }, + integrations: { All: true }, + sentAt: '2019-10-14T09:03:22.563Z', + }, + destination: { + Config: { + apiKey: 'dummyApiKey', + appKey: 'ffdf', + appSecret: 'fhf', + dataCenter: false, + }, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://go.urbanairship.com/api/custom-events', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/vnd.urbanairship+json; version=3', + 'X-UA-Appkey': 'ffdf', + Authorization: 'Bearer dummyApiKey', + }, + params: {}, + body: { + JSON: { + occured: '2019-10-14T09:03:17.562Z', + user: { named_user_id: 'testuserId1' }, + body: { name: 'product_clicked', value: 55 }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, { name: 'airship', description: 'Test 17', @@ -2296,7 +2367,7 @@ export const data = [ }, { name: 'airship', - description: 'Test 22 : session id gets converted to v5 uuid format', + description: 'Test 22 : session id from Web SDK gets converted to v5 uuid format', feature: 'processor', module: 'destination', version: 'v0', @@ -2381,6 +2452,267 @@ export const data = [ }, }, }, + { + name: 'airship', + description: 'Test 23 : session id from mobile SDK gets converted to v5 uuid format', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { email: 'testone@gmail.com', firstName: 'test', lastName: 'one' }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + sessionId: 1731403898, + }, + type: 'track', + messageId: '84e26acc-56a5-4835-8233-591137fca468', + anonymousId: '123456', + event: 'Product Clicked', + userId: 'testuserId1', + properties: {}, + integrations: { All: true }, + }, + destination: { + Config: { + apiKey: 'dummyApiKey', + appKey: 'ffdf', + dataCenter: false, + }, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://go.urbanairship.com/api/custom-events', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/vnd.urbanairship+json; version=3', + 'X-UA-Appkey': 'ffdf', + Authorization: 'Bearer dummyApiKey', + }, + params: {}, + body: { + JSON: { + user: { named_user_id: 'testuserId1' }, + body: { + name: 'product_clicked', + session_id: 'd5627eac-795d-5005-9bb4-2c7c0af6cab0', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'airship', + description: 'Test 24 : session id null gets ignored', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { email: 'testone@gmail.com', firstName: 'test', lastName: 'one' }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + }, + type: 'track', + messageId: '84e26acc-56a5-4835-8233-591137fca468', + anonymousId: '123456', + event: 'Product Clicked', + userId: 'testuserId1', + properties: { + sessionId: null, + }, + integrations: { All: true }, + }, + destination: { + Config: { + apiKey: 'dummyApiKey', + appKey: 'ffdf', + dataCenter: false, + }, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://go.urbanairship.com/api/custom-events', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/vnd.urbanairship+json; version=3', + 'X-UA-Appkey': 'ffdf', + Authorization: 'Bearer dummyApiKey', + }, + params: {}, + body: { + JSON: { + user: { named_user_id: 'testuserId1' }, + body: { + name: 'product_clicked', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, + { + name: 'airship', + description: 'Test 24 : session id undefined gets ignored', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + traits: { email: 'testone@gmail.com', firstName: 'test', lastName: 'one' }, + library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { name: '', version: '' }, + screen: { density: 2 }, + }, + type: 'track', + messageId: '84e26acc-56a5-4835-8233-591137fca468', + anonymousId: '123456', + event: 'Product Clicked', + userId: 'testuserId1', + properties: { + sessionId: undefined, + }, + integrations: { All: true }, + }, + destination: { + Config: { + apiKey: 'dummyApiKey', + appKey: 'ffdf', + dataCenter: false, + }, + }, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://go.urbanairship.com/api/custom-events', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/vnd.urbanairship+json; version=3', + 'X-UA-Appkey': 'ffdf', + Authorization: 'Bearer dummyApiKey', + }, + params: {}, + body: { + JSON: { + user: { named_user_id: 'testuserId1' }, + body: { + name: 'product_clicked', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, ].map((tc) => ({ ...tc, mockFns: (_) => { diff --git a/test/integrations/destinations/algolia/router/data.ts b/test/integrations/destinations/algolia/router/data.ts index dca899693e..adc7be1596 100644 --- a/test/integrations/destinations/algolia/router/data.ts +++ b/test/integrations/destinations/algolia/router/data.ts @@ -2007,7 +2007,6 @@ export const data = [ { from: 'Order Completed', to: 'conversion' }, { from: 'Product Added', to: 'click' }, ], - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1687213909459, }, @@ -2017,16 +2016,11 @@ export const data = [ DestinationDefinition: { Config: { destConfig: { - defaultConfig: [ - 'apiKey', - 'applicationId', - 'eventTypeSettings', - 'oneTrustCookieCategories', - ], + defaultConfig: ['apiKey', 'applicationId', 'eventTypeSettings'], }, secretKeys: ['apiKey', 'applicationId'], excludeKeys: [], - includeKeys: ['oneTrustCookieCategories'], + includeKeys: [], transformAt: 'router', cdkV2Enabled: true, transformAtV1: 'router', @@ -2146,21 +2140,15 @@ export const data = [ { from: 'Order Completed', to: 'conversion' }, { from: 'Product Added', to: 'click' }, ], - oneTrustCookieCategories: [], }, DestinationDefinition: { Config: { cdkV2Enabled: true, destConfig: { - defaultConfig: [ - 'apiKey', - 'applicationId', - 'eventTypeSettings', - 'oneTrustCookieCategories', - ], + defaultConfig: ['apiKey', 'applicationId', 'eventTypeSettings'], }, excludeKeys: [], - includeKeys: ['oneTrustCookieCategories'], + includeKeys: [], saveDestinationResponse: true, secretKeys: ['apiKey', 'applicationId'], supportedMessageTypes: ['track'], diff --git a/test/integrations/destinations/am/deleteUsers/data.ts b/test/integrations/destinations/am/deleteUsers/data.ts index bd10a4d7e0..3431df980e 100644 --- a/test/integrations/destinations/am/deleteUsers/data.ts +++ b/test/integrations/destinations/am/deleteUsers/data.ts @@ -393,4 +393,45 @@ export const data = [ }, }, }, + { + name: 'am', + description: 'user deletion test with EU residencyServer', + feature: 'userDeletion', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + jobId: 'dummy-job-id', + destType: 'AM', + userAttributes: [ + { + userId: 'test_user_id_1', + }, + { + userId: 'test_user_id_2', + }, + ], + config: { + apiKey: '1234', + apiSecret: 'abcd', + residencyServer: 'EU', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + statusCode: 200, + status: 'successful', + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/am/network.ts b/test/integrations/destinations/am/network.ts index 5cd016069c..19181e5066 100644 --- a/test/integrations/destinations/am/network.ts +++ b/test/integrations/destinations/am/network.ts @@ -205,6 +205,44 @@ const deleteNwData = [ }, }, }, + { + httpReq: { + method: 'post', + url: 'https://analytics.eu.amplitude.com/api/2/deletions/users', + data: { + user_ids: ['test_user_id_1', 'test_user_id_2'], + requester: 'RudderStack', + ignore_invalid_id: 'true', + }, + headers: { + 'Content-Type': 'application/json', + Authorization: 'Basic MTIzNDphYmNk', + }, + }, + httpRes: { + data: [ + { + active_scrub_done_date: null, + amplitude_ids: [ + { + amplitude_id: 44547850078, + requested_on_day: '2024-12-01', + requester: 'RudderStack', + }, + { + amplitude_id: 44547886812, + requested_on_day: '2024-12-01', + requester: 'RudderStack', + }, + ], + app: '10000000', + day: '2025-01-10', + status: 'staging', + }, + ], + status: 200, + }, + }, ]; const deliveryNwData = [ diff --git a/test/integrations/destinations/bloomreach/processor/identify.ts b/test/integrations/destinations/bloomreach/processor/identify.ts index 2a79cb57e3..cf9486081b 100644 --- a/test/integrations/destinations/bloomreach/processor/identify.ts +++ b/test/integrations/destinations/bloomreach/processor/identify.ts @@ -30,6 +30,7 @@ export const identify: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -107,6 +108,7 @@ export const identify: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/bloomreach/processor/page.ts b/test/integrations/destinations/bloomreach/processor/page.ts index 3081feeb26..ae454ba3ef 100644 --- a/test/integrations/destinations/bloomreach/processor/page.ts +++ b/test/integrations/destinations/bloomreach/processor/page.ts @@ -40,6 +40,7 @@ export const page: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -97,6 +98,7 @@ export const page: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/bloomreach/processor/track.ts b/test/integrations/destinations/bloomreach/processor/track.ts index a369f508b2..bca516a3b4 100644 --- a/test/integrations/destinations/bloomreach/processor/track.ts +++ b/test/integrations/destinations/bloomreach/processor/track.ts @@ -30,6 +30,7 @@ export const track: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -87,6 +88,7 @@ export const track: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -142,6 +144,7 @@ export const track: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/bloomreach/processor/validation.ts b/test/integrations/destinations/bloomreach/processor/validation.ts index 1a6199abb0..dcd3690837 100644 --- a/test/integrations/destinations/bloomreach/processor/validation.ts +++ b/test/integrations/destinations/bloomreach/processor/validation.ts @@ -34,6 +34,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -78,6 +79,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -118,6 +120,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -162,6 +165,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/branch/processor/data.ts b/test/integrations/destinations/branch/processor/data.ts index dc1bdd33bc..e5519b7c39 100644 --- a/test/integrations/destinations/branch/processor/data.ts +++ b/test/integrations/destinations/branch/processor/data.ts @@ -1,7 +1,53 @@ -export const data = [ +/** + * Auto-migrated and optimized test cases + * Generated on: 2024-12-30T11:04:59.426Z + */ + +import { ProcessorTestData } from '../../../testTypes'; +import { Metadata } from '../../../../../src/types'; + +const baseMetadata: Metadata = { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-30T11:04:58.693Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, +}; + +export const data: ProcessorTestData[] = [ { + id: 'processor-1735556699424', name: 'branch', description: 'Test 0', + scenario: + 'Success scenario where the event will be mapped to standard event through default mappings', + successCriteria: 'Should hit the standard endpoint', feature: 'processor', module: 'destination', version: 'v0', @@ -9,21 +55,6 @@ export const data = [ request: { body: [ { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, message: { anonymousId: 'sampath', channel: 'web', @@ -80,8 +111,30 @@ export const data = [ type: 'track', userId: 'sampath', }, + metadata: baseMetadata, + destination: { + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', + DestinationDefinition: { + DisplayName: 'Branch Metrics', + ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', + Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], + method: 'POST', }, }, output: { @@ -129,6 +182,7 @@ export const data = [ files: {}, userId: 'sampath', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -136,8 +190,11 @@ export const data = [ }, }, { + id: 'processor-1735556699424', name: 'branch', description: 'Test 1', + scenario: 'Success scenario with identify event', + successCriteria: 'Should hit the custom endpoint with userId as event name', feature: 'processor', module: 'destination', version: 'v0', @@ -145,21 +202,6 @@ export const data = [ request: { body: [ { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, message: { anonymousId: 'sampath', channel: 'web', @@ -212,8 +254,30 @@ export const data = [ type: 'identify', userId: 'sampath', }, + metadata: baseMetadata, + destination: { + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', + DestinationDefinition: { + DisplayName: 'Branch Metrics', + ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', + Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], + method: 'POST', }, }, output: { @@ -261,6 +325,7 @@ export const data = [ files: {}, userId: 'sampath', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -268,8 +333,11 @@ export const data = [ }, }, { + id: 'processor-1735556699424', name: 'branch', description: 'Test 2', + scenario: 'Default processor scenario', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', @@ -277,112 +345,6 @@ export const data = [ request: { body: [ { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, - message: { - anonymousId: 'sampath', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - ip: '0.0.0.0', - library: { - name: 'RudderLabs JavaScript SDK', - version: '1.0.0', - }, - locale: 'en-US', - os: { - name: '', - version: '', - }, - screen: { - density: 2, - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - integrations: { - All: true, - }, - traits: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', - originalTimestamp: '2020-01-17T04:53:51.185Z', - receivedAt: '2020-01-17T10:23:52.688+05:30', - request_ip: '[::1]:64059', - sentAt: '2020-01-17T04:53:52.667Z', - timestamp: '2020-01-17T10:23:51.206+05:30', - type: 'page', - userId: 'sampath', - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - statusCode: 400, - statTags: { - destType: 'BRANCH', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - feature: 'processor', - implementation: 'native', - module: 'destination', - }, - error: 'Message type is not supported', - }, - ], - }, - }, - }, - { - name: 'branch', - description: 'Test 3', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, message: { anonymousId: 'sampath', channel: 'web', @@ -409,7 +371,7 @@ export const data = [ }, locale: 'en-US', os: { - name: 'watchos', + name: 'tvos', }, screen: { density: 2, @@ -437,8 +399,30 @@ export const data = [ type: 'track', userId: 'sampath', }, + metadata: baseMetadata, + destination: { + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', + DestinationDefinition: { + DisplayName: 'Branch Metrics', + ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', + Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], + method: 'POST', }, }, output: { @@ -464,7 +448,7 @@ export const data = [ }, ], user_data: { - os: 'watchos', + os: 'tvos', app_version: '1.0.0', screen_dpi: 2, developer_identity: 'sampath', @@ -485,6 +469,7 @@ export const data = [ files: {}, userId: 'sampath', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -492,8 +477,11 @@ export const data = [ }, }, { + id: 'processor-1735556699424', name: 'branch', - description: 'Test 4', + description: 'Test 3', + scenario: 'Successful scenario with track event but without any products', + successCriteria: 'The transformed payload should not contain any content_items', feature: 'processor', module: 'destination', version: 'v0', @@ -501,21 +489,6 @@ export const data = [ request: { body: [ { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, message: { anonymousId: 'sampath', channel: 'web', @@ -533,6 +506,7 @@ export const data = [ manufacturer: 'Google', model: 'AOSP on IA Emulator', name: 'generic_x86_arm', + type: 'ios', attTrackingStatus: 3, }, ip: '0.0.0.0', @@ -542,7 +516,8 @@ export const data = [ }, locale: 'en-US', os: { - name: 'ipados', + name: 'iOS', + version: '14.4.1', }, screen: { density: 2, @@ -560,9 +535,6 @@ export const data = [ }, messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', originalTimestamp: '2020-01-17T04:53:51.185Z', - properties: { - name: 'sampath', - }, receivedAt: '2020-01-17T10:23:52.688+05:30', request_ip: '[::1]:64059', sentAt: '2020-01-17T04:53:52.667Z', @@ -570,8 +542,30 @@ export const data = [ type: 'track', userId: 'sampath', }, + metadata: baseMetadata, + destination: { + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', + DestinationDefinition: { + DisplayName: 'Branch Metrics', + ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', + Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], + method: 'POST', }, }, output: { @@ -591,13 +585,9 @@ export const data = [ params: {}, body: { JSON: { - content_items: [ - { - $product_name: 'sampath', - }, - ], user_data: { - os: 'ipados', + os: 'iOS', + os_version: '14.4.1', app_version: '1.0.0', screen_dpi: 2, developer_identity: 'sampath', @@ -618,6 +608,7 @@ export const data = [ files: {}, userId: 'sampath', }, + metadata: baseMetadata, statusCode: 200, }, ], @@ -625,8 +616,11 @@ export const data = [ }, }, { + id: 'processor-1735556699425', name: 'branch', - description: 'Test 5', + description: 'Test 4', + scenario: 'Failure scenario when event name is not present', + successCriteria: 'Should return error message for missing event name', feature: 'processor', module: 'destination', version: 'v0', @@ -634,31 +628,10 @@ export const data = [ request: { body: [ { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, message: { anonymousId: 'sampath', channel: 'web', context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, device: { adTrackingEnabled: true, advertisingId: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', @@ -666,6 +639,7 @@ export const data = [ manufacturer: 'Google', model: 'AOSP on IA Emulator', name: 'generic_x86_arm', + type: 'ios', attTrackingStatus: 3, }, ip: '0.0.0.0', @@ -675,10 +649,8 @@ export const data = [ }, locale: 'en-US', os: { - name: 'tvos', - }, - screen: { - density: 2, + name: 'iOS', + version: '14.4.1', }, traits: { anonymousId: 'sampath', @@ -687,753 +659,42 @@ export const data = [ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', }, - event: 'product added', integrations: { All: true, }, messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', originalTimestamp: '2020-01-17T04:53:51.185Z', - properties: { - name: 'sampath', - }, - receivedAt: '2020-01-17T10:23:52.688+05:30', - request_ip: '[::1]:64059', - sentAt: '2020-01-17T04:53:52.667Z', - timestamp: '2020-01-17T10:23:51.206+05:30', - type: 'track', - userId: 'sampath', - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api2.branch.io/v2/event/standard', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - params: {}, - body: { - JSON: { - content_items: [ - { - $product_name: 'sampath', - }, - ], - user_data: { - os: 'tvos', - app_version: '1.0.0', - screen_dpi: 2, - developer_identity: 'sampath', - idfa: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - idfv: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - limit_ad_tracking: false, - model: 'AOSP on IA Emulator', - user_agent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - name: 'ADD_TO_CART', - branch_key: '', - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - userId: 'sampath', - }, - statusCode: 200, - }, - ], - }, - }, - }, - { - name: 'branch', - description: 'Test 6', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, - message: { - anonymousId: 'sampath', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - device: { - adTrackingEnabled: true, - advertisingId: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - id: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - manufacturer: 'Google', - model: 'AOSP on IA Emulator', - name: 'generic_x86_arm', - type: 'ios', - attTrackingStatus: 3, - }, - ip: '0.0.0.0', - library: { - name: 'RudderLabs JavaScript SDK', - version: '1.0.0', - }, - locale: 'en-US', - os: { - name: 'iOS', - version: '14.4.1', - }, - screen: { - density: 2, - }, - traits: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - event: 'product added', - integrations: { - All: true, - }, - messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', - originalTimestamp: '2020-01-17T04:53:51.185Z', - receivedAt: '2020-01-17T10:23:52.688+05:30', - request_ip: '[::1]:64059', - sentAt: '2020-01-17T04:53:52.667Z', - timestamp: '2020-01-17T10:23:51.206+05:30', - type: 'track', - userId: 'sampath', - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api2.branch.io/v2/event/standard', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - params: {}, - body: { - JSON: { - user_data: { - os: 'iOS', - os_version: '14.4.1', - app_version: '1.0.0', - screen_dpi: 2, - developer_identity: 'sampath', - idfa: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - idfv: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - limit_ad_tracking: false, - model: 'AOSP on IA Emulator', - user_agent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - name: 'ADD_TO_CART', - branch_key: '', - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - userId: 'sampath', - }, - statusCode: 200, - }, - ], - }, - }, - }, - { - name: 'branch', - description: 'Test 7', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, - message: { - anonymousId: 'sampath', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - device: { - adTrackingEnabled: true, - advertisingId: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - id: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - manufacturer: 'Google', - model: 'AOSP on IA Emulator', - name: 'generic_x86_arm', - type: 'ios', - attTrackingStatus: 3, - }, - ip: '0.0.0.0', - library: { - name: 'RudderLabs JavaScript SDK', - version: '1.0.0', - }, - locale: 'en-US', - screen: { - density: 2, - }, - traits: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - event: 'product added', - integrations: { - All: true, - }, - messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', - originalTimestamp: '2020-01-17T04:53:51.185Z', - receivedAt: '2020-01-17T10:23:52.688+05:30', - request_ip: '[::1]:64059', - sentAt: '2020-01-17T04:53:52.667Z', - timestamp: '2020-01-17T10:23:51.206+05:30', - type: 'track', - userId: 'sampath', - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api2.branch.io/v2/event/standard', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - params: {}, - body: { - JSON: { - user_data: { - app_version: '1.0.0', - screen_dpi: 2, - developer_identity: 'sampath', - limit_ad_tracking: false, - model: 'AOSP on IA Emulator', - user_agent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - name: 'ADD_TO_CART', - branch_key: '', - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - userId: 'sampath', - }, - statusCode: 200, - }, - ], - }, - }, - }, - { - name: 'branch', - description: 'Test 8', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, - message: { - anonymousId: 'sampath', - channel: 'web', - context: { - device: { - adTrackingEnabled: true, - advertisingId: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - id: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - manufacturer: 'Google', - model: 'AOSP on IA Emulator', - name: 'generic_x86_arm', - type: 'ios', - attTrackingStatus: 3, - }, - ip: '0.0.0.0', - library: { - name: 'RudderLabs JavaScript SDK', - version: '1.0.0', - }, - locale: 'en-US', - os: { - name: 'iOS', - version: '14.4.1', - }, - traits: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - event: 'product added', - integrations: { - All: true, - }, - messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', - originalTimestamp: '2020-01-17T04:53:51.185Z', - receivedAt: '2020-01-17T10:23:52.688+05:30', - request_ip: '[::1]:64059', - sentAt: '2020-01-17T04:53:52.667Z', - timestamp: '2020-01-17T10:23:51.206+05:30', - type: 'track', - userId: 'sampath', - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api2.branch.io/v2/event/standard', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - params: {}, - body: { - JSON: { - user_data: { - os: 'iOS', - os_version: '14.4.1', - developer_identity: 'sampath', - idfa: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - idfv: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - limit_ad_tracking: false, - model: 'AOSP on IA Emulator', - user_agent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - name: 'ADD_TO_CART', - branch_key: '', - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - userId: 'sampath', - }, - statusCode: 200, - }, - ], - }, - }, - }, - { - name: 'branch', - description: 'Test 9', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, - message: { - anonymousId: 'sampath', - channel: 'web', - context: { - device: { - adTrackingEnabled: true, - advertisingId: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - id: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - manufacturer: 'Google', - model: 'AOSP on IA Emulator', - name: 'generic_x86_arm', - type: 'ios', - attTrackingStatus: 3, - }, - ip: '0.0.0.0', - library: { - name: 'RudderLabs JavaScript SDK', - version: '1.0.0', - }, - locale: 'en-US', - os: { - name: 'iOS', - version: '14.4.1', - }, - traits: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - integrations: { - All: true, - }, - messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', - originalTimestamp: '2020-01-17T04:53:51.185Z', - receivedAt: '2020-01-17T10:23:52.688+05:30', - request_ip: '[::1]:64059', - sentAt: '2020-01-17T04:53:52.667Z', - timestamp: '2020-01-17T10:23:51.206+05:30', - type: 'track', - userId: 'sampath', - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - statusCode: 400, - error: 'Event name is required', - statTags: { - destType: 'BRANCH', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - feature: 'processor', - implementation: 'native', - module: 'destination', - }, - }, - ], - }, - }, - }, - { - name: 'branch', - description: 'Test 10', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { - destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, - message: { - anonymousId: 'sampath', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - device: { - adTrackingEnabled: true, - advertisingId: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - id: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - manufacturer: 'Google', - model: 'AOSP on IA Emulator', - name: 'generic_x86_arm', - type: 'Android', - attTrackingStatus: 2, - brand: 'testBrand', - }, - ip: '0.0.0.0', - library: { - name: 'RudderLabs JavaScript SDK', - version: '1.0.0', - }, - locale: 'en-US', - os: { - name: 'Android', - version: '9', - }, - screen: { - density: 2, - height: 1794, - width: 1080, - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - integrations: { - All: true, - }, - traits: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', - originalTimestamp: '2020-01-17T04:53:51.185Z', receivedAt: '2020-01-17T10:23:52.688+05:30', request_ip: '[::1]:64059', sentAt: '2020-01-17T04:53:52.667Z', timestamp: '2020-01-17T10:23:51.206+05:30', - type: 'identify', - userId: 'sampath', - }, - }, - ], - }, - }, - output: { - response: { - status: 200, - body: [ - { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api2.branch.io/v2/event/custom', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - params: {}, - body: { - JSON: { - custom_data: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - content_items: [{}], - user_data: { - os: 'Android', - os_version: '9', - app_version: '1.0.0', - model: 'AOSP on IA Emulator', - brand: 'testBrand', - screen_dpi: 2, - screen_height: 1794, - screen_width: 1080, - developer_identity: 'sampath', - user_agent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - android_id: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - aaid: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - limit_ad_tracking: true, - }, - name: 'sampath', - branch_key: '', - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, + type: 'track', userId: 'sampath', }, - statusCode: 200, - }, - ], - }, - }, - }, - { - name: 'branch', - description: 'Test 11', - feature: 'processor', - module: 'destination', - version: 'v0', - input: { - request: { - body: [ - { + metadata: baseMetadata, destination: { - Config: { - branchKey: '', - useNativeSDK: false, - }, + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', DestinationDefinition: { DisplayName: 'Branch Metrics', ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, }, Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', + WorkspaceID: 'default-workspace', Transformations: [], - }, - message: { - anonymousId: 'sampath', - channel: 'web', - context: { - app: { - build: '1.0.0', - name: 'RudderLabs JavaScript SDK', - namespace: 'com.rudderlabs.javascript', - version: '1.0.0', - }, - device: { - adTrackingEnabled: true, - advertisingId: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - id: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - manufacturer: 'Google', - model: 'AOSP on IA Emulator', - name: 'generic_x86_arm', - type: 'ios', - attTrackingStatus: 2, - brand: 'testBrand', - }, - ip: '0.0.0.0', - library: { - name: 'RudderLabs JavaScript SDK', - version: '1.0.0', - }, - locale: 'en-US', - os: { - name: 'iOS', - version: '14.4.1', - }, - screen: { - density: 2, - height: 1794, - width: 1080, - }, - userAgent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - }, - integrations: { - All: true, - }, - traits: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', - originalTimestamp: '2020-01-17T04:53:51.185Z', - receivedAt: '2020-01-17T10:23:52.688+05:30', - request_ip: '[::1]:64059', - sentAt: '2020-01-17T04:53:52.667Z', - timestamp: '2020-01-17T10:23:51.206+05:30', - type: 'identify', - userId: 'sampath', + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, ], + method: 'POST', }, }, output: { @@ -1441,86 +702,38 @@ export const data = [ status: 200, body: [ { - output: { - version: '1', - type: 'REST', - method: 'POST', - endpoint: 'https://api2.branch.io/v2/event/custom', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - params: {}, - body: { - JSON: { - custom_data: { - anonymousId: 'sampath', - email: 'sampath@gmail.com', - }, - content_items: [{}], - user_data: { - os: 'iOS', - os_version: '14.4.1', - app_version: '1.0.0', - model: 'AOSP on IA Emulator', - brand: 'testBrand', - screen_dpi: 2, - screen_height: 1794, - screen_width: 1080, - developer_identity: 'sampath', - user_agent: - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', - idfa: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - idfv: '3f034872-5e28-45a1-9eda-ce22a3e36d1a', - limit_ad_tracking: true, - }, - name: 'sampath', - branch_key: '', - }, - JSON_ARRAY: {}, - XML: {}, - FORM: {}, - }, - files: {}, - userId: 'sampath', + metadata: baseMetadata, + statusCode: 400, + error: 'Event name is required', + statTags: { + destType: 'BRANCH', + destinationId: 'default-destination', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspace', }, - statusCode: 200, }, ], }, }, }, { + id: 'processor-1735556699425', name: 'branch', - description: 'Map event name to branch standard event name in track call', + description: 'Test 5', + scenario: 'Default processor scenario', + successCriteria: 'Processor test should pass successfully', feature: 'processor', module: 'destination', version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - Config: { - branchKey: 'test_branch_key', - eventsMapping: [ - { - from: 'Order Completed', - to: 'PURCHASE', - }, - ], - useNativeSDK: false, - }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, message: { anonymousId: 'anonId123', channel: 'web', @@ -1561,7 +774,7 @@ export const data = [ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', }, - event: 'Order Completed', + event: 'Some Random Event', integrations: { All: true, }, @@ -1582,6 +795,33 @@ export const data = [ type: 'track', userId: 'userId123', }, + metadata: baseMetadata, + destination: { + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', + DestinationDefinition: { + DisplayName: 'Branch Metrics', + ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', + Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: 'test_branch_key', + eventsMapping: [ + { + from: 'Some Random Event', + to: 'PURCHASE', + }, + ], + useNativeSDK: false, + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -1640,6 +880,7 @@ export const data = [ files: {}, userId: 'anonId123', }, + metadata: baseMetadata, statusCode: 200, }, ], diff --git a/test/integrations/destinations/branch/router/data.ts b/test/integrations/destinations/branch/router/data.ts index 6451c463f1..ddfebb4e1b 100644 --- a/test/integrations/destinations/branch/router/data.ts +++ b/test/integrations/destinations/branch/router/data.ts @@ -1,7 +1,18 @@ -export const data = [ +/** + * Auto-migrated and optimized test cases + * Generated on: 2024-12-30T12:23:26.084Z + */ + +import { RouterTestData } from '../../../testTypes'; +import {} from '../../../../../src/types'; + +export const data: RouterTestData[] = [ { + id: 'router-1735561406084', name: 'branch', description: 'Test 0', + scenario: 'Default router scenario', + successCriteria: 'Router test should pass successfully', feature: 'router', module: 'destination', version: 'v0', @@ -10,19 +21,6 @@ export const data = [ body: { input: [ { - destination: { - Config: { branchKey: '', useNativeSDK: false }, - DestinationDefinition: { - DisplayName: 'Branch Metrics', - ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', - Name: 'BRANCH', - }, - Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', - Transformations: [], - }, - metadata: { jobId: 1, userId: 'u1' }, message: { anonymousId: 'sampath', channel: 'web', @@ -34,19 +32,34 @@ export const data = [ version: '1.0.0', }, ip: '0.0.0.0', - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, locale: 'en-US', - os: { name: 'iOS', version: '' }, - screen: { density: 2 }, - traits: { anonymousId: 'sampath', email: 'sampath@gmail.com' }, + os: { + name: 'iOS', + version: '', + }, + screen: { + density: 2, + }, + traits: { + anonymousId: 'sampath', + email: 'sampath@gmail.com', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', }, event: 'product added', - integrations: { All: true }, + integrations: { + All: true, + }, messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', originalTimestamp: '2020-01-17T04:53:51.185Z', - properties: { name: 'sampath' }, + properties: { + name: 'sampath', + }, receivedAt: '2020-01-17T10:23:52.688+05:30', request_ip: '[::1]:64059', sentAt: '2020-01-17T04:53:52.667Z', @@ -54,21 +67,61 @@ export const data = [ type: 'track', userId: 'sampath', }, - }, - { + metadata: { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-30T12:23:25.430Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, destination: { - Config: { branchKey: '', useNativeSDK: false }, + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', DestinationDefinition: { DisplayName: 'Branch Metrics', ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, }, Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', + WorkspaceID: 'default-workspace', Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: { jobId: 2, userId: 'u1' }, + }, + { message: { anonymousId: 'sampath', channel: 'web', @@ -80,15 +133,28 @@ export const data = [ version: '1.0.0', }, ip: '0.0.0.0', - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, locale: 'en-US', - os: { name: 'iOS', version: '' }, - screen: { density: 2 }, + os: { + name: 'iOS', + version: '', + }, + screen: { + density: 2, + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', }, - integrations: { All: true }, - traits: { anonymousId: 'sampath', email: 'sampath@gmail.com' }, + integrations: { + All: true, + }, + traits: { + anonymousId: 'sampath', + email: 'sampath@gmail.com', + }, messageId: 'ea5cfab2-3961-4d8a-8187-3d1858c90a9f', originalTimestamp: '2020-01-17T04:53:51.185Z', receivedAt: '2020-01-17T10:23:52.688+05:30', @@ -98,6 +164,59 @@ export const data = [ type: 'identify', userId: 'sampath', }, + metadata: { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 2, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-30T12:23:25.430Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, + destination: { + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', + DestinationDefinition: { + DisplayName: 'Branch Metrics', + ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', + Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, + }, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], destType: 'branch', @@ -116,13 +235,20 @@ export const data = [ type: 'REST', method: 'POST', endpoint: 'https://api2.branch.io/v2/event/standard', - headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, params: {}, body: { JSON: { branch_key: '', name: 'ADD_TO_CART', - content_items: [{ $product_name: 'sampath' }], + content_items: [ + { + $product_name: 'sampath', + }, + ], user_data: { os: 'iOS', os_version: '', @@ -140,21 +266,63 @@ export const data = [ files: {}, userId: 'sampath', }, - metadata: [{ jobId: 1, userId: 'u1' }], - batched: false, + metadata: [ + { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-30T12:23:25.430Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, + ], statusCode: 200, destination: { - Config: { branchKey: '', useNativeSDK: false }, + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', DestinationDefinition: { DisplayName: 'Branch Metrics', ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, }, Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', + WorkspaceID: 'default-workspace', Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: false, }, { batchedRequest: { @@ -162,13 +330,19 @@ export const data = [ type: 'REST', method: 'POST', endpoint: 'https://api2.branch.io/v2/event/custom', - headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, params: {}, body: { JSON: { branch_key: '', name: 'sampath', - custom_data: { anonymousId: 'sampath', email: 'sampath@gmail.com' }, + custom_data: { + anonymousId: 'sampath', + email: 'sampath@gmail.com', + }, content_items: [{}], user_data: { os: 'iOS', @@ -187,21 +361,63 @@ export const data = [ files: {}, userId: 'sampath', }, - metadata: [{ jobId: 2, userId: 'u1' }], - batched: false, + metadata: [ + { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 2, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2024-12-30T12:23:25.430Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, + }, + ], statusCode: 200, destination: { - Config: { branchKey: '', useNativeSDK: false }, + ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', + Name: 'branch test', DestinationDefinition: { DisplayName: 'Branch Metrics', ID: '1WTpBSTiL3iAUHUdW7rHT4sawgU', Name: 'BRANCH', + Config: {}, + }, + Config: { + branchKey: '', + useNativeSDK: false, }, Enabled: true, - ID: '1WTpIHpH7NTBgjeiUPW1kCUgZGI', - Name: 'branch test', + WorkspaceID: 'default-workspace', Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: false, }, ], }, diff --git a/test/integrations/destinations/braze/processor/data.ts b/test/integrations/destinations/braze/processor/data.ts index 240206791e..9b6f6dac65 100644 --- a/test/integrations/destinations/braze/processor/data.ts +++ b/test/integrations/destinations/braze/processor/data.ts @@ -3160,7 +3160,7 @@ export const data = [ { subscription_group_id: '1234', subscription_state: 'subscribed', - external_id: ['Randomuser2222'], + external_ids: ['Randomuser2222'], phones: ['5055077683'], }, ], @@ -3281,7 +3281,7 @@ export const data = [ { subscription_group_id: '1234', subscription_state: 'unsubscribed', - external_id: ['Randomuser2222'], + external_ids: ['Randomuser2222'], emails: ['abc@test.com'], }, ], diff --git a/test/integrations/destinations/braze/router/data.ts b/test/integrations/destinations/braze/router/data.ts index 6803742e86..8ab04c5d04 100644 --- a/test/integrations/destinations/braze/router/data.ts +++ b/test/integrations/destinations/braze/router/data.ts @@ -219,6 +219,34 @@ export const data = [ metadata: { jobId: 6, userId: 'u1' }, message: { type: 'alias', previousId: 'adsfsaf2', userId: 'dsafsdf2' }, }, + { + destination: { + Config: { + restApiKey: 'dummyApiKey', + prefixProperties: true, + useNativeSDK: false, + dataCenter: 'us-01', + enableSubscriptionGroupInGroupCall: true, + }, + DestinationDefinition: { + DisplayName: 'Braze', + ID: '1WhbSZ6uA3H5ChVifHpfL2H6sie', + Name: 'BRAZE', + }, + Enabled: true, + ID: '1WhcOCGgj9asZu850HvugU2C3Aq', + Name: 'Braze', + Transformations: [], + }, + metadata: { jobId: 7, userId: 'u1' }, + message: { + anonymousId: '56yrtsdfgbgxcb-22b4-401d-aae5-1b994be9afdf', + groupId: 'c90f0fd2-2a02-4f2f-bf07-7e7d2c2ed2b1', + traits: { phone: '5055077683', subscriptionState: 'subscribed' }, + userId: 'user12345', + type: 'group', + }, + }, ], destType: 'braze', }, @@ -299,13 +327,13 @@ export const data = [ JSON: { subscription_groups: [ { - external_id: ['user123'], + external_ids: ['user123', 'user12345'], phones: ['5055077683'], subscription_group_id: 'c90f0fd2-2a02-4f2f-bf07-7e7d2c2ed2b1', subscription_state: 'subscribed', }, { - external_id: ['user877'], + external_ids: ['user877'], phones: ['5055077683'], subscription_group_id: '58d0a278-b55b-4f10-b7d2-98d1c5dd4c30', subscription_state: 'subscribed', @@ -356,6 +384,7 @@ export const data = [ { jobId: 4, userId: 'u1' }, { jobId: 5, userId: 'u1' }, { jobId: 6, userId: 'u1' }, + { jobId: 7, userId: 'u1' }, ], batched: true, statusCode: 200, @@ -403,7 +432,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -473,7 +501,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -543,7 +570,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -597,7 +623,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -651,7 +676,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -804,7 +828,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, @@ -840,7 +863,6 @@ export const data = [ enableNestedArrayOperations: false, enableSubscriptionGroupInGroupCall: false, eventFilteringOption: 'disable', - oneTrustCookieCategories: [], restApiKey: 'dummyApiKey', supportDedup: true, trackAnonymousUser: true, diff --git a/test/integrations/destinations/candu/processor/data.ts b/test/integrations/destinations/candu/processor/data.ts index 6e5ae636bd..22bd0b3567 100644 --- a/test/integrations/destinations/candu/processor/data.ts +++ b/test/integrations/destinations/candu/processor/data.ts @@ -21,12 +21,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -182,12 +177,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -347,12 +337,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -478,12 +463,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -619,12 +599,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -757,12 +732,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -894,12 +864,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -1056,12 +1021,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -1221,12 +1181,7 @@ export const data = [ defaultConfig: ['apiKey'], }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], diff --git a/test/integrations/destinations/candu/router/data.ts b/test/integrations/destinations/candu/router/data.ts index e6c7d96a15..02e1caa3e9 100644 --- a/test/integrations/destinations/candu/router/data.ts +++ b/test/integrations/destinations/candu/router/data.ts @@ -20,12 +20,7 @@ export const data = [ Config: { destConfig: { defaultConfig: ['apiKey'] }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], @@ -152,12 +147,7 @@ export const data = [ Config: { destConfig: { defaultConfig: ['apiKey'] }, excludeKeys: [], - includeKeys: [ - 'apiKey', - 'blackListedEvents', - 'whiteListedEvents', - 'oneTrustCookieCategories', - ], + includeKeys: ['apiKey', 'blackListedEvents', 'whiteListedEvents'], saveDestinationResponse: true, secretKeys: ['apiKey'], supportedMessageTypes: ['identify', 'track'], diff --git a/test/integrations/destinations/clicksend/commonConfig.ts b/test/integrations/destinations/clicksend/commonConfig.ts index 815973b8d9..c5c49e2b92 100644 --- a/test/integrations/destinations/clicksend/commonConfig.ts +++ b/test/integrations/destinations/clicksend/commonConfig.ts @@ -14,11 +14,6 @@ export const destination = { defaultSource: 'php', defaultSenderId: 'abc@gmail.com', defaultSenderPhoneNumber: '+919XXXXXXXX8', - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; diff --git a/test/integrations/destinations/clicksend/router/data.ts b/test/integrations/destinations/clicksend/router/data.ts index 3aa3c0abc4..54018787b0 100644 --- a/test/integrations/destinations/clicksend/router/data.ts +++ b/test/integrations/destinations/clicksend/router/data.ts @@ -18,11 +18,6 @@ const commonDestination = { defaultSenderId: 'abc@gmail.com', defaultSenderPhoneNumber: '+919XXXXXXXX8', defaultSource: 'php', - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, DestinationDefinition: { Config: { diff --git a/test/integrations/destinations/cordial/processor/identify.ts b/test/integrations/destinations/cordial/processor/identify.ts index 074852b199..ef7636a716 100644 --- a/test/integrations/destinations/cordial/processor/identify.ts +++ b/test/integrations/destinations/cordial/processor/identify.ts @@ -39,6 +39,7 @@ export const identify: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -102,6 +103,7 @@ export const identify: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -166,6 +168,7 @@ export const identify: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/cordial/processor/track.ts b/test/integrations/destinations/cordial/processor/track.ts index 3e7a560a52..3ead5a959c 100644 --- a/test/integrations/destinations/cordial/processor/track.ts +++ b/test/integrations/destinations/cordial/processor/track.ts @@ -40,6 +40,7 @@ export const track: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -96,6 +97,7 @@ export const track: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/cordial/processor/validation.ts b/test/integrations/destinations/cordial/processor/validation.ts index 61f2e1cbed..ea7dff6dac 100644 --- a/test/integrations/destinations/cordial/processor/validation.ts +++ b/test/integrations/destinations/cordial/processor/validation.ts @@ -27,6 +27,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -71,6 +72,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/emarsys/deleteUsers/data.ts b/test/integrations/destinations/emarsys/deleteUsers/data.ts index 96b27cad0d..2596e9648c 100644 --- a/test/integrations/destinations/emarsys/deleteUsers/data.ts +++ b/test/integrations/destinations/emarsys/deleteUsers/data.ts @@ -64,11 +64,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -113,11 +108,6 @@ export const data = [ defaultContactList: undefined, eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -161,11 +151,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], @@ -210,11 +195,6 @@ export const data = [ defaultContactList: 'dummy', eventsMapping: commonEventMap, fieldMapping: commonFieldMap, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, ], diff --git a/test/integrations/destinations/emarsys/processor/data.ts b/test/integrations/destinations/emarsys/processor/data.ts index badd14e7cc..ddb61b83c7 100644 --- a/test/integrations/destinations/emarsys/processor/data.ts +++ b/test/integrations/destinations/emarsys/processor/data.ts @@ -112,11 +112,6 @@ export const data = [ emersysProperty: '3', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -285,11 +280,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -456,11 +446,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -599,11 +584,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -722,11 +702,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -842,11 +817,6 @@ export const data = [ emersysProperty: '2', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -964,11 +934,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1093,11 +1058,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1220,11 +1180,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1346,11 +1301,6 @@ export const data = [ emersysProperty: 'custom_id', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, @@ -1463,11 +1413,6 @@ export const data = [ emersysProperty: '3', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }, }, diff --git a/test/integrations/destinations/emarsys/router/data.ts b/test/integrations/destinations/emarsys/router/data.ts index 5f6dad1077..4a7bcf9332 100644 --- a/test/integrations/destinations/emarsys/router/data.ts +++ b/test/integrations/destinations/emarsys/router/data.ts @@ -29,11 +29,6 @@ const config = { emersysProperty: '2', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }; const commonDestination = { diff --git a/test/integrations/destinations/facebook_pixel/dataDelivery/business.ts b/test/integrations/destinations/facebook_pixel/dataDelivery/business.ts index 1b425ac5fa..2b4af61ac3 100644 --- a/test/integrations/destinations/facebook_pixel/dataDelivery/business.ts +++ b/test/integrations/destinations/facebook_pixel/dataDelivery/business.ts @@ -42,7 +42,7 @@ export const testScenariosForV1API: ProxyV1TestData[] = [ body: { output: { status: 400, - message: 'Invalid OAuth 2.0 access token', + message: 'The access token could not be decrypted', statTags: { ...statTags, errorCategory: 'dataValidation', @@ -51,7 +51,7 @@ export const testScenariosForV1API: ProxyV1TestData[] = [ }, response: [ { - error: 'Invalid OAuth 2.0 access token', + error: 'The access token could not be decrypted', statusCode: 400, metadata: generateMetadata(1), }, diff --git a/test/integrations/destinations/facebook_pixel/dataDelivery/data.ts b/test/integrations/destinations/facebook_pixel/dataDelivery/data.ts index 3366e62c5a..0e004c1183 100644 --- a/test/integrations/destinations/facebook_pixel/dataDelivery/data.ts +++ b/test/integrations/destinations/facebook_pixel/dataDelivery/data.ts @@ -45,12 +45,13 @@ export const v0TestData = [ body: { output: { status: 400, - message: 'Invalid OAuth 2.0 access token', + message: 'The access token could not be decrypted', destinationResponse: { error: { code: 190, fbtrace_id: 'fbpixel_trace_id', message: 'The access token could not be decrypted', + error_user_msg: 'The access token could not be decrypted', type: 'OAuthException', }, status: 500, @@ -202,7 +203,7 @@ export const v0TestData = [ body: { output: { status: 429, - message: 'API User Too Many Calls', + message: 'User request limit reached', destinationResponse: { error: { message: 'User request limit reached', @@ -414,7 +415,7 @@ export const v0TestData = [ body: { output: { status: 400, - message: 'Capability or permissions issue.', + message: 'Some error in permission', destinationResponse: { error: { message: 'Some error in permission', @@ -466,7 +467,8 @@ export const v0TestData = [ body: { output: { status: 500, - message: 'Unhandled random error', + message: + '{"message":"Unhandled random error","type":"RandomException","code":5,"error_subcode":12,"fbtrace_id":"facebook_px_trace_id_10"}', destinationResponse: { error: { message: 'Unhandled random error', @@ -488,6 +490,66 @@ export const v0TestData = [ }, }, + { + name: 'facebook_pixel', + description: 'Test 10: should handle error with code: 100 & subcode: 2804009', + feature: 'dataDelivery', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + body: { + XML: {}, + FORM: testFormData, + JSON: {}, + JSON_ARRAY: {}, + }, + type: 'REST', + files: {}, + method: 'POST', + userId: '', + headers: {}, + version: '1', + endpoint: `https://graph.facebook.com/${VERSION}/12345678912804009/events?access_token=2804009_valid_access_token`, + params: { + destination: 'facebook_pixel', + }, + }, + method: 'POST', + }, + }, + output: { + response: { + status: 400, + body: { + output: { + status: 400, + message: + 'Your purchase event doesn’t include a value parameter. Enter a value. For example: 1.99', + destinationResponse: { + error: { + message: 'Invalid parameter', + type: 'OAuthException', + code: 100, + error_user_msg: + 'Your purchase event doesn’t include a value parameter. Enter a value. For example: 1.99', + error_user_title: 'Missing Value for Purchase Event', + error_subcode: 2804009, + is_transient: false, + fbtrace_id: 'AP4G-xxxxxxxx', + }, + status: 400, + }, + statTags: { + ...statTags, + errorType: 'aborted', + }, + }, + }, + }, + }, + }, { name: 'facebook_pixel', description: 'Test 9: should handle error with code: 21009', diff --git a/test/integrations/destinations/facebook_pixel/dataDelivery/oauth.ts b/test/integrations/destinations/facebook_pixel/dataDelivery/oauth.ts index c6d938c627..bb4fd582f0 100644 --- a/test/integrations/destinations/facebook_pixel/dataDelivery/oauth.ts +++ b/test/integrations/destinations/facebook_pixel/dataDelivery/oauth.ts @@ -28,11 +28,11 @@ export const oauthScenariosV1: ProxyV1TestData[] = [ body: { output: { status: 400, - message: 'Capability or permissions issue.', + message: 'Some error in permission', statTags, response: [ { - error: 'Capability or permissions issue.', + error: 'Some error in permission', statusCode: 400, metadata: generateMetadata(1), }, diff --git a/test/integrations/destinations/facebook_pixel/dataDelivery/other.ts b/test/integrations/destinations/facebook_pixel/dataDelivery/other.ts index e25cc8e07c..154c6f75ad 100644 --- a/test/integrations/destinations/facebook_pixel/dataDelivery/other.ts +++ b/test/integrations/destinations/facebook_pixel/dataDelivery/other.ts @@ -31,14 +31,14 @@ export const otherScenariosV1: ProxyV1TestData[] = [ body: { output: { status: 429, - message: 'API User Too Many Calls', + message: 'User request limit reached', statTags: { ...statTags, errorType: 'throttled', }, response: [ { - error: 'API User Too Many Calls', + error: 'User request limit reached', statusCode: 429, metadata: generateMetadata(1), }, @@ -72,7 +72,8 @@ export const otherScenariosV1: ProxyV1TestData[] = [ body: { output: { status: 500, - message: 'Unhandled random error', + message: + '{"message":"Unhandled random error","type":"RandomException","code":5,"error_subcode":12,"fbtrace_id":"facebook_px_trace_id_10"}', statTags: { ...statTags, errorType: 'retryable', @@ -80,7 +81,8 @@ export const otherScenariosV1: ProxyV1TestData[] = [ }, response: [ { - error: 'Unhandled random error', + error: + '{"message":"Unhandled random error","type":"RandomException","code":5,"error_subcode":12,"fbtrace_id":"facebook_px_trace_id_10"}', statusCode: 500, metadata: generateMetadata(1), }, diff --git a/test/integrations/destinations/facebook_pixel/network.ts b/test/integrations/destinations/facebook_pixel/network.ts index 411d36cf19..a6ff50623b 100644 --- a/test/integrations/destinations/facebook_pixel/network.ts +++ b/test/integrations/destinations/facebook_pixel/network.ts @@ -15,6 +15,7 @@ export const networkCallsData = [ data: { error: { message: 'The access token could not be decrypted', + error_user_msg: 'The access token could not be decrypted', type: 'OAuthException', code: 190, fbtrace_id: 'fbpixel_trace_id', @@ -208,4 +209,29 @@ export const networkCallsData = [ statusText: 'OK', }, }, + { + httpReq: { + url: `https://graph.facebook.com/${VERSION}/12345678912804009/events?access_token=2804009_valid_access_token`, + data: getFormData(testFormData).toString(), + params: { destination: 'facebook_pixel' }, + headers: { 'User-Agent': 'RudderLabs' }, + method: 'POST', + }, + httpRes: { + status: 400, + data: { + error: { + code: 100, + error_subcode: 2804009, + error_user_msg: + 'Your purchase event doesn’t include a value parameter. Enter a value. For example: 1.99', + error_user_title: 'Missing Value for Purchase Event', + fbtrace_id: 'AP4G-xxxxxxxx', + is_transient: false, + message: 'Invalid parameter', + type: 'OAuthException', + }, + }, + }, + }, ]; diff --git a/test/integrations/destinations/facebook_pixel/processor/configLevelFeaturesTestData.ts b/test/integrations/destinations/facebook_pixel/processor/configLevelFeaturesTestData.ts index 5a7beb4174..a8baee0586 100644 --- a/test/integrations/destinations/facebook_pixel/processor/configLevelFeaturesTestData.ts +++ b/test/integrations/destinations/facebook_pixel/processor/configLevelFeaturesTestData.ts @@ -116,6 +116,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -203,6 +204,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -294,6 +296,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -397,6 +400,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ }), }, ], + method: 'POST', }, }, output: { @@ -500,6 +504,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ }), }, ], + method: 'POST', }, }, output: { @@ -611,6 +616,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ }), }, ], + method: 'POST', }, }, output: { @@ -702,6 +708,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/facebook_pixel/processor/ecommTestData.ts b/test/integrations/destinations/facebook_pixel/processor/ecommTestData.ts index 8e7f50ec2d..3daf22d5c2 100644 --- a/test/integrations/destinations/facebook_pixel/processor/ecommTestData.ts +++ b/test/integrations/destinations/facebook_pixel/processor/ecommTestData.ts @@ -124,6 +124,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -207,6 +208,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -314,6 +316,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -398,6 +401,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -482,6 +486,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -561,6 +566,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -669,6 +675,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -754,6 +761,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -800,6 +808,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -879,6 +888,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -988,6 +998,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -1097,6 +1108,7 @@ export const ecommTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/facebook_pixel/processor/identifyTestData.ts b/test/integrations/destinations/facebook_pixel/processor/identifyTestData.ts index d315b03cea..7d872efae0 100644 --- a/test/integrations/destinations/facebook_pixel/processor/identifyTestData.ts +++ b/test/integrations/destinations/facebook_pixel/processor/identifyTestData.ts @@ -120,6 +120,7 @@ export const identifyTestData: ProcessorTestData[] = [ destination: overrideDestination(commonDestination, { advancedMapping: false }), }, ], + method: 'POST', }, }, output: { @@ -160,6 +161,7 @@ export const identifyTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/facebook_pixel/processor/pageScreenTestData.ts b/test/integrations/destinations/facebook_pixel/processor/pageScreenTestData.ts index dee772522a..443c9e25be 100644 --- a/test/integrations/destinations/facebook_pixel/processor/pageScreenTestData.ts +++ b/test/integrations/destinations/facebook_pixel/processor/pageScreenTestData.ts @@ -148,6 +148,7 @@ export const pageScreenTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -228,6 +229,7 @@ export const pageScreenTestData: ProcessorTestData[] = [ destination: overrideDestination(commonDestination, { standardPageCall: true }), }, ], + method: 'POST', }, }, output: { @@ -288,6 +290,7 @@ export const pageScreenTestData: ProcessorTestData[] = [ destination: overrideDestination(commonDestination, { standardPageCall: true }), }, ], + method: 'POST', }, }, output: { @@ -371,6 +374,7 @@ export const pageScreenTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -455,6 +459,7 @@ export const pageScreenTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -532,6 +537,7 @@ export const pageScreenTestData: ProcessorTestData[] = [ destination: overrideDestination(commonDestination, { standardPageCall: true }), }, ], + method: 'POST', }, }, output: { @@ -590,6 +596,7 @@ export const pageScreenTestData: ProcessorTestData[] = [ destination: overrideDestination(commonDestination, { standardPageCall: true }), }, ], + method: 'POST', }, }, output: { @@ -673,6 +680,7 @@ export const pageScreenTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/facebook_pixel/processor/trackTestData.ts b/test/integrations/destinations/facebook_pixel/processor/trackTestData.ts index 9fd65945c4..a3f2ff0ed4 100644 --- a/test/integrations/destinations/facebook_pixel/processor/trackTestData.ts +++ b/test/integrations/destinations/facebook_pixel/processor/trackTestData.ts @@ -86,6 +86,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -159,6 +160,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/fb/dataDelivery/data.ts b/test/integrations/destinations/fb/dataDelivery/data.ts index 9ee19af265..dfa5dbc65e 100644 --- a/test/integrations/destinations/fb/dataDelivery/data.ts +++ b/test/integrations/destinations/fb/dataDelivery/data.ts @@ -59,6 +59,7 @@ export const existingTestData = [ message: 'Invalid OAuth 2.0 access token', destinationResponse: { error: { + error_user_msg: 'Invalid OAuth 2.0 access token', code: 190, fbtrace_id: 'fbpixel_trace_id', message: 'The access token could not be decrypted', @@ -274,7 +275,7 @@ export const existingTestData = [ body: { output: { status: 429, - message: 'API User Too Many Calls', + message: 'User request limit reached', destinationResponse: { error: { message: 'User request limit reached', diff --git a/test/integrations/destinations/fb/dataDelivery/other.ts b/test/integrations/destinations/fb/dataDelivery/other.ts index 9ac3f14fb5..36d3e45f53 100644 --- a/test/integrations/destinations/fb/dataDelivery/other.ts +++ b/test/integrations/destinations/fb/dataDelivery/other.ts @@ -31,14 +31,14 @@ export const otherScenariosV1: ProxyV1TestData[] = [ body: { output: { status: 429, - message: 'API User Too Many Calls', + message: 'User request limit reached', statTags: { ...statTags, errorType: 'throttled', }, response: [ { - error: 'API User Too Many Calls', + error: 'User request limit reached', statusCode: 429, metadata: generateMetadata(1), }, diff --git a/test/integrations/destinations/fb/network.ts b/test/integrations/destinations/fb/network.ts index 31bbaf0b6e..1aed48136c 100644 --- a/test/integrations/destinations/fb/network.ts +++ b/test/integrations/destinations/fb/network.ts @@ -30,6 +30,7 @@ export const networkCallsData = [ data: { error: { message: 'The access token could not be decrypted', + error_user_msg: 'Invalid OAuth 2.0 access token', type: 'OAuthException', code: 190, fbtrace_id: 'fbpixel_trace_id', diff --git a/test/integrations/destinations/fb_custom_audience/dataDelivery/data.ts b/test/integrations/destinations/fb_custom_audience/dataDelivery/data.ts index b41c656d9f..cd440aaa37 100644 --- a/test/integrations/destinations/fb_custom_audience/dataDelivery/data.ts +++ b/test/integrations/destinations/fb_custom_audience/dataDelivery/data.ts @@ -623,6 +623,8 @@ export const existingTestData = [ fbtrace_id: 'A3b8C6PpI-kdIOwPwV4PANi', message: 'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.', + error_user_msg: + 'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.', type: 'OAuthException', }, status: 400, diff --git a/test/integrations/destinations/fb_custom_audience/network.ts b/test/integrations/destinations/fb_custom_audience/network.ts index 369c27afa9..ba14d537ad 100644 --- a/test/integrations/destinations/fb_custom_audience/network.ts +++ b/test/integrations/destinations/fb_custom_audience/network.ts @@ -514,6 +514,8 @@ export const networkCallsData = [ error: { message: 'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.', + error_user_msg: + 'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.', type: 'OAuthException', code: 190, error_subcode: 463, diff --git a/test/integrations/destinations/fb_custom_audience/router/data.ts b/test/integrations/destinations/fb_custom_audience/router/data.ts index cfc24968a8..834b6315f6 100644 --- a/test/integrations/destinations/fb_custom_audience/router/data.ts +++ b/test/integrations/destinations/fb_custom_audience/router/data.ts @@ -611,7 +611,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -687,7 +686,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -795,7 +793,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -951,7 +948,6 @@ export const data = [ disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', diff --git a/test/integrations/destinations/fb_custom_audience/router/rETL.ts b/test/integrations/destinations/fb_custom_audience/router/rETL.ts index 0ba7f8b531..f8d5fc89a0 100644 --- a/test/integrations/destinations/fb_custom_audience/router/rETL.ts +++ b/test/integrations/destinations/fb_custom_audience/router/rETL.ts @@ -8,7 +8,6 @@ const destinationV2: Destination = { disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', @@ -167,7 +166,6 @@ export const destinationV1: Destination = { disableFormat: false, isHashRequired: true, isRaw: false, - oneTrustCookieCategories: [], skipVerify: false, subType: 'NA', type: 'NA', diff --git a/test/integrations/destinations/ga4/processor/ecomTestData.ts b/test/integrations/destinations/ga4/processor/ecomTestData.ts index 238e44222b..3a6f197270 100644 --- a/test/integrations/destinations/ga4/processor/ecomTestData.ts +++ b/test/integrations/destinations/ga4/processor/ecomTestData.ts @@ -292,6 +292,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -362,6 +363,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -434,6 +436,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -504,6 +507,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -574,6 +578,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -647,6 +652,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -721,6 +727,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -794,6 +801,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -869,6 +877,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -943,6 +952,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1017,6 +1027,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1093,6 +1104,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1170,6 +1182,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1244,6 +1257,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1315,6 +1329,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1385,6 +1400,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1456,6 +1472,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1525,6 +1542,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1591,6 +1609,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1657,6 +1676,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1723,6 +1743,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1800,6 +1821,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1873,6 +1895,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1943,6 +1966,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2014,6 +2038,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2087,6 +2112,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2164,6 +2190,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2247,6 +2274,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2321,6 +2349,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2410,6 +2439,7 @@ export const ecommTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/ga4/processor/groupTestData.ts b/test/integrations/destinations/ga4/processor/groupTestData.ts index 68daad3a8e..9e97ac33cd 100644 --- a/test/integrations/destinations/ga4/processor/groupTestData.ts +++ b/test/integrations/destinations/ga4/processor/groupTestData.ts @@ -113,6 +113,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -184,6 +185,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -265,6 +267,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/ga4/processor/pageTestData.ts b/test/integrations/destinations/ga4/processor/pageTestData.ts index 672f7e8f63..3f5d357e6e 100644 --- a/test/integrations/destinations/ga4/processor/pageTestData.ts +++ b/test/integrations/destinations/ga4/processor/pageTestData.ts @@ -122,6 +122,7 @@ export const pageTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -191,6 +192,7 @@ export const pageTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -263,6 +265,7 @@ export const pageTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -448,6 +451,7 @@ export const pageTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/ga4/processor/trackTestData.ts b/test/integrations/destinations/ga4/processor/trackTestData.ts index ce991ff845..d99cc24bdf 100644 --- a/test/integrations/destinations/ga4/processor/trackTestData.ts +++ b/test/integrations/destinations/ga4/processor/trackTestData.ts @@ -158,6 +158,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -225,6 +226,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -294,6 +296,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -365,6 +368,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -432,6 +436,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -502,6 +507,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -569,6 +575,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -637,6 +644,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -703,6 +711,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -773,6 +782,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -844,6 +854,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -914,6 +925,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -981,6 +993,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1049,6 +1062,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1115,6 +1129,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1185,6 +1200,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1253,6 +1269,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1318,6 +1335,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1383,6 +1401,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1451,6 +1470,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1523,6 +1543,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1598,6 +1619,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1673,6 +1695,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1749,6 +1772,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1815,6 +1839,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1879,6 +1904,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -1944,6 +1970,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2010,6 +2037,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2076,6 +2104,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2142,6 +2171,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2215,6 +2245,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2292,6 +2323,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2379,6 +2411,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2458,6 +2491,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2542,6 +2576,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2667,6 +2702,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2752,6 +2788,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2829,6 +2866,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -2909,6 +2947,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/ga4/processor/validationTestData.ts b/test/integrations/destinations/ga4/processor/validationTestData.ts index 0030ee178e..a7587cbac3 100644 --- a/test/integrations/destinations/ga4/processor/validationTestData.ts +++ b/test/integrations/destinations/ga4/processor/validationTestData.ts @@ -136,6 +136,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -194,6 +195,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -250,6 +252,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -301,6 +304,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -352,6 +356,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -402,6 +407,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -452,6 +458,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -497,6 +504,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -542,6 +550,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -594,6 +603,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -647,6 +657,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -700,6 +711,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -746,6 +758,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -796,6 +809,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -851,6 +865,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -898,6 +913,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -942,6 +958,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/gainsight_px/router/data.ts b/test/integrations/destinations/gainsight_px/router/data.ts index 1b3d5be875..3a5255f7d2 100644 --- a/test/integrations/destinations/gainsight_px/router/data.ts +++ b/test/integrations/destinations/gainsight_px/router/data.ts @@ -57,7 +57,7 @@ const destination2 = { { from: 'inboxready_signup_date', to: 'inboxready_signup_date' }, { from: 'gpt_setup', to: 'gpt_setup' }, ], - oneTrustCookieCategories: [], + apiKey: 'sample-api-key', eventDelivery: false, eventDeliveryTS: 1624472902670, diff --git a/test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts b/test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts index ab3e19dc2f..3ecae2b92d 100644 --- a/test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts +++ b/test/integrations/destinations/google_adwords_offline_conversions/processor/data.ts @@ -231,8 +231,6 @@ export const data = [ JSON: { conversions: [ { - gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -528,8 +526,6 @@ export const data = [ adPersonalization: 'UNSPECIFIED', adUserData: 'UNSPECIFIED', }, - gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -821,8 +817,6 @@ export const data = [ adPersonalization: 'UNSPECIFIED', adUserData: 'UNSPECIFIED', }, - gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -1911,7 +1905,6 @@ export const data = [ userId: '12345', properties: { gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', conversionCustomVariable: 'conversionCustomVariable', @@ -1935,7 +1928,6 @@ export const data = [ ], userIdentifierSource: 'FIRST_PARTY', conversionEnvironment: 'WEB', - gclid: 'gclid', conversionDateTime: '2022-01-01 12:32:45-08:00', conversionValue: '1', currency: 'GBP', @@ -2052,7 +2044,6 @@ export const data = [ ], properties: { gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', conversionCustomVariable: 'conversionCustomVariable', @@ -2076,7 +2067,6 @@ export const data = [ ], userIdentifierSource: 'FIRST_PARTY', conversionEnvironment: 'WEB', - gclid: 'gclid', conversionDateTime: '2022-01-01 12:32:45-08:00', conversionValue: '1', currency: 'GBP', @@ -2093,7 +2083,6 @@ export const data = [ adUserData: 'UNSPECIFIED', }, gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -2110,15 +2099,7 @@ export const data = [ }, ], }, - userIdentifiers: [ - { - userIdentifierSource: 'FIRST_PARTY', - hashedPhoneNumber: - '04e1dabb7c1348b72bfa87da179c9697c69af74827649266a5da8cdbb367abcd', - }, - ], conversionEnvironment: 'WEB', - gclid: 'gclid', conversionDateTime: '2022-01-01 12:32:45-08:00', conversionValue: 1, currencyCode: 'GBP', @@ -2169,7 +2150,6 @@ export const data = [ ], properties: { gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', conversionCustomVariable: 'conversionCustomVariable', @@ -2193,7 +2173,6 @@ export const data = [ ], userIdentifierSource: 'FIRST_PARTY', conversionEnvironment: 'WEB', - gclid: 'gclid', conversionDateTime: '2022-01-01 12:32:45-08:00', conversionValue: '1', currency: 'GBP', @@ -3751,20 +3730,73 @@ export const data = [ metadata: { secret: { access_token: 'abcd1234', - refresh_token: 'efgh5678', developer_token: 'ijkl91011', + refresh_token: 'efgh5678', }, }, - statusCode: 400, - error: 'Either of email or phone is required for user identifier', - statTags: { - errorCategory: 'dataValidation', - errorType: 'instrumentation', - destType: 'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS', - module: 'destination', - implementation: 'native', - feature: 'processor', + output: { + body: { + FORM: {}, + JSON: { + conversions: [ + { + cartData: { + items: [ + { + productId: '123445', + quantity: 123, + }, + ], + }, + consent: { + adPersonalization: 'UNSPECIFIED', + adUserData: 'UNSPECIFIED', + }, + conversionDateTime: '2022-01-01 12:32:45-08:00', + conversionEnvironment: 'WEB', + gclid: 'gclid', + }, + ], + partialFailure: true, + }, + JSON_ARRAY: {}, + XML: {}, + }, + endpoint: + 'https://googleads.googleapis.com/v16/customers/9625812972:uploadClickConversions', + files: {}, + headers: { + Authorization: 'Bearer abcd1234', + 'Content-Type': 'application/json', + 'developer-token': 'ijkl91011', + 'login-customer-id': '8617859087', + }, + method: 'POST', + params: { + customVariables: [ + { + from: 'value', + to: 'revenue', + }, + { + from: 'total', + to: 'cost', + }, + ], + customerId: '9625812972', + event: 'Sign-up - click', + properties: { + conversionDateTime: '2022-01-01 12:32:45-08:00', + gclid: 'gclid', + product_id: '123445', + quantity: 123, + }, + }, + type: 'REST', + userId: '', + version: '1', }, + statusCode: 200, }, ], }, @@ -5704,4 +5736,197 @@ export const data = [ }, mockFns: timestampMock, }, + { + name: 'google_adwords_offline_conversions', + description: 'Test 28 : when both gbraid and wbraid are available', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + device: { + id: '0572f78fa49c648e', + name: 'generic_x86_arm', + type: 'Android', + model: 'AOSP on IA Emulator', + manufacturer: 'Google', + adTrackingEnabled: true, + advertisingId: '44c97318-9040-4361-8bc7-4eb30f665ca8', + }, + traits: { + phone: 'alex@example.com', + firstName: 'John', + lastName: 'Gomes', + city: 'London', + state: 'England', + countryCode: 'GB', + postalCode: 'EC3M', + streetAddress: '71 Cherry Court SOUTHAMPTON SO53 5PD UK', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + locale: 'en-US', + ip: '0.0.0.0', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + }, + event: 'Promotion Clicked', + type: 'track', + messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', + originalTimestamp: '2019-10-14T11:15:18.299Z', + anonymousId: '00000000000000000000000000', + userId: '12345', + properties: { + gbraid: 'gbraid', + wbraid: 'wbraid', + externalAttributionCredit: 10, + externalAttributionModel: 'externalAttributionModel', + conversionCustomVariable: 'conversionCustomVariable', + value: 'value', + merchantId: '9876merchantId', + feedCountryCode: 'feedCountryCode', + feedLanguageCode: 'feedLanguageCode', + localTransactionCost: 20, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + quantity: '2', + price: '50', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + }, + ], + userIdentifierSource: 'FIRST_PARTY', + conversionEnvironment: 'WEB', + conversionValue: '1', + currency: 'GBP', + orderId: 'PL-123QR', + }, + integrations: { + All: true, + }, + name: 'ApplicationLoaded', + sentAt: '2019-10-14T11:15:53.296Z', + }, + metadata: { + secret: { + access_token: 'abcd1234', + refresh_token: 'efgh5678', + developer_token: 'ijkl91011', + }, + }, + destination: { + Config: { + customerId: '962-581-2972', + subAccount: false, + eventsToOfflineConversionsTypeMapping: [ + { + from: 'Sign up completed', + to: 'click', + }, + { + from: 'Download', + to: 'call', + }, + { + from: 'Promotion Clicked', + to: 'click', + }, + { + from: 'Product Searched', + to: 'call', + }, + ], + eventsToConversionsNamesMapping: [ + { + from: 'Sign up completed', + to: 'Sign-up - click', + }, + { + from: 'Download', + to: 'Page view', + }, + { + from: 'Promotion Clicked', + to: 'Sign-up - click', + }, + { + from: 'Product Searched', + to: 'search', + }, + ], + customVariables: [ + { + from: 'value', + to: 'revenue', + }, + { + from: 'total', + to: 'cost', + }, + ], + UserIdentifierSource: 'THIRD_PARTY', + conversionEnvironment: 'WEB', + hashUserIdentifier: true, + defaultUserIdentifier: 'email', + validateOnly: false, + rudderAccountId: '2EOknn1JNH7WK1MfNku4fGYKkRK', + }, + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: "You can't use both wbraid and gbraid.", + metadata: { + secret: { + access_token: 'abcd1234', + developer_token: 'ijkl91011', + refresh_token: 'efgh5678', + }, + }, + statTags: { + destType: 'GOOGLE_ADWORDS_OFFLINE_CONVERSIONS', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + }, + statusCode: 400, + }, + ], + }, + }, + mockFns: timestampMock, + }, ]; diff --git a/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts b/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts index 9d1ba220c8..bcc718485b 100644 --- a/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts +++ b/test/integrations/destinations/google_adwords_offline_conversions/router/data.ts @@ -314,7 +314,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -390,7 +389,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -464,7 +462,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -674,7 +671,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -738,8 +734,6 @@ export const data = [ adPersonalization: 'UNSPECIFIED', adUserData: 'UNSPECIFIED', }, - gbraid: 'gbraid', - wbraid: 'wbraid', externalAttributionData: { externalAttributionCredit: 10, externalAttributionModel: 'externalAttributionModel', @@ -988,7 +982,6 @@ export const data = [ { from: 'Product Clicked', to: 'Store sales' }, ], authStatus: 'active', - oneTrustCookieCategories: [], customVariables: [{ from: '', to: '' }], }, }, @@ -1154,7 +1147,6 @@ export const data = [ defaultUserIdentifier: 'email', hashUserIdentifier: true, validateOnly: false, - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1715104236592, rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', @@ -1267,7 +1259,6 @@ export const data = [ defaultUserIdentifier: 'email', hashUserIdentifier: true, validateOnly: false, - oneTrustCookieCategories: [], eventDelivery: false, eventDeliveryTS: 1715104236592, rudderAccountId: '25u5whFH7gVTnCiAjn4ykoCLGoC', diff --git a/test/integrations/destinations/hs/router/data.ts b/test/integrations/destinations/hs/router/data.ts index b47d6b7f07..2f0879528b 100644 --- a/test/integrations/destinations/hs/router/data.ts +++ b/test/integrations/destinations/hs/router/data.ts @@ -1988,13 +1988,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2070,13 +2064,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2150,13 +2138,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2231,13 +2213,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2330,13 +2306,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2425,13 +2395,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2511,13 +2475,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2621,13 +2579,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2702,13 +2654,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, @@ -2801,13 +2747,7 @@ export const data = [ rsEventName: 'Order Complete', }, ], - ketchConsentPurposes: [ - { - purpose: '', - }, - ], lookupField: 'email', - oneTrustCookieCategories: [], useNativeSDK: false, whitelistedEvents: [], }, diff --git a/test/integrations/destinations/http/processor/configuration.ts b/test/integrations/destinations/http/processor/configuration.ts index b493a236ee..43d39952b9 100644 --- a/test/integrations/destinations/http/processor/configuration.ts +++ b/test/integrations/destinations/http/processor/configuration.ts @@ -26,6 +26,7 @@ export const configuration: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -77,6 +78,7 @@ export const configuration: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -122,6 +124,7 @@ export const configuration: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -175,6 +178,7 @@ export const configuration: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/intercom/processor/validationTestData.ts b/test/integrations/destinations/intercom/processor/validationTestData.ts index 45fe3c1b9e..11a303d82b 100644 --- a/test/integrations/destinations/intercom/processor/validationTestData.ts +++ b/test/integrations/destinations/intercom/processor/validationTestData.ts @@ -108,6 +108,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -151,6 +152,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -197,6 +199,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -245,6 +248,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -293,6 +297,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -353,6 +358,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -397,6 +403,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -447,6 +454,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -490,6 +498,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -534,6 +543,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/intercom/router/data.ts b/test/integrations/destinations/intercom/router/data.ts index cc89d3f1e2..43af421f3a 100644 --- a/test/integrations/destinations/intercom/router/data.ts +++ b/test/integrations/destinations/intercom/router/data.ts @@ -812,6 +812,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest1, + method: 'POST', }, }, output: { @@ -993,6 +994,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest2, + method: 'POST', }, }, output: { @@ -1212,6 +1214,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest4, + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/intercom_v2/router/data.ts b/test/integrations/destinations/intercom_v2/router/data.ts index 75f5ba6ae7..4574dde9f6 100644 --- a/test/integrations/destinations/intercom_v2/router/data.ts +++ b/test/integrations/destinations/intercom_v2/router/data.ts @@ -424,6 +424,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest1, + method: 'POST', }, }, output: { @@ -589,6 +590,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest2, + method: 'POST', }, }, output: { @@ -682,6 +684,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest3, + method: 'POST', }, }, output: { @@ -807,6 +810,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest4, + method: 'POST', }, }, output: { @@ -881,6 +885,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest5, + method: 'POST', }, }, output: { @@ -945,6 +950,7 @@ export const data: RouterTestData[] = [ input: { request: { body: rETLRecordV2RouterRequest, + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/iterable/dataDelivery/business.ts b/test/integrations/destinations/iterable/dataDelivery/business.ts new file mode 100644 index 0000000000..0d6059806e --- /dev/null +++ b/test/integrations/destinations/iterable/dataDelivery/business.ts @@ -0,0 +1,799 @@ +import { ProxyV1TestData } from '../../../testTypes'; +import { generateMetadata, generateProxyV1Payload } from '../../../testUtils'; +import { + correctIdentifyData, + correctTrackData, + headerBlockWithCorrectAccessToken, + partiallyCorrectIdentifyData, + partiallyCorrectTrackData, + wrongIdentifyData, + wrongTrackData, +} from './network'; + +export const statTags = { + destType: 'ITERABLE', + errorCategory: 'network', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + errorType: 'aborted', + feature: 'dataDelivery', + implementation: 'native', + module: 'destination', +}; + +export const metadata = [generateMetadata(1), generateMetadata(2)]; + +export const singleMetadata = [ + { + jobId: 1, + attemptNum: 1, + userId: 'default-userId', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + sourceId: 'default-sourceId', + secret: { + accessToken: 'default-accessToken', + }, + dontBatch: false, + }, +]; + +export const singleTrackPayload = { + email: 'sayan@gmail.com', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + id: '1234', + createdAt: 1598631966468, + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + campaignId: 0, + templateId: 0, + createNewFields: true, +}; + +export const updateEmailData = { + currentEmail: 'sayan', + currentUserId: 'abcdeeeeeeeexxxx102', + newEmail: 'sayan@gmail.com', +}; + +export const testScenariosForV1API: ProxyV1TestData[] = [ + { + id: 'ITERABLE_v1_other_scenario_1', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test correct Payload Response Handling from Destination', + successCriteria: 'Should return 200 status code with success', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: correctTrackData, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/events/trackBulk', + }, + metadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: '[ITERABLE Response Handler] - Request Processed Successfully', + destinationResponse: { + status: 200, + response: { + createdFields: [], + disallowedEventNames: [], + failCount: 0, + failedUpdates: { + forgottenEmails: [], + forgottenUserIds: [], + invalidEmails: [], + invalidUserIds: [], + notFoundEmails: [], + notFoundUserIds: [], + }, + filteredOutFields: [], + invalidEmails: [], + invalidUserIds: [], + successCount: 2, + }, + }, + response: [ + { + statusCode: 200, + metadata: generateMetadata(1), + error: 'success', + }, + { + statusCode: 200, + metadata: generateMetadata(2), + error: 'success', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_2', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test Malformed Payload Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: wrongTrackData, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/events/trackBulk', + }, + metadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 400, + statTags, + message: + 'ITERABLE: Error transformer proxy during ITERABLE response transformation. {"obj.events[1].createdAt":"Number value expected"}', + response: [ + { + statusCode: 400, + metadata: generateMetadata(1), + error: + '{"msg":"[/api/events/trackBulk] Invalid JSON body","code":"BadJsonBody","params":{"obj.events[1].createdAt":"Number value expected"}}', + }, + { + statusCode: 400, + metadata: generateMetadata(2), + error: + '{"msg":"[/api/events/trackBulk] Invalid JSON body","code":"BadJsonBody","params":{"obj.events[1].createdAt":"Number value expected"}}', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_3', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test partially successful Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: partiallyCorrectTrackData, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/events/trackBulk', + }, + metadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: '[ITERABLE Response Handler] - Request Processed Successfully', + destinationResponse: { + status: 200, + response: { + successCount: 1, + failCount: 1, + invalidEmails: ['sayan'], + invalidUserIds: [], + disallowedEventNames: [], + filteredOutFields: [], + createdFields: [], + failedUpdates: { + invalidEmails: ['sayan'], + invalidUserIds: [], + notFoundEmails: [], + notFoundUserIds: [], + forgottenEmails: [], + forgottenUserIds: [], + }, + + status: 200, + }, + }, + response: [ + { + statusCode: 400, + metadata: generateMetadata(1), + error: 'email error:"sayan" in "invalidEmails,failedUpdates.invalidEmails".', + }, + { + statusCode: 200, + metadata: generateMetadata(2), + error: 'success', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_4', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test correct identify Payload Response Handling from Destination', + successCriteria: 'Should return 200 status code with success', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: correctIdentifyData, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/users/bulkUpdate', + }, + metadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: '[ITERABLE Response Handler] - Request Processed Successfully', + destinationResponse: { + status: 200, + response: { + createdFields: [], + noOpEmails: [], + noOpUserIds: [], + failCount: 0, + failedUpdates: { + conflictEmails: [], + conflictUserIds: [], + forgottenEmails: [], + forgottenUserIds: [], + invalidEmails: [], + invalidUserIds: [], + notFoundEmails: [], + notFoundUserIds: [], + invalidDataEmails: [], + invalidDataUserIds: [], + }, + filteredOutFields: [], + invalidEmails: [], + invalidUserIds: [], + successCount: 2, + }, + }, + response: [ + { + statusCode: 200, + metadata: generateMetadata(1), + error: 'success', + }, + { + statusCode: 200, + metadata: generateMetadata(2), + error: 'success', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_5', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test Malformed identify Payload Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: wrongIdentifyData, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/users/bulkUpdate', + }, + metadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 400, + statTags, + message: + 'ITERABLE: Error transformer proxy during ITERABLE response transformation. {"obj.users[1].preferUserId":"Boolean value expected"}', + response: [ + { + statusCode: 400, + metadata: generateMetadata(1), + error: + '{"msg":"[/api/users/bulkUpdate] Invalid JSON body","code":"BadJsonBody","params":{"obj.users[1].preferUserId":"Boolean value expected"}}', + }, + { + statusCode: 400, + metadata: generateMetadata(2), + error: + '{"msg":"[/api/users/bulkUpdate] Invalid JSON body","code":"BadJsonBody","params":{"obj.users[1].preferUserId":"Boolean value expected"}}', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_6', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test partially successful identify Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: partiallyCorrectIdentifyData, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/users/bulkUpdate', + }, + metadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: '[ITERABLE Response Handler] - Request Processed Successfully', + destinationResponse: { + status: 200, + response: { + successCount: 1, + failCount: 1, + invalidEmails: ['shrouti'], + invalidUserIds: [], + noOpEmails: [], + noOpUserIds: [], + filteredOutFields: [], + createdFields: [], + failedUpdates: { + invalidEmails: ['shrouti'], + conflictEmails: [], + conflictUserIds: [], + invalidUserIds: [], + notFoundEmails: [], + notFoundUserIds: [], + forgottenEmails: [], + forgottenUserIds: [], + invalidDataEmails: [], + invalidDataUserIds: [], + }, + }, + }, + response: [ + { + statusCode: 200, + metadata: generateMetadata(1), + error: 'success', + }, + { + statusCode: 400, + metadata: generateMetadata(2), + error: 'email error:"shrouti" in "invalidEmails,failedUpdates.invalidEmails".', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_7', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test partially unsuccessful updateEmail Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: updateEmailData, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/users/updateEmail', + }, + singleMetadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 400, + statTags, + message: + 'ITERABLE: Error transformer proxy during ITERABLE response transformation. "Invalid currentEmail sayan"', + response: [ + { + statusCode: 400, + metadata: generateMetadata(1), + error: + '{"msg":"Invalid currentEmail sayan","code":"InvalidEmailAddressError","params":null}', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_8', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test single track correct Payload Response Handling from Destination', + successCriteria: 'Should return 200 status code with success', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: singleTrackPayload, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/events/track', + }, + singleMetadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: '[ITERABLE Response Handler] - Request Processed Successfully', + destinationResponse: { + status: 200, + response: { + msg: 'Event with id: 1234 tracked.', + code: 'Success', + params: { + id: '1234', + }, + }, + }, + response: [ + { + statusCode: 200, + metadata: generateMetadata(1), + error: 'success', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_9', + name: 'iterable', + description: + '[Proxy API] :: Scenario to wrong sinle track event Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: { ...singleTrackPayload, email: 'sayan' }, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/events/track', + }, + singleMetadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 400, + statTags, + message: + 'ITERABLE: Error transformer proxy during ITERABLE response transformation. "Invalid email: sayan"', + response: [ + { + statusCode: 400, + metadata: generateMetadata(1), + error: + '{"msg":"Invalid email: sayan","code":"InvalidEmailAddressError","params":null}', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_10', + name: 'iterable', + description: + '[Proxy API] :: Scenario to wrong single track event for catalogs Response Handling from Destination', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: { + documents: { + Tiffany: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, + ABC: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + }, + replaceUploadedFieldsOnly: true, + }, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/catalogs/rudder-test/items', + }, + singleMetadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 404, + statTags, + message: + 'ITERABLE: Error transformer proxy during ITERABLE response transformation. "Catalog not found: rudder-test"', + response: [ + { + statusCode: 404, + metadata: generateMetadata(1), + error: + '{"error":"NotFound","message":"Catalog not found: rudder-test","code":"error.catalogs.notFound","data":{"args":["rudder-test"]}}', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_11', + name: 'iterable', + description: + '[Proxy API] :: Scenario to test catalog track correct Payload Response Handling from Destination', + successCriteria: 'Should return 200 status code with success', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: { + documents: { + Tiffany: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, + ABC: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + }, + replaceUploadedFieldsOnly: true, + }, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/catalogs/test-ruchira/items', + }, + singleMetadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: '[ITERABLE Response Handler] - Request Processed Successfully', + destinationResponse: { + status: 200, + response: { + code: 'Success', + msg: 'Request to bulk-upload documents into test-ruchira processed successfully', + params: null, + }, + }, + response: [ + { + statusCode: 200, + metadata: generateMetadata(1), + error: 'success', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_12', + name: 'iterable', + description: + '[Proxy API] :: Scenario to correct device token registration event Response Handling from Destination with wrong permission', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: { + email: 'sayan@gmail.com', + device: { + token: '1234', + platform: 'APNS', + applicationName: 'rudder', + dataFields: {}, + }, + userId: 'abcdeeeeeeeexxxx102', + preferUserId: true, + }, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/users/registerDeviceToken', + }, + singleMetadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 401, + statTags, + message: + 'ITERABLE: Error transformer proxy during ITERABLE response transformation. {"ip":"103.189.130.133","endpoint":"/api/users/registerDeviceToken","apiKeyIdentifier":"af831922","apiKeyType":"ServerSide"}', + response: [ + { + statusCode: 401, + metadata: generateMetadata(1), + error: + '{"msg":"Disabled API key or insufficient privileges","code":"BadApiKey","params":{"ip":"103.189.130.133","endpoint":"/api/users/registerDeviceToken","apiKeyIdentifier":"af831922","apiKeyType":"ServerSide"}}', + }, + ], + }, + }, + }, + }, + }, + { + id: 'ITERABLE_v1_other_scenario_13', + name: 'iterable', + description: + '[Proxy API] :: Scenario to correct browser token registration event Response Handling from Destination with wrong permission', + successCriteria: 'Should return 400 status code with error message', + scenario: 'Business', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + JSON: { + email: 'sayan@gmail.com', + browserToken: '1234567', + userId: 'abcdeeeeeeeexxxx102', + }, + headers: headerBlockWithCorrectAccessToken, + endpoint: 'https://api.iterable.com/api/users/registerBrowserToken', + }, + singleMetadata, + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 401, + statTags, + message: + 'ITERABLE: Error transformer proxy during ITERABLE response transformation. {"ip":"103.189.130.129","endpoint":"/api/users/registerBrowserToken","apiKeyIdentifier":"af831922","apiKeyType":"ServerSide"}', + response: [ + { + statusCode: 401, + metadata: generateMetadata(1), + error: + '{"msg":"Disabled API key or insufficient privileges","code":"BadApiKey","params":{"ip":"103.189.130.129","endpoint":"/api/users/registerBrowserToken","apiKeyIdentifier":"af831922","apiKeyType":"ServerSide"}}', + }, + ], + }, + }, + }, + }, + }, +]; diff --git a/test/integrations/destinations/iterable/dataDelivery/data.ts b/test/integrations/destinations/iterable/dataDelivery/data.ts new file mode 100644 index 0000000000..fc969bb8e1 --- /dev/null +++ b/test/integrations/destinations/iterable/dataDelivery/data.ts @@ -0,0 +1,3 @@ +import { testScenariosForV1API } from './business'; + +export const data = [...testScenariosForV1API]; diff --git a/test/integrations/destinations/iterable/dataDelivery/network.ts b/test/integrations/destinations/iterable/dataDelivery/network.ts new file mode 100644 index 0000000000..72189581be --- /dev/null +++ b/test/integrations/destinations/iterable/dataDelivery/network.ts @@ -0,0 +1,575 @@ +export const headerBlockWithCorrectAccessToken = { + 'Content-Type': 'application/json', + api_key: 'DUMMY_API_KEY', +}; + +export const headerBlockWithWrongAccessToken = { + 'Content-Type': 'application/json', + api_key: 'DUMMY_WRONG_API_KEY', +}; +export const correctTrackData = { + events: [ + { + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + email: 'sayan@gmail.com', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + createdAt: 1598631966468, + }, + { + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'pradip@gmail.com', + }, + email: 'pradip@gmail.com', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + createdAt: 1598631966468, + }, + ], +}; + +export const wrongTrackData = { + events: [ + { + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + email: 'sayan', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + createdAt: 'abc', + }, + { + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'pradip@gmail.com', + }, + email: 'pradip@gmail.com', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + createdAt: 1598631966468, + }, + ], +}; + +export const partiallyCorrectTrackData = { + events: [ + { + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + email: 'sayan', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + createdAt: 1598631966468, + }, + { + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'pradip@gmail.com', + }, + email: 'pradip@gmail.com', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + createdAt: 1598631966468, + }, + ], +}; + +export const correctIdentifyData = { + users: [ + { + email: 'manashi@website.com', + dataFields: { + city: 'Bangalore', + name: 'manashi', + email: 'manashi@website.com', + country: 'India', + }, + userId: 'abcdeeeeeeeexxxx102', + preferUserId: true, + mergeNestedObjects: true, + }, + { + email: 'shrouti@website.com', + dataFields: { + city: 'Bangalore', + name: 'shrouti', + email: 'shrouti@website.com', + country: 'India', + }, + userId: 'abcdeeeegggggxxxx102', + preferUserId: true, + mergeNestedObjects: true, + }, + ], +}; + +export const wrongIdentifyData = { + users: [ + { + email: 'manashi@website.com', + dataFields: { + city: 'Bangalore', + name: 'manashi', + email: 'manashi@website.com', + country: 'India', + }, + userId: 'abcdeeeeeeeexxxx102', + preferUserId: true, + mergeNestedObjects: true, + }, + { + email: 'shrouti@website.com', + dataFields: { + city: 'Bangalore', + name: 'shrouti', + email: 'shrouti@website.com', + country: 'India', + }, + userId: 'abcdeeeegggggxxxx102', + preferUserId: 'abc', + mergeNestedObjects: true, + }, + ], +}; + +export const partiallyCorrectIdentifyData = { + users: [ + { + email: 'manashi@website.com', + dataFields: { + city: 'Bangalore', + name: 'manashi', + email: 'manashi@website.com', + country: 'India', + }, + userId: 'abcdeeeeeeeexxxx102', + preferUserId: true, + mergeNestedObjects: true, + }, + { + email: 'shrouti', + dataFields: { + city: 'Bangalore', + name: 'shrouti', + email: 'shrouti@website.com', + country: 'India', + }, + userId: 'abcdeeeegggggxxxx102', + preferUserId: true, + mergeNestedObjects: true, + }, + ], +}; + +// MOCK DATA +const businessMockData = [ + { + description: 'Mock response from destination depicting request with a correct track payload', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/events/trackBulk', + headers: headerBlockWithCorrectAccessToken, + data: correctTrackData, + }, + httpRes: { + data: { + successCount: 2, + failCount: 0, + invalidEmails: [], + invalidUserIds: [], + disallowedEventNames: [], + filteredOutFields: [], + createdFields: [], + failedUpdates: { + invalidEmails: [], + invalidUserIds: [], + notFoundEmails: [], + notFoundUserIds: [], + forgottenEmails: [], + forgottenUserIds: [], + }, + }, + status: 200, + statusText: 'OK', + }, + }, + { + description: + 'Mock response from destination depicting request with a partially wrong track payload', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/events/trackBulk', + headers: headerBlockWithCorrectAccessToken, + data: partiallyCorrectTrackData, + }, + httpRes: { + data: { + successCount: 1, + failCount: 1, + invalidEmails: ['sayan'], + invalidUserIds: [], + disallowedEventNames: [], + filteredOutFields: [], + createdFields: [], + failedUpdates: { + invalidEmails: ['sayan'], + invalidUserIds: [], + notFoundEmails: [], + notFoundUserIds: [], + forgottenEmails: [], + forgottenUserIds: [], + }, + + status: 200, + }, + status: 200, + statusText: 'OK', + }, + }, + { + description: 'Mock response from destination depicting request with a wrong data', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/events/trackBulk', + headers: headerBlockWithCorrectAccessToken, + data: wrongTrackData, + }, + httpRes: { + data: { + msg: '[/api/events/trackBulk] Invalid JSON body', + code: 'BadJsonBody', + params: { + 'obj.events[1].createdAt': 'Number value expected', + }, + }, + status: 400, + }, + }, + { + description: + 'Mock response from destination depicting request with a correct track payload but wrong API key', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/events/trackBulk', + headers: { ...headerBlockWithCorrectAccessToken, api_key: 'WRONG_API_KEY' }, + data: correctTrackData, + }, + httpRes: { + data: { + msg: 'Invalid API key', + code: 'BadApiKey', + params: { + ip: '152.58.182.124', + endpoint: '/api/events/trackBulk', + }, + }, + status: 401, + }, + }, + { + description: 'Mock response from destination depicting request with a correct Identify payload', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/users/bulkUpdate', + headers: headerBlockWithCorrectAccessToken, + data: correctIdentifyData, + }, + httpRes: { + data: { + successCount: 2, + failCount: 0, + invalidEmails: [], + invalidUserIds: [], + filteredOutFields: [], + createdFields: [], + noOpEmails: [], + noOpUserIds: [], + failedUpdates: { + invalidEmails: [], + invalidUserIds: [], + notFoundEmails: [], + notFoundUserIds: [], + invalidDataEmails: [], + invalidDataUserIds: [], + conflictEmails: [], + conflictUserIds: [], + forgottenEmails: [], + forgottenUserIds: [], + }, + }, + status: 200, + statusText: 'OK', + }, + }, + { + description: + 'Mock response from destination depicting identify request with a partially wrong track payload', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/users/bulkUpdate', + headers: headerBlockWithCorrectAccessToken, + data: partiallyCorrectIdentifyData, + }, + httpRes: { + data: { + successCount: 1, + failCount: 1, + invalidEmails: ['shrouti'], + invalidUserIds: [], + filteredOutFields: [], + createdFields: [], + noOpEmails: [], + noOpUserIds: [], + failedUpdates: { + invalidEmails: ['shrouti'], + invalidUserIds: [], + notFoundEmails: [], + notFoundUserIds: [], + invalidDataEmails: [], + invalidDataUserIds: [], + conflictEmails: [], + conflictUserIds: [], + forgottenEmails: [], + forgottenUserIds: [], + }, + }, + status: 200, + statusText: 'OK', + }, + }, + { + description: 'Mock response from destination depicting identify request with a wrong data', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/users/bulkUpdate', + headers: headerBlockWithCorrectAccessToken, + data: wrongIdentifyData, + }, + httpRes: { + data: { + msg: '[/api/users/bulkUpdate] Invalid JSON body', + code: 'BadJsonBody', + params: { + 'obj.users[1].preferUserId': 'Boolean value expected', + }, + }, + status: 400, + }, + }, + { + description: 'Mock response from destination depicting update email request with a wrong data', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/users/updateEmail', + headers: headerBlockWithCorrectAccessToken, + data: { + currentEmail: 'sayan', + currentUserId: 'abcdeeeeeeeexxxx102', + newEmail: 'sayan@gmail.com', + }, + }, + httpRes: { + data: { + msg: 'Invalid currentEmail sayan', + code: 'InvalidEmailAddressError', + params: null, + }, + status: 400, + }, + }, + { + description: + 'Mock response from destination depicting request with a correct single track payload', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/events/track', + headers: headerBlockWithCorrectAccessToken, + data: { + email: 'sayan@gmail.com', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + id: '1234', + createdAt: 1598631966468, + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + campaignId: 0, + templateId: 0, + createNewFields: true, + }, + }, + httpRes: { + data: { + msg: 'Event with id: 1234 tracked.', + code: 'Success', + params: { + id: '1234', + }, + }, + status: 200, + statusText: 'OK', + }, + }, + { + description: + 'Mock response from destination depicting request with a wrong email single track payload', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/events/track', + headers: headerBlockWithCorrectAccessToken, + data: { + email: 'sayan', + userId: 'abcdeeeeeeeexxxx102', + eventName: 'Email Opened', + id: '1234', + createdAt: 1598631966468, + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + campaignId: 0, + templateId: 0, + createNewFields: true, + }, + }, + httpRes: { + data: { + msg: 'Invalid email: sayan', + code: 'InvalidEmailAddressError', + params: null, + }, + status: 400, + }, + }, + { + description: + 'Mock response from destination depicting request with a correct catalog bulk payload', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/catalogs/rudder-test/items', + headers: headerBlockWithCorrectAccessToken, + data: { + documents: { + Tiffany: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, + ABC: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + }, + replaceUploadedFieldsOnly: true, + }, + }, + httpRes: { + data: { + error: 'NotFound', + message: 'Catalog not found: rudder-test', + code: 'error.catalogs.notFound', + data: { + args: ['rudder-test'], + }, + }, + status: 404, + }, + }, + { + description: + 'Mock response from destination depicting request with a correct catalog track payload', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/catalogs/test-ruchira/items', + headers: headerBlockWithCorrectAccessToken, + data: { + documents: { + Tiffany: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, + ABC: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + }, + replaceUploadedFieldsOnly: true, + }, + }, + httpRes: { + data: { + msg: 'Request to bulk-upload documents into test-ruchira processed successfully', + code: 'Success', + params: null, + }, + status: 200, + statusText: 'OK', + }, + }, + { + description: + 'Mock response from destination depicting request with a correct register device token payload with insufficient permission', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/users/registerDeviceToken', + headers: headerBlockWithCorrectAccessToken, + data: { + email: 'sayan@gmail.com', + device: { + token: '1234', + platform: 'APNS', + applicationName: 'rudder', + dataFields: {}, + }, + userId: 'abcdeeeeeeeexxxx102', + preferUserId: true, + }, + }, + httpRes: { + data: { + msg: 'Disabled API key or insufficient privileges', + code: 'BadApiKey', + params: { + ip: '103.189.130.133', + endpoint: '/api/users/registerDeviceToken', + apiKeyIdentifier: 'af831922', + apiKeyType: 'ServerSide', + }, + }, + status: 401, + }, + }, + { + description: + 'Mock response from destination depicting request with a correct registerbrowswer token payload with insufficient permission', + httpReq: { + method: 'POST', + url: 'https://api.iterable.com/api/users/registerBrowserToken', + headers: headerBlockWithCorrectAccessToken, + data: { + email: 'sayan@gmail.com', + browserToken: '1234567', + userId: 'abcdeeeeeeeexxxx102', + }, + }, + httpRes: { + data: { + msg: 'Disabled API key or insufficient privileges', + code: 'BadApiKey', + params: { + ip: '103.189.130.129', + endpoint: '/api/users/registerBrowserToken', + apiKeyIdentifier: 'af831922', + apiKeyType: 'ServerSide', + }, + }, + status: 401, + }, + }, +]; + +export const networkCallsData = [...businessMockData]; diff --git a/test/integrations/destinations/iterable/processor/aliasTestData.ts b/test/integrations/destinations/iterable/processor/aliasTestData.ts index 1ee4134859..48f92f5ac2 100644 --- a/test/integrations/destinations/iterable/processor/aliasTestData.ts +++ b/test/integrations/destinations/iterable/processor/aliasTestData.ts @@ -1,10 +1,40 @@ -import { - generateMetadata, - overrideDestination, - transformResultBuilder, -} from './../../../testUtils'; -import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; +import { Destination, Metadata } from '../../../../../src/types'; +import { overrideDestination } from '../../../testUtils'; + +const baseMetadata: Metadata = { + sourceId: 'default-sourceId', + workspaceId: 'default-workspaceId', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destinationId', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2025-01-06T04:12:38.713Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, +}; const destination: Destination = { ID: '123', @@ -29,23 +59,6 @@ const destination: Destination = { Enabled: true, }; -const headers = { - api_key: 'testApiKey', - 'Content-Type': 'application/json', -}; - -const properties = { - path: '/abc', - referrer: '', - search: '', - title: '', - url: '', - category: 'test-category', -}; - -const sentAt = '2020-08-28T16:26:16.473Z'; -const originalTimestamp = '2020-08-28T16:26:06.468Z'; - export const aliasTestData: ProcessorTestData[] = [ { id: 'iterable-alias-test-1', @@ -59,21 +72,29 @@ export const aliasTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { anonymousId: 'anonId', userId: 'new@email.com', previousId: 'old@email.com', name: 'ApplicationLoaded', context: {}, - properties, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, type: 'alias', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: generateMetadata(1), + metadata: baseMetadata, + destination, }, ], }, @@ -83,17 +104,30 @@ export const aliasTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, + method: 'POST', endpoint: 'https://api.iterable.com/api/users/updateEmail', - JSON: { - currentEmail: 'old@email.com', - newEmail: 'new@email.com', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + currentEmail: 'old@email.com', + newEmail: 'new@email.com', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -111,21 +145,29 @@ export const aliasTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: overrideDestination(destination, { dataCenter: 'EUDC' }), message: { anonymousId: 'anonId', userId: 'new@email.com', previousId: 'old@email.com', name: 'ApplicationLoaded', context: {}, - properties, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, type: 'alias', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: generateMetadata(1), + metadata: baseMetadata, + destination: overrideDestination(destination, { dataCenter: 'EUDC' }), }, ], }, @@ -135,17 +177,30 @@ export const aliasTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, + method: 'POST', endpoint: 'https://api.eu.iterable.com/api/users/updateEmail', - JSON: { - currentEmail: 'old@email.com', - newEmail: 'new@email.com', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', }, - }), + params: {}, + body: { + JSON: { + currentEmail: 'old@email.com', + newEmail: 'new@email.com', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, diff --git a/test/integrations/destinations/iterable/processor/identifyTestData.ts b/test/integrations/destinations/iterable/processor/identifyTestData.ts index 21d294e232..792e16566c 100644 --- a/test/integrations/destinations/iterable/processor/identifyTestData.ts +++ b/test/integrations/destinations/iterable/processor/identifyTestData.ts @@ -1,64 +1,40 @@ -import { - generateMetadata, - transformResultBuilder, - generateIndentifyPayload, - overrideDestination, -} from './../../../testUtils'; -import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; +import { Metadata } from '../../../../../src/types'; -const destination: Destination = { - ID: '123', - Name: 'iterable', - DestinationDefinition: { - ID: '123', - Name: 'iterable', - DisplayName: 'Iterable', - Config: {}, - }, - WorkspaceID: '123', - Transformations: [], - Config: { - apiKey: 'testApiKey', - dataCenter: 'USDC', - preferUserId: false, - trackAllPages: true, - trackNamedPages: false, - mapToSingleEvent: false, - trackCategorisedPages: false, - }, - Enabled: true, -}; - -const headers = { - api_key: 'testApiKey', - 'Content-Type': 'application/json', -}; - -const user1Traits = { - name: 'manashi', - country: 'India', - city: 'Bangalore', - email: 'manashi@website.com', -}; - -const user2Traits = { - am_pm: 'AM', - pPower: 'AM', - boolean: true, - userId: 'Jacqueline', - firstname: 'Jacqueline', - administrative_unit: 'Minnesota', +const baseMetadata: Metadata = { + sourceId: 'default-sourceId', + workspaceId: 'default-workspaceId', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destinationId', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2025-01-06T03:57:13.523Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, }; -const userId = 'userId'; -const anonymousId = 'anonId'; -const sentAt = '2020-08-28T16:26:16.473Z'; -const originalTimestamp = '2020-08-28T16:26:06.468Z'; - -const updateUserEndpoint = 'https://api.iterable.com/api/users/update'; -const updateUserEndpointEUDC = 'https://api.eu.iterable.com/api/users/update'; - export const identifyTestData: ProcessorTestData[] = [ { id: 'iterable-identify-test-1', @@ -72,20 +48,55 @@ export const identifyTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { - anonymousId, + anonymousId: 'anonId', context: { - traits: user1Traits, + traits: { + name: 'manashi', + country: 'India', + city: 'Bangalore', + email: 'manashi@website.com', + }, + }, + traits: { + name: 'manashi', + country: 'India', + city: 'Bangalore', + email: 'manashi@website.com', }, - traits: user1Traits, type: 'identify', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -95,20 +106,38 @@ export const identifyTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateUserEndpoint, - JSON: { - email: user1Traits.email, - userId: anonymousId, - dataFields: user1Traits, - preferUserId: false, - mergeNestedObjects: true, + method: 'POST', + endpoint: 'https://api.iterable.com/api/users/update', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', }, - }), + params: {}, + body: { + JSON: { + email: 'manashi@website.com', + userId: 'anonId', + dataFields: { + name: 'manashi', + country: 'India', + city: 'Bangalore', + email: 'manashi@website.com', + }, + preferUserId: false, + mergeNestedObjects: true, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -126,20 +155,76 @@ export const identifyTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, - message: generateIndentifyPayload({ - userId, - anonymousId, + message: { + type: 'identify', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { - traits: { email: 'ruchira@rudderlabs.com' }, + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, + traits: { + email: 'ruchira@rudderlabs.com', + }, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', }, - type: 'identify', - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + rudderId: '62amo6xzksaeyupr4y0pfaucwj0upzs6g7yx', + messageId: 'hk02avz2xijdkid4i0mvncbm478g9lybdpgc', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -149,22 +234,35 @@ export const identifyTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateUserEndpoint, - JSON: { - email: 'ruchira@rudderlabs.com', - userId, - dataFields: { + method: 'POST', + endpoint: 'https://api.iterable.com/api/users/update', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { email: 'ruchira@rudderlabs.com', + userId: 'userId', + dataFields: { + email: 'ruchira@rudderlabs.com', + }, + preferUserId: false, + mergeNestedObjects: true, }, - preferUserId: false, - mergeNestedObjects: true, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -182,20 +280,76 @@ export const identifyTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { ...destination, Config: { ...destination.Config, preferUserId: true } }, - message: generateIndentifyPayload({ - userId, - anonymousId, + message: { + type: 'identify', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { - traits: { email: 'ruchira@rudderlabs.com' }, + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, + traits: { + email: 'ruchira@rudderlabs.com', + }, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', }, - type: 'identify', - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + rudderId: '1bbuv14fd7e8ogmsx7prcmw6ob37aq1zj6mo', + messageId: '1y56axyob5fp3lg3b1y1pij50kp15pyc2ubj', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: true, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -205,22 +359,35 @@ export const identifyTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateUserEndpoint, - JSON: { - email: 'ruchira@rudderlabs.com', - userId, - dataFields: { + method: 'POST', + endpoint: 'https://api.iterable.com/api/users/update', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { email: 'ruchira@rudderlabs.com', + userId: 'userId', + dataFields: { + email: 'ruchira@rudderlabs.com', + }, + preferUserId: true, + mergeNestedObjects: true, }, - preferUserId: true, - mergeNestedObjects: true, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -239,21 +406,77 @@ export const identifyTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { ...destination, Config: { ...destination.Config, preferUserId: true } }, - message: generateIndentifyPayload({ - userId, - anonymousId, + message: { + type: 'identify', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, traits: {}, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', }, - traits: { email: 'ruchira@rudderlabs.com' }, - type: 'identify', - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + traits: { + email: 'ruchira@rudderlabs.com', + }, + rudderId: 'iakido48935yw0kmw2swvjldsqoaophjzlhe', + messageId: 'hzycemnjaxr9cuqyyh003x9zlwfqnvbgzv4n', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: true, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -263,22 +486,35 @@ export const identifyTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateUserEndpoint, - JSON: { - email: 'ruchira@rudderlabs.com', - userId, - dataFields: { + method: 'POST', + endpoint: 'https://api.iterable.com/api/users/update', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { email: 'ruchira@rudderlabs.com', + userId: 'userId', + dataFields: { + email: 'ruchira@rudderlabs.com', + }, + preferUserId: true, + mergeNestedObjects: true, }, - preferUserId: true, - mergeNestedObjects: true, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -296,12 +532,12 @@ export const identifyTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { ...destination, Config: { ...destination.Config, preferUserId: true } }, message: { - userId, - anonymousId, + userId: 'userId', + anonymousId: 'anonId', context: { externalId: [ { @@ -312,12 +548,44 @@ export const identifyTestData: ProcessorTestData[] = [ ], mappedToDestination: 'true', }, - traits: user2Traits, + traits: { + am_pm: 'AM', + pPower: 'AM', + boolean: true, + userId: 'Jacqueline', + firstname: 'Jacqueline', + administrative_unit: 'Minnesota', + }, type: 'identify', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: true, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -327,20 +595,41 @@ export const identifyTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateUserEndpoint, - JSON: { - email: 'lynnanderson@smith.net', - userId, - dataFields: { ...user2Traits, email: 'lynnanderson@smith.net' }, - preferUserId: true, - mergeNestedObjects: true, + method: 'POST', + endpoint: 'https://api.iterable.com/api/users/update', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', }, - }), + params: {}, + body: { + JSON: { + email: 'lynnanderson@smith.net', + userId: 'userId', + dataFields: { + am_pm: 'AM', + pPower: 'AM', + boolean: true, + userId: 'Jacqueline', + firstname: 'Jacqueline', + administrative_unit: 'Minnesota', + email: 'lynnanderson@smith.net', + }, + preferUserId: true, + mergeNestedObjects: true, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -358,12 +647,12 @@ export const identifyTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { userId: 'Matthew', - anonymousId, + anonymousId: 'anonId', context: { externalId: [ { @@ -374,12 +663,44 @@ export const identifyTestData: ProcessorTestData[] = [ ], mappedToDestination: 'true', }, - traits: user2Traits, + traits: { + am_pm: 'AM', + pPower: 'AM', + boolean: true, + userId: 'Jacqueline', + firstname: 'Jacqueline', + administrative_unit: 'Minnesota', + }, type: 'identify', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -389,19 +710,39 @@ export const identifyTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateUserEndpoint, - JSON: { - userId: 'Matthew', - dataFields: { ...user2Traits, userId: 'Matthew' }, - preferUserId: false, - mergeNestedObjects: true, + method: 'POST', + endpoint: 'https://api.iterable.com/api/users/update', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'Matthew', + dataFields: { + am_pm: 'AM', + pPower: 'AM', + boolean: true, + userId: 'Matthew', + firstname: 'Jacqueline', + administrative_unit: 'Minnesota', + }, + preferUserId: false, + mergeNestedObjects: true, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -419,20 +760,55 @@ export const identifyTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: overrideDestination(destination, { dataCenter: 'EUDC' }), message: { - anonymousId, + anonymousId: 'anonId', context: { - traits: user1Traits, + traits: { + name: 'manashi', + country: 'India', + city: 'Bangalore', + email: 'manashi@website.com', + }, + }, + traits: { + name: 'manashi', + country: 'India', + city: 'Bangalore', + email: 'manashi@website.com', }, - traits: user1Traits, type: 'identify', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'EUDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -442,20 +818,38 @@ export const identifyTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateUserEndpointEUDC, - JSON: { - email: user1Traits.email, - userId: anonymousId, - dataFields: user1Traits, - preferUserId: false, - mergeNestedObjects: true, + method: 'POST', + endpoint: 'https://api.eu.iterable.com/api/users/update', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', }, - }), + params: {}, + body: { + JSON: { + email: 'manashi@website.com', + userId: 'anonId', + dataFields: { + name: 'manashi', + country: 'India', + city: 'Bangalore', + email: 'manashi@website.com', + }, + preferUserId: false, + mergeNestedObjects: true, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, diff --git a/test/integrations/destinations/iterable/processor/pageScreenTestData.ts b/test/integrations/destinations/iterable/processor/pageScreenTestData.ts index a27cf9fe3b..6fd35cf8fb 100644 --- a/test/integrations/destinations/iterable/processor/pageScreenTestData.ts +++ b/test/integrations/destinations/iterable/processor/pageScreenTestData.ts @@ -1,55 +1,40 @@ -import { - generateMetadata, - overrideDestination, - transformResultBuilder, -} from './../../../testUtils'; -import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; +import { Metadata } from '../../../../../src/types'; -const destination: Destination = { - ID: '123', - Name: 'iterable', - DestinationDefinition: { - ID: '123', - Name: 'iterable', - DisplayName: 'Iterable', - Config: {}, - }, - WorkspaceID: '123', - Transformations: [], - Config: { - apiKey: 'testApiKey', - dataCenter: 'USDC', - preferUserId: false, - trackAllPages: true, - trackNamedPages: false, - mapToSingleEvent: false, - trackCategorisedPages: false, - }, - Enabled: true, -}; - -const headers = { - api_key: 'testApiKey', - 'Content-Type': 'application/json', -}; - -const properties = { - path: '/abc', - referrer: '', - search: '', - title: '', - url: '', - category: 'test-category', +const baseMetadata: Metadata = { + sourceId: 'default-sourceId', + workspaceId: 'default-workspaceId', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destinationId', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2025-01-06T04:03:53.932Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, }; -const anonymousId = 'anonId'; -const sentAt = '2020-08-28T16:26:16.473Z'; -const originalTimestamp = '2020-08-28T16:26:06.468Z'; - -const pageEndpoint = 'https://api.iterable.com/api/events/track'; -const pageEndpointEUDC = 'https://api.eu.iterable.com/api/events/track'; - export const pageScreenTestData: ProcessorTestData[] = [ { id: 'iterable-page-test-1', @@ -63,23 +48,55 @@ export const pageScreenTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { - anonymousId, + anonymousId: 'anonId', name: 'ApplicationLoaded', context: { traits: { email: 'sayan@gmail.com', }, }, - properties, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, type: 'page', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -89,20 +106,40 @@ export const pageScreenTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: pageEndpoint, - JSON: { - userId: anonymousId, - dataFields: properties, - email: 'sayan@gmail.com', - createdAt: 1598631966468, - eventName: 'ApplicationLoaded page', - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'anonId', + dataFields: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, + email: 'sayan@gmail.com', + createdAt: 1598631966468, + eventName: 'ApplicationLoaded page', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -120,26 +157,57 @@ export const pageScreenTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - ...destination, - Config: { ...destination.Config, mapToSingleEvent: true }, - }, message: { - anonymousId, + anonymousId: 'anonId', name: 'ApplicationLoaded', context: { traits: { email: 'sayan@gmail.com', }, }, - properties: { ...properties, campaignId: '123456', templateId: '1213458' }, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + campaignId: '123456', + templateId: '1213458', + }, type: 'page', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: true, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -149,22 +217,44 @@ export const pageScreenTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: pageEndpoint, - JSON: { - campaignId: 123456, - templateId: 1213458, - userId: anonymousId, - email: 'sayan@gmail.com', - createdAt: 1598631966468, - eventName: 'Loaded a Page', - dataFields: { ...properties, campaignId: '123456', templateId: '1213458' }, - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + campaignId: 123456, + templateId: 1213458, + userId: 'anonId', + email: 'sayan@gmail.com', + createdAt: 1598631966468, + eventName: 'Loaded a Page', + dataFields: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + campaignId: '123456', + templateId: '1213458', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -182,26 +272,55 @@ export const pageScreenTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - ...destination, - Config: { ...destination.Config, trackNamedPages: true, trackAllPages: false }, - }, message: { - anonymousId, + anonymousId: 'anonId', name: 'ApplicationLoaded', context: { traits: { email: 'sayan@gmail.com', }, }, - properties, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, type: 'page', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: false, + trackNamedPages: true, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -211,20 +330,40 @@ export const pageScreenTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: pageEndpoint, - JSON: { - userId: anonymousId, - email: 'sayan@gmail.com', - createdAt: 1598631966468, - eventName: 'ApplicationLoaded page', - dataFields: properties, - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'anonId', + email: 'sayan@gmail.com', + createdAt: 1598631966468, + eventName: 'ApplicationLoaded page', + dataFields: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -242,26 +381,55 @@ export const pageScreenTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - ...destination, - Config: { ...destination.Config, trackCategorisedPages: true, trackAllPages: false }, - }, message: { - anonymousId, + anonymousId: 'anonId', name: 'ApplicationLoaded', context: { traits: { email: 'sayan@gmail.com', }, }, - properties, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, type: 'screen', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: false, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: true, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -271,20 +439,40 @@ export const pageScreenTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: pageEndpoint, - JSON: { - userId: anonymousId, - dataFields: properties, - email: 'sayan@gmail.com', - createdAt: 1598631966468, - eventName: 'ApplicationLoaded screen', - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'anonId', + dataFields: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, + email: 'sayan@gmail.com', + createdAt: 1598631966468, + eventName: 'ApplicationLoaded screen', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -302,26 +490,57 @@ export const pageScreenTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - ...destination, - Config: { ...destination.Config, mapToSingleEvent: true }, - }, message: { - anonymousId, + anonymousId: 'anonId', name: 'ApplicationLoaded', context: { traits: { email: 'sayan@gmail.com', }, }, - properties: { ...properties, campaignId: '123456', templateId: '1213458' }, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + campaignId: '123456', + templateId: '1213458', + }, type: 'screen', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: true, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -331,22 +550,44 @@ export const pageScreenTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: pageEndpoint, - JSON: { - campaignId: 123456, - templateId: 1213458, - userId: anonymousId, - email: 'sayan@gmail.com', - createdAt: 1598631966468, - eventName: 'Loaded a Screen', - dataFields: { ...properties, campaignId: '123456', templateId: '1213458' }, - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + campaignId: 123456, + templateId: 1213458, + userId: 'anonId', + email: 'sayan@gmail.com', + createdAt: 1598631966468, + eventName: 'Loaded a Screen', + dataFields: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + campaignId: '123456', + templateId: '1213458', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -364,26 +605,55 @@ export const pageScreenTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: { - ...destination, - Config: { ...destination.Config, trackNamedPages: true, trackAllPages: false }, - }, message: { - anonymousId, + anonymousId: 'anonId', name: 'ApplicationLoaded', context: { traits: { email: 'sayan@gmail.com', }, }, - properties, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, type: 'screen', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: false, + trackNamedPages: true, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -393,20 +663,40 @@ export const pageScreenTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: pageEndpoint, - JSON: { - userId: anonymousId, - email: 'sayan@gmail.com', - createdAt: 1598631966468, - eventName: 'ApplicationLoaded screen', - dataFields: properties, - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'anonId', + email: 'sayan@gmail.com', + createdAt: 1598631966468, + eventName: 'ApplicationLoaded screen', + dataFields: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -424,23 +714,55 @@ export const pageScreenTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: overrideDestination(destination, { dataCenter: 'EUDC' }), message: { - anonymousId, + anonymousId: 'anonId', name: 'ApplicationLoaded', context: { traits: { email: 'sayan@gmail.com', }, }, - properties, + properties: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, type: 'page', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'EUDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -450,20 +772,40 @@ export const pageScreenTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: pageEndpointEUDC, - JSON: { - userId: anonymousId, - dataFields: properties, - email: 'sayan@gmail.com', - createdAt: 1598631966468, - eventName: 'ApplicationLoaded page', - }, - }), + method: 'POST', + endpoint: 'https://api.eu.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'anonId', + dataFields: { + path: '/abc', + referrer: '', + search: '', + title: '', + url: '', + category: 'test-category', + }, + email: 'sayan@gmail.com', + createdAt: 1598631966468, + eventName: 'ApplicationLoaded page', + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, diff --git a/test/integrations/destinations/iterable/processor/trackTestData.ts b/test/integrations/destinations/iterable/processor/trackTestData.ts index 2b7d2a9c47..91271097a8 100644 --- a/test/integrations/destinations/iterable/processor/trackTestData.ts +++ b/test/integrations/destinations/iterable/processor/trackTestData.ts @@ -1,137 +1,40 @@ -import { - generateMetadata, - generateTrackPayload, - overrideDestination, - transformResultBuilder, -} from './../../../testUtils'; -import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; +import { Metadata } from '../../../../../src/types'; -const destination: Destination = { - ID: '123', - Name: 'iterable', - DestinationDefinition: { - ID: '123', - Name: 'iterable', - DisplayName: 'Iterable', - Config: {}, - }, - WorkspaceID: '123', - Transformations: [], - Config: { - apiKey: 'testApiKey', - dataCenter: 'USDC', - preferUserId: false, - trackAllPages: true, - trackNamedPages: false, - mapToSingleEvent: false, - trackCategorisedPages: false, - }, - Enabled: true, -}; - -const headers = { - api_key: 'testApiKey', - 'Content-Type': 'application/json', -}; - -const properties = { - subject: 'resume validate', - sendtime: '2020-01-01', - sendlocation: 'akashdeep@gmail.com', -}; - -const customEventProperties = { - campaignId: '1', - templateId: '0', - user_actual_id: 12345, - category: 'test-category', - email: 'ruchira@rudderlabs.com', - user_actual_role: 'system_admin, system_user', -}; - -const productInfo = { - price: 797, - variant: 'Oak', - quantity: 1, - quickship: true, - full_price: 1328, - product_id: 10606, - non_interaction: 1, - sku: 'JB24691400-W05', - name: 'Vira Console Cabinet', - cart_id: 'bd9b8dbf4ef8ee01d4206b04fe2ee6ae', +const baseMetadata: Metadata = { + sourceId: 'default-sourceId', + workspaceId: 'default-workspaceId', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destinationId', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2025-01-06T04:00:49.698Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, }; -const orderCompletedProductInfo = { - price: 45, - quantity: 1, - total: '1000', - name: 'Shoes', - orderId: 10000, - product_id: 1234, - campaignId: '123456', - templateId: '1213458', -}; - -const products = [ - { - product_id: '507f1f77bcf86cd799439011', - sku: '45790-32', - name: 'Monopoly: 3rd Edition', - price: '19', - position: '1', - category: 'cars', - url: 'https://www.example.com/product/path', - image_url: 'https://www.example.com/product/path.jpg', - quantity: '2', - }, - { - product_id: '507f1f77bcf86cd7994390112', - sku: '45790-322', - name: 'Monopoly: 3rd Edition2', - price: '192', - quantity: 22, - position: '12', - category: 'Cars2', - url: 'https://www.example.com/product/path2', - image_url: 'https://www.example.com/product/path.jpg2', - }, -]; - -const items = [ - { - id: '507f1f77bcf86cd799439011', - sku: '45790-32', - name: 'Monopoly: 3rd Edition', - categories: ['cars'], - price: 19, - quantity: 2, - imageUrl: 'https://www.example.com/product/path.jpg', - url: 'https://www.example.com/product/path', - }, - { - id: '507f1f77bcf86cd7994390112', - sku: '45790-322', - name: 'Monopoly: 3rd Edition2', - categories: ['Cars2'], - price: 192, - quantity: 22, - imageUrl: 'https://www.example.com/product/path.jpg2', - url: 'https://www.example.com/product/path2', - }, -]; - -const userId = 'userId'; -const anonymousId = 'anonId'; -const sentAt = '2020-08-28T16:26:16.473Z'; -const originalTimestamp = '2020-08-28T16:26:06.468Z'; - -const endpoint = 'https://api.iterable.com/api/events/track'; -const endpointEUDC = 'https://api.eu.iterable.com/api/events/track'; -const updateCartEndpoint = 'https://api.iterable.com/api/commerce/updateCart'; -const trackPurchaseEndpoint = 'https://api.iterable.com/api/commerce/trackPurchase'; - export const trackTestData: ProcessorTestData[] = [ { id: 'iterable-track-test-1', @@ -145,19 +48,48 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { - anonymousId, + anonymousId: 'anonId', event: 'Email Opened', type: 'track', context: {}, - properties, - sentAt, - originalTimestamp, + properties: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -167,19 +99,36 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint, - JSON: { - userId: 'anonId', - createdAt: 1598631966468, - eventName: 'Email Opened', - dataFields: properties, - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'anonId', + createdAt: 1598631966468, + eventName: 'Email Opened', + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -197,29 +146,107 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, - message: generateTrackPayload({ - userId, - anonymousId, - event: 'product added', + message: { + type: 'track', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, traits: { email: 'sayan@gmail.com', }, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', }, + rudderId: '227egb53wnacyz7f5hopt3jwriuwwk8n2y8i', + messageId: '40q64xrajd4kqt5174iy8889da8kjij55u85', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + event: 'product added', properties: { campaignId: '1', templateId: '0', orderId: 10000, total: 1000, - products, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, }, - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -229,25 +256,59 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateCartEndpoint, - JSON: { - user: { - email: 'sayan@gmail.com', - dataFields: { + method: 'POST', + endpoint: 'https://api.iterable.com/api/commerce/updateCart', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + user: { email: 'sayan@gmail.com', + dataFields: { + email: 'sayan@gmail.com', + }, + userId: 'userId', + preferUserId: false, + mergeNestedObjects: true, }, - userId, - preferUserId: false, - mergeNestedObjects: true, + items: [ + { + id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + categories: ['cars'], + price: 19, + quantity: 2, + imageUrl: 'https://www.example.com/product/path.jpg', + url: 'https://www.example.com/product/path', + }, + { + id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + categories: ['Cars2'], + price: 192, + quantity: 22, + imageUrl: 'https://www.example.com/product/path.jpg2', + url: 'https://www.example.com/product/path2', + }, + ], }, - items, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -265,29 +326,107 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, - message: generateTrackPayload({ - userId, - anonymousId, - event: 'order completed', + message: { + type: 'track', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, traits: { email: 'sayan@gmail.com', }, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', }, + rudderId: 'npe99e7yc7apntgd9roobt2n8i7262rsg6vr', + messageId: '68ygodw5mj88lmjm5sm765tatvscrucqo6kx', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + event: 'order completed', properties: { orderId: 10000, total: '1000', campaignId: '123456', templateId: '1213458', - products, + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], }, - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -297,37 +436,94 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: trackPurchaseEndpoint, - JSON: { - dataFields: { - orderId: 10000, - total: '1000', - campaignId: '123456', - templateId: '1213458', - products, - }, - id: '10000', - createdAt: 1598631966468, - campaignId: 123456, - templateId: 1213458, - total: 1000, - user: { - email: 'sayan@gmail.com', + method: 'POST', + endpoint: 'https://api.iterable.com/api/commerce/trackPurchase', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { dataFields: { + orderId: 10000, + total: '1000', + campaignId: '123456', + templateId: '1213458', + products: [ + { + product_id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + price: '19', + position: '1', + category: 'cars', + url: 'https://www.example.com/product/path', + image_url: 'https://www.example.com/product/path.jpg', + quantity: '2', + }, + { + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', + }, + ], + }, + id: '10000', + createdAt: 1598631966468, + campaignId: 123456, + templateId: 1213458, + total: 1000, + user: { email: 'sayan@gmail.com', + dataFields: { + email: 'sayan@gmail.com', + }, + userId: 'userId', + preferUserId: false, + mergeNestedObjects: true, }, - userId, - preferUserId: false, - mergeNestedObjects: true, + items: [ + { + id: '507f1f77bcf86cd799439011', + sku: '45790-32', + name: 'Monopoly: 3rd Edition', + categories: ['cars'], + price: 19, + quantity: 2, + imageUrl: 'https://www.example.com/product/path.jpg', + url: 'https://www.example.com/product/path', + }, + { + id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + categories: ['Cars2'], + price: 192, + quantity: 22, + imageUrl: 'https://www.example.com/product/path.jpg2', + url: 'https://www.example.com/product/path2', + }, + ], }, - items, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -345,23 +541,85 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, - message: generateTrackPayload({ - userId, - anonymousId, - event: 'test track event GA3', + message: { + type: 'track', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, traits: { email: 'sayan@gmail.com', }, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', + }, + rudderId: 'id2nbnto38rw1v5wiqyc81xe61c7t420zpjb', + messageId: '28pdlaljhp7i1woa7b0fhj47rlz3g4z2pvdw', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + event: 'test track event GA3', + properties: { + campaignId: '1', + templateId: '0', + user_actual_id: 12345, + category: 'test-category', + email: 'ruchira@rudderlabs.com', + user_actual_role: 'system_admin, system_user', + }, + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, }, - properties: customEventProperties, - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -371,22 +629,42 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint, - JSON: { - email: 'ruchira@rudderlabs.com', - dataFields: customEventProperties, - userId, - eventName: 'test track event GA3', - createdAt: 1598631966468, - campaignId: 1, - templateId: 0, - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + email: 'ruchira@rudderlabs.com', + dataFields: { + campaignId: '1', + templateId: '0', + user_actual_id: 12345, + category: 'test-category', + email: 'ruchira@rudderlabs.com', + user_actual_role: 'system_admin, system_user', + }, + userId: 'userId', + eventName: 'test track event GA3', + createdAt: 1598631966468, + campaignId: 1, + templateId: 0, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -404,23 +682,89 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, - message: generateTrackPayload({ - userId, - anonymousId, - event: 'product added', + message: { + type: 'track', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, traits: { email: 'jessica@jlpdesign.net', }, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', + }, + rudderId: 'gm8wm4385x4kfzl464h7tjtob474i17anotc', + messageId: 'jslc0490479rziix9h0ya6z6qpn2taqmryro', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + event: 'product added', + properties: { + price: 797, + variant: 'Oak', + quantity: 1, + quickship: true, + full_price: 1328, + product_id: 10606, + non_interaction: 1, + sku: 'JB24691400-W05', + name: 'Vira Console Cabinet', + cart_id: 'bd9b8dbf4ef8ee01d4206b04fe2ee6ae', }, - properties: productInfo, - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -430,33 +774,46 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateCartEndpoint, - JSON: { - user: { - email: 'jessica@jlpdesign.net', - dataFields: { + method: 'POST', + endpoint: 'https://api.iterable.com/api/commerce/updateCart', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + user: { email: 'jessica@jlpdesign.net', + dataFields: { + email: 'jessica@jlpdesign.net', + }, + userId: 'userId', + preferUserId: false, + mergeNestedObjects: true, }, - userId, - preferUserId: false, - mergeNestedObjects: true, + items: [ + { + id: 10606, + sku: 'JB24691400-W05', + name: 'Vira Console Cabinet', + price: 797, + quantity: 1, + }, + ], }, - items: [ - { - id: productInfo.product_id, - sku: productInfo.sku, - name: productInfo.name, - price: productInfo.price, - quantity: productInfo.quantity, - }, - ], + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -474,29 +831,92 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, - message: generateTrackPayload({ - userId, - anonymousId, - event: 'product added', + message: { + type: 'track', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, traits: { email: 'jessica@jlpdesign.net', }, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', }, + rudderId: '4osg2zcrsrh2accmbijxm0zqixtxyrsun8uc', + messageId: 'x901bx7paxtr7ktja5mhd1mi8q4lr5vlrl2x', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + event: 'product added', properties: { campaignId: '1', templateId: '0', orderId: 10000, total: 1000, - ...products[1], + product_id: '507f1f77bcf86cd7994390112', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + price: '192', + quantity: 22, + position: '12', + category: 'Cars2', + url: 'https://www.example.com/product/path2', + image_url: 'https://www.example.com/product/path.jpg2', }, - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -506,36 +926,49 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: updateCartEndpoint, - JSON: { - user: { - email: 'jessica@jlpdesign.net', - dataFields: { + method: 'POST', + endpoint: 'https://api.iterable.com/api/commerce/updateCart', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + user: { email: 'jessica@jlpdesign.net', + dataFields: { + email: 'jessica@jlpdesign.net', + }, + userId: 'userId', + preferUserId: false, + mergeNestedObjects: true, }, - userId, - preferUserId: false, - mergeNestedObjects: true, + items: [ + { + price: 192, + url: 'https://www.example.com/product/path2', + sku: '45790-322', + name: 'Monopoly: 3rd Edition2', + id: '507f1f77bcf86cd7994390112', + quantity: 22, + imageUrl: 'https://www.example.com/product/path.jpg2', + categories: ['Cars2'], + }, + ], }, - items: [ - { - price: 192, - url: products[1].url, - sku: products[1].sku, - name: products[1].name, - id: products[1].product_id, - quantity: products[1].quantity, - imageUrl: products[1].image_url, - categories: [products[1].category], - }, - ], + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -553,23 +986,87 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, - message: generateTrackPayload({ - userId, - anonymousId, - event: 'order completed', + message: { + type: 'track', + sentAt: '2020-08-28T16:26:16.473Z', + userId: 'userId', + channel: 'web', context: { + os: { + name: '', + version: '1.12.3', + }, + app: { + name: 'RudderLabs JavaScript SDK', + build: '1.0.0', + version: '1.1.11', + namespace: 'com.rudderlabs.javascript', + }, traits: { email: 'jessica@jlpdesign.net', }, + locale: 'en-US', + device: { + token: 'token', + id: 'id', + type: 'ios', + }, + screen: { + density: 2, + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.1.11', + }, + campaign: {}, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0', }, - properties: orderCompletedProductInfo, - sentAt, - originalTimestamp, - }), - metadata: generateMetadata(1), + rudderId: '9ovlz4kuew0wjcbwymj3vlhkngzixp9evf19', + messageId: 'ev0qyvsclinoh4z4e1uz4d8pdhrnf17q0rjd', + anonymousId: 'anonId', + originalTimestamp: '2020-08-28T16:26:06.468Z', + event: 'order completed', + properties: { + price: 45, + quantity: 1, + total: '1000', + name: 'Shoes', + orderId: 10000, + product_id: 1234, + campaignId: '123456', + templateId: '1213458', + }, + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, + }, }, ], }, @@ -579,38 +1076,60 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: trackPurchaseEndpoint, - JSON: { - dataFields: orderCompletedProductInfo, - user: { - email: 'jessica@jlpdesign.net', + method: 'POST', + endpoint: 'https://api.iterable.com/api/commerce/trackPurchase', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { dataFields: { + price: 45, + quantity: 1, + total: '1000', + name: 'Shoes', + orderId: 10000, + product_id: 1234, + campaignId: '123456', + templateId: '1213458', + }, + user: { email: 'jessica@jlpdesign.net', + dataFields: { + email: 'jessica@jlpdesign.net', + }, + userId: 'userId', + preferUserId: false, + mergeNestedObjects: true, }, - userId, - preferUserId: false, - mergeNestedObjects: true, + id: '10000', + total: 1000, + campaignId: 123456, + templateId: 1213458, + createdAt: 1598631966468, + items: [ + { + id: 1234, + name: 'Shoes', + price: 45, + quantity: 1, + }, + ], }, - id: '10000', - total: 1000, - campaignId: 123456, - templateId: 1213458, - createdAt: 1598631966468, - items: [ - { - id: orderCompletedProductInfo.product_id, - name: orderCompletedProductInfo.name, - price: orderCompletedProductInfo.price, - quantity: orderCompletedProductInfo.quantity, - }, - ], + JSON_ARRAY: {}, + XML: {}, + FORM: {}, }, - }), + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -628,18 +1147,47 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { - anonymousId, + anonymousId: 'anonId', type: 'track', context: {}, - properties, - sentAt, - originalTimestamp, + properties: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -649,18 +1197,35 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint, - JSON: { - userId: anonymousId, - createdAt: 1598631966468, - dataFields: properties, - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'anonId', + createdAt: 1598631966468, + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -678,19 +1243,48 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { - userId, - anonymousId, + userId: 'userId', + anonymousId: 'anonId', type: 'track', context: {}, - properties, - sentAt, - originalTimestamp, + properties: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'USDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -700,18 +1294,35 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint, - JSON: { - userId, - createdAt: 1598631966468, - dataFields: properties, - }, - }), + method: 'POST', + endpoint: 'https://api.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'userId', + createdAt: 1598631966468, + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, @@ -729,19 +1340,48 @@ export const trackTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination: overrideDestination(destination, { dataCenter: 'EUDC' }), message: { - anonymousId, + anonymousId: 'anonId', event: 'Email Opened', type: 'track', context: {}, - properties, - sentAt, - originalTimestamp, + properties: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', + }, + metadata: baseMetadata, + destination: { + ID: '123', + Name: 'iterable', + DestinationDefinition: { + ID: '123', + Name: 'iterable', + DisplayName: 'Iterable', + Config: {}, + }, + Config: { + apiKey: 'testApiKey', + dataCenter: 'EUDC', + preferUserId: false, + trackAllPages: true, + trackNamedPages: false, + mapToSingleEvent: false, + trackCategorisedPages: false, + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - metadata: generateMetadata(1), }, ], }, @@ -751,19 +1391,36 @@ export const trackTestData: ProcessorTestData[] = [ status: 200, body: [ { - output: transformResultBuilder({ + output: { + version: '1', + type: 'REST', userId: '', - headers, - endpoint: endpointEUDC, - JSON: { - userId: 'anonId', - createdAt: 1598631966468, - eventName: 'Email Opened', - dataFields: properties, - }, - }), + method: 'POST', + endpoint: 'https://api.eu.iterable.com/api/events/track', + headers: { + api_key: 'testApiKey', + 'Content-Type': 'application/json', + }, + params: {}, + body: { + JSON: { + userId: 'anonId', + createdAt: 1598631966468, + eventName: 'Email Opened', + dataFields: { + subject: 'resume validate', + sendtime: '2020-01-01', + sendlocation: 'akashdeep@gmail.com', + }, + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: baseMetadata, statusCode: 200, - metadata: generateMetadata(1), }, ], }, diff --git a/test/integrations/destinations/iterable/processor/validationTestData.ts b/test/integrations/destinations/iterable/processor/validationTestData.ts index 86728a868b..8f0813de3f 100644 --- a/test/integrations/destinations/iterable/processor/validationTestData.ts +++ b/test/integrations/destinations/iterable/processor/validationTestData.ts @@ -1,8 +1,41 @@ -import { generateMetadata } from './../../../testUtils'; -import { Destination } from '../../../../../src/types'; import { ProcessorTestData } from '../../../testTypes'; +import { Metadata, Destination } from '../../../../../src/types'; -const destination: Destination = { +const baseMetadata: Metadata = { + sourceId: 'default-sourceId', + workspaceId: 'default-workspaceId', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destinationId', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: '2025-01-06T04:14:40.785Z', + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, +}; + +const baseDestination: Destination = { ID: '123', Name: 'iterable', DestinationDefinition: { @@ -11,8 +44,6 @@ const destination: Destination = { DisplayName: 'Iterable', Config: {}, }, - WorkspaceID: '123', - Transformations: [], Config: { apiKey: 'testApiKey', mapToSingleEvent: false, @@ -21,26 +52,11 @@ const destination: Destination = { trackNamedPages: false, }, Enabled: true, -}; - -const properties = { - url: 'https://dominos.com', - title: 'Pizza', - referrer: 'https://google.com', -}; - -const sentAt = '2020-08-28T16:26:16.473Z'; -const originalTimestamp = '2020-08-28T16:26:06.468Z'; - -const expectedStatTags = { - destType: 'ITERABLE', - errorCategory: 'dataValidation', - errorType: 'instrumentation', - feature: 'processor', - implementation: 'native', - module: 'destination', - destinationId: 'default-destinationId', - workspaceId: 'default-workspaceId', + WorkspaceID: '123', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }; export const validationTestData: ProcessorTestData[] = [ @@ -56,9 +72,9 @@ export const validationTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { userId: 'sajal12', anonymousId: 'abcdeeeeeeeexxxx102', @@ -67,12 +83,17 @@ export const validationTestData: ProcessorTestData[] = [ email: 'abc@example.com', }, }, - properties, + properties: { + url: 'https://dominos.com', + title: 'Pizza', + referrer: 'https://google.com', + }, type: 'page', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: generateMetadata(1), + metadata: baseMetadata, + destination: baseDestination, }, ], }, @@ -82,10 +103,19 @@ export const validationTestData: ProcessorTestData[] = [ status: 200, body: [ { + metadata: baseMetadata, statusCode: 400, error: 'Invalid page call', - statTags: { ...expectedStatTags, errorType: 'configuration' }, - metadata: generateMetadata(1), + statTags: { + destType: 'ITERABLE', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'processor', + implementation: 'native', + module: 'destination', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + }, }, ], }, @@ -103,16 +133,17 @@ export const validationTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { context: {}, type: 'identify', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: generateMetadata(1), + metadata: baseMetadata, + destination: baseDestination, }, ], }, @@ -122,10 +153,19 @@ export const validationTestData: ProcessorTestData[] = [ status: 200, body: [ { + metadata: baseMetadata, statusCode: 400, error: 'userId or email is mandatory for this request', - statTags: expectedStatTags, - metadata: generateMetadata(1), + statTags: { + destType: 'ITERABLE', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + }, }, ], }, @@ -143,16 +183,17 @@ export const validationTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { context: {}, type: 'group', - sentAt, - originalTimestamp, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: generateMetadata(1), + metadata: baseMetadata, + destination: baseDestination, }, ], }, @@ -162,10 +203,19 @@ export const validationTestData: ProcessorTestData[] = [ status: 200, body: [ { + metadata: baseMetadata, statusCode: 400, error: 'Message type group not supported', - statTags: expectedStatTags, - metadata: generateMetadata(1), + statTags: { + destType: 'ITERABLE', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + }, }, ], }, @@ -183,17 +233,22 @@ export const validationTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { context: {}, type: 'alias', - properties, - sentAt, - originalTimestamp, + properties: { + url: 'https://dominos.com', + title: 'Pizza', + referrer: 'https://google.com', + }, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: generateMetadata(1), + metadata: baseMetadata, + destination: baseDestination, }, ], }, @@ -203,10 +258,19 @@ export const validationTestData: ProcessorTestData[] = [ status: 200, body: [ { + metadata: baseMetadata, statusCode: 400, error: 'Missing required value from "previousId"', - statTags: expectedStatTags, - metadata: generateMetadata(1), + statTags: { + destType: 'ITERABLE', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + }, }, ], }, @@ -224,19 +288,24 @@ export const validationTestData: ProcessorTestData[] = [ version: 'v0', input: { request: { + method: 'POST', body: [ { - destination, message: { context: {}, type: 'alias', previousId: 'old@email.com', anonymousId: 'anonId', - properties, - sentAt, - originalTimestamp, + properties: { + url: 'https://dominos.com', + title: 'Pizza', + referrer: 'https://google.com', + }, + sentAt: '2020-08-28T16:26:16.473Z', + originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: generateMetadata(1), + metadata: baseMetadata, + destination: baseDestination, }, ], }, @@ -246,10 +315,19 @@ export const validationTestData: ProcessorTestData[] = [ status: 200, body: [ { + metadata: baseMetadata, statusCode: 400, error: 'Missing required value from "userId"', - statTags: expectedStatTags, - metadata: generateMetadata(1), + statTags: { + destType: 'ITERABLE', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + destinationId: 'default-destinationId', + workspaceId: 'default-workspaceId', + }, }, ], }, diff --git a/test/integrations/destinations/iterable/router/data.ts b/test/integrations/destinations/iterable/router/data.ts index 1917c078eb..63c6f12a5e 100644 --- a/test/integrations/destinations/iterable/router/data.ts +++ b/test/integrations/destinations/iterable/router/data.ts @@ -1,7 +1,15 @@ -export const data = [ +import { RouterTestData } from '../../../testTypes'; +import {} from '../../../../../src/types'; +import { generateMetadata } from '../../../testUtils'; +import { getBrowserInfo } from '../../../../../src/v0/util'; + +export const data: RouterTestData[] = [ { + id: 'router-1736135082961', name: 'iterable', description: 'Test 0', + scenario: 'Default router scenario', + successCriteria: 'Router test should pass successfully', feature: 'router', module: 'destination', version: 'v0', @@ -15,7 +23,10 @@ export const data = [ sentAt: '2022-09-27T11:13:03.777Z', messageId: '9ad41366-8060-4c9f-b181-f6bea67d5469', originalTimestamp: '2022-09-27T11:13:03.777Z', - traits: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, + traits: { + ruchira: 'donaldbaker@ellis.com', + new_field2: 'GB', + }, channel: 'sources', rudderId: '3d51640c-ab09-42c1-b7b2-db6ab433b35e', context: { @@ -29,7 +40,11 @@ export const data = [ }, mappedToDestination: 'true', externalId: [ - { id: 'Tiffany', type: 'ITERABLE-test-ruchira', identifierType: 'itemId' }, + { + id: 'Tiffany', + type: 'ITERABLE-test-ruchira', + identifierType: 'itemId', + }, ], }, timestamp: '2022-09-27T11:12:59.079Z', @@ -38,10 +53,26 @@ export const data = [ recordId: '10', request_ip: '10.1.86.248', }, - metadata: { jobId: 2, userId: 'u1' }, + metadata: generateMetadata(1), destination: { - Config: { apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', hubID: '22066036' }, + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', + hubID: '22066036', + }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, { @@ -50,7 +81,10 @@ export const data = [ sentAt: '2022-09-27T11:13:03.777Z', messageId: '9ad41366-8060-4c9f-b181-f6bea67d5469', originalTimestamp: '2022-09-27T11:13:03.777Z', - traits: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + traits: { + ruchira: 'abc@ellis.com', + new_field2: 'GB1', + }, channel: 'sources', rudderId: '3d51640c-ab09-42c1-b7b2-db6ab433b35e', context: { @@ -64,7 +98,11 @@ export const data = [ }, mappedToDestination: 'true', externalId: [ - { id: 'ABC', type: 'ITERABLE-test-ruchira', identifierType: 'itemId' }, + { + id: 'ABC', + type: 'ITERABLE-test-ruchira', + identifierType: 'itemId', + }, ], }, timestamp: '2022-09-27T11:12:59.079Z', @@ -73,15 +111,32 @@ export const data = [ recordId: '10', request_ip: '10.1.86.248', }, - metadata: { jobId: 2, userId: 'u1' }, + metadata: generateMetadata(2), destination: { - Config: { apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', hubID: '22066036' }, + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', + hubID: '22066036', + }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, ], destType: 'iterable', }, + method: 'POST', }, }, output: { @@ -103,8 +158,14 @@ export const data = [ body: { JSON: { documents: { - Tiffany: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, - ABC: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + Tiffany: { + ruchira: 'donaldbaker@ellis.com', + new_field2: 'GB', + }, + ABC: { + ruchira: 'abc@ellis.com', + new_field2: 'GB1', + }, }, replaceUploadedFieldsOnly: true, }, @@ -114,16 +175,29 @@ export const data = [ }, files: {}, }, - metadata: [ - { jobId: 2, userId: 'u1' }, - { jobId: 2, userId: 'u1' }, - ], - batched: true, + metadata: [generateMetadata(1), generateMetadata(2)], statusCode: 200, destination: { - Config: { apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', hubID: '22066036' }, + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: { + apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', + hubID: '22066036', + }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: true, }, ], }, @@ -131,8 +205,11 @@ export const data = [ }, }, { + id: 'router-1736135082962', name: 'iterable', description: 'routerTest 1', + scenario: 'Default router scenario', + successCriteria: 'Router test should pass successfully', feature: 'router', module: 'destination', version: 'v0', @@ -145,8 +222,15 @@ export const data = [ type: 'track', event: 'Email Opened', sentAt: '2020-08-28T16:26:16.473Z', - context: { library: { name: 'analytics-node', version: '0.0.3' } }, - _metadata: { nodeVersion: '10.22.0' }, + context: { + library: { + name: 'analytics-node', + version: '0.0.3', + }, + }, + _metadata: { + nodeVersion: '10.22.0', + }, messageId: 'node-570110489d3e99b234b18af9a9eca9d4-6009779e-82d7-469d-aaeb-5ccf162b0453', properties: { @@ -157,8 +241,16 @@ export const data = [ anonymousId: 'abcdeeeeeeeexxxx102', originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: { jobId: 2, userId: 'u1' }, + metadata: generateMetadata(2), destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', mapToSingleEvent: false, @@ -167,6 +259,11 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, { @@ -187,16 +284,29 @@ export const data = [ email: 'manashi@website.com', country: 'India', }, - library: { name: 'analytics-node', version: '0.0.3' }, + library: { + name: 'analytics-node', + version: '0.0.3', + }, + }, + _metadata: { + nodeVersion: '10.22.0', }, - _metadata: { nodeVersion: '10.22.0' }, messageId: 'node-cc3ef811f686139ee527b806ee0129ef-163a3a88-266f-447e-8cce-34a8f42f8dcd', anonymousId: 'abcdeeeeeeeexxxx102', originalTimestamp: '2020-08-28T16:26:06.462Z', }, - metadata: { jobId: 3, userId: 'u1' }, + metadata: generateMetadata(3), destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', mapToSingleEvent: false, @@ -205,6 +315,11 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, { @@ -217,14 +332,24 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - traits: { email: 'sayan@gmail.com' }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + traits: { + email: 'sayan@gmail.com', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, type: 'page', messageId: '5e10d13a-bf9a-44bf-b884-43a9e591ea71', @@ -239,12 +364,22 @@ export const data = [ url: '', category: 'test-category', }, - integrations: { All: true }, + integrations: { + All: true, + }, name: 'ApplicationLoaded', sentAt: '2019-10-14T11:15:53.296Z', }, - metadata: { jobId: 4, userId: 'u1' }, + metadata: generateMetadata(4), destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '12345', dataCenter: 'USDC', @@ -254,6 +389,11 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, { @@ -276,7 +416,9 @@ export const data = [ task_run_id: 'c5tar6cqgmgmcjvupdi0', version: 'release.v1.6.8', }, - device: { token: 54321 }, + device: { + token: 54321, + }, }, messageId: '2f052f7c-f694-4849-a7ed-a432f7ffa0a4', originalTimestamp: '2021-10-28T14:03:50.503Z', @@ -297,7 +439,7 @@ export const data = [ type: 'identify', userId: 'lynnanderson@smith.net', }, - metadata: { jobId: 5, userId: 'u1' }, + metadata: generateMetadata(5), destination: { ID: '1zia9wKshXt80YksLmUdJnr7IHI', Name: 'test_iterable', @@ -337,7 +479,6 @@ export const data = [ transformAt: 'processor', transformAtV1: 'processor', }, - ResponseRules: null, }, Config: { apiKey: '12345', @@ -348,11 +489,12 @@ export const data = [ trackNamedPages: true, }, Enabled: true, + WorkspaceID: 'default-workspace', Transformations: [], + RevisionID: 'default-revision', IsProcessorEnabled: true, + IsConnectionEnabled: true, }, - libraries: [], - request: { query: {} }, }, { message: { @@ -364,14 +506,24 @@ export const data = [ namespace: 'com.rudderlabs.javascript', version: '1.0.0', }, - traits: { email: 'sayan@gmail.com' }, - library: { name: 'RudderLabs JavaScript SDK', version: '1.0.0' }, + traits: { + email: 'sayan@gmail.com', + }, + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', locale: 'en-US', ip: '0.0.0.0', - os: { name: '', version: '' }, - screen: { density: 2 }, + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, }, event: 'product added', type: 'track', @@ -409,12 +561,22 @@ export const data = [ }, ], }, - integrations: { All: true }, + integrations: { + All: true, + }, name: 'ApplicationLoaded', sentAt: '2019-10-14T11:15:53.296Z', }, - metadata: { jobId: 6, userId: 'u1' }, + metadata: generateMetadata(6), destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', dataCenter: 'USDC', @@ -424,14 +586,26 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, { message: { type: 'page', sentAt: '2020-08-28T16:26:16.473Z', - context: { library: { name: 'analytics-node', version: '0.0.3' } }, - _metadata: { nodeVersion: '10.22.0' }, + context: { + library: { + name: 'analytics-node', + version: '0.0.3', + }, + }, + _metadata: { + nodeVersion: '10.22.0', + }, messageId: 'node-6f62b91e789a636929ca38aed01c5f6e-103c720d-81bd-4742-98d6-d45a65aed23e', properties: { @@ -442,8 +616,16 @@ export const data = [ anonymousId: 'abcdeeeeeeeexxxx102', originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: { jobId: 7, userId: 'u1' }, + metadata: generateMetadata(7), destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', dataCenter: 'USDC', @@ -453,14 +635,26 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, { message: { type: 'alias', sentAt: '2020-08-28T16:26:16.473Z', - context: { library: { name: 'analytics-node', version: '0.0.3' } }, - _metadata: { nodeVersion: '10.22.0' }, + context: { + library: { + name: 'analytics-node', + version: '0.0.3', + }, + }, + _metadata: { + nodeVersion: '10.22.0', + }, messageId: 'node-6f62b91e789a636929ca38aed01c5f6e-103c720d-81bd-4742-98d6-d45a65aed23e', properties: { @@ -473,8 +667,16 @@ export const data = [ anonymousId: 'abcdeeeeeeeexxxx102', originalTimestamp: '2020-08-28T16:26:06.468Z', }, - metadata: { jobId: 8, userId: 'u1' }, + metadata: generateMetadata(8), destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', dataCenter: 'USDC', @@ -484,11 +686,17 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, ], destType: 'iterable', }, + method: 'POST', }, }, output: { @@ -528,10 +736,17 @@ export const data = [ }, files: {}, }, - metadata: [{ jobId: 2, userId: 'u1' }], - batched: true, + metadata: [generateMetadata(2)], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', mapToSingleEvent: false, @@ -540,7 +755,13 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: true, }, { batchedRequest: { @@ -576,10 +797,17 @@ export const data = [ }, files: {}, }, - metadata: [{ jobId: 3, userId: 'u1' }], - batched: true, + metadata: [generateMetadata(3)], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', mapToSingleEvent: false, @@ -588,7 +816,13 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: true, }, { batchedRequest: { @@ -596,7 +830,10 @@ export const data = [ type: 'REST', method: 'POST', endpoint: 'https://api.iterable.com/api/events/trackBulk', - headers: { 'Content-Type': 'application/json', api_key: '12345' }, + headers: { + 'Content-Type': 'application/json', + api_key: '12345', + }, params: {}, body: { JSON: { @@ -623,10 +860,17 @@ export const data = [ }, files: {}, }, - metadata: [{ jobId: 4, userId: 'u1' }], - batched: true, + metadata: [generateMetadata(4)], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '12345', dataCenter: 'USDC', @@ -636,7 +880,13 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: true, }, { batchedRequest: { @@ -653,7 +903,9 @@ export const data = [ JSON: { user: { email: 'sayan@gmail.com', - dataFields: { email: 'sayan@gmail.com' }, + dataFields: { + email: 'sayan@gmail.com', + }, userId: '12345', preferUserId: true, mergeNestedObjects: true, @@ -687,10 +939,17 @@ export const data = [ }, files: {}, }, - metadata: [{ jobId: 6, userId: 'u1' }], - batched: false, + metadata: [generateMetadata(6)], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', dataCenter: 'USDC', @@ -700,7 +959,13 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: false, }, { batchedRequest: { @@ -734,10 +999,17 @@ export const data = [ }, files: {}, }, - metadata: [{ jobId: 7, userId: 'u1' }], - batched: true, + metadata: [generateMetadata(7)], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', dataCenter: 'USDC', @@ -747,7 +1019,13 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: true, }, { batchedRequest: { @@ -761,17 +1039,27 @@ export const data = [ }, params: {}, body: { - JSON: { currentEmail: 'old@email.com', newEmail: 'new@email.com' }, + JSON: { + currentEmail: 'old@email.com', + newEmail: 'new@email.com', + }, JSON_ARRAY: {}, XML: {}, FORM: {}, }, files: {}, }, - metadata: [{ jobId: 8, userId: 'u1' }], - batched: false, + metadata: [generateMetadata(8)], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '62d12498c37c4fd8a1a546c2d35c2f60', dataCenter: 'USDC', @@ -781,7 +1069,13 @@ export const data = [ trackNamedPages: false, }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: false, }, { batchedRequest: { @@ -789,7 +1083,10 @@ export const data = [ type: 'REST', method: 'POST', endpoint: 'https://api.iterable.com/api/users/bulkUpdate', - headers: { 'Content-Type': 'application/json', api_key: '12345' }, + headers: { + 'Content-Type': 'application/json', + api_key: '12345', + }, params: {}, body: { JSON: { @@ -817,8 +1114,7 @@ export const data = [ }, files: {}, }, - metadata: [{ jobId: 5, userId: 'u1' }], - batched: true, + metadata: [generateMetadata(5)], statusCode: 200, destination: { ID: '1zia9wKshXt80YksLmUdJnr7IHI', @@ -859,7 +1155,6 @@ export const data = [ transformAt: 'processor', transformAtV1: 'processor', }, - ResponseRules: null, }, Config: { apiKey: '12345', @@ -870,9 +1165,13 @@ export const data = [ trackNamedPages: true, }, Enabled: true, + WorkspaceID: 'default-workspace', Transformations: [], + RevisionID: 'default-revision', IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: true, }, ], }, @@ -880,8 +1179,11 @@ export const data = [ }, }, { + id: 'router-1736135082962', name: 'iterable', description: 'Simple identify call with EUDC dataCenter', + scenario: 'Default router scenario', + successCriteria: 'Router test should pass successfully', feature: 'router', module: 'destination', version: 'v0', @@ -895,7 +1197,10 @@ export const data = [ sentAt: '2022-09-27T11:13:03.777Z', messageId: '9ad41366-8060-4c9f-b181-f6bea67d5469', originalTimestamp: '2022-09-27T11:13:03.777Z', - traits: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, + traits: { + ruchira: 'donaldbaker@ellis.com', + new_field2: 'GB', + }, channel: 'sources', rudderId: '3d51640c-ab09-42c1-b7b2-db6ab433b35e', context: { @@ -909,7 +1214,11 @@ export const data = [ }, mappedToDestination: 'true', externalId: [ - { id: 'Tiffany', type: 'ITERABLE-test-ruchira', identifierType: 'itemId' }, + { + id: 'Tiffany', + type: 'ITERABLE-test-ruchira', + identifierType: 'itemId', + }, ], }, timestamp: '2022-09-27T11:12:59.079Z', @@ -918,14 +1227,27 @@ export const data = [ recordId: '10', request_ip: '10.1.86.248', }, - metadata: { jobId: 2, userId: 'u1' }, + metadata: generateMetadata(1), destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', dataCenter: 'EUDC', hubID: '22066036', }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, { @@ -934,7 +1256,10 @@ export const data = [ sentAt: '2022-09-27T11:13:03.777Z', messageId: '9ad41366-8060-4c9f-b181-f6bea67d5469', originalTimestamp: '2022-09-27T11:13:03.777Z', - traits: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + traits: { + ruchira: 'abc@ellis.com', + new_field2: 'GB1', + }, channel: 'sources', rudderId: '3d51640c-ab09-42c1-b7b2-db6ab433b35e', context: { @@ -948,7 +1273,11 @@ export const data = [ }, mappedToDestination: 'true', externalId: [ - { id: 'ABC', type: 'ITERABLE-test-ruchira', identifierType: 'itemId' }, + { + id: 'ABC', + type: 'ITERABLE-test-ruchira', + identifierType: 'itemId', + }, ], }, timestamp: '2022-09-27T11:12:59.079Z', @@ -957,19 +1286,33 @@ export const data = [ recordId: '10', request_ip: '10.1.86.248', }, - metadata: { jobId: 2, userId: 'u1' }, + metadata: generateMetadata(2), destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', dataCenter: 'EUDC', hubID: '22066036', }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, }, ], destType: 'iterable', }, + method: 'POST', }, }, output: { @@ -991,8 +1334,14 @@ export const data = [ body: { JSON: { documents: { - Tiffany: { ruchira: 'donaldbaker@ellis.com', new_field2: 'GB' }, - ABC: { ruchira: 'abc@ellis.com', new_field2: 'GB1' }, + Tiffany: { + ruchira: 'donaldbaker@ellis.com', + new_field2: 'GB', + }, + ABC: { + ruchira: 'abc@ellis.com', + new_field2: 'GB1', + }, }, replaceUploadedFieldsOnly: true, }, @@ -1002,20 +1351,30 @@ export const data = [ }, files: {}, }, - metadata: [ - { jobId: 2, userId: 'u1' }, - { jobId: 2, userId: 'u1' }, - ], - batched: true, + metadata: [generateMetadata(1), generateMetadata(2)], statusCode: 200, destination: { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, Config: { apiKey: '583af2f8-15ba-49c0-8511-76383e7de07e', dataCenter: 'EUDC', hubID: '22066036', }, Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, }, + batched: true, }, ], }, diff --git a/test/integrations/destinations/klaviyo/processor/ecomTestData.ts b/test/integrations/destinations/klaviyo/processor/ecomTestData.ts index 34eff45232..83055cfef1 100644 --- a/test/integrations/destinations/klaviyo/processor/ecomTestData.ts +++ b/test/integrations/destinations/klaviyo/processor/ecomTestData.ts @@ -80,6 +80,7 @@ export const ecomTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -188,6 +189,7 @@ export const ecomTestData: ProcessorTestData[] = [ metadata: generateMetadata(2), }, ], + method: 'POST', }, }, output: { @@ -300,6 +302,7 @@ export const ecomTestData: ProcessorTestData[] = [ metadata: generateMetadata(3), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/groupTestData.ts b/test/integrations/destinations/klaviyo/processor/groupTestData.ts index 0002f7ce90..844729b822 100644 --- a/test/integrations/destinations/klaviyo/processor/groupTestData.ts +++ b/test/integrations/destinations/klaviyo/processor/groupTestData.ts @@ -67,6 +67,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -131,6 +132,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(2), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/groupTestDataV2.ts b/test/integrations/destinations/klaviyo/processor/groupTestDataV2.ts index da7769b110..871388aed2 100644 --- a/test/integrations/destinations/klaviyo/processor/groupTestDataV2.ts +++ b/test/integrations/destinations/klaviyo/processor/groupTestDataV2.ts @@ -108,6 +108,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -168,6 +169,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -228,6 +230,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(2), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/identifyTestData.ts b/test/integrations/destinations/klaviyo/processor/identifyTestData.ts index 0dd4751133..ec663cf8e9 100644 --- a/test/integrations/destinations/klaviyo/processor/identifyTestData.ts +++ b/test/integrations/destinations/klaviyo/processor/identifyTestData.ts @@ -133,6 +133,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -212,6 +213,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(2), }, ], + method: 'POST', }, }, output: { @@ -296,6 +298,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(3), }, ], + method: 'POST', }, }, output: { @@ -352,6 +355,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(4), }, ], + method: 'POST', }, }, output: { @@ -406,6 +410,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(5), }, ], + method: 'POST', }, }, output: { @@ -488,6 +493,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(6), }, ], + method: 'POST', }, }, output: { @@ -565,6 +571,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(7), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/identifyTestDataV2.ts b/test/integrations/destinations/klaviyo/processor/identifyTestDataV2.ts index 612bfe88f8..33c85e7d6a 100644 --- a/test/integrations/destinations/klaviyo/processor/identifyTestDataV2.ts +++ b/test/integrations/destinations/klaviyo/processor/identifyTestDataV2.ts @@ -162,6 +162,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(2), }, ], + method: 'POST', }, }, output: { @@ -254,6 +255,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(2), }, ], + method: 'POST', }, }, output: { @@ -357,6 +359,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(4), }, ], + method: 'POST', }, }, output: { @@ -424,6 +427,7 @@ export const identifyData: ProcessorTestData[] = [ metadata: generateMetadata(5), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/screenTestData.ts b/test/integrations/destinations/klaviyo/processor/screenTestData.ts index 0a20110236..d14c397bdc 100644 --- a/test/integrations/destinations/klaviyo/processor/screenTestData.ts +++ b/test/integrations/destinations/klaviyo/processor/screenTestData.ts @@ -67,6 +67,7 @@ export const screenTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/screenTestDataV2.ts b/test/integrations/destinations/klaviyo/processor/screenTestDataV2.ts index 5ccbed600c..a50659343c 100644 --- a/test/integrations/destinations/klaviyo/processor/screenTestDataV2.ts +++ b/test/integrations/destinations/klaviyo/processor/screenTestDataV2.ts @@ -75,6 +75,7 @@ export const screenTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/trackTestData.ts b/test/integrations/destinations/klaviyo/processor/trackTestData.ts index 3bc2b1747a..9bc4dfae21 100644 --- a/test/integrations/destinations/klaviyo/processor/trackTestData.ts +++ b/test/integrations/destinations/klaviyo/processor/trackTestData.ts @@ -88,6 +88,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -170,6 +171,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(2), }, ], + method: 'POST', }, }, output: { @@ -244,6 +246,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(3), }, ], + method: 'POST', }, }, output: { @@ -312,6 +315,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(4), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/trackTestDataV2.ts b/test/integrations/destinations/klaviyo/processor/trackTestDataV2.ts index ecea141d38..78a3a0d718 100644 --- a/test/integrations/destinations/klaviyo/processor/trackTestDataV2.ts +++ b/test/integrations/destinations/klaviyo/processor/trackTestDataV2.ts @@ -101,6 +101,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(2), }, ], + method: 'POST', }, }, output: { @@ -183,6 +184,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(3), }, ], + method: 'POST', }, }, output: { @@ -265,6 +267,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/validationTestData.ts b/test/integrations/destinations/klaviyo/processor/validationTestData.ts index 801e03d541..94d0c7818b 100644 --- a/test/integrations/destinations/klaviyo/processor/validationTestData.ts +++ b/test/integrations/destinations/klaviyo/processor/validationTestData.ts @@ -55,6 +55,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/processor/validationTestDataV2.ts b/test/integrations/destinations/klaviyo/processor/validationTestDataV2.ts index 10e2d15db0..2deb1debbb 100644 --- a/test/integrations/destinations/klaviyo/processor/validationTestDataV2.ts +++ b/test/integrations/destinations/klaviyo/processor/validationTestDataV2.ts @@ -55,6 +55,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/router/data.ts b/test/integrations/destinations/klaviyo/router/data.ts index 1b3f7f39ad..02e22937e1 100644 --- a/test/integrations/destinations/klaviyo/router/data.ts +++ b/test/integrations/destinations/klaviyo/router/data.ts @@ -34,6 +34,7 @@ export const data: RouterTestData[] = [ input: { request: { body: routerRequest, + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/klaviyo/router/dataV2.ts b/test/integrations/destinations/klaviyo/router/dataV2.ts index 5a0a06fad1..5201abc712 100644 --- a/test/integrations/destinations/klaviyo/router/dataV2.ts +++ b/test/integrations/destinations/klaviyo/router/dataV2.ts @@ -89,6 +89,7 @@ export const dataV2: RouterTestData[] = [ input: { request: { body: routerRequestV2, + method: 'POST', }, }, output: { @@ -422,6 +423,7 @@ export const dataV2: RouterTestData[] = [ ], destType: 'klaviyo', }, + method: 'POST', }, }, output: { @@ -694,6 +696,7 @@ export const dataV2: RouterTestData[] = [ ], destType: 'klaviyo', }, + method: 'POST', }, }, output: { @@ -1113,6 +1116,7 @@ export const dataV2: RouterTestData[] = [ ], destType: 'klaviyo', }, + method: 'POST', }, }, output: { @@ -1371,6 +1375,7 @@ export const dataV2: RouterTestData[] = [ ], destType: 'klaviyo', }, + method: 'POST', }, }, output: { @@ -1734,6 +1739,7 @@ export const dataV2: RouterTestData[] = [ ], destType: 'klaviyo', }, + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/koddi/processor/clicks.ts b/test/integrations/destinations/koddi/processor/clicks.ts index 6101e9bafe..0b27c42442 100644 --- a/test/integrations/destinations/koddi/processor/clicks.ts +++ b/test/integrations/destinations/koddi/processor/clicks.ts @@ -40,6 +40,7 @@ export const clicks: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/koddi/processor/conversions.ts b/test/integrations/destinations/koddi/processor/conversions.ts index 1647ffed7d..f4516bfb98 100644 --- a/test/integrations/destinations/koddi/processor/conversions.ts +++ b/test/integrations/destinations/koddi/processor/conversions.ts @@ -52,6 +52,7 @@ export const conversions: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -122,6 +123,7 @@ export const conversions: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/koddi/processor/impressions.ts b/test/integrations/destinations/koddi/processor/impressions.ts index 840ed9139f..90c1d6b6ae 100644 --- a/test/integrations/destinations/koddi/processor/impressions.ts +++ b/test/integrations/destinations/koddi/processor/impressions.ts @@ -40,6 +40,7 @@ export const impressions: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts b/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts index 287e35e5a7..19e34e6549 100644 --- a/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/configLevelFeaturesTestData.ts @@ -36,11 +36,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; @@ -94,6 +89,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ destination: overrideDestination(commonDestination, { hashData: false }), }, ], + method: 'POST', }, }, output: { @@ -169,6 +165,7 @@ export const configLevelFeaturesTestData: ProcessorTestData[] = [ }), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts b/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts index f9dfc528db..f8fd0a4639 100644 --- a/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/trackTestData.ts @@ -32,11 +32,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; @@ -153,6 +148,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -226,6 +222,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -332,6 +329,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -419,6 +417,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -477,6 +476,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -563,6 +563,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { @@ -656,6 +657,7 @@ export const trackTestData: ProcessorTestData[] = [ destination: commonDestination, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts b/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts index 5cb6ff8cf2..e93da3e205 100644 --- a/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts +++ b/test/integrations/destinations/linkedin_ads/processor/validationTestData.ts @@ -36,11 +36,6 @@ const commonDestination: Destination = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, Enabled: true, }; @@ -118,6 +113,7 @@ export const validationTestData: ProcessorTestData[] = [ destination: overrideDestination(commonDestination, { hashData: false }), }, ], + method: 'POST', }, }, output: { @@ -173,6 +169,7 @@ export const validationTestData: ProcessorTestData[] = [ }), }, ], + method: 'POST', }, }, output: { @@ -224,6 +221,7 @@ export const validationTestData: ProcessorTestData[] = [ }, }, ], + method: 'POST', }, }, output: { @@ -270,6 +268,7 @@ export const validationTestData: ProcessorTestData[] = [ }), }, ], + method: 'POST', }, }, output: { @@ -356,6 +355,7 @@ export const validationTestData: ProcessorTestData[] = [ }), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/linkedin_ads/router/data.ts b/test/integrations/destinations/linkedin_ads/router/data.ts index cf7defe6af..16abc0cd06 100644 --- a/test/integrations/destinations/linkedin_ads/router/data.ts +++ b/test/integrations/destinations/linkedin_ads/router/data.ts @@ -20,11 +20,6 @@ const config = { to: '34567', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }; const commonDestination = { diff --git a/test/integrations/destinations/linkedin_audience/processor/business.ts b/test/integrations/destinations/linkedin_audience/processor/business.ts index 28cb6a9a97..8878d58ced 100644 --- a/test/integrations/destinations/linkedin_audience/processor/business.ts +++ b/test/integrations/destinations/linkedin_audience/processor/business.ts @@ -85,6 +85,7 @@ export const businessTestData: ProcessorTestData[] = [ }, }, ], + method: 'POST', }, }, output: { @@ -188,6 +189,7 @@ export const businessTestData: ProcessorTestData[] = [ }, }, ], + method: 'POST', }, }, output: { @@ -317,6 +319,7 @@ export const businessTestData: ProcessorTestData[] = [ }, }, ], + method: 'POST', }, }, output: { @@ -468,6 +471,7 @@ export const businessTestData: ProcessorTestData[] = [ }, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/linkedin_audience/processor/validation.ts b/test/integrations/destinations/linkedin_audience/processor/validation.ts index 3ad37b2f4d..ae63251e24 100644 --- a/test/integrations/destinations/linkedin_audience/processor/validation.ts +++ b/test/integrations/destinations/linkedin_audience/processor/validation.ts @@ -86,6 +86,7 @@ export const validationTestData: ProcessorTestData[] = [ }, }, ], + method: 'POST', }, }, output: { @@ -227,6 +228,7 @@ export const validationTestData: ProcessorTestData[] = [ }, }, ], + method: 'POST', }, }, output: { @@ -337,6 +339,7 @@ export const validationTestData: ProcessorTestData[] = [ }, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/moengage/processor/data.ts b/test/integrations/destinations/moengage/processor/data.ts index df6e1226b6..50309c0372 100644 --- a/test/integrations/destinations/moengage/processor/data.ts +++ b/test/integrations/destinations/moengage/processor/data.ts @@ -292,7 +292,7 @@ export const data = [ FORM: {}, }, files: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', }, statusCode: 200, }, @@ -418,7 +418,7 @@ export const data = [ files: {}, method: 'POST', params: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', headers: { 'MOE-APPKEY': 'W0ZHNMPI2O4KHJ48ZILZACRA', 'Content-Type': 'application/json', @@ -686,7 +686,7 @@ export const data = [ files: {}, method: 'POST', params: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', headers: { 'MOE-APPKEY': 'W0ZHNMPI2O4KHJ48ZILZACRA', 'Content-Type': 'application/json', @@ -719,7 +719,7 @@ export const data = [ files: {}, method: 'POST', params: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', headers: { 'MOE-APPKEY': 'W0ZHNMPI2O4KHJ48ZILZACRA', 'Content-Type': 'application/json', @@ -851,7 +851,7 @@ export const data = [ files: {}, method: 'POST', params: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', headers: { 'MOE-APPKEY': 'W0ZHNMPI2O4KHJ48ZILZACRA', 'Content-Type': 'application/json', @@ -983,7 +983,7 @@ export const data = [ files: {}, method: 'POST', params: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', headers: { 'MOE-APPKEY': 'W0ZHNMPI2O4KHJ48ZILZACRA', 'Content-Type': 'application/json', @@ -1875,7 +1875,7 @@ export const data = [ FORM: {}, }, files: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', }, statusCode: 200, }, @@ -2008,7 +2008,7 @@ export const data = [ files: {}, method: 'POST', params: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', headers: { 'MOE-APPKEY': 'W0ZHNMPI2O4KHJ48ZILZACRA', 'Content-Type': 'application/json', @@ -2041,7 +2041,7 @@ export const data = [ files: {}, method: 'POST', params: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', headers: { 'MOE-APPKEY': 'W0ZHNMPI2O4KHJ48ZILZACRA', 'Content-Type': 'application/json', @@ -2318,7 +2318,7 @@ export const data = [ FORM: {}, }, files: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', }, statusCode: 200, }, @@ -2599,7 +2599,7 @@ export const data = [ FORM: {}, }, files: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', }, statusCode: 200, }, @@ -2875,7 +2875,7 @@ export const data = [ method: 'POST', params: {}, type: 'REST', - userId: 'anon-dummyId-1', + userId: 'userId16', version: '1', }, statusCode: 200, diff --git a/test/integrations/destinations/moengage/router/data.ts b/test/integrations/destinations/moengage/router/data.ts index b24453fd34..a31f407b2c 100644 --- a/test/integrations/destinations/moengage/router/data.ts +++ b/test/integrations/destinations/moengage/router/data.ts @@ -324,7 +324,7 @@ export const data = [ FORM: {}, }, files: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', }, metadata: [{ jobId: 1, userId: 'u1' }], batched: false, @@ -393,7 +393,7 @@ export const data = [ FORM: {}, }, files: {}, - userId: '4eb021e9-a2af-4926-ae82-fe996d12f3c5', + userId: 'rudder123', }, metadata: [{ jobId: 2, userId: 'u1' }], batched: false, diff --git a/test/integrations/destinations/movable_ink/processor/identify.ts b/test/integrations/destinations/movable_ink/processor/identify.ts index 0fe806df4a..60c9b39d76 100644 --- a/test/integrations/destinations/movable_ink/processor/identify.ts +++ b/test/integrations/destinations/movable_ink/processor/identify.ts @@ -31,6 +31,7 @@ export const identify: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/movable_ink/processor/track.ts b/test/integrations/destinations/movable_ink/processor/track.ts index 890de11a0c..e34e1799e5 100644 --- a/test/integrations/destinations/movable_ink/processor/track.ts +++ b/test/integrations/destinations/movable_ink/processor/track.ts @@ -33,6 +33,7 @@ export const track: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -96,6 +97,7 @@ export const track: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -159,6 +161,7 @@ export const track: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/movable_ink/processor/validation.ts b/test/integrations/destinations/movable_ink/processor/validation.ts index 6aafb5e2c0..575337a20f 100644 --- a/test/integrations/destinations/movable_ink/processor/validation.ts +++ b/test/integrations/destinations/movable_ink/processor/validation.ts @@ -27,6 +27,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -71,6 +72,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -111,6 +113,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -154,6 +157,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -197,6 +201,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -241,6 +246,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/reddit/dataDelivery/business.ts b/test/integrations/destinations/reddit/dataDelivery/business.ts index b48004a2ed..cc2feccffa 100644 --- a/test/integrations/destinations/reddit/dataDelivery/business.ts +++ b/test/integrations/destinations/reddit/dataDelivery/business.ts @@ -39,6 +39,71 @@ const validRequestPayload = { ], }; +const validRequestMultipleEventsInPayload = { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + ], +}; + const commonHeaders = { Authorization: 'Bearer dummyAccessToken', 'Content-Type': 'application/json', @@ -73,13 +138,14 @@ export const testScenariosForV0API = [ status: 200, body: { output: { - destResp: { + destinationResponse: { response: { message: 'Successfully processed 1 conversion events.', }, status: 200, }, - message: 'Request Processed Successfully', + message: + '[Generic Response Handler] Request for destination: reddit Processed Successfully', status: 200, }, }, @@ -116,8 +182,15 @@ export const testScenariosForV1API = [ body: { output: { message: 'Request Processed Successfully', + destinationResponse: { + response: { + message: 'Successfully processed 1 conversion events.', + }, + status: 200, + }, response: [ { + error: 'success', metadata: generateMetadata(1), statusCode: 200, }, @@ -180,4 +253,63 @@ export const testScenariosForV1API = [ }, }, }, + { + id: 'reddit_v1_scenario_3', + name: 'reddit', + description: + '[Proxy v1 API] :: Test for a valid request with a partial event failure from the destination', + scenario: 'PartialFailure', + feature: 'dataDelivery', + module: 'destination', + version: 'v1', + input: { + request: { + body: generateProxyV1Payload( + { + headers: commonHeaders, + JSON: validRequestMultipleEventsInPayload, + endpoint: + 'https://ads-api.reddit.com/api/v2.0/conversions/events/partial_failed_events', + }, + [generateMetadata(1), generateMetadata(2)], + ), + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + message: 'REDDIT: Error transformer proxy during REDDIT response transformation', + response: [ + { + metadata: { ...generateMetadata(1), dontBatch: true }, + statusCode: 500, + error: + '{"message":"There were 1 invalid conversion events. None were processed.","invalid_events":[{"error_message":"event_at timestamp must be less than 168h0m0s old","event":{"event_at":"2018-10-14T09:03:17.562Z","event_type":{"tracking_type":"Purchase"},"event_metadata":{"item_count":0,"products":[{}],"conversion_id":"c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1"},"user":{"aaid":"c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a","email":"ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2","external_id":"7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d","ip_address":"e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36","screen_dimensions":{}}}}]}', + }, + { + metadata: { ...generateMetadata(2), dontBatch: true }, + statusCode: 500, + error: + '{"message":"There were 1 invalid conversion events. None were processed.","invalid_events":[{"error_message":"event_at timestamp must be less than 168h0m0s old","event":{"event_at":"2018-10-14T09:03:17.562Z","event_type":{"tracking_type":"Purchase"},"event_metadata":{"item_count":0,"products":[{}],"conversion_id":"c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1"},"user":{"aaid":"c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a","email":"ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2","external_id":"7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d","ip_address":"e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36","screen_dimensions":{}}}}]}', + }, + ], + statTags: { + destType: 'REDDIT', + destinationId: 'default-destinationId', + errorCategory: 'network', + errorType: 'retryable', + feature: 'dataDelivery', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + status: 500, + }, + }, + }, + }, + }, ]; diff --git a/test/integrations/destinations/reddit/dataDelivery/oauth.ts b/test/integrations/destinations/reddit/dataDelivery/oauth.ts index 8c0d486a7a..e3c5875a06 100644 --- a/test/integrations/destinations/reddit/dataDelivery/oauth.ts +++ b/test/integrations/destinations/reddit/dataDelivery/oauth.ts @@ -84,14 +84,13 @@ export const v0oauthScenarios = [ status: 401, body: { output: { - authErrorCategory: 'REFRESH_TOKEN', destinationResponse: { response: 'Authorization Required', status: 401, }, message: - 'Request failed due to Authorization Required during reddit response transformation', - statTags: expectedStatTags, + '[Generic Response Handler] Request failed for destination reddit with status: 401', + statTags: { ...expectedStatTags, errorType: 'aborted' }, status: 401, }, }, @@ -121,7 +120,6 @@ export const v0oauthScenarios = [ status: 401, body: { output: { - authErrorCategory: 'REFRESH_TOKEN', destinationResponse: { response: { success: false, @@ -134,8 +132,8 @@ export const v0oauthScenarios = [ status: 401, }, message: - 'This server could not verify that you are authorized to access the document you requested. during reddit response transformation', - statTags: expectedStatTags, + '[Generic Response Handler] Request failed for destination reddit with status: 401', + statTags: { ...expectedStatTags, errorType: 'aborted' }, status: 401, }, }, diff --git a/test/integrations/destinations/reddit/network.ts b/test/integrations/destinations/reddit/network.ts index 80c18c00a0..54d7a95b73 100644 --- a/test/integrations/destinations/reddit/network.ts +++ b/test/integrations/destinations/reddit/network.ts @@ -210,4 +210,111 @@ export const networkCallsData = [ statusText: 'Unauthorized', }, }, + { + httpReq: { + url: 'https://ads-api.reddit.com/api/v2.0/conversions/events/partial_failed_events', + data: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 3, + products: [ + { + id: '123', + name: 'Monopoly', + category: 'Games', + }, + { + id: '345', + name: 'UNO', + category: 'Games', + }, + ], + }, + }, + ], + }, + params: { destination: 'reddit' }, + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + method: 'POST', + }, + httpRes: { + data: { + message: 'There were 1 invalid conversion events. None were processed.', + invalid_events: [ + { + error_message: 'event_at timestamp must be less than 168h0m0s old', + event: { + event_at: '2018-10-14T09:03:17.562Z', + event_type: { + tracking_type: 'Purchase', + }, + event_metadata: { + item_count: 0, + products: [{}], + conversion_id: 'c054005afd85a4de74638a776eb8348d44ee875184d7a401830705b7a06e7df1', + }, + user: { + aaid: 'c12d34889302d3c656b5699fa9190b51c50d6f62fce57e13bd56b503d66c487a', + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + }, + }, + ], + }, + status: 400, + statusText: 'Bad Request', + }, + }, ]; diff --git a/test/integrations/destinations/reddit/router/data.ts b/test/integrations/destinations/reddit/router/data.ts index b5bed48ae7..f2dd887b84 100644 --- a/test/integrations/destinations/reddit/router/data.ts +++ b/test/integrations/destinations/reddit/router/data.ts @@ -178,6 +178,131 @@ export const data = [ userId: 'u1', }, }, + { + message: { + context: { + traits: { email: 'testone@gmail.com' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + ip: '54.100.200.255', + }, + type: 'track', + session_id: '16733896350494', + originalTimestamp: '2019-10-14T09:03:17.562Z', + anonymousId: '123456', + event: 'Order Completed', + userId: 'testuserId1', + properties: { + checkout_id: '12345', + order_id: '1234', + affiliation: 'Apple Store', + total: 20, + revenue: 15, + shipping: 4, + tax: 1, + discount: 1.5, + coupon: 'ImagePro', + currency: 'USD', + products: [ + { + product_id: '123', + sku: 'G-32', + name: 'Monopoly', + price: 14, + quantity: 1, + category: 'Games', + url: 'https://www.website.com/product/path', + image_url: 'https://www.website.com/product/path.jpg', + }, + { + product_id: '345', + sku: 'F-32', + name: 'UNO', + price: 3.45, + quantity: 2, + category: 'Games', + }, + ], + }, + integrations: { All: true }, + sentAt: '2019-10-14T09:03:22.563Z', + }, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 4, + userId: 'u1', + dontBatch: true, + }, + }, + { + message: { + context: { + traits: { email: 'testone@gmail.com' }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + ip: '54.100.200.255', + }, + type: 'track', + originalTimestamp: '2019-10-14T09:03:17.562Z', + anonymousId: '123456', + event: 'Product List Viewed', + userId: 'testuserId1', + properties: { + list_id: 'list1', + category: "What's New", + value: 2600, + value_decimal: 26, + products: [ + { + product_id: '017c6f5d5cf86a4b22432066', + sku: '8732-98', + name: 'Just Another Game', + price: 22, + position: 2, + category: 'Games and Entertainment', + url: 'https://www.myecommercewebsite.com/product', + image_url: 'https://www.myecommercewebsite.com/product/path.jpg', + }, + { + product_id: '89ac6f5d5cf86a4b64eac145', + sku: '1267-01', + name: 'Wrestling Trump Cards', + price: 4, + position: 21, + category: 'Card Games', + }, + ], + }, + integrations: { All: true }, + sentAt: '2019-10-14T09:03:22.563Z', + }, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 5, + userId: 'u1', + dontBatch: true, + }, + }, ], destType: 'reddit', }, @@ -325,6 +450,147 @@ export const data = [ DestinationDefinition: { Config: { cdkV2Enabled: true } }, }, }, + { + batchedRequest: { + body: { + JSON: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { tracking_type: 'Purchase' }, + user: { + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: + '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: + 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 2, + currency: 'USD', + value: 1500, + value_decimal: 15, + products: [ + { id: '123', name: 'Monopoly', category: 'Games' }, + { id: '345', name: 'UNO', category: 'Games' }, + ], + }, + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_fsddXXXfsfd', + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + params: {}, + files: {}, + }, + metadata: [ + { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 4, + userId: 'u1', + dontBatch: true, + }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + }, + { + batchedRequest: { + body: { + JSON: { + events: [ + { + event_at: '2019-10-14T09:03:17.562Z', + event_type: { tracking_type: 'ViewContent' }, + user: { + email: 'ac144532d9e4efeab19475d9253a879173ea12a3d2238d1cb8a332a7b3a105f2', + external_id: + '7b023241a3132b792a5a33915a5afb3133cbb1e13d72879689bf6504de3b036d', + ip_address: + 'e80bd55a3834b7c2a34ade23c7ecb54d2a49838227080f50716151e765a619db', + user_agent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + screen_dimensions: {}, + }, + event_metadata: { + item_count: 0, + value: 2600, + value_decimal: 26, + products: [ + { + id: '017c6f5d5cf86a4b22432066', + name: 'Just Another Game', + category: 'Games and Entertainment', + }, + { + id: '89ac6f5d5cf86a4b64eac145', + name: 'Wrestling Trump Cards', + category: 'Card Games', + }, + ], + }, + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://ads-api.reddit.com/api/v2.0/conversions/events/a2_fsddXXXfsfd', + headers: { + Authorization: 'Bearer dummyAccessToken', + 'Content-Type': 'application/json', + }, + params: {}, + files: {}, + }, + metadata: [ + { + destinationId: 'destId', + workspaceId: 'wspId', + secret: { accessToken: 'dummyAccessToken' }, + jobId: 5, + userId: 'u1', + dontBatch: true, + }, + ], + batched: true, + statusCode: 200, + destination: { + Config: { + accountId: 'a2_fsddXXXfsfd', + hashData: true, + eventsMapping: [{ from: 'Order Completed', to: 'Purchase' }], + }, + DestinationDefinition: { Config: { cdkV2Enabled: true } }, + }, + }, ], }, }, diff --git a/test/integrations/destinations/refiner/processor/groupTestData.ts b/test/integrations/destinations/refiner/processor/groupTestData.ts index e3a05357f5..7ee6ad7e68 100644 --- a/test/integrations/destinations/refiner/processor/groupTestData.ts +++ b/test/integrations/destinations/refiner/processor/groupTestData.ts @@ -62,6 +62,7 @@ export const groupTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/refiner/processor/identifyTestData.ts b/test/integrations/destinations/refiner/processor/identifyTestData.ts index cc3704bb45..0d4b4a0d03 100644 --- a/test/integrations/destinations/refiner/processor/identifyTestData.ts +++ b/test/integrations/destinations/refiner/processor/identifyTestData.ts @@ -88,6 +88,7 @@ export const identifyTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/refiner/processor/pageTestData.ts b/test/integrations/destinations/refiner/processor/pageTestData.ts index b6c782202e..c53804db9f 100644 --- a/test/integrations/destinations/refiner/processor/pageTestData.ts +++ b/test/integrations/destinations/refiner/processor/pageTestData.ts @@ -75,6 +75,7 @@ export const pageTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/refiner/processor/trackTestData.ts b/test/integrations/destinations/refiner/processor/trackTestData.ts index e10ac6f0f5..cdea22540d 100644 --- a/test/integrations/destinations/refiner/processor/trackTestData.ts +++ b/test/integrations/destinations/refiner/processor/trackTestData.ts @@ -85,6 +85,7 @@ export const trackTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/refiner/processor/validationTestData.ts b/test/integrations/destinations/refiner/processor/validationTestData.ts index 20a9694fdf..5b408b5e5c 100644 --- a/test/integrations/destinations/refiner/processor/validationTestData.ts +++ b/test/integrations/destinations/refiner/processor/validationTestData.ts @@ -83,6 +83,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -125,6 +126,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -166,6 +168,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { @@ -208,6 +211,7 @@ export const validationTestData: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/rockerbox/processor/data.ts b/test/integrations/destinations/rockerbox/processor/data.ts index 76dd8ef11b..4a64ff09f6 100644 --- a/test/integrations/destinations/rockerbox/processor/data.ts +++ b/test/integrations/destinations/rockerbox/processor/data.ts @@ -85,13 +85,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -206,13 +199,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -339,13 +325,6 @@ export const data = [ clientAuthId: { web: 'test-client-auth-id', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: 'Marketing Sample', - }, - ], - }, customDomain: { web: 'https://cookiedomain.com', }, @@ -501,13 +480,6 @@ export const data = [ clientAuthId: { web: '', }, - oneTrustCookieCategories: { - web: [ - { - oneTrustCookieCategory: '', - }, - ], - }, customDomain: { web: '', }, diff --git a/test/integrations/destinations/rockerbox/router/data.ts b/test/integrations/destinations/rockerbox/router/data.ts index af943d7e6b..535b4f7da5 100644 --- a/test/integrations/destinations/rockerbox/router/data.ts +++ b/test/integrations/destinations/rockerbox/router/data.ts @@ -19,9 +19,6 @@ export const data = [ eventsMap: [{ from: 'Product Added', to: 'conv.add_to_cart' }], useNativeSDK: { web: false }, clientAuthId: { web: 'test-client-auth-id' }, - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, customDomain: { web: 'https://cookiedomain.com' }, enableCookieSync: { web: true }, }, @@ -108,9 +105,6 @@ export const data = [ enableCookieSync: { web: true }, eventFilteringOption: 'disable', eventsMap: [{ from: 'Product Added', to: 'conv.add_to_cart' }], - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, useNativeSDK: { web: false }, whitelistedEvents: [{ eventName: '' }], }, @@ -143,9 +137,6 @@ export const data = [ eventsMap: [{ from: 'Product Viewed', to: 'conv.add_to_cart' }], useNativeSDK: { web: false }, clientAuthId: { web: 'test-client-auth-id' }, - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, customDomain: { web: 'https://cookiedomain.com' }, enableCookieSync: { web: true }, }, @@ -232,9 +223,6 @@ export const data = [ enableCookieSync: { web: true }, eventFilteringOption: 'disable', eventsMap: [{ from: 'Product Viewed', to: 'conv.add_to_cart' }], - oneTrustCookieCategories: { - web: [{ oneTrustCookieCategory: 'Marketing Sample' }], - }, useNativeSDK: { web: false }, whitelistedEvents: [{ eventName: '' }], }, diff --git a/test/integrations/destinations/topsort/mocks.ts b/test/integrations/destinations/topsort/mocks.ts new file mode 100644 index 0000000000..0a3e24b30f --- /dev/null +++ b/test/integrations/destinations/topsort/mocks.ts @@ -0,0 +1,5 @@ +import utils from '../../../../src/v0/util'; + +export const defaultMockFns = () => { + jest.spyOn(utils, 'generateUUID').mockReturnValue('test-id-123-123-123'); +}; diff --git a/test/integrations/destinations/topsort/processor/data.ts b/test/integrations/destinations/topsort/processor/data.ts new file mode 100644 index 0000000000..73f838f140 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/data.ts @@ -0,0 +1,9 @@ +import { trackClicksTestData } from './trackClicksTestData'; +import { trackImpressionsTestData } from './trackImpressionsTestData'; +import { trackPurchasesTestData } from './trackPurchasesTestData'; + +export const data = [ + ...trackClicksTestData, + ...trackImpressionsTestData, + ...trackPurchasesTestData, +]; diff --git a/test/integrations/destinations/topsort/processor/trackClicksTestData.ts b/test/integrations/destinations/topsort/processor/trackClicksTestData.ts new file mode 100644 index 0000000000..7e187cc0d4 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackClicksTestData.ts @@ -0,0 +1,575 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Clicked', + to: 'clicks', + }, + { + from: 'Order Completed', + to: 'clicks', + }, + { + from: 'Order Refunded', + to: 'clicks', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackClicksTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Verifies that a Product Clicked event with all necessary properties is successfully processed and mapped correctly by Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Clicked', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Validates the correct processing and mapping of an Order Completed event with multiple products.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Tests the handling of an invalid event type (abc) and ensures that Topsort correctly drops the event with a 400 error indicating unsupported event type.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: { + type: 'abc', + event: 'Order Refunded', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }, + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: 'Only "track" events are supported. Dropping event.', + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 3', + name: 'topsort', + description: + 'Verifies the correct processing of an Order Completed event with multiple products and handles an error for an unrecognized Order Updated2 event in Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Updated2', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + { + error: "Event 'order updated2' not found in Topsort event mappings", + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts b/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts new file mode 100644 index 0000000000..385a068d70 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackImpressionsTestData.ts @@ -0,0 +1,384 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Viewed', + to: 'impressions', + }, + { + from: 'Checkout Started', + to: 'impressions', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackImpressionsTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Track call with impressions event, verifies that a Product Viewed event is correctly mapped', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Viewed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Verifies that a Checkout Started event with multiple products is correctly mapped and ingested as impressions in Topsort.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Checkout Started', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-id-123-123-123', + }, + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/categories/dairy', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 2, + productId: '577c6f5d5cf86a4c7735ba03', + }, + id: 'test-id-123-123-123', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Verifies that an invalid event (Checkout done) that is not found in Topsort’s event mappings is handled and returns an error with a status code 400.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Checkout done', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: "Event 'checkout done' not found in Topsort event mappings", + statTags: { + destType: 'TOPSORT', + destinationId: 'default-destinationId', + errorCategory: 'dataValidation', + errorType: 'configuration', + feature: 'processor', + implementation: 'native', + module: 'destination', + workspaceId: 'default-workspaceId', + }, + metadata: generateMetadata(1), + statusCode: 400, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts b/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts new file mode 100644 index 0000000000..b1ab98b8f1 --- /dev/null +++ b/test/integrations/destinations/topsort/processor/trackPurchasesTestData.ts @@ -0,0 +1,460 @@ +import { Destination } from '../../../../../src/types'; +import { ProcessorTestData } from '../../../testTypes'; +import { + generateMetadata, + generateSimplifiedTrackPayload, + transformResultBuilder, +} from '../../../testUtils'; +import { defaultMockFns } from '../mocks'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', // Base URL for Topsort API + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Order Completed', + to: 'purchases', + }, + { + from: 'Product Added', + to: 'purchases', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const trackPurchasesTestData: ProcessorTestData[] = [ + { + id: 'Test 0', + name: 'topsort', + description: + 'Verifies that a Product Added event is correctly mapped and ingested as a purchase event in Topsort with the appropriate product details.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Added', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 1', + name: 'topsort', + description: + 'Verifies that a Checkout Started event with multiple products is correctly mapped with items.', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + unitPrice: 40, + }, + { + productId: '577c6f5d5cf86a4c7735ba03', + unitPrice: 5, + }, + ], + id: 'test-id-123-123-123', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, + { + id: 'Test 2', + name: 'topsort', + description: + 'Verifies that both a Product Added and an Order Completed event are correctly mapped and ingested into Topsort as purchase events', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200 and correctly map the properties to the specified parameters.', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Product Added', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + { + message: generateSimplifiedTrackPayload({ + type: 'track', + event: 'Order Completed', // The RudderStack event + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + context: { + page: { + path: '/categories/dairy', + }, + }, + anonymousId: 'david_bowie_anonId', + }), + metadata: generateMetadata(1), + destination, + }, + ], + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: [ + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + { + output: transformResultBuilder({ + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + userId: '', + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'david_bowie_anonId', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }), + metadata: generateMetadata(1), + statusCode: 200, + }, + ], + }, + }, + mockFns: defaultMockFns, + }, +]; diff --git a/test/integrations/destinations/topsort/router/data.ts b/test/integrations/destinations/topsort/router/data.ts new file mode 100644 index 0000000000..d226f8610c --- /dev/null +++ b/test/integrations/destinations/topsort/router/data.ts @@ -0,0 +1,421 @@ +import { Destination } from '../../../../../src/types'; +import { RouterTestData } from '../../../testTypes'; +import { generateMetadata } from '../../../testUtils'; + +const destination: Destination = { + ID: '123', + Name: 'topsort', + DestinationDefinition: { + ID: '123', + Name: 'topsort', + DisplayName: 'topsort', + Config: { + endpoint: 'https://api.topsort.com/v2/events', + }, + }, + Config: { + apiKey: 'test-api', + connectionMode: { + web: 'cloud', + }, + consentManagement: {}, + oneTrustCookieCategories: {}, + ketchConsentPurposes: {}, + topsortEvents: [ + { + from: 'Product Clicked', + to: 'clicks', + }, + { + from: 'Product Added', + to: 'purchases', + }, + { + from: 'Product Removed', + to: 'impressions', + }, + ], + }, + Enabled: true, + WorkspaceID: '123', + Transformations: [], +}; + +export const data: RouterTestData[] = [ + { + id: 'topsort-router-test-1', + name: 'topsort', + description: 'Basic Router Test for track call having clicks event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Clicked', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + }, + }, + }, + ], + destType: 'topsort', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + impressions: [], + clicks: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/category/123', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, + { + id: 'topsort-router-test-2', + name: 'topsort', + description: 'Basic Router Test for track call having impressions event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Removed', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + { + product_id: '577c6f5d5cf86a4c7735ba03', + sku: '3309-483-2201', + price: 5, + position: 2, + }, + ], + }, + }, + }, + ], + destType: 'topsort', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + impressions: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + placement: { + path: '/category/123', + pageSize: 15, + categoryIds: ['9BLIe'], + position: 1, + productId: '622c6f5d5cf86a4c77358033', + }, + id: 'test-msg-id', + }, + ], + clicks: [], + purchases: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, + { + id: 'topsort-router-test-3', + name: 'topsort', + description: 'Basic Router Test for track call having purchases event', + scenario: 'Business', + successCriteria: + 'The response should have a status code of 200, and the output should correctly map the properties.', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + destination, + metadata: generateMetadata(1), + message: { + type: 'track', + event: 'Product Added', + originalTimestamp: '2024-11-05T15:19:08+00:00', + messageId: 'test-msg-id', + anonymousId: 'sampath', + channel: 'web', + context: { + page: { + path: '/category/123', + }, + ip: '0.0.0.0', + }, + integrations: { All: true }, + properties: { + product_id: '622c6f5d5cf86a4c77358033', + price: 49.99, + quantity: 5, + position: 1, + resolvedBidId: '13841873482r7903r823', + page: 1, + pageSize: 15, + category_id: '9BLIe', + url: 'https://www.website.com/product/path', + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + entity: { + id: '235', + type: 'product', + }, + products: [ + { + product_id: '622c6f5d5cf86a4c77358033', + sku: '8472-998-0112', + price: 40, + position: 1, + }, + ], + }, + }, + }, + ], + destType: 'topsort', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://api.topsort.com/v2/events', + headers: { + 'content-type': 'application/json', + Authorization: 'Bearer test-api', + }, + params: {}, + body: { + JSON: { + purchases: [ + { + occurredAt: '2024-11-05T15:19:08+00:00', + opaqueUserId: 'sampath', + resolvedBidId: '13841873482r7903r823', + entity: { + id: '235', + type: 'product', + }, + additionalAttribution: { + id: 'a13362', + type: 'product', + }, + items: [ + { + productId: '622c6f5d5cf86a4c77358033', + quantity: 5, + unitPrice: 49.99, + }, + ], + id: 'test-msg-id', + }, + ], + clicks: [], + impressions: [], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + }, + metadata: [generateMetadata(1)], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, +]; diff --git a/test/integrations/destinations/tune/processor/trackTestData.ts b/test/integrations/destinations/tune/processor/trackTestData.ts index 63178d0e33..d42c4136b6 100644 --- a/test/integrations/destinations/tune/processor/trackTestData.ts +++ b/test/integrations/destinations/tune/processor/trackTestData.ts @@ -22,8 +22,6 @@ const destination: Destination = { }, subdomain: 'demo', consentManagement: {}, - oneTrustCookieCategories: {}, - ketchConsentPurposes: {}, tuneEvents: [ { eventName: 'Product added', @@ -80,6 +78,7 @@ export const trackTestdata: ProcessorTestData[] = [ destination, }, ], + method: 'POST', }, }, output: { @@ -142,6 +141,7 @@ export const trackTestdata: ProcessorTestData[] = [ destination, }, ], + method: 'POST', }, }, output: { @@ -200,6 +200,7 @@ export const trackTestdata: ProcessorTestData[] = [ destination, }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/tune/router/data.ts b/test/integrations/destinations/tune/router/data.ts index f21714d058..66d19f481d 100644 --- a/test/integrations/destinations/tune/router/data.ts +++ b/test/integrations/destinations/tune/router/data.ts @@ -17,8 +17,6 @@ const destination: Destination = { }, subdomain: 'demo', consentManagement: {}, - oneTrustCookieCategories: {}, - ketchConsentPurposes: {}, tuneEvents: [ { eventName: 'Product added', @@ -80,6 +78,7 @@ export const data: RouterTestData[] = [ ], destType: 'tune', }, + method: 'POST', }, }, output: { @@ -158,6 +157,7 @@ export const data: RouterTestData[] = [ ], destType: 'tune', }, + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/webhook/processor/data.ts b/test/integrations/destinations/webhook/processor/data.ts index 92fe8f50d9..7720bc683c 100644 --- a/test/integrations/destinations/webhook/processor/data.ts +++ b/test/integrations/destinations/webhook/processor/data.ts @@ -3285,7 +3285,7 @@ export const data = [ Config: { webhookUrl: 'https://webhook.site/81dc2730-807f-4bbc-8914-5b37d21c8a55', webhookMethod: 'POST', - oneTrustCookieCategories: [], + connectionMode: 'cloud', eventDelivery: false, eventDeliveryTS: 1720497286192, @@ -3294,7 +3294,7 @@ export const data = [ Config: { secretKeys: ['headers.to'], excludeKeys: [], - includeKeys: ['oneTrustCookieCategories', 'consentManagement'], + includeKeys: ['consentManagement'], cdkV2Enabled: true, transformAtV1: 'processor', isAudienceSupported: true, diff --git a/test/integrations/destinations/wunderkind/processor/validation.ts b/test/integrations/destinations/wunderkind/processor/validation.ts index aeabdd497b..38c94ecef1 100644 --- a/test/integrations/destinations/wunderkind/processor/validation.ts +++ b/test/integrations/destinations/wunderkind/processor/validation.ts @@ -30,6 +30,7 @@ export const validation: ProcessorTestData[] = [ metadata: generateMetadata(1), }, ], + method: 'POST', }, }, output: { diff --git a/test/integrations/destinations/zoho/common.ts b/test/integrations/destinations/zoho/common.ts index bea4437e6f..1d89dbce6d 100644 --- a/test/integrations/destinations/zoho/common.ts +++ b/test/integrations/destinations/zoho/common.ts @@ -65,11 +65,6 @@ const commonDeletionDestConfig: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -186,11 +181,6 @@ const commonUpsertDestConfig: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -225,11 +215,6 @@ const commonUpsertDestConfig2: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -264,11 +249,6 @@ const commonUpsertDestConfig2CustomModule: Destination = { to: 'false', }, ], - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; @@ -293,11 +273,6 @@ const commonUpsertDestConfig3: Destination = { module: 'Leads', trigger: 'workflow', addDefaultDuplicateCheck: true, - oneTrustCookieCategories: [ - { - oneTrustCookieCategory: 'Marketing', - }, - ], }, }; diff --git a/test/integrations/sources/shopify/constants.ts b/test/integrations/sources/shopify/constants.ts index f9df305841..af53a3180e 100644 --- a/test/integrations/sources/shopify/constants.ts +++ b/test/integrations/sources/shopify/constants.ts @@ -83,6 +83,21 @@ export const dummyContext = { }, }; +export const note_attributes = [ + { + name: 'cartId', + value: '9c623f099fc8819aa4d6a958b65dfe7d', + }, + { + name: 'cartToken', + value: 'Z2NwLXVzLWVhc3QxOjAxSkQzNUFXVEI4VkVUNUpTTk1LSzBCMzlF', + }, + { + name: 'rudderAnonymousId', + value: '50ead33e-d763-4854-b0ab-765859ef05cb', + }, +]; + export const responseDummyContext = { document: { location: { diff --git a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts index 38f682ac6d..3db2e3ab10 100644 --- a/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts +++ b/test/integrations/sources/shopify/pixelTestScenarios/CheckoutStepsTests.ts @@ -2037,7 +2037,7 @@ export const pixelCheckoutStepsScenarios = [ SHOPIFY: true, }, type: 'track', - event: 'Payment Info Submitted', + event: 'Payment Info Entered', properties: { buyerAcceptsEmailMarketing: false, buyerAcceptsSmsMarketing: false, diff --git a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts index ade496efb7..b6fa5be322 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/CheckoutEventsTests.ts @@ -1,7 +1,6 @@ // This file contains the test scenarios for the server-side events from the Shopify GraphQL API for // the v1 transformation flow -import { mockFns } from '../mocks'; -import { dummySourceConfig } from '../constants'; +import { dummySourceConfig, note_attributes } from '../constants'; export const checkoutEventsTestScenarios = [ { @@ -27,7 +26,7 @@ export const checkoutEventsTestScenarios = [ updated_at: '2024-11-05T21:22:02-05:00', landing_site: '/', note: '', - note_attributes: [], + note_attributes, referring_site: '', shipping_lines: [], shipping_address: [], @@ -145,7 +144,7 @@ export const checkoutEventsTestScenarios = [ updated_at: '2024-11-05T21:22:02-05:00', landing_site: '/', note: '', - note_attributes: [], + note_attributes, referring_site: '', shipping_lines: [], shipping_address: [], @@ -218,16 +217,16 @@ export const checkoutEventsTestScenarios = [ SHOPIFY: true, }, type: 'track', - event: 'Checkout Started', + event: 'Checkout Started - Webhook', properties: { - order_id: 35550298931313, + order_id: '35550298931313', value: '600.00', - tax: '0.00', + tax: 0, currency: 'USD', products: [ { - product_id: 7234590408817, - price: '600.00', + product_id: '7234590408817', + price: 600.0, brand: 'Hydrogen Vendor', quantity: 1, }, @@ -237,7 +236,7 @@ export const checkoutEventsTestScenarios = [ traits: { shippingAddress: [], }, - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -269,7 +268,7 @@ export const checkoutEventsTestScenarios = [ created_at: '2024-09-16T03:50:1500:00', updated_at: '2024-09-17T03:29:02-04:00', note: '', - note_attributes: [], + note_attributes, shipping_address: { first_name: 'testuser', address1: 'oakwood bridge', @@ -396,7 +395,7 @@ export const checkoutEventsTestScenarios = [ output: { batch: [ { - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', context: { cart_token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', integration: { @@ -415,7 +414,7 @@ export const checkoutEventsTestScenarios = [ created_at: '2024-09-16T03:50:1500:00', updated_at: '2024-09-17T03:29:02-04:00', note: '', - note_attributes: [], + note_attributes, shipping_address: { first_name: 'testuser', address1: 'oakwood bridge', @@ -534,17 +533,16 @@ export const checkoutEventsTestScenarios = [ }, properties: { currency: 'USD', - order_id: 35374569160817, + order_id: '35374569160817', products: [ { brand: 'pixel-testing-rs', - price: '729.95', - product_id: 7234590638193, + price: 729.95, + product_id: '7234590638193', quantity: 1, }, ], - tax: '0.00', - value: '736.85', + tax: 0, }, timestamp: '2024-09-17T07:29:02.000Z', traits: { @@ -680,7 +678,7 @@ export const checkoutEventsTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, number: 17, order_number: 1017, order_status_url: @@ -988,7 +986,7 @@ export const checkoutEventsTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, number: 17, order_number: 1017, order_status_url: @@ -1208,15 +1206,14 @@ export const checkoutEventsTestScenarios = [ type: 'track', event: 'Order Updated', properties: { - order_id: 5778367414385, - value: '600.00', - tax: '0.00', + order_id: '5778367414385', + tax: 0, currency: 'USD', products: [ { - product_id: 7234590408817, + product_id: '7234590408817', title: 'The Collection Snowboard: Hydrogen', - price: '600.00', + price: 600, brand: 'Hydrogen Vendor', quantity: 1, }, @@ -1289,7 +1286,7 @@ export const checkoutEventsTestScenarios = [ }, }, timestamp: '2024-11-06T02:54:50.000Z', - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -1326,6 +1323,7 @@ export const checkoutEventsTestScenarios = [ current_total_tax: '0.00', email: 'henry@wfls.com', name: '#1017', + note_attributes, order_number: 1017, order_status_url: 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', @@ -1486,6 +1484,7 @@ export const checkoutEventsTestScenarios = [ current_total_tax: '0.00', email: 'henry@wfls.com', name: '#1017', + note_attributes, order_number: 1017, order_status_url: 'https://pixel-testing-rs.myshopify.com/59026964593/orders/676613a0027fc8240e16d67fdc9f5ac8/authenticate?key=a70bbe7ec8abcc46b77e4331e4df8c60', @@ -1597,15 +1596,15 @@ export const checkoutEventsTestScenarios = [ type: 'track', event: 'Order Created', properties: { - order_id: 5778367414385, + order_id: '5778367414385', value: '600.00', - tax: '0.00', + tax: 0, currency: 'USD', products: [ { - product_id: 7234590408817, + product_id: '7234590408817', title: 'The Collection Snowboard: Hydrogen', - price: '600.00', + price: 600, brand: 'Hydrogen Vendor', quantity: 1, }, @@ -1675,7 +1674,7 @@ export const checkoutEventsTestScenarios = [ }, }, timestamp: '2024-11-06T02:54:50.000Z', - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, @@ -1684,4 +1683,4 @@ export const checkoutEventsTestScenarios = [ }, }, }, -].map((d1) => ({ ...d1, mockFns })); +]; diff --git a/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts b/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts index f04fd7e08e..d68d0a8f59 100644 --- a/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts +++ b/test/integrations/sources/shopify/webhookTestScenarios/GenericTrackTests.ts @@ -1,7 +1,7 @@ // This file contains the test scenarios for the server-side events from the Shopify GraphQL API for // the v1 transformation flow import { mockFns } from '../mocks'; -import { dummySourceConfig } from '../constants'; +import { dummySourceConfig, note_attributes } from '../constants'; export const genericTrackTestScenarios = [ { @@ -24,6 +24,7 @@ export const genericTrackTestScenarios = [ token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', line_items: [], note: '', + note_attributes, updated_at: '2024-09-17T08:15:13.280Z', created_at: '2024-09-16T03:50:15.478Z', }, @@ -43,7 +44,7 @@ export const genericTrackTestScenarios = [ output: { batch: [ { - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', context: { integration: { name: 'SHOPIFY', @@ -58,6 +59,7 @@ export const genericTrackTestScenarios = [ id: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', line_items: [], note: '', + note_attributes, token: 'Z2NwLXVzLWVhc3QxOjAxSjdXRjdOQjY0NlFFNFdQVEg0MTRFM1E2', updated_at: '2024-09-17T08:15:13.280Z', }, @@ -149,7 +151,7 @@ export const genericTrackTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, order_number: 1017, original_total_additional_fees_set: null, original_total_duties_set: null, @@ -363,7 +365,7 @@ export const genericTrackTestScenarios = [ merchant_of_record_app_id: null, name: '#1017', note: null, - note_attributes: [], + note_attributes, order_number: 1017, original_total_additional_fees_set: null, original_total_duties_set: null, @@ -545,7 +547,7 @@ export const genericTrackTestScenarios = [ traits: { email: 'henry@wfls.com', }, - anonymousId: '5d3e2cb6-4011-5c9c-b7ee-11bc1e905097', + anonymousId: '50ead33e-d763-4854-b0ab-765859ef05cb', }, ], }, diff --git a/test/integrations/testTypes.ts b/test/integrations/testTypes.ts index 3c5cf60600..971ef5969c 100644 --- a/test/integrations/testTypes.ts +++ b/test/integrations/testTypes.ts @@ -45,6 +45,7 @@ export interface TestCaseData { skipGo?: string; scenario?: string; successCriteria?: string; + tags?: string[]; comment?: string; feature: string; module: string; @@ -92,6 +93,7 @@ export type ProcessorTestData = { version: string; input: { request: { + method: string; body: ProcessorTransformationRequest[]; }; }; @@ -101,7 +103,7 @@ export type ProcessorTestData = { body: ProcessorTransformationResponse[]; }; }; - mockFns?: (mockAdapter: MockAdapter) => {}; + mockFns?: (mockAdapter: MockAdapter) => void; }; export type RouterTestData = { id: string; @@ -116,6 +118,7 @@ export type RouterTestData = { input: { request: { body: RouterTransformationRequest; + method: string; }; }; output: { diff --git a/test/integrations/testUtils.ts b/test/integrations/testUtils.ts index 7e6e6b9acb..73d08e452c 100644 --- a/test/integrations/testUtils.ts +++ b/test/integrations/testUtils.ts @@ -277,6 +277,7 @@ export const generateSimplifiedTrackPayload: any = (parametersOverride: any) => device: parametersOverride.context.device, os: parametersOverride.context.os, app: parametersOverride.context.app, + page: parametersOverride.context.page, }), anonymousId: parametersOverride.anonymousId || 'default-anonymousId', originalTimestamp: parametersOverride.originalTimestamp || '2021-01-03T17:02:53.193Z', diff --git a/test/scripts/migrateTest.ts b/test/scripts/migrateTest.ts new file mode 100644 index 0000000000..6757aa4bd1 --- /dev/null +++ b/test/scripts/migrateTest.ts @@ -0,0 +1,155 @@ +import fs from 'fs'; +import path from 'path'; + +import prettier from 'prettier'; +import { Command } from 'commander'; + +// Initialize command line options +const program = new Command(); +program + .option('-d, --destination ', 'Destination name to migrate') + .option('-f, --feature ', 'Feature type (processor/router/proxy)', 'processor') + // .option('-p, --path ', 'Base path for test files', path.join(__dirname, 'destinations')) + .parse(process.argv); + +const options = program.opts(); + +// Default values and utility functions from the previous example +import { + migrateProcessorTestCase, + migrateRouterTestCase, + migrateProxyTestCase, + extractCommonValues, + generateOptimizedTestFile, +} from './migrationUtils'; +import { getTestData, getTestDataFilePaths } from '../integrations/testUtils'; + +function readTestFile(filePath: string): any { + try { + const fileContent = getTestData(filePath); + return fileContent; + } catch (error) { + console.error(`Error reading test file ${filePath}:`, error); + return null; + } +} + +async function formatWithPrettier(content: string, filepath: string): Promise { + try { + // Try to load prettier config from the project + const prettierConfig = await prettier.resolveConfig(filepath); + + // Format the content using prettier with either found config or defaults + const formattedContent = await prettier.format(content, { + ...prettierConfig, + filepath, // This helps prettier determine parser based on file extension + parser: 'typescript', // Fallback to typescript parser if not determined from filepath + }); + + return formattedContent; + } catch (error) { + console.error('Error formatting file with prettier:', error); + // Return original content if formatting fails + return content; + } +} + +async function enhancedwriteTestFile( + filePath: string, + testCases: any[], + feature: string, +): Promise { + try { + // Extract common values + const commonValues = extractCommonValues(testCases); + + // Generate optimized content + const content = generateOptimizedTestFile(testCases, commonValues, feature); + + // Format with prettier + const formattedContent = await formatWithPrettier(content, filePath); + + // Write the formatted content + fs.writeFileSync(filePath, formattedContent); + } catch (error) { + console.error(`Error writing to file ${filePath}:`, error); + throw error; + } +} + +async function migrateTestFiles(): Promise { + const { destination, feature } = options; + + if (!destination) { + console.error('Please specify a destination with -d or --destination'); + process.exit(1); + } + + console.log(`Starting migration for destination: ${destination}, feature: ${feature}`); + + const basePath = path.resolve(__dirname, '..'); + + const testFiles = getTestDataFilePaths(basePath, options); + + if (testFiles.length === 0) { + console.log('No test files found matching the criteria'); + return; + } + + let migratedCount = 0; + let errorCount = 0; + + for (const filePath of testFiles) { + console.log(`\nProcessing file: ${filePath}`); + try { + const testCases = readTestFile(filePath); + if (!testCases) continue; + + const migratedTests = testCases.map((testCase: any, index: number) => { + try { + switch (feature.toLowerCase()) { + case 'processor': + return migrateProcessorTestCase(testCase, index); + case 'router': + return migrateRouterTestCase(testCase, index); + case 'proxy': + return migrateProxyTestCase(testCase, index); + default: + throw new Error(`Unsupported feature type: ${feature}`); + } + } catch (error) { + console.error(`Error migrating test case: ${testCase.name || 'unnamed'}`, error); + return testCase; + } + }); + + // Create backup of original file + const backupPath = filePath.replace('data.ts', 'data.backup.ts'); + fs.copyFileSync(filePath, backupPath); + console.log(`Created backup at: ${backupPath}`); + + // Write migrated tests + await enhancedwriteTestFile(filePath, migratedTests, feature.toLowerCase()); + console.log(`Successfully migrated ${migratedTests.length} test cases in ${filePath}`); + migratedCount += migratedTests.length; + } catch (error) { + console.error(`Error processing file ${filePath}:`, error); + errorCount++; + } + } + + console.log('\nMigration Summary:'); + console.log(`Total files processed: ${testFiles.length}`); + console.log(`Total test cases migrated: ${migratedCount}`); + console.log(`Files with errors: ${errorCount}`); +} + +// Run migration if this script is called directly +if (require.main === module) { + migrateTestFiles().catch((error) => { + console.error('Migration failed:', error); + process.exit(1); + }); +} + +export { migrateTestFiles }; diff --git a/test/scripts/migrationUtils.ts b/test/scripts/migrationUtils.ts new file mode 100644 index 0000000000..67d158a85f --- /dev/null +++ b/test/scripts/migrationUtils.ts @@ -0,0 +1,465 @@ +import { removeUndefinedValues } from '@rudderstack/integrations-lib'; +import { + Metadata, + Destination, + ProcessorTransformationRequest, + RouterTransformationRequest, + ProxyV1Request, + ProcessorTransformationResponse, + RouterTransformationResponse, +} from '../../src/types'; + +import { + TestCaseData, + ProcessorTestData, + RouterTestData, + ProxyV1TestData, +} from '../integrations/testTypes'; + +// Default metadata to fill in missing fields +const defaultMetadata: Metadata = { + sourceId: 'default-source', + workspaceId: 'default-workspace', + namespace: 'default-namespace', + instanceId: 'default-instance', + sourceType: 'default-source-type', + sourceCategory: 'default-category', + trackingPlanId: 'default-tracking-plan', + trackingPlanVersion: 1, + sourceTpConfig: {}, + mergedTpConfig: {}, + destinationId: 'default-destination', + jobRunId: 'default-job-run', + jobId: 1, + sourceBatchId: 'default-batch', + sourceJobId: 'default-source-job', + sourceJobRunId: 'default-source-job-run', + sourceTaskId: 'default-task', + sourceTaskRunId: 'default-task-run', + recordId: {}, + destinationType: 'default-destination-type', + messageId: 'default-message-id', + oauthAccessToken: 'default-token', + messageIds: ['default-message-id'], + rudderId: 'default-rudder-id', + receivedAt: new Date().toISOString(), + eventName: 'default-event', + eventType: 'default-type', + sourceDefinitionId: 'default-source-def', + destinationDefinitionId: 'default-dest-def', + transformationId: 'default-transform', + dontBatch: false, +}; + +// Default destination configuration +const defaultDestination: Destination = { + ID: 'default-destination-id', + Name: 'Default Destination', + DestinationDefinition: { + ID: 'default-dest-def-id', + Name: 'Default Destination Definition', + DisplayName: 'Default Display Name', + Config: {}, + }, + Config: {}, + Enabled: true, + WorkspaceID: 'default-workspace', + Transformations: [], + RevisionID: 'default-revision', + IsProcessorEnabled: true, + IsConnectionEnabled: true, +}; + +// Utility function to migrate generic test cases +export function migrateTestCase(oldTestCase: any): TestCaseData { + return { + id: oldTestCase.id || `test-${Date.now()}`, + name: oldTestCase.name || 'Migrated Test Case', + description: oldTestCase.description || 'Migrated from legacy test case', + scenario: oldTestCase.scenario || 'Default scenario', + successCriteria: oldTestCase.successCriteria || 'Test should pass successfully', + feature: oldTestCase.feature || 'default-feature', + module: oldTestCase.module || 'default-module', + version: oldTestCase.version || '1.0.0', + input: { + request: { + method: oldTestCase.input?.request?.method || 'POST', + body: oldTestCase.input?.request?.body || {}, + headers: oldTestCase.input?.request?.headers || {}, + params: oldTestCase.input?.request?.params || {}, + }, + pathSuffix: oldTestCase.input?.pathSuffix, + }, + output: { + response: { + status: oldTestCase.output?.response?.status || 200, + body: oldTestCase.output?.response?.body || {}, + headers: oldTestCase.output?.response?.headers || {}, + }, + }, + }; +} + +// Utility function to migrate processor test cases +export function migrateProcessorTestCase(oldTestCase: any, index: number): ProcessorTestData { + const processorRequest: ProcessorTransformationRequest = { + message: oldTestCase.input?.request?.body[0]?.message || {}, + metadata: { ...defaultMetadata, ...oldTestCase.input?.request?.body[0]?.metadata }, + destination: { ...defaultDestination, ...oldTestCase.input?.request?.body[0]?.destination }, + }; + + const processorResponse: ProcessorTransformationResponse = { + output: oldTestCase.output?.response?.body[0]?.output, + metadata: { ...defaultMetadata, ...oldTestCase.output?.response?.body[0]?.metadata }, + statusCode: oldTestCase.output?.response?.body[0]?.statusCode || 200, + error: oldTestCase.output?.response?.body[0]?.error, + statTags: oldTestCase.output?.response?.body[0]?.statTags, + }; + + return removeUndefinedValues({ + id: oldTestCase.id || `processor-${Date.now()}`, + name: oldTestCase.name || 'Processor Test Case', + description: oldTestCase.description || 'Migrated processor test case', + scenario: oldTestCase.scenario || 'Default processor scenario', + successCriteria: oldTestCase.successCriteria || 'Processor test should pass successfully', + feature: oldTestCase.feature || 'processor', + module: oldTestCase.module || 'transformation', + version: oldTestCase.version || '1.0.0', + input: { + request: { + method: oldTestCase.input?.request?.method || 'POST', + body: [processorRequest], + }, + }, + output: { + response: { + status: 200, + body: [processorResponse], + }, + }, + mockFns: oldTestCase.mockFns ? `Add mock of index ${index}` : undefined, + }) as ProcessorTestData; +} + +// Utility function to migrate router test cases +export function migrateRouterTestCase(oldTestCase: any, index: number): RouterTestData { + const input = Array.isArray(oldTestCase.input.request.body.input) + ? oldTestCase.input.request.body.input.map((item: any) => ({ + message: item.message || {}, + metadata: { ...defaultMetadata, ...item.metadata }, + destination: { ...defaultDestination, ...item.destination }, + })) + : { + message: oldTestCase.input.request.body.input?.message || {}, + metadata: { ...defaultMetadata, ...oldTestCase.input.request.body.input?.metadata }, + destination: { + ...defaultDestination, + ...oldTestCase.input.request.body.input?.destination, + }, + }; + const routerRequest: RouterTransformationRequest = { + input: input, + destType: oldTestCase.input?.request?.body?.destType || 'default-destination-type', + }; + + const routerResponse: RouterTransformationResponse = oldTestCase.output.response.body.output.map( + (op) => { + return removeUndefinedValues({ + batchedRequest: op.batchedRequest, + metadata: op.metadata.map((m: any) => ({ ...defaultMetadata, ...m })), + statusCode: op.statusCode || 200, + destination: { ...defaultDestination, ...op.destination }, + batched: op.batched || false, + error: op.error, + statTags: op.statTags, + }); + }, + ); + + return removeUndefinedValues({ + id: oldTestCase.id || `router-${Date.now()}`, + name: oldTestCase.name || 'Router Test Case', + description: oldTestCase.description || 'Migrated router test case', + scenario: oldTestCase.scenario || 'Default router scenario', + successCriteria: oldTestCase.successCriteria || 'Router test should pass successfully', + feature: oldTestCase.feature || 'router', + module: oldTestCase.module || 'transformation', + version: oldTestCase.version || '1.0.0', + input: { + request: { + body: routerRequest, + method: oldTestCase.input?.request?.method || 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: routerResponse, + }, + }, + }, + mockFns: oldTestCase.mockFns ? `Add mock of index ${index}` : undefined, + }) as RouterTestData; +} + +// Utility function to migrate proxy test cases +export function migrateProxyTestCase(oldTestCase: any, index: number): ProxyV1TestData { + const proxyRequest: ProxyV1Request = { + version: oldTestCase.input?.request?.body?.version || '1.0.0', + type: oldTestCase.input?.request?.body?.type || 'default-type', + method: oldTestCase.input?.request?.body?.method || 'POST', + endpoint: oldTestCase.input?.request?.body?.endpoint || '/default-endpoint', + userId: oldTestCase.input?.request?.body?.userId || 'default-user', + metadata: [ + { + jobId: 1, + attemptNum: 1, + userId: 'default-user', + sourceId: 'default-source', + destinationId: 'default-destination', + workspaceId: 'default-workspace', + secret: {}, + dontBatch: false, + }, + ], + destinationConfig: {}, + }; + + return { + id: oldTestCase.id || `proxy-${Date.now()}`, + name: oldTestCase.name || 'Proxy Test Case', + description: oldTestCase.description || 'Migrated proxy test case', + scenario: oldTestCase.scenario || 'Default proxy scenario', + successCriteria: oldTestCase.successCriteria || 'Proxy test should pass successfully', + feature: oldTestCase.feature || 'proxy', + module: oldTestCase.module || 'delivery', + version: oldTestCase.version || '1.0.0', + input: { + request: { + body: proxyRequest, + method: oldTestCase.input?.request?.method || 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: { + status: 200, + message: 'Success', + response: [ + { + error: '', + statusCode: 200, + metadata: proxyRequest.metadata[0], + }, + ], + }, + }, + }, + }, + }; +} + +interface CommonValues { + metadata?: Metadata; + destination?: Destination; + baseRequest?: { + headers?: Record; + params?: Record; + }; + commonConfig?: Record; +} + +function deepDiff(obj1: any, obj2: any): any { + const diff: any = {}; + + for (const key in obj1) { + if (typeof obj1[key] === 'object' && obj1[key] !== null) { + const nestedDiff = deepDiff(obj1[key], obj2[key] || {}); + if (Object.keys(nestedDiff).length > 0) { + diff[key] = nestedDiff; + } + } else if (obj1[key] !== obj2[key]) { + diff[key] = obj2[key]; + } + } + + return diff; +} + +export function extractCommonValues(testCases: any[]): CommonValues { + const commonValues: CommonValues = {}; + + // Only proceed if we have test cases + if (testCases.length === 0) return commonValues; + + // Extract metadata from first test case as base + const firstCase = testCases[0]; + let isMetadataCommon = true; + let isDestinationCommon = true; + let baseMetadata: Metadata | undefined; + let baseDestination: Destination | undefined; + + // For processor and router cases + if (firstCase.input?.request?.body) { + if (Array.isArray(firstCase.input.request.body)) { + baseMetadata = firstCase.input.request.body[0]?.metadata; + baseDestination = firstCase.input.request.body[0]?.destination; + } else { + baseMetadata = firstCase.input.request.body?.metadata; + baseDestination = firstCase.input.request.body?.destination; + } + } + + // Compare with other test cases + for (const testCase of testCases.slice(1)) { + let currentMetadata; + let currentDestination; + + if (testCase.input?.request?.body) { + if (Array.isArray(testCase.input.request.body)) { + currentMetadata = testCase.input.request.body[0]?.metadata; + currentDestination = testCase.input.request.body[0]?.destination; + } else { + currentMetadata = testCase.input.request.body?.metadata; + currentDestination = testCase.input.request.body?.destination; + } + } + + // Check if metadata is common + if (baseMetadata && currentMetadata) { + const metadataDiff = deepDiff(baseMetadata, currentMetadata); + if (Object.keys(metadataDiff).length > 0) { + isMetadataCommon = false; + } + } + + // Check if destination is common + if (baseDestination && currentDestination) { + const destinationDiff = deepDiff(baseDestination, currentDestination); + if (Object.keys(destinationDiff).length > 0) { + isDestinationCommon = false; + } + } + } + + if (isMetadataCommon && baseMetadata) { + commonValues.metadata = baseMetadata; + } + + if (isDestinationCommon && baseDestination) { + commonValues.destination = baseDestination; + } + + return commonValues; +} + +export function generateOptimizedTestFile( + testCases: any[], + commonValues: CommonValues, + feature: string, +): string { + const variables: string[] = []; + const imports: Set = new Set([]); + + // Add necessary imports based on common values + if (commonValues.metadata) imports.add('Metadata'); + if (commonValues.destination) imports.add('Destination'); + + // Generate common variables + if (commonValues.metadata) { + variables.push( + `const baseMetadata: Metadata = ${JSON.stringify(commonValues.metadata, null, 2)};`, + ); + } + + if (commonValues.destination) { + variables.push(` +const baseDestination: Destination = ${JSON.stringify(commonValues.destination, null, 2)};`); + } + + // Process test cases to use common variables + const processedTests = testCases.map((testCase) => { + const processedCase = { ...testCase }; + + if (commonValues.metadata && testCase.input?.request?.body) { + // Handle input metadata + if (Array.isArray(testCase.input.request.body)) { + processedCase.input.request.body = testCase.input.request.body.map((item: any) => ({ + ...item, + metadata: 'baseMetadata', // special marker + })); + } else { + processedCase.input.request.body.metadata = 'baseMetadata'; // special marker + processedCase.output.metadata = 'baseMetadata'; // special marker + } + // Handle output metadata + if (Array.isArray(testCase.output.response.body)) { + processedCase.output.response.body = testCase.output.response.body.map((item: any) => ({ + ...item, + metadata: 'baseMetadata', // special marker + })); + } else { + processedCase.output.response.body.metadata = 'baseMetadata'; // special marker + } + } + + if (commonValues.destination && testCase.input?.request?.body) { + // Handle input destination + if (Array.isArray(testCase.input.request.body)) { + processedCase.input.request.body = testCase.input.request.body.map((item: any) => ({ + ...item, + destination: 'baseDestination', // special marker + })); + } else { + processedCase.input.request.body.destination = 'baseDestination'; // special marker + } + // Handle output destination + if (Array.isArray(testCase.output.response.body)) { + processedCase.output.response.body = testCase.output.response.body.map((item: any) => ({ + ...item, + metadata: 'baseMetadata', // special marker + })); + } else { + processedCase.output.response.body.metadata = 'baseMetadata'; // special marker + } + } + + return processedCase; + }); + + // const functionReplacer = (key, value) => { + // if (typeof value === 'function') { + // return value.toString(); + // } + // return value; + // }; + + let type = ''; + if (feature === 'processor') { + type = 'ProcessorTestData'; + } else if (feature === 'router') { + type = 'RouterTestData'; + } + + // Generate the final file content + const content = `/** + * Auto-migrated and optimized test cases + * Generated on: ${new Date().toISOString()} + */ + + import { ${type} } from '../../../testTypes'; + import { ${Array.from(imports).join(', ')} } from '../../../../../src/types'; + + ${variables.join('\n')} + + export const data: ${type}[] = ${JSON.stringify(processedTests, null, 2)}; + `; + + // Replace our special markers with actual variable references + return content + .replaceAll('"baseMetadata"', 'baseMetadata') + .replaceAll('"baseDestination"', 'baseDestination'); +} diff --git a/test/test_reporter/allureReporter.ts b/test/test_reporter/allureReporter.ts new file mode 100644 index 0000000000..3165aaa96a --- /dev/null +++ b/test/test_reporter/allureReporter.ts @@ -0,0 +1,134 @@ +import * as allure from 'allure-js-commons'; +import { diff as jsonDiff } from 'jest-diff'; +import _ from 'lodash'; +import { TestCaseData } from '../integrations/testTypes'; +import { compareObjects } from '../integrations/testUtils'; + +interface TestReportData { + testCase: TestCaseData; + actualResponse: any; + status: 'passed' | 'failed'; + diff?: string; +} + +/** + * Enhanced test reporter with detailed JSON diff and Allure integration + */ +export const enhancedTestReport = { + /** + * Generate a detailed test report with JSON diff for failed cases + */ + generateDetailedReport(data: TestReportData) { + const { testCase, actualResponse, status } = data; + const expectedResponse = testCase.output.response?.body; + + // Create Allure test case details + allure.description(` + Feature: ${testCase.feature} + Description: ${testCase.description} + Success Criteria: ${testCase.successCriteria || 'N/A'} + Scenario: ${testCase.scenario || 'N/A'} + Test ID: ${testCase.id || 'N/A'} + API Version: ${testCase.version || 'N/A'} + `); + + // Add request/response as attachments + allure.attachment( + 'Request', + JSON.stringify(testCase.input.request, null, 2), + 'application/json', + ); + allure.attachment( + 'Actual Response', + JSON.stringify(actualResponse, null, 2), + 'application/json', + ); + + if (status === 'failed') { + const diffResult = jsonDiff(expectedResponse, actualResponse, { + expand: false, // Compact diff view + contextLines: 3, // Show 3 lines of context around changes + }); + + const diffKeys = compareObjects(expectedResponse, actualResponse); + + if (diffResult) { + allure.attachment( + 'Expected Response', + JSON.stringify(expectedResponse, null, 2), + 'application/json', + ); + + allure.attachment('Diff Keys', JSON.stringify(diffKeys), 'text/plain'); + } + + // Add failure details + const failureMessage = `Test failed for ${testCase.name}\nSee JSON diff for details`; + allure.step(failureMessage, () => { + throw new Error(failureMessage); + }); + } + + return status; + }, + + /** + * Validate test case response with enhanced reporting + */ + validateTestResponse(testCase: TestCaseData, response: any): boolean { + const expectedResponse = testCase.output.response?.body; + const actualResponse = response; + const status = _.isEqual(actualResponse, expectedResponse) ? 'passed' : 'failed'; + + this.generateDetailedReport({ + testCase, + actualResponse, + status, + }); + + return status === 'passed'; + }, +}; + +/** + * Enhanced test utilities with better organization + */ +export const enhancedTestUtils = { + /** + * Setup test suite with Allure reporting + */ + setupTestSuite(testData: TestCaseData) { + allure.epic(testData.name); + allure.feature(testData.module); + allure.story(testData.feature); + allure.displayName(testData.description); + if (testData.scenario) { + allure.tag(testData.scenario); + } + if (testData.tags) { + allure.tags(...testData.tags); + } + if (testData.id) { + allure.allureId(testData.id); + } + }, + + /** + * Run pre-test preparations + */ + beforeTestRun(testCase: TestCaseData) { + allure.step('Test Setup', () => { + // Setup new test + this.setupTestSuite(testCase); + }); + }, + + /** + * Run post-test cleanup and reporting + */ + afterTestRun(testCase: TestCaseData, response: any) { + allure.step('Test Verification', () => { + return enhancedTestReport.validateTestResponse(testCase, response); + }); + }, +};