diff --git a/.github/workflows/check-pod.yaml b/.github/workflows/check-pod.yaml deleted file mode 100644 index f8019fcbd..000000000 --- a/.github/workflows/check-pod.yaml +++ /dev/null @@ -1,58 +0,0 @@ -name: Check Pod - -on: - pull_request: - push: - branches: - - main - -jobs: - check: - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - - name: Select Specific Xcode Version (13.4.1) - run: | - sudo xcode-select -s /Applications/Xcode_13.4.1.app - echo "Selected Xcode version:" - xcodebuild -version - - # Run the steps we document in the Release Process. - # unzip commands included as proof-of-life for the Carthage output. - - name: Print Ruby version - run: ruby --version - - name: Print Carthage version - run: 'echo -n "carthage version: " && carthage version' - - name: Print CocoaPods version - run: 'echo -n "pod version: " && pod --version --verbose' - - name: Print Make version - run: make --version - - name: Build Carthage dependencies - run: make update - - name: Build Ably framework - run: make carthage_package - - name: Print contents of generated ZIP file - run: | - unzip -l Ably.framework.zip - unzip -l Ably.framework.zip | grep 'Mac/Ably.framework' - unzip -l Ably.framework.zip | grep 'tvOS/Ably.framework' - unzip -l Ably.framework.zip | grep 'iOS/Ably.framework' - - name: Validate pod - run: pod lib lint - # We move Ably.framework.zip into a directory. This is because, by - # default, macOS’s Archive Utility unzips directly-nested zip files, so - # if Ably.framework.zip were at the top level of the zip file that - # actions/upload-artifact creates, then Archive Utility would unzip - # Ably.framework.zip too, which we don’t want, since we want this file - # to be kept intact so that we can upload it to GitHub releases as - # described in CONTRIBUTING.md. - - name: Prepare built framework for archiving - run: | - mkdir -p carthage-built-framework-artifact-contents/carthage-built-framework - mv Ably.framework.zip carthage-built-framework-artifact-contents/carthage-built-framework - - name: Archive built framework - uses: actions/upload-artifact@v3 - with: - name: carthage-built-framework - path: carthage-built-framework-artifact-contents diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index cb5a39c6b..000000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Docs Generation - -on: - pull_request: - push: - branches: - - main - tags: - - '*' - -jobs: - build: - runs-on: macos-latest - - permissions: - deployments: write - id-token: write - - steps: - - uses: actions/checkout@v2 - - - name: Select Specific Xcode Version - run: | - sudo xcode-select -s /Applications/Xcode_13.2.app - echo "Selected Xcode version:" - xcodebuild -version - - - name: Install Dependencies - run: | - make submodules - bundle install - make update_carthage_dependencies_macos - - - name: Build Documentation - run: | - ./Scripts/jazzy.sh - ls -al Docs/jazzy - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-region: eu-west-2 - role-to-assume: arn:aws:iam::${{ secrets.ABLY_AWS_ACCOUNT_ID_SDK }}:role/ably-sdk-builds-ably-cocoa - role-session-name: "${{ github.run_id }}-${{ github.run_number }}" - - - name: Upload Documentation - uses: ably/sdk-upload-action@v1 - with: - sourcePath: Docs/jazzy - githubToken: ${{ secrets.GITHUB_TOKEN }} - artifactName: jazzydoc - diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml deleted file mode 100644 index d1c123738..000000000 --- a/.github/workflows/features.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Features - -on: - pull_request: - push: - branches: - - main - -jobs: - build: - uses: ably/features/.github/workflows/sdk-features.yml@main - with: - repository-name: ably-cocoa - secrets: inherit diff --git a/.github/workflows/integration-test-iOS16_2-1.yaml b/.github/workflows/integration-test-iOS16_2-1.yaml new file mode 100644 index 000000000..c7eae610d --- /dev/null +++ b/.github/workflows/integration-test-iOS16_2-1.yaml @@ -0,0 +1,137 @@ +name: "Integration Test: iOS 16.2 (workflow 1)" +on: + pull_request: + push: + branches: + - main +# IMPORTANT NOTES: +# - Changes made to this file needs to replicated across other integration-test-*.yaml files. +# - The Fastlane lane name is duplicated in more than one place within this workflow. +jobs: + check-1: + runs-on: macos-latest + env: + LC_CTYPE: en_US.UTF-8 + LANG: en_US.UTF-8 + ABLY_ENV: sandbox + steps: + - name: Check out SDK repo + uses: actions/checkout@v2 + - name: Log environment information + run: ./Scripts/log-environment-information.sh + - name: Check out xcparse repo + uses: actions/checkout@v3 + with: + repository: ably-forks/xcparse + ref: emit-test-case-info + path: xcparse + - id: get-xcparse-commit-sha + name: Get xcparse commit SHA + run: | + cd xcparse + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: "actions/cache@v3 (xcparse binary)" + uses: actions/cache@v3 + with: + path: xcparse/.build/debug/xcparse + key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} + - name: Install Dependencies and Run Tests Continuously + env: + TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + run: | + brew install xcbeautify + brew install coreutils # for `timeout` + make submodules + bundle install + make update_carthage_dependencies_ios + Scripts/continuously-run-tests-and-upload-results.sh --lane test_iOS16_2 + - uses: actions/upload-artifact@v3 + with: + name: xcresult-bundles-1.tar.gz + path: xcresult-bundles.tar.gz + check-2: + runs-on: macos-latest + env: + LC_CTYPE: en_US.UTF-8 + LANG: en_US.UTF-8 + ABLY_ENV: sandbox + steps: + - name: Check out SDK repo + uses: actions/checkout@v2 + - name: Log environment information + run: ./Scripts/log-environment-information.sh + - name: Check out xcparse repo + uses: actions/checkout@v3 + with: + repository: ably-forks/xcparse + ref: emit-test-case-info + path: xcparse + - id: get-xcparse-commit-sha + name: Get xcparse commit SHA + run: | + cd xcparse + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: "actions/cache@v3 (xcparse binary)" + uses: actions/cache@v3 + with: + path: xcparse/.build/debug/xcparse + key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} + - name: Install Dependencies and Run Tests Continuously + env: + TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + run: | + brew install xcbeautify + brew install coreutils # for `timeout` + make submodules + bundle install + make update_carthage_dependencies_ios + Scripts/continuously-run-tests-and-upload-results.sh --lane test_iOS16_2 + - uses: actions/upload-artifact@v3 + with: + name: xcresult-bundles-2.tar.gz + path: xcresult-bundles.tar.gz + needs: + - check-1 + check-3: + runs-on: macos-latest + env: + LC_CTYPE: en_US.UTF-8 + LANG: en_US.UTF-8 + ABLY_ENV: sandbox + steps: + - name: Check out SDK repo + uses: actions/checkout@v2 + - name: Log environment information + run: ./Scripts/log-environment-information.sh + - name: Check out xcparse repo + uses: actions/checkout@v3 + with: + repository: ably-forks/xcparse + ref: emit-test-case-info + path: xcparse + - id: get-xcparse-commit-sha + name: Get xcparse commit SHA + run: | + cd xcparse + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: "actions/cache@v3 (xcparse binary)" + uses: actions/cache@v3 + with: + path: xcparse/.build/debug/xcparse + key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} + - name: Install Dependencies and Run Tests Continuously + env: + TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + run: | + brew install xcbeautify + brew install coreutils # for `timeout` + make submodules + bundle install + make update_carthage_dependencies_ios + Scripts/continuously-run-tests-and-upload-results.sh --lane test_iOS16_2 + - uses: actions/upload-artifact@v3 + with: + name: xcresult-bundles-3.tar.gz + path: xcresult-bundles.tar.gz + needs: + - check-2 diff --git a/.github/workflows/integration-test-iOS16_2-2.yaml b/.github/workflows/integration-test-iOS16_2-2.yaml new file mode 100644 index 000000000..c4253260a --- /dev/null +++ b/.github/workflows/integration-test-iOS16_2-2.yaml @@ -0,0 +1,137 @@ +name: "Integration Test: iOS 16.2 (workflow 2)" +on: + pull_request: + push: + branches: + - main +# IMPORTANT NOTES: +# - Changes made to this file needs to replicated across other integration-test-*.yaml files. +# - The Fastlane lane name is duplicated in more than one place within this workflow. +jobs: + check-1: + runs-on: macos-latest + env: + LC_CTYPE: en_US.UTF-8 + LANG: en_US.UTF-8 + ABLY_ENV: sandbox + steps: + - name: Check out SDK repo + uses: actions/checkout@v2 + - name: Log environment information + run: ./Scripts/log-environment-information.sh + - name: Check out xcparse repo + uses: actions/checkout@v3 + with: + repository: ably-forks/xcparse + ref: emit-test-case-info + path: xcparse + - id: get-xcparse-commit-sha + name: Get xcparse commit SHA + run: | + cd xcparse + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: "actions/cache@v3 (xcparse binary)" + uses: actions/cache@v3 + with: + path: xcparse/.build/debug/xcparse + key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} + - name: Install Dependencies and Run Tests Continuously + env: + TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + run: | + brew install xcbeautify + brew install coreutils # for `timeout` + make submodules + bundle install + make update_carthage_dependencies_ios + Scripts/continuously-run-tests-and-upload-results.sh --lane test_iOS16_2 + - uses: actions/upload-artifact@v3 + with: + name: xcresult-bundles-1.tar.gz + path: xcresult-bundles.tar.gz + check-2: + runs-on: macos-latest + env: + LC_CTYPE: en_US.UTF-8 + LANG: en_US.UTF-8 + ABLY_ENV: sandbox + steps: + - name: Check out SDK repo + uses: actions/checkout@v2 + - name: Log environment information + run: ./Scripts/log-environment-information.sh + - name: Check out xcparse repo + uses: actions/checkout@v3 + with: + repository: ably-forks/xcparse + ref: emit-test-case-info + path: xcparse + - id: get-xcparse-commit-sha + name: Get xcparse commit SHA + run: | + cd xcparse + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: "actions/cache@v3 (xcparse binary)" + uses: actions/cache@v3 + with: + path: xcparse/.build/debug/xcparse + key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} + - name: Install Dependencies and Run Tests Continuously + env: + TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + run: | + brew install xcbeautify + brew install coreutils # for `timeout` + make submodules + bundle install + make update_carthage_dependencies_ios + Scripts/continuously-run-tests-and-upload-results.sh --lane test_iOS16_2 + - uses: actions/upload-artifact@v3 + with: + name: xcresult-bundles-2.tar.gz + path: xcresult-bundles.tar.gz + needs: + - check-1 + check-3: + runs-on: macos-latest + env: + LC_CTYPE: en_US.UTF-8 + LANG: en_US.UTF-8 + ABLY_ENV: sandbox + steps: + - name: Check out SDK repo + uses: actions/checkout@v2 + - name: Log environment information + run: ./Scripts/log-environment-information.sh + - name: Check out xcparse repo + uses: actions/checkout@v3 + with: + repository: ably-forks/xcparse + ref: emit-test-case-info + path: xcparse + - id: get-xcparse-commit-sha + name: Get xcparse commit SHA + run: | + cd xcparse + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: "actions/cache@v3 (xcparse binary)" + uses: actions/cache@v3 + with: + path: xcparse/.build/debug/xcparse + key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} + - name: Install Dependencies and Run Tests Continuously + env: + TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + run: | + brew install xcbeautify + brew install coreutils # for `timeout` + make submodules + bundle install + make update_carthage_dependencies_ios + Scripts/continuously-run-tests-and-upload-results.sh --lane test_iOS16_2 + - uses: actions/upload-artifact@v3 + with: + name: xcresult-bundles-3.tar.gz + path: xcresult-bundles.tar.gz + needs: + - check-2 diff --git a/.github/workflows/integration-test-iOS16_2.yaml b/.github/workflows/integration-test-iOS16_2.yaml deleted file mode 100644 index 918a11621..000000000 --- a/.github/workflows/integration-test-iOS16_2.yaml +++ /dev/null @@ -1,117 +0,0 @@ -name: "Integration Test: iOS 16.2" - -on: - pull_request: - push: - branches: - - main - -# IMPORTANT NOTES: -# - Changes made to this file needs to replicated across other integration-test-*.yaml files. -# - The Fastlane lane name is duplicated in more than one place within this workflow. - -jobs: - check: - runs-on: macos-latest - - env: - LC_CTYPE: en_US.UTF-8 - LANG: en_US.UTF-8 - ABLY_ENV: sandbox - - steps: - - name: Check out SDK repo - uses: actions/checkout@v2 - - - name: Log environment information - run: ./Scripts/log-environment-information.sh - - - name: Check out xcparse repo - uses: actions/checkout@v3 - with: - repository: ably-forks/xcparse - ref: emit-test-case-info - path: xcparse - - - id: get-xcparse-commit-sha - name: Get xcparse commit SHA - run: | - cd xcparse - echo "::set-output name=sha::$(git rev-parse HEAD)" - - - name: "actions/cache@v3 (xcparse binary)" - uses: actions/cache@v3 - with: - path: xcparse/.build/debug/xcparse - key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} - - - name: Reset Simulators - run: xcrun simctl erase all - - - name: Install Dependencies and Run Tests - run: | - brew install xcbeautify - make submodules - bundle install - make update_carthage_dependencies_ios - bundle exec fastlane test_iOS16_2 - - - name: Check Static Analyzer Output - id: analyzer-output - run: | - if [[ -z $(find ./derived_data -name "report-*.html") ]]; then - echo "Static Analyzer found no issues." - else - echo "Static Analyzer found some issues. HTML report will be available in Artifacts section. Failing build." - exit 1 - fi - - - name: Static Analyzer Reports Uploading - if: ${{ failure() && steps.analyzer-output.outcome == 'failure' }} - uses: actions/upload-artifact@v2 - with: - name: static-analyzer-reports-test_iOS16_2 - path: ./derived_data/**/report-*.html - - - name: Run Examples Tests - working-directory: ./Examples/Tests - run: | - pod repo update - pod install - bundle exec fastlane scan -s Tests --output-directory "fastlane/test_output/examples/test_iOS16_2" - - - name: Build APNS Example Project - working-directory: ./Examples/AblyPush - run: | - xcodebuild build -scheme "AblyPushExample" -destination "platform=iOS Simulator,name=iPhone 14" -configuration "Debug" - - - name: Xcodebuild Logs Artifact - if: always() - uses: actions/upload-artifact@v2 - with: - name: xcodebuild-logs - path: ~/Library/Developer/Xcode/DerivedData/*/Logs - - - name: Upload test output artifact - if: always() - uses: actions/upload-artifact@v2 - with: - name: test-output - path: fastlane/test_output - - - name: Upload test results to observability server - if: always() - env: - TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} - run: Scripts/upload_test_results.sh - - - name: Swift Package Manager - Installation Test - working-directory: ./ - run: | - echo 'Current Branch: ' $GITHUB_HEAD_REF - echo 'Current Revision (SHA):' $GITHUB_SHA - echo Current Path: $(pwd) - export PACKAGE_URL=file://$(pwd) - export PACKAGE_BRANCH_NAME=$GITHUB_HEAD_REF - export PACKAGE_REVISION=$GITHUB_SHA - swift test --package-path Examples/SPM -v diff --git a/.github/workflows/integration-test-macOS.yaml b/.github/workflows/integration-test-macOS.yaml deleted file mode 100644 index a456ff7f1..000000000 --- a/.github/workflows/integration-test-macOS.yaml +++ /dev/null @@ -1,112 +0,0 @@ -name: "Integration Test: macOS Latest" - -on: - pull_request: - push: - branches: - - main - -# IMPORTANT NOTES: -# - Changes made to this file needs to replicated across other integration-test-*.yaml files. -# - The Fastlane lane name is duplicated in more than one place within this workflow. - -jobs: - check: - runs-on: macos-latest - - env: - LC_CTYPE: en_US.UTF-8 - LANG: en_US.UTF-8 - ABLY_ENV: sandbox - - steps: - - name: Check out SDK repo - uses: actions/checkout@v2 - - - name: Log environment information - run: ./Scripts/log-environment-information.sh - - - name: Check out xcparse repo - uses: actions/checkout@v3 - with: - repository: ably-forks/xcparse - ref: emit-test-case-info - path: xcparse - - - id: get-xcparse-commit-sha - name: Get xcparse commit SHA - run: | - cd xcparse - echo "::set-output name=sha::$(git rev-parse HEAD)" - - - name: "actions/cache@v3 (xcparse binary)" - uses: actions/cache@v3 - with: - path: xcparse/.build/debug/xcparse - key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} - - - name: Reset Simulators - run: xcrun simctl erase all - - - name: Install Dependencies and Run Tests - run: | - brew install xcbeautify - make submodules - bundle install - make update_carthage_dependencies_macos - bundle exec fastlane test_macOS - - - name: Check Static Analyzer Output - id: analyzer-output - run: | - if [[ -z $(find ./derived_data -name "report-*.html") ]]; then - echo "Static Analyzer found no issues." - else - echo "Static Analyzer found some issues. HTML report will be available in Artifacts section. Failing build." - exit 1 - fi - - - name: Static Analyzer Reports Uploading - if: ${{ failure() && steps.analyzer-output.outcome == 'failure' }} - uses: actions/upload-artifact@v2 - with: - name: static-analyzer-reports-test_macOS - path: ./derived_data/**/report-*.html - - - name: Run Examples Tests - working-directory: ./Examples/Tests - run: | - pod repo update - pod install - bundle exec fastlane scan -s Tests --output-directory "fastlane/test_output/examples/test_macOS" - - - name: Xcodebuild Logs Artifact - if: always() - uses: actions/upload-artifact@v2 - with: - name: xcodebuild-logs - path: ~/Library/Developer/Xcode/DerivedData/*/Logs - - - name: Upload test output artifact - if: always() - uses: actions/upload-artifact@v2 - with: - name: test-output - path: fastlane/test_output - - - name: Upload test results to observability server - if: always() - env: - TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} - run: Scripts/upload_test_results.sh - - - name: Swift Package Manager - Installation Test - working-directory: ./ - run: | - echo 'Current Branch: ' $GITHUB_HEAD_REF - echo 'Current Revision (SHA):' $GITHUB_SHA - echo Current Path: $(pwd) - export PACKAGE_URL=file://$(pwd) - export PACKAGE_BRANCH_NAME=$GITHUB_HEAD_REF - export PACKAGE_REVISION=$GITHUB_SHA - swift test --package-path Examples/SPM -v diff --git a/.github/workflows/integration-test-tvOS16_1.yaml b/.github/workflows/integration-test-tvOS16_1.yaml deleted file mode 100644 index f8827137a..000000000 --- a/.github/workflows/integration-test-tvOS16_1.yaml +++ /dev/null @@ -1,112 +0,0 @@ -name: "Integration Test: tvOS 16.1" - -on: - pull_request: - push: - branches: - - main - -# IMPORTANT NOTES: -# - Changes made to this file needs to replicated across other integration-test-*.yaml files. -# - The Fastlane lane name is duplicated in more than one place within this workflow. - -jobs: - check: - runs-on: macos-latest - - env: - LC_CTYPE: en_US.UTF-8 - LANG: en_US.UTF-8 - ABLY_ENV: sandbox - - steps: - - name: Check out SDK repo - uses: actions/checkout@v2 - - - name: Log environment information - run: ./Scripts/log-environment-information.sh - - - name: Check out xcparse repo - uses: actions/checkout@v3 - with: - repository: ably-forks/xcparse - ref: emit-test-case-info - path: xcparse - - - id: get-xcparse-commit-sha - name: Get xcparse commit SHA - run: | - cd xcparse - echo "::set-output name=sha::$(git rev-parse HEAD)" - - - name: "actions/cache@v3 (xcparse binary)" - uses: actions/cache@v3 - with: - path: xcparse/.build/debug/xcparse - key: ${{ runner.os }}-xcparse-${{ steps.get-xcparse-commit-sha.outputs.sha }} - - - name: Reset Simulators - run: xcrun simctl erase all - - - name: Install Dependencies and Run Tests - run: | - brew install xcbeautify - make submodules - bundle install - make update_carthage_dependencies_tvos - bundle exec fastlane test_tvOS16_1 - - - name: Check Static Analyzer Output - id: analyzer-output - run: | - if [[ -z $(find ./derived_data -name "report-*.html") ]]; then - echo "Static Analyzer found no issues." - else - echo "Static Analyzer found some issues. HTML report will be available in Artifacts section. Failing build." - exit 1 - fi - - - name: Static Analyzer Reports Uploading - if: ${{ failure() && steps.analyzer-output.outcome == 'failure' }} - uses: actions/upload-artifact@v2 - with: - name: static-analyzer-reports-test_tvOS16_1 - path: ./derived_data/**/report-*.html - - - name: Run Examples Tests - working-directory: ./Examples/Tests - run: | - pod repo update - pod install - bundle exec fastlane scan -s Tests --output-directory "fastlane/test_output/examples/test_tvOS_16_1" - - - name: Xcodebuild Logs Artifact - if: always() - uses: actions/upload-artifact@v2 - with: - name: xcodebuild-logs - path: ~/Library/Developer/Xcode/DerivedData/*/Logs - - - name: Upload test output artifact - if: always() - uses: actions/upload-artifact@v2 - with: - name: test-output - path: fastlane/test_output - - - name: Upload test results to observability server - if: always() - env: - TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} - run: Scripts/upload_test_results.sh - - - name: Swift Package Manager - Installation Test - working-directory: ./ - run: | - echo 'Current Branch: ' $GITHUB_HEAD_REF - echo 'Current Revision (SHA):' $GITHUB_SHA - echo Current Path: $(pwd) - export PACKAGE_URL=file://$(pwd) - export PACKAGE_BRANCH_NAME=$GITHUB_HEAD_REF - export PACKAGE_REVISION=$GITHUB_SHA - swift test --package-path Examples/SPM -v diff --git a/Ably.xcodeproj/project.pbxproj b/Ably.xcodeproj/project.pbxproj index 928235f3e..e30b5bb14 100644 --- a/Ably.xcodeproj/project.pbxproj +++ b/Ably.xcodeproj/project.pbxproj @@ -268,6 +268,9 @@ 21881E7A283BD08300CFD9E2 /* GCDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A22171266F526600C87C42 /* GCDTests.swift */; }; 21881E7B283BD0DF00CFD9E2 /* StringifiableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D520C4DD2680A1E3000012B2 /* StringifiableTests.swift */; }; 21881E7C283BD0E100CFD9E2 /* StringifiableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D520C4DD2680A1E3000012B2 /* StringifiableTests.swift */; }; + 21FD9F272A015BE400216482 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FD9F262A015BE400216482 /* Test.swift */; }; + 21FD9F282A015BE400216482 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FD9F262A015BE400216482 /* Test.swift */; }; + 21FD9F292A015BE400216482 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FD9F262A015BE400216482 /* Test.swift */; }; 560579D924AF1BA900A4D03D /* ARTDefaultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */; }; 560579DA24AF1BA900A4D03D /* ARTDefaultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */; }; 560579DB24AF1BA900A4D03D /* ARTDefaultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */; }; @@ -1219,6 +1222,7 @@ 21DCDA8229F818630073A211 /* Ably-iOS.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Ably-iOS.xctestplan"; path = "Test/Ably-iOS.xctestplan"; sourceTree = SOURCE_ROOT; }; 21DCDA8329F81B350073A211 /* Ably-macOS.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Ably-macOS.xctestplan"; sourceTree = ""; }; 21DCDA8429F81B550073A211 /* Ably-tvOS.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Ably-tvOS.xctestplan"; sourceTree = ""; }; + 21FD9F262A015BE400216482 /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; 560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARTDefaultTests.swift; sourceTree = ""; }; 56190953238C3D3200A862A6 /* CryptoTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoTest.m; sourceTree = ""; }; 841134772722205400CFA837 /* ARTArchiveTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTArchiveTests.m; sourceTree = ""; }; @@ -1733,6 +1737,7 @@ 2147F03429E5872C0071CB94 /* MockInternalLogCore.swift */, D50D86E829E9444600EA72EA /* JSON.swift */, 210F67B029E9DB62007B9345 /* TestProxyTransportFactory.swift */, + 21FD9F262A015BE400216482 /* Test.swift */, ); path = "Test Utilities"; sourceTree = ""; @@ -3040,6 +3045,7 @@ 2132C21629D20F69000C4355 /* ResumeRequestResponseTests.swift in Sources */, EB7913A81C6E54C3000ABF9B /* CryptoTests.swift in Sources */, 2132C22229D233EB000C4355 /* DefaultErrorCheckerTests.swift in Sources */, + 21FD9F272A015BE400216482 /* Test.swift in Sources */, D777EEE820650ADF002EBA03 /* PushChannelTests.swift in Sources */, 217FCF3F29D626E4006E5F2D /* StaticJitterCoefficients.swift in Sources */, D746AE2D1BBB625E003ECEF8 /* RestClientChannelsTests.swift in Sources */, @@ -3229,6 +3235,7 @@ 56190955238C3D3200A862A6 /* CryptoTest.m in Sources */, D7093C1D219E466600723F17 /* AuthTests.swift in Sources */, 21276CC329F00BAA00107B5F /* ContinuousClockTests.swift in Sources */, + 21FD9F282A015BE400216482 /* Test.swift in Sources */, D7093C25219E466E00723F17 /* RealtimeClientConnectionTests.swift in Sources */, 217FCF4029D626E4006E5F2D /* StaticJitterCoefficients.swift in Sources */, ); @@ -3285,6 +3292,7 @@ 56190956238C3D3200A862A6 /* CryptoTest.m in Sources */, D7093C7A219EE26400723F17 /* RestPaginatedTests.swift in Sources */, 21276CC429F00BAA00107B5F /* ContinuousClockTests.swift in Sources */, + 21FD9F292A015BE400216482 /* Test.swift in Sources */, D7093C81219EE26400723F17 /* UtilitiesTests.swift in Sources */, 217FCF4129D626E4006E5F2D /* StaticJitterCoefficients.swift in Sources */, ); diff --git a/Scripts/continuously-run-tests-and-upload-results.sh b/Scripts/continuously-run-tests-and-upload-results.sh new file mode 100755 index 000000000..2c5002626 --- /dev/null +++ b/Scripts/continuously-run-tests-and-upload-results.sh @@ -0,0 +1,139 @@ +#!/bin/bash + +set -e + +# 1. Check dependencies. + +if ! which timeout > /dev/null +then + echo "You need to install timeout (\`brew install coreutils\` on macOS)." 2>&1 + exit 1 +fi + +# 2. Grab command-line options. + +# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash +while [[ "$#" -gt 0 ]]; do + case $1 in + -l|--lane) lane="$2"; shift ;; + -u|--upload-server-base-url) upload_server_base_url="$2"; shift ;; + *) echo "Unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +if [[ -z $lane ]] +then + echo "You need to specify the Fastlane lane to run (-l / --lane)." 2>&1 + exit 1 +fi + +# 3. Capture the time at which we started, to make sure we don’t exceed the +# maximum job running time. +started_at=`date +%s` +# https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration +let github_job_maximum_execution_seconds=6*60*60 +# We assume that the part of the job that ran before this script took at most 10 minutes, and that uploading the artifacts will take 30 minutes. +let must_end_by=$((started_at + github_job_maximum_execution_seconds - (10 + 30) * 60)) + +echo "We’ll make sure this script ends by `date -r${must_end_by}`." 2>&1 + +# 4. Run the tests in a loop and report the results. + +declare -i iteration=1 +while true +do + echo "BEGIN ITERATION ${iteration}" 2>&1 + + rm -rf fastlane/test_output + rm -rf xcodebuild_output + xcrun simctl erase all + + set +e + let allowed_execution_time=$must_end_by-`date +%s` + set -e + + if [[ $allowed_execution_time -le 0 ]]; then + echo "ITERATION ${iteration}: Allowed execution time reached. Exiting." 2>&1 + exit 0 + fi + + echo "ITERATION ${iteration}: Running fastlane with a timeout of ${allowed_execution_time} seconds." 2>&1 + + set +e + timeout --kill-after=20 ${allowed_execution_time} bundle exec fastlane --verbose $lane + tests_exit_value=$? + set -e + + if [[ tests_exit_value -eq 124 || tests_exit_value -eq 137 ]]; then + # Execution timed out. + echo "ITERATION ${iteration}: Cancelled the execution of fastlane since it exceeded timeout imposed by maximum GitHub running time. Terminating this script." + echo "There are `du -d0 -h xcresult-bundles | awk -F '\t' '{print $1}'` of xcresult bundles." + tar --create --gzip xcresult-bundles > xcresult-bundles.tar.gz + echo "The file xcresult-bundles.tar.gz that will be uploaded as an artifact is `du -d0 -h xcresult-bundles.tar.gz | awk -F '\t' '{print $1}'`." + exit 0 + fi + + if [[ tests_exit_value -eq 0 ]] + then + echo "ITERATION ${iteration}: Tests passed." + else + echo "ITERATION ${iteration}: Tests failed (exit value ${tests_exit_value})." + fi + + echo "ITERATION ${iteration}: BEGIN xcodebuild raw output." + ls xcodebuild_output + cat xcodebuild_output/** + echo "ITERATION ${iteration}: END xcodebuild raw output." + + echo "ITERATION ${iteration}: Uploading results to observability server." + + # https://unix.stackexchange.com/questions/446847/conditionally-pass-params-to-a-script + optional_params=() + + if [[ ! -z $upload_server_base_url ]] + then + optional_params+=(--upload-server-base-url "${upload_server_base_url}") + fi + + ./Scripts/upload_test_results.sh \ + --iteration $iteration \ + "${optional_params[@]}" + + # Find the .xcresult bundle and copy it to the directory that will eventually be saved as an artifact. + + result_bundles=$(find fastlane/test_output/sdk -name '*.xcresult') + if [[ -z $result_bundles ]] + then + number_of_result_bundles=0 + else + number_of_result_bundles=$(echo "${result_bundles}" | wc -l) + fi + + if [[ $number_of_result_bundles -eq 0 ]] + then + echo "ITERATION ${iteration}: No result bundles found." + exit 1 + fi + + if [[ $number_of_result_bundles -gt 1 ]] + then + echo -e "ITERATION ${iteration}: Multiple result bundles found:\n${result_bundles}" + exit 1 + fi + + echo "ITERATION ${iteration}: Report bundle found: ${result_bundles}" + + if [[ ! -d xcresult-bundles ]]; then + mkdir xcresult-bundles + fi + + mkdir "xcresult-bundles/${iteration}" + cp -r "${result_bundles}" "xcresult-bundles/${iteration}" + + echo "ITERATION ${iteration}: Copied result bundle to xcresult-bundles/${iteration}." + + echo "END ITERATION ${iteration}" 2>&1 + + iteration+=1 +done diff --git a/Scripts/fetch-test-logs.sh b/Scripts/fetch-test-logs.sh new file mode 100755 index 000000000..a2bbd1e3d --- /dev/null +++ b/Scripts/fetch-test-logs.sh @@ -0,0 +1,493 @@ +#!/bin/bash + +# Retrieves the raw xcodebuild output for one or more test observability server +# uploads. +# +# Only works for tests that were run using the +# continuously-run-tests-and-upload-results script in this directory. + +# Usage: +# ./fetch-test-logs.sh --repo ably/ably-cocoa --test-case-id --filter [filter] +# +# or +# +# ./fetch-test-logs.sh --repo ably/ably-cocoa --upload-id + +# Options: +# +# -r / --repo : The 'org/name'-formatted name of the GitHub repo, for +# example 'ably/ably-cocoa'. +# +# -t / --test-case-id : The ID of a test case saved on the test +# observability server. Will fetch all uploads that match the filter specified +# using the --filter option, and then save the results inside the directory +# specified by the --output-directory option, in the following hierarchy, where +# uploads are split into those where the test case failed and those where it +# didn’t (which doesn’t necessarily imply that the test case passed; it may not +# have run at all): +# +# +# ├── info.json (contains metadata about the results in this directory) +# ├── upload_logs +# │   ├── failed +# │ │   └── xcodebuild-logs-upload-, ... +# │   └── not_failed +# │ └── xcodebuild-logs-upload-, ... +# └── test-case-logs (unless --no-extract-test-case-logs specified) +# ├── failed +# │   └── xcodebuild-logs-upload-, ... +# └── not_failed +# └── xcodebuild-logs-upload-, ... +# +# The upload_logs directory contains the full logs for that upload, and the +# test_case_logs directory contains just the segments of the logs that +# correspond to the specific test case. +# +# -d / --output-directory : Where to output the logs generated by the +# --test-case-id option to. Defaults to ./xcodebuild-logs-test-case--. +# +# -f / --filter : A URL query string describing a filter to be applied +# to the uploads fetched when using the --test-case-id option. For example, +# "branches[]=main&createdBefore=2022-02-20". +# +# -n / --no-extract-test-case-logs: Will cause the --test-case-id option to not +# attempt to extract the segment of the upload log that corresponds to the test +# case. +# +# -i / --upload-id : The ID of a upload saved on the test observability +# server. +# +# -u / --upload-server-base-url : Allows you to specify a URL to use as +# the upload server base URL. Defaults to https://test-observability.herokuapp.com. +# +# -o / --output-file : Where to output the logs generated by the +# --upload-id option to. Defaults to ./xcodebuild-logs-upload-. +# +# -c / --cache-directory : Where to cache the GitHub logs. Defaults to +# ~/Library/Caches/com.ably.testObservabilityLogs. Will be created if doesn’t +# exist. +# +# -a / --no-use-github-auth: Will not prompt the user for an access token to be +# used for making requests to the GitHub API. Useful if all the required GitHub +# job logs are already cached locally. + +set -e + +check_dependencies() { + if ! which jq >/dev/null; then + echo "You need to install jq." 2>&1 + exit 1 + fi +} + +get_github_access_token() { + # https://stackoverflow.com/questions/3980668/how-to-get-a-password-from-a-shell-script-without-echoing#comment4260181_3980904 + read -s -p "Enter your GitHub access token (this will be used to fetch logs from the GitHub API): " github_access_token + + echo + + if [[ -z $github_access_token ]]; then + echo "You need to specify a GitHub access token." 2>&1 + exit 1 + fi + + echo +} + +# Args: +# $1: JSON representation of the test observability server upload +# $2: Path to write the logs to +fetch_and_write_logs_for_upload() { + upload_json=$1 + output_file=$2 + + # (TIL I learned that `echo` will interpret backslash sequences, which we + # don’t want. Appparently in general printf is recommended over echo.) + # https://stackoverflow.com/questions/43528202/prevent-echo-from-interpreting-backslash-escapes + github_repository=$(printf '%s' $upload_json | jq --raw-output '.githubRepository') + github_run_id=$(printf '%s' $upload_json | jq --raw-output '.githubRunId') + github_run_attempt=$(printf '%s' $upload_json | jq --raw-output '.githubRunAttempt') + github_job=$(printf '%s' $upload_json | jq --raw-output '.githubJob') + iteration=$(printf '%s' $upload_json | jq --raw-output '.iteration') + + echo "Upload comes from GitHub repository ${github_repository}. It has GitHub run ID ${github_run_id}, run attempt number ${github_run_attempt}, and job name ${github_job}. It corresponds to loop iteration ${iteration}." + + # Check whether we have a cached log for this job. + # (We cache the job logs because when running the tests continuously, with + # verbose logging enabled, a job log can be ~1.5GB.) + + log_file_name="github-log-${github_repository//\//-}-run-${github_run_id}-attempt-${github_run_attempt}-job-${github_job}" + log_file_path="${cache_directory}/${log_file_name}" + + if [[ -f "${log_file_path}" ]]; then + echo "GitHub job log file already exists at ${log_file_path}. Skipping download." 2>&1 + else + echo "GitHub job log file not yet downloaded." 2>&1 + + # (I wonder if this information that I’m fetching from GitHub is stuff that + # I should have just had in the upload in the first place? Not that + # important right now.) + + github_api_base_url="https://api.github.com" + + # From the GitHub API, fetch the jobs for this workflow run attempt. + # https://docs.github.com/en/rest/reference/actions#list-jobs-for-a-workflow-run-attempt + github_jobs_json=$(curl \ + --fail \ + -H "Accept: application/vnd.github.v3+json" \ + "${github_auth_curl_args[@]}" \ + "${github_api_base_url}/repos/${github_repository}/actions/runs/${github_run_id}/attempts/${github_run_attempt}/jobs") + + # From this list of jobs, find the one that corresponds to our upload. + github_job_id=$(printf "%s" $github_jobs_json | jq \ + --arg jobName "${github_job}" \ + '.jobs[] | select(.name == $jobName) | .id') + + if [[ -z $github_job_id ]]; then + echo "Could not find job with name ${github_job} in attempt ${github_run_attempt} of run ${github_run_id} in GitHub repository ${github_repository}." 2>&1 + exit 1 + fi + + echo "Upload corresponds to GitHub job ID ${github_job_id}. Downloading logs. This may take a while." + + # From the GitHub API, fetch the logs for this job and cache them. + # https://docs.github.com/en/rest/reference/actions#download-job-logs-for-a-workflow-run + + if [[ ! -d "${cache_directory}" ]]; then + mkdir -p "${cache_directory}" + fi + + curl \ + --fail \ + --location \ + -H "Accept: application/vnd.github.v3+json" \ + "${github_auth_curl_args[@]}" \ + "${github_api_base_url}/repos/${github_repository}/actions/jobs/${github_job_id}/logs" >"${log_file_path}.partial" + + mv "${log_file_path}.partial" "${log_file_path}" + + echo "Saved GitHub job logs to ${log_file_path}." + fi + + # Extract the part of the logs that corresponds to the raw xcodebuild output for this iteration. + # https://stackoverflow.com/a/18870500 + + echo "Finding xcodebuild output for iteration ${iteration}." + + xcodebuild_output_start_marker="ITERATION ${iteration}: BEGIN xcodebuild raw output" + xcodebuild_output_start_line_number=$(sed -n "/${xcodebuild_output_start_marker}/=" "${log_file_path}") + + if [[ -z "${xcodebuild_output_start_line_number}" ]]; then + echo "Couldn’t find start of xcodebuild raw output (couldn’t find marker \"${xcodebuild_output_start_marker}\")." 2>&1 + echo "This may be because the GitHub job hasn’t finished yet, or because the tests are not being run in a loop, or it may be an upload created before this functionality was implemented." 2>&1 + echo "You may need to delete the cached log file ${log_file_path}." 2>&1 + exit 1 + fi + + xcodebuild_output_end_marker="ITERATION ${iteration}: END xcodebuild raw output" + xcodebuild_output_end_line_number=$(sed -n "/${xcodebuild_output_end_marker}/=" "${log_file_path}") + + if [[ -z "${xcodebuild_output_end_line_number}" ]]; then + echo "Couldn’t find end of xcodebuild raw output (couldn’t find marker \"${xcodebuild_output_end_marker}\")." 2>&1 + exit 1 + fi + + # Strip the GitHub-added timestamps (which just correspond to the time that `cat` was executed on the log file, and hence aren’t of any use) from the start of each line. + + echo "Stripping GitHub timestamps." + + # https://arkit.co.in/print-given-range-of-lines-using-awk-perl-head-tail-and-python/ + sed -n "${xcodebuild_output_start_line_number},${xcodebuild_output_end_line_number} p" "${log_file_path}" | sed -e 's/^[^ ]* //' >"${output_file}" + + echo "Wrote xcodebuild output to ${output_file}." 2>&1 +} + +default_output_file_for_upload_id() { + echo "xcodebuild-logs-upload-$1" +} + +run_for_test_case() { + # From the test observability server API, fetch the test case and extract its + # properties. + + echo "Fetching test case ${test_case_id} from ${upload_server_base_url}." 2>&1 + + test_case_json=$(curl --fail --header "Accept: application/json" "${upload_server_base_url}/repos/${repo}/test_cases/${test_case_id}") + + test_class_name=$(printf '%s' $test_case_json | jq --raw-output '.testClassName') + test_case_name=$(printf '%s' $test_case_json | jq --raw-output '.testCaseName') + + printf "Test case ${test_case_id} has test class name ${test_class_name} and test case name ${test_case_name}.\n\n" + + # From the test observability server API, fetch the filtered uploads. + + if [[ -z $filter ]]; then + filter_description="no filter" + filter_query="" + else + filter_description="filter ${filter}" + filter_query="?${filter}" + fi + + echo "Fetching uploads for test case ${test_case_id}, with ${filter_description}, from ${upload_server_base_url}." 2>&1 + + uploads_json=$(curl --fail --header "Accept: application/json" "${upload_server_base_url}/repos/${repo}/test_cases/${test_case_id}/uploads${filter_query}") + + number_of_uploads=$(printf '%s' $uploads_json | jq '. | length') + + if [[ ${number_of_uploads} -eq 1 ]]; then + echo "There is 1 upload". 2>&1 + else + echo "There are ${number_of_uploads} uploads". 2>&1 + fi + + echo + + mkdir "${output_directory}" + mkdir "${output_directory}/upload_logs" + mkdir "${output_directory}/test_case_logs" + + failed_upload_logs_output_directory="${output_directory}/upload_logs/failed" + mkdir "${failed_upload_logs_output_directory}" + not_failed_upload_logs_output_directory="${output_directory}/upload_logs/not_failed" + mkdir "${not_failed_upload_logs_output_directory}" + + failed_test_case_logs_output_directory="${output_directory}/test_case_logs/failed" + mkdir "${failed_test_case_logs_output_directory}" + not_failed_test_case_logs_output_directory="${output_directory}/test_case_logs/not_failed" + mkdir "${not_failed_test_case_logs_output_directory}" + + jq -n \ + --arg testCaseId "${test_case_id}" \ + --arg filter "${filter}" \ + --arg uploadServerBaseUrl "${upload_server_base_url}" \ + '{ fetchedAt: (now | todateiso8601), testCaseId: $testCaseId, filter: $filter, uploadServerBaseUrl: $uploadServerBaseUrl }' \ + >"${output_directory}/info.json" + + for ((i = 0; i < number_of_uploads; i += 1)); do + failed=$(printf '%s' $uploads_json | jq ".[${i}].failed") + upload_json=$(printf '%s' $uploads_json | jq ".[${i}].upload") + + upload_id=$(printf '%s' $upload_json | jq --raw-output '.id') + + echo "[$((i + 1)) of ${number_of_uploads}] Processing upload ${upload_id}." 2>&1 + + output_file_without_directory=$(default_output_file_for_upload_id "${upload_id}") + + if [[ $failed == "true" ]]; then + upload_log_output_file="${failed_upload_logs_output_directory}/${output_file_without_directory}" + test_case_log_output_file="${failed_test_case_logs_output_directory}/${output_file_without_directory}" + else + upload_log_output_file="${not_failed_upload_logs_output_directory}/${output_file_without_directory}" + test_case_log_output_file="${not_failed_test_case_logs_output_directory}/${output_file_without_directory}" + fi + + fetch_and_write_logs_for_upload "${upload_json}" "${upload_log_output_file}" + + if [[ -z "${no_extract_test_case_logs}" ]]; then + extract_logs_for_test_case "${test_class_name}" "${test_case_name}" "${upload_log_output_file}" "${test_case_log_output_file}" + fi + + echo + done +} + +# Args: +# $1: Test class name e.g. RealtimeClientPresenceTests +# $2: Test case name e.g. test__037__Presence__update__should_update_the_data_for_the_present_member_with_a_value() +# $3: Path of the xcodebuild logs for the entire test suite run +# $4: Path of where to write the test case logs to. +extract_logs_for_test_case() { + # Extract the part of the logs that corresponds to the raw xcodebuild output for this iteration. (We have similar code in fetch_and_write_logs_for_upload.) + + test_class_name=$1 + test_case_name=$2 + upload_log_file=$3 + output_file=$4 + + # (For some reason, the test case name in the observability server has + # trailing (), but in the xcodebuild logs it doesn’t. So strip them.) + sanitised_test_case_name="${test_case_name//[()]/}" + + echo "Finding logs for test class ${test_class_name}, test case ${test_case_name} in ${upload_log_file}." 2>&1 + + test_case_log_start_marker="Test Case.*${test_class_name} ${sanitised_test_case_name}.*started" + test_case_log_start_line_number=$(sed -n "/${test_case_log_start_marker}/=" "${upload_log_file}") + + if [[ -z "${test_case_log_start_line_number}" ]]; then + echo "Couldn’t find start of test case output (couldn’t find marker \"${test_case_log_start_marker}\")." 2>&1 + exit 1 + fi + + test_case_log_end_marker="Test Case.*${test_class_name} ${sanitised_test_case_name}.*(passed|failed)|Restarting after unexpected exit, crash, or test timeout in ${test_class_name}\/${sanitised_test_case_name}\(\)" + test_case_log_end_line_number=$(sed -En "/${test_case_log_end_marker}/=" "${upload_log_file}") + + if [[ -z "${test_case_log_end_line_number}" ]]; then + echo "Couldn’t find end of test case output (couldn’t find marker \"${test_case_log_end_marker}\")." 2>&1 + exit 1 + fi + + sed -n "${test_case_log_start_line_number},${test_case_log_end_line_number} p" "${upload_log_file}" >"${output_file}" + + echo "Wrote test case log to ${output_file}." 2>&1 +} + +run_for_upload() { + # From the test observability server API, fetch the upload, to find the + # GitHub run ID, attempt number, job name, and iteration. + + echo "Fetching upload ${upload_id} from ${upload_server_base_url}." 2>&1 + + upload_json=$(curl --fail --header "Accept: application/json" "${upload_server_base_url}/repos/${repo}/uploads/${upload_id}") + + fetch_and_write_logs_for_upload "${upload_json}" "${output_file}" +} + +check_dependencies + +# Grab and validate command-line options, and apply defaults. + +# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash +while [[ "$#" -gt 0 ]]; do + case $1 in + -r | --repo) + repo="$2" + shift + ;; + -t | --test-case-id) + if [[ -z "$2" ]]; then + echo "You must specify a test case ID when using the --test-case-id option." 2>&1 + exit 1 + fi + test_case_id="$2" + shift + ;; + -d | --output-directory) + if [[ -z "$2" ]]; then + echo "You must specify an output directory when using the --output-directory option." 2>&1 + exit 1 + fi + output_directory="$2" + shift + ;; + -f | --filter) + if [[ -z "$2" ]]; then + echo "You must specify a filter when using the --filter option." 2>&1 + exit 1 + fi + filter="$2" + shift + ;; + -n | --no-extract-test-case-logs) no_extract_test_case_logs="1" ;; + -i | --upload-id) + if [[ -z "$2" ]]; then + echo "You must specify an upload ID when using the --upload-id option." 2>&1 + exit 1 + fi + upload_id="$2" + shift + ;; + -u | --upload-server-base-url) + if [[ -z "$2" ]]; then + echo "You must specify a base URL when using the --upload-server-base-url option." 2>&1 + exit 1 + fi + upload_server_base_url="$2" + shift + ;; + -o | --output-file) + if [[ -z "$2" ]]; then + echo "You must specify an output file when using the --output-file option." 2>&1 + exit 1 + fi + output_file="$2" + shift + ;; + -c | --cache-directory) + if [[ -z "$2" ]]; then + echo "You must specify a cache directory when using the --cache-directory option." 2>&1 + exit 1 + fi + cache_directory="$2" + shift + ;; + -a | --no-use-github-auth) no_use_github_auth="1" ;; + *) + echo "Unknown parameter passed: $1" 2>&1 + exit 1 + ;; + esac + shift +done + +if [[ -z $repo ]]; then + echo "You need to specify a repo (-r / --repo)." 2>&1 + exit 1 +fi + +if [[ -z $test_case_id && -z $upload_id ]]; then + echo "You need to specify the test case ID (-t / --test-case-id) or upload ID (-i / --upload-id)." 2>&1 + exit 1 +fi + +if [[ -n $test_case_id && -n $upload_id ]]; then + echo "You cannot specify both a test case ID and an upload ID." 2>&1 + exit 1 +fi + +if [[ -n $test_case_id && -n $upload_id ]]; then + echo "You cannot specify both a test case ID and an upload ID." 2>&1 + exit 1 +fi + +if [[ -z $test_case_id && -n $output_directory ]]; then + echo "You can only specify an output directory with a test case ID (-t / --test-case-id)." 2>&1 + exit 1 +fi + +if [[ -z $output_directory ]]; then + output_directory="xcodebuild-logs-test-case-${test_case_id}-$(date -Iseconds)" +fi + +if [[ -z $test_case_id && -n $filter ]]; then + echo "You can only specify a filter with a test case ID (-t / --test-case-id)." 2>&1 + exit 1 +fi + +if [[ -z $test_case_id && -n $no_extract_test_case_logs ]]; then + echo "You can only specify the --no-extract-test-case-logs option with a test case ID (-t / --test-case-id)." 2>&1 + exit 1 +fi + +if [[ -z $upload_server_base_url ]]; then + upload_server_base_url="https://test-observability.herokuapp.com" +fi + +if [[ -z $upload_id && -n $output_file ]]; then + echo "You can only specify an output file with an upload ID (-i / --upload-id)." 2>&1 + exit 1 +fi + +if [[ -z $output_file ]]; then + output_file=$(default_output_file_for_upload_id "${upload_id}") +fi + +if [[ -z $cache_directory ]]; then + cache_directory="${HOME}/Library/Caches/com.ably.testObservabilityLogs" +fi + +github_auth_curl_args=() +if [[ -z $no_use_github_auth ]]; then + # Get the GitHub access token from the user. We don’t allow them to specify it on the command line. + github_access_token="" + get_github_access_token + github_auth_curl_args+=(-H "Authorization: token ${github_access_token}") +fi + +# Run the appropriate function based on arguments. + +if [[ -n $test_case_id ]]; then + run_for_test_case +elif [[ -n $upload_id ]]; then + run_for_upload +fi diff --git a/Scripts/set-ci-length-and-parallelism.sh b/Scripts/set-ci-length-and-parallelism.sh new file mode 100755 index 000000000..efd705441 --- /dev/null +++ b/Scripts/set-ci-length-and-parallelism.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +set -e + +# Usage: +# ./set-ci-length-and-parallelism.sh --workflows --jobs-per-workflow + +# Check dependencies. +if ! which yq > /dev/null; then + echo "You need to install yq." 2>&1 + exit 1 +fi + +# Grab and validate command-line options. + +# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash +while [[ "$#" -gt 0 ]]; do + case $1 in + --workflows) + if [[ -z "$2" ]]; then + echo "You must specify the number of workflows." 2>&1 + exit 1 + fi + num_workflows="$2" + shift + ;; + --jobs-per-workflow) + if [[ -z "$2" ]]; then + echo "You must specify the number of jobs per workflow." 2>&1 + exit 1 + fi + jobs_per_workflow="$2" + shift + ;; + *) + echo "Unknown parameter passed: $1" 2>&1 + exit 1 + ;; + esac + shift +done + +if [[ -z $num_workflows ]]; then + echo "You need to specify the number of workflows (--workflows)." 2>&1 + exit 1 +fi + +if [[ ! $num_workflows =~ ^-?[0-9]+$ ]]; then + echo "The number of workflows must be a number." 2>&1 + exit 1 +fi + +if [[ $num_workflows -lt 1 ]]; then + echo "The number of workflows must be 1 or more." 2>&1 + exit 1 +fi + +if [[ -z $jobs_per_workflow ]]; then + echo "You need to specify the number of jobs per workflow (--jobs-per-workflow)." 2>&1 + exit 1 +fi + +if [[ ! $jobs_per_workflow =~ ^-?[0-9]+$ ]]; then + echo "The number of jobs per workflow must be a number." 2>&1 + exit 1 +fi + +if [[ $jobs_per_workflow -lt 1 ]]; then + echo "The number of jobs per workflow must be 1 or more." 2>&1 + exit 1 +fi + +workflow_file_without_extension=".github/workflows/integration-test-iOS16_2" +workflow_file_extension=".yaml" + +workflow_file="${workflow_file_without_extension}${workflow_file_extension}" +workflow_name=$(yq .name $workflow_file) + +# First, we apply the number of jobs per workflow. + +yq -i '(.jobs.check | key) = "check-1"' $workflow_file +yq -i "(.jobs.check-1.steps[] | select(.with.path == \"xcresult-bundles.tar.gz\")).with.name = \"xcresult-bundles-1.tar.gz\"" $workflow_file + +for ((i=2; i <= $jobs_per_workflow; i += 1)) +do + yq -i ".jobs.check-${i} = .jobs.check-$(($i-1))" $workflow_file + yq -i ".jobs.check-${i}.needs = [\"check-$(($i-1))\"]" $workflow_file + yq -i "(.jobs.check-${i}.steps[] | select(.with.path == \"xcresult-bundles.tar.gz\")).with.name = \"xcresult-bundles-${i}.tar.gz\"" $workflow_file +done + +# Now, we duplicate the workflow file the requested number of times. + +mv $workflow_file "${workflow_file_without_extension}-1${workflow_file_extension}" + +for ((i=1; i <= $num_workflows; i += 1)) +do + new_workflow_file="${workflow_file_without_extension}-${i}${workflow_file_extension}" + + if [[ $i -gt 1 ]]; then + cp "${workflow_file_without_extension}-$((i-1))${workflow_file_extension}" $new_workflow_file + fi + + yq -i ".name = \"${workflow_name} (workflow ${i})\"" $new_workflow_file +done diff --git a/Test/Test Utilities/Test.swift b/Test/Test Utilities/Test.swift new file mode 100644 index 000000000..42a3cbd7e --- /dev/null +++ b/Test/Test Utilities/Test.swift @@ -0,0 +1,12 @@ +/** + Represents an execution of a test case method. + */ +struct Test { + var id = UUID() + private var function: StaticString + + init(function: StaticString = #function) { + self.function = function + NSLog("Created test \(id) for function \(function)") + } +} diff --git a/Test/Test Utilities/TestProxyTransportFactory.swift b/Test/Test Utilities/TestProxyTransportFactory.swift index c382483e0..97db213c6 100644 --- a/Test/Test Utilities/TestProxyTransportFactory.swift +++ b/Test/Test Utilities/TestProxyTransportFactory.swift @@ -1,6 +1,12 @@ import Ably.Private class TestProxyTransportFactory: RealtimeTransportFactory { + let internalQueue: DispatchQueue + + init(internalQueue: DispatchQueue) { + self.internalQueue = internalQueue + } + // This value will be used by all TestProxyTransportFactory instances created by this factory (including those created before this property is updated). var fakeNetworkResponse: FakeNetworkResponse? @@ -14,7 +20,8 @@ class TestProxyTransportFactory: RealtimeTransportFactory { options: options, resumeKey: resumeKey, connectionSerial: connectionSerial, - logger: logger + logger: logger, + internalQueue: internalQueue ) } } diff --git a/Test/Test Utilities/TestUtilities.swift b/Test/Test Utilities/TestUtilities.swift index afa7eeb37..e0523441d 100644 --- a/Test/Test Utilities/TestUtilities.swift +++ b/Test/Test Utilities/TestUtilities.swift @@ -50,8 +50,8 @@ let testTimeout = DispatchTimeInterval.seconds(20) let testResourcesPath = "ably-common/test-resources/" let echoServerAddress = "https://echo.ably.io/createJWT" -func uniqueChannelName(prefix: String = "", - testIdentifier: String = #function, +func uniqueChannelName(for test: Test, + prefix: String = "", timestamp: TimeInterval = Date.timeIntervalSinceReferenceDate) -> String { let platform: String #if targetEnvironment(macCatalyst) @@ -67,7 +67,7 @@ func uniqueChannelName(prefix: String = "", #else platform = "Unknown" #endif - return "\(prefix)-\(platform)-\(testIdentifier.replacingOccurrences(of: "()", with: ""))-\(timestamp)-\(NSUUID().uuidString)" + return "\(prefix)-\(platform)-\(test.id)-\(timestamp)-\(NSUUID().uuidString)" } /// Common test utilities. @@ -102,20 +102,29 @@ class AblyTests { static var testApplication: [String: Any]? - struct QueueIdentity { + class QueueIdentity { let label: String + + init(label: String) { + self.label = label + NSLog("Created QueueIdentity \(label)") + } + + deinit { + NSLog("deinit QueueIdentity \(label)") + } } static let queueIdentityKey = DispatchSpecificKey() - static var queue: DispatchQueue = { - let queue = DispatchQueue(label: "io.ably.tests", qos: .userInitiated) + static func createInternalQueue(for test: Test) -> DispatchQueue { + let queue = DispatchQueue(label: "io.ably.tests.\(test.id).\(UUID().uuidString)", qos: .userInitiated) queue.setSpecific(key: queueIdentityKey, value: QueueIdentity(label: queue.label)) return queue - }() + } - static func createUserQueue() -> DispatchQueue { - let queue = DispatchQueue(label: "io.ably.tests.callbacks.\(UUID().uuidString)", qos: .userInitiated) + static func createUserQueue(for test: Test) -> DispatchQueue { + let queue = DispatchQueue(label: "io.ably.tests.callbacks.\(test.id).\(UUID().uuidString)", qos: .userInitiated) queue.setSpecific(key: queueIdentityKey, value: QueueIdentity(label: queue.label)) return queue } @@ -124,9 +133,9 @@ class AblyTests { return DispatchQueue.getSpecific(key: queueIdentityKey)?.label } - class func commonAppSetup(debug: Bool = false, forceNewApp: Bool = false) throws -> ARTClientOptions { - let options = try AblyTests.clientOptions(debug: debug) - options.testOptions.channelNamePrefix = "test-\(UUID().uuidString)" + class func commonAppSetup(for test: Test, debug: Bool = false, forceNewApp: Bool = false) throws -> ARTClientOptions { + let options = try AblyTests.clientOptions(for: test, debug: debug) + options.testOptions.channelNamePrefix = "test-\(test.id)-\(UUID().uuidString)" if forceNewApp { testApplication = nil @@ -161,7 +170,7 @@ class AblyTests { return options } - class func clientOptions(debug: Bool = false, key: String? = nil, requestToken: Bool = false) throws -> ARTClientOptions { + class func clientOptions(for test: Test, debug: Bool = false, key: String? = nil, requestToken: Bool = false) throws -> ARTClientOptions { let options = ARTClientOptions() options.environment = getEnvironment() if debug { @@ -171,10 +180,10 @@ class AblyTests { options.key = key } if requestToken { - options.token = try getTestToken() + options.token = try getTestToken(for: test) } options.dispatchQueue = DispatchQueue.main - options.internalDispatchQueue = queue + options.internalDispatchQueue = createInternalQueue(for: test) return options } @@ -208,7 +217,7 @@ class AblyTests { let autoConnect = modifiedOptions.autoConnect modifiedOptions.autoConnect = false - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: modifiedOptions.internalDispatchQueue) modifiedOptions.testOptions.transportFactory = transportFactory let realtime = ARTRealtime(options: modifiedOptions) realtime.internal.setReachabilityClass(TestReachability.self) @@ -518,22 +527,22 @@ class PublishTestMessage { } /// Access Token -func getTestToken(key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, file: FileString = #file, line: UInt = #line) throws -> String { - return try getTestTokenDetails(key: key, clientId: clientId, capability: capability, ttl: ttl, file: file, line: line).token +func getTestToken(for test: Test, key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, file: FileString = #file, line: UInt = #line) throws -> String { + return try getTestTokenDetails(for: test, key: key, clientId: clientId, capability: capability, ttl: ttl, file: file, line: line).token } -func getTestToken(key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, file: FileString = #file, line: UInt = #line, completion: @escaping (Swift.Result) -> Void) { - getTestTokenDetails(key: key, clientId: clientId, capability: capability, ttl: ttl) { result in +func getTestToken(for test: Test, key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, file: FileString = #file, line: UInt = #line, completion: @escaping (Swift.Result) -> Void) { + getTestTokenDetails(for: test, key: key, clientId: clientId, capability: capability, ttl: ttl) { result in completion(result.map(\.token)) } } /// Access TokenDetails -func getTestTokenDetails(key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, queryTime: Bool? = nil, completion: @escaping (Swift.Result) -> Void) { +func getTestTokenDetails(for test: Test, key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, queryTime: Bool? = nil, completion: @escaping (Swift.Result) -> Void) { let options: ARTClientOptions if let key = key { do { - options = try AblyTests.clientOptions() + options = try AblyTests.clientOptions(for: test) } catch { completion(.failure(error)) return @@ -542,7 +551,7 @@ func getTestTokenDetails(key: String? = nil, clientId: String? = nil, capability } else { do { - options = try AblyTests.commonAppSetup() + options = try AblyTests.commonAppSetup(for: test) } catch { completion(.failure(error)) return @@ -580,8 +589,8 @@ func getTestTokenDetails(key: String? = nil, clientId: String? = nil, capability } } -func getTestTokenDetails(key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, queryTime: Bool? = nil, completion: @escaping (ARTTokenDetails?, Error?) -> Void) { - getTestTokenDetails(key: key, clientId: clientId, capability: capability, ttl: ttl, queryTime: queryTime) { result in +func getTestTokenDetails(for test: Test, key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, queryTime: Bool? = nil, completion: @escaping (ARTTokenDetails?, Error?) -> Void) { + getTestTokenDetails(for: test, key: key, clientId: clientId, capability: capability, ttl: ttl, queryTime: queryTime) { result in switch result { case .success(let tokenDetails): completion(tokenDetails, nil) @@ -591,9 +600,9 @@ func getTestTokenDetails(key: String? = nil, clientId: String? = nil, capability } } -func getTestTokenDetails(key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, queryTime: Bool? = nil, file: FileString = #file, line: UInt = #line) throws -> ARTTokenDetails { +func getTestTokenDetails(for test: Test, key: String? = nil, clientId: String? = nil, capability: String? = nil, ttl: TimeInterval? = nil, queryTime: Bool? = nil, file: FileString = #file, line: UInt = #line) throws -> ARTTokenDetails { let result = try AblyTests.waitFor(timeout: testTimeout, file: file, line: line) { value in - getTestTokenDetails(key: key, clientId: clientId, capability: capability, ttl: ttl, queryTime: queryTime) { result in + getTestTokenDetails(for: test, key: key, clientId: clientId, capability: capability, ttl: ttl, queryTime: queryTime) { result in value(result) } } @@ -601,8 +610,8 @@ func getTestTokenDetails(key: String? = nil, clientId: String? = nil, capability return try result.get() } -func getJWTToken(invalid: Bool = false, expiresIn: Int = 3600, clientId: String = "testClientIDiOS", capability: String = "{\"*\":[\"*\"]}", jwtType: String = "", encrypted: Int = 0) throws -> String? { - let options = try AblyTests.commonAppSetup() +func getJWTToken(for test: Test, invalid: Bool = false, expiresIn: Int = 3600, clientId: String = "testClientIDiOS", capability: String = "{\"*\":[\"*\"]}", jwtType: String = "", encrypted: Int = 0) throws -> String? { + let options = try AblyTests.commonAppSetup(for: test) guard let components = options.key?.components(separatedBy: ":"), let keyName = components.first, var keySecret = components.last else { fail("Invalid API key: \(options.key ?? "nil")") return nil @@ -628,8 +637,8 @@ func getJWTToken(invalid: Bool = false, expiresIn: Int = 3600, clientId: String return String(data: responseData, encoding: String.Encoding.utf8) } -func getKeys() throws -> Dictionary { - let options = try AblyTests.commonAppSetup() +func getKeys(for test: Test) throws -> Dictionary { + let options = try AblyTests.commonAppSetup(for: test) guard let components = options.key?.components(separatedBy: ":"), let keyName = components.first, let keySecret = components.last else { fatalError("Invalid API key)") } @@ -804,10 +813,6 @@ class MockHTTP: ARTHttp { private var rule: Rule? private var count: Int = 0 - init(logger: InternalLog) { - super.init(queue: AblyTests.queue, logger: logger) - } - func setNetworkState(network: FakeNetworkResponse, resetAfter numberOfRequests: Int) { queue.async { self.networkState = network @@ -994,9 +999,9 @@ class TestProxyHTTPExecutor: NSObject, ARTHTTPExecutor { private var callbackAfterRequest: ((URLRequest) -> Void)? private var callbackProcessingDataResponse: ((Data?) -> Data)? - init(logger: InternalLog) { + init(queue: DispatchQueue, logger: InternalLog) { self.logger = logger - self.http = ARTHttp(queue: AblyTests.queue, logger: logger) + self.http = ARTHttp(queue: queue, logger: logger) } init(http: ARTHttp, logger: InternalLog) { @@ -1111,8 +1116,11 @@ class TestProxyTransport: ARTWebSocketTransport { return _factory } - init(factory: TestProxyTransportFactory, rest: ARTRestInternal, options: ARTClientOptions, resumeKey: String?, connectionSerial: NSNumber?, logger: InternalLog) { + private var internalQueue: DispatchQueue + + init(factory: TestProxyTransportFactory, rest: ARTRestInternal, options: ARTClientOptions, resumeKey: String?, connectionSerial: NSNumber?, logger: InternalLog, internalQueue: DispatchQueue) { self._factory = factory + self.internalQueue = internalQueue super.init(rest: rest, options: options, resumeKey: resumeKey, connectionSerial: connectionSerial, logger: logger) } @@ -1155,7 +1163,7 @@ class TestProxyTransport: ARTWebSocketTransport { var actionsIgnored = [ARTProtocolMessageAction]() var queue: DispatchQueue { - return websocket?.delegateDispatchQueue ?? AblyTests.queue + return websocket?.delegateDispatchQueue ?? internalQueue } private var callbackBeforeProcessingIncomingMessage: ((ARTProtocolMessage) -> Void)? @@ -1563,23 +1571,23 @@ extension ARTRealtime { } } - func simulateNoInternetConnection(transportFactory: TestProxyTransportFactory) { + func simulateNoInternetConnection(transportFactory: TestProxyTransportFactory, internalQueue: DispatchQueue) { guard let reachability = self.internal.reachability as? TestReachability else { fatalError("Expected test reachability") } - AblyTests.queue.async { + internalQueue.async { transportFactory.fakeNetworkResponse = .noInternet reachability.simulate(false) } } - func simulateRestoreInternetConnection(after seconds: TimeInterval? = nil, transportFactory: TestProxyTransportFactory) { + func simulateRestoreInternetConnection(after seconds: TimeInterval? = nil, transportFactory: TestProxyTransportFactory, internalQueue: DispatchQueue) { guard let reachability = self.internal.reachability as? TestReachability else { fatalError("Expected test reachability") } - AblyTests.queue.asyncAfter(deadline: .now() + (seconds ?? 0)) { + internalQueue.asyncAfter(deadline: .now() + (seconds ?? 0)) { transportFactory.fakeNetworkResponse = nil reachability.simulate(true) } diff --git a/Test/Tests/AuthTests.swift b/Test/Tests/AuthTests.swift index a7f6bc08d..6f152a73e 100644 --- a/Test/Tests/AuthTests.swift +++ b/Test/Tests/AuthTests.swift @@ -42,8 +42,8 @@ private func check(_ details: ARTTokenDetails) { private let channelName = "test_JWT" private let messageName = "message_JWT" -private func createAuthUrlTestsOptions() throws -> ARTClientOptions { - let options = try AblyTests.clientOptions() +private func createAuthUrlTestsOptions(for test: Test) throws -> ARTClientOptions { + let options = try AblyTests.clientOptions(for: test) options.authUrl = URL(string: echoServerAddress)! return options } @@ -54,9 +54,9 @@ private func createJsonEncoder() -> ARTJsonLikeEncoder { return encoder } -private func jwtContentTypeTestsSetupDependencies() throws -> ARTRest { - let options = try AblyTests.clientOptions() - let keys = try getKeys() +private func jwtContentTypeTestsSetupDependencies(for test: Test) throws -> ARTRest { + let options = try AblyTests.clientOptions(for: test) + let keys = try getKeys(for: test) options.authUrl = URL(string: echoServerAddress)! options.authParams = [URLQueryItem]() options.authParams?.append(URLQueryItem(name: "keyName", value: keys["keyName"])) @@ -74,7 +74,8 @@ class AuthTests: XCTestCase { // RSA1 func test__003__Basic__should_work_over_HTTPS_only() throws { - let clientOptions = try AblyTests.commonAppSetup() + let test = Test() + let clientOptions = try AblyTests.commonAppSetup(for: test) clientOptions.tls = false expect { ARTRest(options: clientOptions) }.to(raiseException()) @@ -82,13 +83,14 @@ class AuthTests: XCTestCase { // RSA11 func test__004__Basic__should_send_the_API_key_in_the_Authorization_header() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - client.channels.get(uniqueChannelName()).publish(nil, data: "message") { _ in + client.channels.get(uniqueChannelName(for: test)).publish(nil, data: "message") { _ in done() } } @@ -117,14 +119,15 @@ class AuthTests: XCTestCase { // RSA3a func test__010__Token__token_auth__should_work_over_HTTP() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) options.tls = false let clientHTTP = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) clientHTTP.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - clientHTTP.channels.get(uniqueChannelName()).publish(nil, data: "message") { _ in + clientHTTP.channels.get(uniqueChannelName(for: test)).publish(nil, data: "message") { _ in done() } } @@ -135,14 +138,15 @@ class AuthTests: XCTestCase { } func test__011__Token__token_auth__should_work_over_HTTPS() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) options.tls = true let clientHTTPS = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) clientHTTPS.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - clientHTTPS.channels.get(uniqueChannelName()).publish(nil, data: "message") { _ in + clientHTTPS.channels.get(uniqueChannelName(for: test)).publish(nil, data: "message") { _ in done() } } @@ -155,15 +159,16 @@ class AuthTests: XCTestCase { // RSA3b func test__012__Token__token_auth__for_REST_requests__should_send_the_token_in_the_Authorization_header() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken() + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test) let client = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - client.channels.get(uniqueChannelName()).publish(nil, data: "message") { _ in + client.channels.get(uniqueChannelName(for: test)).publish(nil, data: "message") { _ in done() } } @@ -182,10 +187,11 @@ class AuthTests: XCTestCase { // RSA3c func test__013__Token__token_auth__for_Realtime_connections__should_send_the_token_in_the_querystring_as_a_param_named_accessToken() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken() + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -226,18 +232,19 @@ class AuthTests: XCTestCase { // RSA4a func test__020__Token__authentication_method__should_indicate_an_error_and_not_retry_the_request_when_the_server_responds_with_a_token_error_and_there_is_no_way_to_renew_the_token() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken() + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test) let rest = ARTRest(options: options) // No means to renew the token is provided XCTAssertNil(rest.internal.options.key) XCTAssertNil(rest.internal.options.authCallback) XCTAssertNil(rest.internal.options.authUrl) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) testHTTPExecutor.simulateIncomingServerErrorOnNextRequest(ARTErrorCode.tokenRevoked.intValue, description: "token revoked") waitUntil(timeout: testTimeout) { done in @@ -253,10 +260,11 @@ class AuthTests: XCTestCase { // RSA4a func test__021__Token__authentication_method__should_transition_the_connection_to_the_FAILED_state_when_the_server_responds_with_a_token_error_and_there_is_no_way_to_renew_the_token() throws { - let options = try AblyTests.clientOptions() - options.tokenDetails = try getTestTokenDetails(ttl: 0.1) + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.tokenDetails = try getTestTokenDetails(for: test, ttl: 0.1) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) // Token will expire, expecting 40142 waitUntil(timeout: testTimeout) { done in @@ -270,7 +278,7 @@ class AuthTests: XCTestCase { XCTAssertNil(realtime.internal.options.authCallback) XCTAssertNil(realtime.internal.options.authUrl) - let channel = realtime.channels.get(uniqueChannelName()) + let channel = realtime.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout.multiplied(by: 2)) { done in realtime.connect() @@ -287,21 +295,22 @@ class AuthTests: XCTestCase { // RSA4b func test__022__Token__authentication_method__on_token_error__reissues_token_and_retries_REST_requests() throws { + let test = Test() var authCallbackCalled = 0 - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) options.authCallback = { _, callback in authCallbackCalled += 1 - getTestTokenDetails { token, err in + getTestTokenDetails(for: test) { token, err in callback(token, err) } } let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) testHTTPExecutor.simulateIncomingServerErrorOnNextRequest(ARTErrorCode.tokenRevoked.intValue, description: "token revoked") @@ -321,14 +330,15 @@ class AuthTests: XCTestCase { // RSA4b func test__023__Token__authentication_method__in_REST__if_the_token_creation_failed_or_the_subsequent_request_with_the_new_token_failed_due_to_a_token_error__then_the_request_should_result_in_an_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) testHTTPExecutor.setListenerAfterRequest { _ in testHTTPExecutor.simulateIncomingServerErrorOnNextRequest(ARTErrorCode.tokenRevoked.intValue, description: "token revoked") @@ -351,7 +361,8 @@ class AuthTests: XCTestCase { // RSA4b func test__024__Token__authentication_method__in_Realtime__if_the_token_creation_failed_then_the_connection_should_move_to_the_DISCONNECTED_state_and_reports_the_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.authCallback = { _, completion in completion(nil, NSError(domain: NSURLErrorDomain, code: -1003, userInfo: [NSLocalizedDescriptionKey: "A server with the specified hostname could not be found."])) } @@ -377,9 +388,10 @@ class AuthTests: XCTestCase { // RSA4b func test__025__Token__authentication_method__in_Realtime__if_the_connection_fails_due_to_a_terminal_token_error__then_the_connection_should_move_to_the_FAILED_state_and_reports_the_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.authCallback = { _, completion in - getTestToken { result in + getTestToken(for: test) { result in switch result { case .success(let token): let invalidToken = String(token.reversed()) @@ -412,17 +424,18 @@ class AuthTests: XCTestCase { // RSA4b1 func test__028__Token__authentication_method__local_token_validity_check__should_be_done_if_queryTime_is_true_and_local_time_is_in_sync_with_server() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let testKey = options.key! - let tokenDetails = try getTestTokenDetails(key: testKey, ttl: 5.0, queryTime: true) + let tokenDetails = try getTestTokenDetails(for: test, key: testKey, ttl: 5.0, queryTime: true) options.queryTime = true options.tokenDetails = tokenDetails options.key = nil let rest = ARTRest(options: options) - let proxyHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let proxyHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) // Sync server time offset let authOptions = ARTAuthOptions(key: testKey) @@ -446,7 +459,7 @@ class AuthTests: XCTestCase { rest.internal.httpExecutor = proxyHTTPExecutor waitUntil(timeout: testTimeout) { done in - rest.channels.get(uniqueChannelName()).history { _, error in + rest.channels.get(uniqueChannelName(for: test)).history { _, error in guard let error = error else { fail("Error is nil"); done(); return } @@ -462,17 +475,18 @@ class AuthTests: XCTestCase { } func test__029__Token__authentication_method__local_token_validity_check__should_NOT_be_done_if_queryTime_is_false_and_local_time_is_NOT_in_sync_with_server() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let testKey = options.key! - let tokenDetails = try getTestTokenDetails(key: testKey, ttl: 5.0, queryTime: true) + let tokenDetails = try getTestTokenDetails(for: test, key: testKey, ttl: 5.0, queryTime: true) options.queryTime = false options.tokenDetails = tokenDetails options.key = nil let rest = ARTRest(options: options) - let proxyHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let proxyHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = proxyHTTPExecutor // No server time offset @@ -486,7 +500,7 @@ class AuthTests: XCTestCase { } waitUntil(timeout: testTimeout) { done in - rest.channels.get(uniqueChannelName()).history { _, error in + rest.channels.get(uniqueChannelName(for: test)).history { _, error in guard let error = error else { fail("Error is nil"); done(); return } @@ -505,7 +519,8 @@ class AuthTests: XCTestCase { // RSA4d func test__026__Token__authentication_method__if_a_request_by_a_realtime_client_to_an_authUrl_results_in_an_HTTP_403_the_client_library_should_transition_to_the_FAILED_state() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false options.authUrl = URL(string: "https://echo.ably.io/respondwith?status=403")! let realtime = ARTRealtime(options: options) @@ -523,7 +538,8 @@ class AuthTests: XCTestCase { // RSA4d func test__027__Token__authentication_method__if_an_authCallback_results_in_an_HTTP_403_the_client_library_should_transition_to_the_FAILED_state() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false var authCallbackHasBeenInvoked = false options.authCallback = { _, completion in @@ -558,7 +574,8 @@ class AuthTests: XCTestCase { // RSA4c1 & RSA4c2 func test__032__Token__options__if_an_attempt_by_the_realtime_client_library_to_authenticate_is_made_using_the_authUrl_or_authCallback__the_request_to_authUrl_fails__if_the_connection_is_CONNECTING__then_the_connection_attempt_should_be_treated_as_unsuccessful() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false options.authUrl = URL(string: "http://echo.ably.io")! let realtime = ARTRealtime(options: options) @@ -584,8 +601,9 @@ class AuthTests: XCTestCase { // RSA4c3 func test__033__Token__options__if_an_attempt_by_the_realtime_client_library_to_authenticate_is_made_using_the_authUrl_or_authCallback__the_request_to_authUrl_fails__if_the_connection_is_CONNECTED__then_the_connection_should_remain_CONNECTED() throws { - let token = try getTestToken() - let options = try AblyTests.clientOptions() + let test = Test() + let token = try getTestToken(for: test) + let options = try AblyTests.clientOptions(for: test) options.authUrl = URL(string: "http://echo.ably.io")! options.authParams = [URLQueryItem]() options.authParams?.append(URLQueryItem(name: "type", value: "text")) @@ -621,7 +639,8 @@ class AuthTests: XCTestCase { // RSA4c1 & RSA4c2 func test__034__Token__options__if_an_attempt_by_the_realtime_client_library_to_authenticate_is_made_using_the_authUrl_or_authCallback__the_request_to_authCallback_fails__if_the_connection_is_CONNECTING__then_the_connection_attempt_should_be_treated_as_unsuccessful() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false options.authCallback = { _, completion in completion(nil, NSError(domain: NSURLErrorDomain, code: -1003, userInfo: [NSLocalizedDescriptionKey: "A server with the specified hostname could not be found."])) @@ -651,9 +670,10 @@ class AuthTests: XCTestCase { // RSA4c3 func test__035__Token__options__if_an_attempt_by_the_realtime_client_library_to_authenticate_is_made_using_the_authUrl_or_authCallback__the_request_to_authCallback_fails__if_the_connection_is_CONNECTED__then_the_connection_should_remain_CONNECTED() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { _, completion in - getTestTokenDetails(completion: completion) + getTestTokenDetails(for: test, completion: completion) } let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -687,7 +707,8 @@ class AuthTests: XCTestCase { // RSA4c1 & RSA4c2 func test__036__Token__options__if_an_attempt_by_the_realtime_client_library_to_authenticate_is_made_using_the_authUrl_or_authCallback__the_provided_token_is_in_an_invalid_format__if_the_connection_is_CONNECTING__then_the_connection_attempt_should_be_treated_as_unsuccessful() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false options.authUrl = URL(string: "http://echo.ably.io")! options.authParams = [URLQueryItem]() @@ -720,12 +741,13 @@ class AuthTests: XCTestCase { // RSA4c3 func test__037__Token__options__if_an_attempt_by_the_realtime_client_library_to_authenticate_is_made_using_the_authUrl_or_authCallback__the_provided_token_is_in_an_invalid_format__if_the_connection_is_CONNECTED__then_the_connection_should_remain_CONNECTED() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.authUrl = URL(string: "http://echo.ably.io")! options.authParams = [URLQueryItem]() options.authParams?.append(URLQueryItem(name: "type", value: "text")) - let token = try getTestToken() + let token = try getTestToken(for: test) options.authParams?.append(URLQueryItem(name: "body", value: token)) let realtime = ARTRealtime(options: options) @@ -772,7 +794,8 @@ class AuthTests: XCTestCase { // RSA4c1 & RSA4c2 func test__038__Token__options__if_an_attempt_by_the_realtime_client_library_to_authenticate_is_made_using_the_authUrl_or_authCallback__the_attempt_times_out_after_realtimeRequestTimeout__if_the_connection_is_CONNECTING__then_the_connection_attempt_should_be_treated_as_unsuccessful() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false options.authCallback = { _, _ in // Ignore `completion` closure to force a time out @@ -803,10 +826,11 @@ class AuthTests: XCTestCase { // RSA4c3 func test__039__Token__options__if_an_attempt_by_the_realtime_client_library_to_authenticate_is_made_using_the_authUrl_or_authCallback__the_attempt_times_out_after_realtimeRequestTimeout__if_the_connection_is_CONNECTED__then_the_connection_should_remain_CONNECTED() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false options.authCallback = { _, completion in - getTestTokenDetails(completion: completion) + getTestTokenDetails(for: test, completion: completion) } options.testOptions.realtimeRequestTimeout = 0.5 @@ -851,13 +875,14 @@ class AuthTests: XCTestCase { // RSA15a func test__041__Token__token_auth_and_clientId__should_check_clientId_consistency__on_rest() throws { + let test = Test() let expectedClientId = "client_string" - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true options.clientId = expectedClientId let client = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -885,11 +910,12 @@ class AuthTests: XCTestCase { } func test__042__Token__token_auth_and_clientId__should_check_clientId_consistency__on_realtime() throws { + let test = Test() let expectedClientId = "client_string" - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = expectedClientId options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -900,7 +926,7 @@ class AuthTests: XCTestCase { let state = stateChange.current let error = stateChange.reason if state == .connected, error == nil { - let currentChannel = client.channels.get(uniqueChannelName()) + let currentChannel = client.channels.get(uniqueChannelName(for: test)) currentChannel.subscribe { _ in done() } @@ -917,7 +943,8 @@ class AuthTests: XCTestCase { } func test__043__Token__token_auth_and_clientId__should_check_clientId_consistency__with_wildcard() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "*" expect { ARTRest(options: options) }.to(raiseException()) expect { ARTRealtime(options: options) }.to(raiseException()) @@ -925,7 +952,8 @@ class AuthTests: XCTestCase { // RSA15b func test__040__Token__token_auth_and_clientId__should_permit_to_be_unauthenticated() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = nil let clientBasic = ARTRest(options: options) @@ -955,8 +983,9 @@ class AuthTests: XCTestCase { // RSA15c func test__044__Token__token_auth_and_clientId__Incompatible_client__with_Realtime__it_should_change_the_connection_state_to_FAILED_and_emit_an_error() throws { - let options = try AblyTests.commonAppSetup() - let wrongTokenDetails = try getTestTokenDetails(clientId: "wrong") + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let wrongTokenDetails = try getTestTokenDetails(for: test, clientId: "wrong") options.clientId = "john" options.autoConnect = false @@ -976,7 +1005,8 @@ class AuthTests: XCTestCase { } func test__045__Token__token_auth_and_clientId__Incompatible_client__with_Rest__it_should_result_in_an_appropriate_error_response() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let rest = ARTRest(options: options) @@ -1022,12 +1052,13 @@ class AuthTests: XCTestCase { // RSA6 func test__008__Token__should_omit_capability_field_if_it_is_not_specified() throws { + let test = Test() let tokenParams = ARTTokenParams() XCTAssertNil(tokenParams.capability) - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -1054,12 +1085,13 @@ class AuthTests: XCTestCase { // RSA6 func test__009__Token__should_add_capability_field_if_the_user_specifies_it() throws { + let test = Test() let tokenParams = ARTTokenParams() tokenParams.capability = "{\"*\":[\"*\"]}" - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -1087,12 +1119,13 @@ class AuthTests: XCTestCase { // RSA7a1 func test__046__Token__clientId_and_authenticated_clients__should_not_pass_clientId_with_published_message() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "mary" let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish("foo", data: nil) { error in XCTAssertNil(error) @@ -1111,15 +1144,16 @@ class AuthTests: XCTestCase { // RSA7a2 func test__047__Token__clientId_and_authenticated_clients__should_obtain_a_token_if_clientId_is_assigned() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" let client = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - client.channels.get(uniqueChannelName()).publish(nil, data: "message") { error in + client.channels.get(uniqueChannelName(for: test)).publish(nil, data: "message") { error in if let e = error { XCTFail(e.localizedDescription) } @@ -1134,7 +1168,8 @@ class AuthTests: XCTestCase { // RSA7a3 func test__048__Token__clientId_and_authenticated_clients__should_convenience_clientId_return_a_string() throws { - let clientOptions = try AblyTests.commonAppSetup() + let test = Test() + let clientOptions = try AblyTests.commonAppSetup(for: test) clientOptions.clientId = "String" XCTAssertEqual(ARTRest(options: clientOptions).internal.options.clientId, "String") @@ -1142,11 +1177,12 @@ class AuthTests: XCTestCase { // RSA7a4 func test__049__Token__clientId_and_authenticated_clients__ClientOptions_clientId_takes_precendence_when_a_clientId_value_is_provided_in_both_ClientOptions_clientId_and_ClientOptions_defaultTokenParams() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.clientId = "john" options.authCallback = { tokenParams, completion in XCTAssertEqual(tokenParams.clientId, options.clientId) - getTestToken(clientId: tokenParams.clientId) { result in + getTestToken(for: test, clientId: tokenParams.clientId) { result in switch result { case .success(let token): completion(token as ARTTokenDetailsCompatible, nil) @@ -1157,7 +1193,7 @@ class AuthTests: XCTestCase { } options.defaultTokenParams = ARTTokenParams(clientId: "tester") let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(client.auth.clientId, "john") waitUntil(timeout: testTimeout) { done in @@ -1181,7 +1217,8 @@ class AuthTests: XCTestCase { // RSA12a func test__051__Token__clientId_and_authenticated_clients__Auth_clientId_attribute_is_null__identity_should_be_anonymous_for_all_operations() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let realtime = AblyTests.newRealtime(options).client defer { realtime.dispose(); realtime.close() } @@ -1209,9 +1246,10 @@ class AuthTests: XCTestCase { // RSA12b func test__052__Token__clientId_and_authenticated_clients__Auth_clientId_attribute_is_null__identity_may_change_and_become_identified() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.token = try getTestToken(clientId: "tester") + options.token = try getTestToken(for: test, clientId: "tester") let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } XCTAssertNil(realtime.auth.clientId) @@ -1234,7 +1272,8 @@ class AuthTests: XCTestCase { // RSA7b1 func test__053__Token__clientId_and_authenticated_clients__auth_clientId_not_null__when_clientId_attribute_is_assigned_on_client_options() throws { - let clientOptions = try AblyTests.commonAppSetup() + let test = Test() + let clientOptions = try AblyTests.commonAppSetup(for: test) clientOptions.clientId = "Exist" XCTAssertEqual(ARTRest(options: clientOptions).auth.clientId, "Exist") @@ -1242,12 +1281,13 @@ class AuthTests: XCTestCase { // RSA7b2 func test__054__Token__clientId_and_authenticated_clients__auth_clientId_not_null__when_tokenRequest_or_tokenDetails_has_clientId_not_null_or_wildcard_string() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" options.useTokenAuth = true let client = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor // TokenDetails @@ -1273,8 +1313,9 @@ class AuthTests: XCTestCase { // RSA7b3 func test__055__Token__clientId_and_authenticated_clients__auth_clientId_not_null__should_CONNECTED_ProtocolMessages_contain_a_clientId() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(clientId: "john") + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, clientId: "john") XCTAssertNil(options.clientId) options.autoConnect = false let realtime = AblyTests.newRealtime(options).client @@ -1296,8 +1337,9 @@ class AuthTests: XCTestCase { // RSA7b4 func test__056__Token__clientId_and_authenticated_clients__auth_clientId_not_null__client_does_not_have_an_identity_when_a_wildcard_string_____is_present() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(clientId: "*") + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, clientId: "*") let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in @@ -1310,7 +1352,8 @@ class AuthTests: XCTestCase { // RSA7c func test__050__Token__clientId_and_authenticated_clients__should_clientId_be_null_or_string() throws { - let clientOptions = try AblyTests.commonAppSetup() + let test = Test() + let clientOptions = try AblyTests.commonAppSetup(for: test) clientOptions.clientId = "*" expect { ARTRest(options: clientOptions) }.to(raiseException()) @@ -1320,7 +1363,8 @@ class AuthTests: XCTestCase { // RSA8e func test__062__requestToken__arguments__should_not_merge_with_the_configured_params_and_options_but_instead_replace_all_corresponding_values__even_when__null_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "сlientId" let rest = ARTRest(options: options) @@ -1328,7 +1372,7 @@ class AuthTests: XCTestCase { tokenParams.ttl = 2000 tokenParams.capability = "{\"cansubscribe:*\":[\"subscribe\"]}" - let precedenceOptions = try AblyTests.commonAppSetup() + let precedenceOptions = try AblyTests.commonAppSetup(for: test) waitUntil(timeout: testTimeout) { done in rest.auth.requestToken(tokenParams, with: precedenceOptions) { tokenDetails, error in @@ -1341,11 +1385,11 @@ class AuthTests: XCTestCase { } } - let options2 = try AblyTests.commonAppSetup() + let options2 = try AblyTests.commonAppSetup(for: test) options2.clientId = nil let rest2 = ARTRest(options: options2) - let precedenceOptions2 = try AblyTests.commonAppSetup() + let precedenceOptions2 = try AblyTests.commonAppSetup(for: test) precedenceOptions2.clientId = nil waitUntil(timeout: testTimeout) { done in @@ -1362,7 +1406,8 @@ class AuthTests: XCTestCase { // RSA8e func test__063__requestToken__arguments__should_use_configured_defaults_if_the_object_arguments_are_omitted() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "tester" let rest = ARTRest(options: options) @@ -1423,9 +1468,10 @@ class AuthTests: XCTestCase { // RSA8c func test__064__requestToken__authUrl__query_will_provide_a_token_string() throws { - let testToken = try getTestToken() + let test = Test() + let testToken = try getTestToken(for: test) - let options = try AblyTests.clientOptions() + let options = try AblyTests.clientOptions(for: test) options.authUrl = URL(string: "http://echo.ably.io") XCTAssertNotNil(options.authUrl) // Plain text @@ -1434,7 +1480,7 @@ class AuthTests: XCTestCase { options.authParams!.append(URLQueryItem(name: "body", value: testToken)) let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -1449,7 +1495,8 @@ class AuthTests: XCTestCase { } func test__065__requestToken__authUrl__query_will_provide_a_TokenDetails() throws { - let testTokenDetails = try XCTUnwrap(getTestTokenDetails(clientId: "tester"), "TokenDetails is empty") + let test = Test() + let testTokenDetails = try XCTUnwrap(getTestTokenDetails(for: test, clientId: "tester"), "TokenDetails is empty") let jsonTokenDetails = try XCTUnwrap(createJsonEncoder().encode(testTokenDetails), "Invalid TokenDetails") let options = ARTClientOptions() @@ -1461,7 +1508,7 @@ class AuthTests: XCTestCase { options.authParams?.append(URLQueryItem(name: "body", value: jsonTokenDetails.toUTF8String)) let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -1485,10 +1532,11 @@ class AuthTests: XCTestCase { } func test__066__requestToken__authUrl__query_will_provide_a_TokenRequest() throws { + let test = Test() let tokenParams = ARTTokenParams() tokenParams.capability = "{\"test\":[\"subscribe\"]}" - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) options.authUrl = URL(string: "http://echo.ably.io") XCTAssertNotNil(options.authUrl) @@ -1513,7 +1561,7 @@ class AuthTests: XCTestCase { options.authParams?.append(URLQueryItem(name: "body", value: jsonTokenRequest.toUTF8String)) rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -1623,6 +1671,7 @@ class AuthTests: XCTestCase { // RSA8c2 func test__067__requestToken__authUrl__TokenParams_should_take_precedence_over_any_configured_authParams_when_a_name_conflict_occurs() { + let test = Test() let options = ARTClientOptions() options.clientId = "john" options.authUrl = URL(string: "http://auth.ably.io") @@ -1638,7 +1687,7 @@ class AuthTests: XCTestCase { tokenParams.clientId = "tester" let client = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -1666,7 +1715,8 @@ class AuthTests: XCTestCase { // RSA8a func test__057__requestToken__implicitly_creates_a_TokenRequest_and_requests_a_token() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) var createTokenRequestMethodWasCalled = false @@ -1690,7 +1740,8 @@ class AuthTests: XCTestCase { // RSA8b func test__071__requestToken__should_support_all_TokenParams__using_defaults() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = currentClientId let rest = ARTRest(options: options) @@ -1714,7 +1765,8 @@ class AuthTests: XCTestCase { } func test__072__requestToken__should_support_all_TokenParams__overriding_defaults() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = currentClientId let rest = ARTRest(options: options) @@ -1744,7 +1796,8 @@ class AuthTests: XCTestCase { // RSA8d func test__073__requestToken__When_authCallback_option_is_set__it_will_invoke_the_callback__with_a_token_string() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) let expectedTokenParams = ARTTokenParams() options.authCallback = { tokenParams, completion in @@ -1763,9 +1816,10 @@ class AuthTests: XCTestCase { } func test__074__requestToken__When_authCallback_option_is_set__it_will_invoke_the_callback__with_a_TokenDetails() throws { + let test = Test() let expectedTokenParams = ARTTokenParams() - let options = try AblyTests.clientOptions() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { tokenParams, completion in XCTAssertNil(tokenParams.clientId) completion(ARTTokenDetails(token: "token_from_details"), nil) @@ -1782,7 +1836,8 @@ class AuthTests: XCTestCase { } func test__075__requestToken__When_authCallback_option_is_set__it_will_invoke_the_callback__with_a_TokenRequest() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let expectedTokenParams = ARTTokenParams() expectedTokenParams.clientId = "foo" var rest: ARTRest! @@ -1810,12 +1865,13 @@ class AuthTests: XCTestCase { // RSA8f1 func test__058__requestToken__ensure_the_message_published_does_not_have_a_clientId() throws { - let options = try AblyTests.commonAppSetup() - options.token = try getTestToken(clientId: nil) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.token = try getTestToken(for: test, clientId: nil) let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let message = ARTMessage(name: nil, data: "message without an explicit clientId") @@ -1844,10 +1900,11 @@ class AuthTests: XCTestCase { // RSA8f2 func test__059__requestToken__ensure_that_the_message_is_rejected() throws { - let options = try AblyTests.commonAppSetup() - options.token = try getTestToken(clientId: nil) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.token = try getTestToken(for: test, clientId: nil) let rest = ARTRest(options: options) - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let message = ARTMessage(name: nil, data: "message with an explicit clientId", clientId: "john") @@ -1864,7 +1921,8 @@ class AuthTests: XCTestCase { // RSA8f3 func test__060__requestToken__ensure_the_message_published_with_a_wildcard_____does_not_have_a_clientId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) waitUntil(timeout: testTimeout) { done in @@ -1874,9 +1932,9 @@ class AuthTests: XCTestCase { } } - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let message = ARTMessage(name: nil, data: "no client") @@ -1905,11 +1963,12 @@ class AuthTests: XCTestCase { // RSA8f4 func test__061__requestToken__ensure_the_message_published_with_a_wildcard_____has_the_provided_clientId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) // Request a token with a wildcard '*' value clientId - options.token = try getTestToken(clientId: "*") + options.token = try getTestToken(for: test, clientId: "*") let rest = ARTRest(options: options) - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let message = ARTMessage(name: nil, data: "message with an explicit clientId", clientId: "john") @@ -1935,7 +1994,8 @@ class AuthTests: XCTestCase { // RSA9h func test__076__createTokenRequest__should_not_merge_with_the_configured_params_and_options_but_instead_replace_all_corresponding_values__even_when__null_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" let rest = ARTRest(options: options) @@ -2020,7 +2080,8 @@ class AuthTests: XCTestCase { } func test__077__createTokenRequest__should_override_defaults_if_AuthOptions_provided() throws { - let defaultOptions = try AblyTests.commonAppSetup() + let test = Test() + let defaultOptions = try AblyTests.commonAppSetup(for: test) defaultOptions.authCallback = { _, _ in fail("Should not be called") } @@ -2049,10 +2110,11 @@ class AuthTests: XCTestCase { } func test__078__createTokenRequest__should_use_defaults_if_no_AuthOptions_is_provided() throws { + let test = Test() var currentTokenRequest: ARTTokenRequest? var callbackCalled = false - let defaultOptions = try AblyTests.commonAppSetup() + let defaultOptions = try AblyTests.commonAppSetup(for: test) defaultOptions.authCallback = { _, completion in callbackCalled = true guard let tokenRequest = currentTokenRequest else { @@ -2077,7 +2139,8 @@ class AuthTests: XCTestCase { } func test__079__createTokenRequest__should_replace_defaults_if__nil__option_s_field_passed() throws { - let defaultOptions = try AblyTests.commonAppSetup() + let test = Test() + let defaultOptions = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: defaultOptions) let customOptions = ARTAuthOptions() @@ -2095,7 +2158,8 @@ class AuthTests: XCTestCase { // RSA9h func test__080__createTokenRequest__should_use_configured_defaults_if_the_object_arguments_are_omitted() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let tokenParams = ARTTokenParams() @@ -2144,7 +2208,8 @@ class AuthTests: XCTestCase { // RSA9a func test__081__createTokenRequest__should_create_and_sign_a_TokenRequest() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let expectedClientId = "client_string" let tokenParams = ARTTokenParams(clientId: expectedClientId) @@ -2165,7 +2230,8 @@ class AuthTests: XCTestCase { // RSA9b func test__082__createTokenRequest__should_support_AuthOptions() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let auth: ARTAuth = rest.auth let authOptions = ARTAuthOptions(key: "key:secret") @@ -2184,7 +2250,8 @@ class AuthTests: XCTestCase { // RSA9c func test__083__createTokenRequest__should_generate_a_unique_16_plus_character_nonce_if_none_is_provided() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) waitUntil(timeout: testTimeout) { done in // First @@ -2214,7 +2281,8 @@ class AuthTests: XCTestCase { // RSA9d func test__087__createTokenRequest__should_generate_a_timestamp__from_current_time_if_not_provided() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) waitUntil(timeout: testTimeout) { done in rest.auth.createTokenRequest(nil, options: nil, callback: { tokenRequest, error in @@ -2229,7 +2297,8 @@ class AuthTests: XCTestCase { } func test__088__createTokenRequest__should_generate_a_timestamp__will_retrieve_the_server_time_if_queryTime_is_true() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) var serverTimeRequestWasMade = false let block: @convention(block) (AspectInfo) -> Void = { _ in @@ -2242,7 +2311,7 @@ class AuthTests: XCTestCase { let authOptions = ARTAuthOptions() authOptions.queryTime = true - authOptions.key = try AblyTests.commonAppSetup().key + authOptions.key = try AblyTests.commonAppSetup(for: test).key waitUntil(timeout: testTimeout) { done in rest.auth.createTokenRequest(nil, options: authOptions, callback: { tokenRequest, error in @@ -2260,7 +2329,8 @@ class AuthTests: XCTestCase { // RSA9e func test__089__createTokenRequest__TTL__should_be_optional() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) waitUntil(timeout: testTimeout) { done in rest.auth.createTokenRequest(nil, options: nil, callback: { tokenRequest, error in @@ -2293,7 +2363,8 @@ class AuthTests: XCTestCase { } func test__090__createTokenRequest__TTL__should_be_specified_in_milliseconds() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let params = ARTTokenParams() params.ttl = NSNumber(value: 42) @@ -2321,7 +2392,8 @@ class AuthTests: XCTestCase { } func test__091__createTokenRequest__TTL__should_be_valid_to_request_a_token_for_24_hours() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let tokenParams = ARTTokenParams() let dayInSeconds = TimeInterval(24 * 60 * 60) tokenParams.ttl = dayInSeconds as NSNumber @@ -2340,7 +2412,8 @@ class AuthTests: XCTestCase { // RSA9f func test__084__createTokenRequest__should_provide_capability_has_json_text() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let tokenParams = ARTTokenParams() tokenParams.capability = "{ - }" @@ -2370,7 +2443,8 @@ class AuthTests: XCTestCase { // RSA9g func test__085__createTokenRequest__should_generate_a_valid_HMAC() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let tokenParams = ARTTokenParams(clientId: "client_string") @@ -2398,7 +2472,8 @@ class AuthTests: XCTestCase { // RSA9i func test__086__createTokenRequest__should_respect_all_requirements() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let expectedClientId = "client_string" let tokenParams = ARTTokenParams(clientId: expectedClientId) let expectedTtl = 6.0 @@ -2408,7 +2483,7 @@ class AuthTests: XCTestCase { let authOptions = ARTAuthOptions() authOptions.queryTime = true - authOptions.key = try AblyTests.commonAppSetup().key + authOptions.key = try AblyTests.commonAppSetup(for: test).key var serverTime: Date? waitUntil(timeout: testTimeout) { done in @@ -2440,10 +2515,11 @@ class AuthTests: XCTestCase { // RSA10a func test__092__authorize__should_always_create_a_token() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true let rest = ARTRest(options: options) - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "first check") { error in @@ -2494,8 +2570,9 @@ class AuthTests: XCTestCase { // RSA10a func test__093__authorize__should_create_a_new_token_if_one_already_exist_and_ensure_Token_Auth_is_used_for_all_future_requests() throws { - let options = try AblyTests.commonAppSetup() - let testToken = try getTestToken() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let testToken = try getTestToken(for: test) options.token = testToken let rest = ARTRest(options: options) @@ -2508,7 +2585,7 @@ class AuthTests: XCTestCase { XCTAssertNotEqual(tokenDetails.token, testToken) XCTAssertEqual(rest.auth.internal.method, ARTAuthMethod.token) - publishTestMessage(rest, channelName: uniqueChannelName(), completion: { error in + publishTestMessage(rest, channelName: uniqueChannelName(for: test), completion: { error in XCTAssertNil(error) XCTAssertEqual(rest.auth.internal.method, ARTAuthMethod.token) XCTAssertEqual(rest.auth.tokenDetails?.token, tokenDetails.token) @@ -2520,7 +2597,8 @@ class AuthTests: XCTestCase { // RSA10a func test__094__authorize__should_create_a_token_immediately_and_ensures_Token_Auth_is_used_for_all_future_requests() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) XCTAssertNil(rest.auth.tokenDetails?.token) @@ -2532,7 +2610,7 @@ class AuthTests: XCTestCase { XCTAssertNotNil(tokenDetails.token) XCTAssertEqual(rest.auth.internal.method, ARTAuthMethod.token) - publishTestMessage(rest, channelName: uniqueChannelName(), completion: { error in + publishTestMessage(rest, channelName: uniqueChannelName(for: test), completion: { error in XCTAssertNil(error) XCTAssertEqual(rest.auth.internal.method, ARTAuthMethod.token) XCTAssertEqual(rest.auth.tokenDetails?.token, tokenDetails.token) @@ -2544,7 +2622,8 @@ class AuthTests: XCTestCase { // RSA10b func test__095__authorize__should_supports_all_TokenParams_and_AuthOptions() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) waitUntil(timeout: testTimeout) { done in rest.auth.authorize(ARTTokenParams(), options: ARTAuthOptions(), callback: { _, error in @@ -2559,7 +2638,8 @@ class AuthTests: XCTestCase { // RSA10e func test__096__authorize__should_use_the_requestToken_implementation() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) var requestMethodWasCalled = false let block: @convention(block) (AspectInfo) -> Void = { _ in @@ -2588,7 +2668,8 @@ class AuthTests: XCTestCase { // RSA10f func test__097__authorize__should_return_TokenDetails_with_valid_token_metadata() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" let rest = ARTRest(options: options) @@ -2610,13 +2691,14 @@ class AuthTests: XCTestCase { // RSA10g func test__099__authorize__on_subsequent_authorisations__should_store_the_AuthOptions_with_authUrl() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor let auth = rest.auth - let token = try getTestToken() + let token = try getTestToken(for: test) let authOptions = ARTAuthOptions() // Use authUrl for authentication with plain text token response authOptions.authUrl = URL(string: "http://echo.ably.io")! @@ -2653,7 +2735,8 @@ class AuthTests: XCTestCase { } func test__100__authorize__on_subsequent_authorisations__should_store_the_AuthOptions_with_authCallback() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let auth = rest.auth var authCallbackHasBeenInvoked = false @@ -2686,7 +2769,8 @@ class AuthTests: XCTestCase { } func test__101__authorize__on_subsequent_authorisations__should_not_store_queryTime() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let authOptions = ARTAuthOptions() authOptions.key = options.key @@ -2720,7 +2804,8 @@ class AuthTests: XCTestCase { } func test__102__authorize__on_subsequent_authorisations__should_store_the_TokenParams() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let tokenParams = ARTTokenParams() tokenParams.clientId = ExpectedTokenParams.clientId @@ -2752,7 +2837,8 @@ class AuthTests: XCTestCase { } func test__103__authorize__on_subsequent_authorisations__should_use_configured_defaults_if_the_object_arguments_are_omitted() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let tokenParams = ARTTokenParams() @@ -2767,7 +2853,7 @@ class AuthTests: XCTestCase { XCTAssertEqual(tokenParams.ttl as? TimeInterval, ExpectedTokenParams.ttl) XCTAssertEqual(tokenParams.capability, ExpectedTokenParams.capability) authCallbackCalled += 1 - getTestTokenDetails(key: options.key, completion: completion) + getTestTokenDetails(for: test, key: options.key, completion: completion) } waitUntil(timeout: testTimeout) { done in @@ -2791,7 +2877,8 @@ class AuthTests: XCTestCase { // RSA10h func test__098__authorize__should_use_the_configured_Auth_clientId__if_not_null__by_default() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var rest = ARTRest(options: options) // ClientId null @@ -2825,7 +2912,8 @@ class AuthTests: XCTestCase { // RSA10i func test__104__authorize__should_adhere_to_all_requirements_relating_to__TokenParams() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" let rest = ARTRest(options: options) @@ -2851,9 +2939,10 @@ class AuthTests: XCTestCase { } func test__105__authorize__should_adhere_to_all_requirements_relating_to__authCallback() throws { + let test = Test() var currentTokenRequest: ARTTokenRequest? - var rest = ARTRest(options: try AblyTests.commonAppSetup()) + var rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) rest.auth.createTokenRequest(nil, options: nil, callback: { tokenRequest, _ in currentTokenRequest = tokenRequest }) @@ -2861,7 +2950,7 @@ class AuthTests: XCTestCase { currentTokenRequest = try XCTUnwrap(currentTokenRequest, "Token request is nil") - let options = try AblyTests.clientOptions() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { _, completion in completion(currentTokenRequest!, nil) } @@ -2899,8 +2988,9 @@ class AuthTests: XCTestCase { } func test__107__authorize__should_adhere_to_all_requirements_relating_to__authUrl_with_json() throws { + let test = Test() - let tokenDetails = try XCTUnwrap(getTestTokenDetails(), "TokenDetails is empty") + let tokenDetails = try XCTUnwrap(getTestTokenDetails(for: test), "TokenDetails is empty") let tokenDetailsData = try XCTUnwrap(createJsonEncoder().encode(tokenDetails), "Couldn't encode token details") let tokenDetailsJSON = try XCTUnwrap(String(data: tokenDetailsData, encoding: .utf8), "JSON TokenDetails is empty") @@ -2940,7 +3030,8 @@ class AuthTests: XCTestCase { // https://github.com/ably/ably-cocoa/issues/618 func test__108__authorize__should_adhere_to_all_requirements_relating_to__authUrl_returning_TokenRequest_decodes_TTL_as_expected() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var rest = ARTRest(options: options) var tokenRequest: ARTTokenRequest! @@ -2975,7 +3066,8 @@ class AuthTests: XCTestCase { } func test__109__authorize__should_adhere_to_all_requirements_relating_to__authUrl_with_plain_text() throws { - let token = try getTestToken() + let test = Test() + let token = try getTestToken(for: test) let options = ARTClientOptions() // Use authUrl for authentication with plain text token response options.authUrl = URL(string: "http://echo.ably.io")! @@ -3010,12 +3102,13 @@ class AuthTests: XCTestCase { // RSA10j func test__110__authorize__when_TokenParams_and_AuthOptions_are_provided__should_supersede_configured_AuthOptions__using_key__even_if_arguments_objects_are_empty() throws { - let defaultOptions = try AblyTests.clientOptions() // sandbox + let test = Test() + let defaultOptions = try AblyTests.clientOptions(for: test) // sandbox defaultOptions.key = "xxxx:xxxx" let rest = ARTRest(options: defaultOptions) let authOptions = ARTAuthOptions() - authOptions.key = try AblyTests.commonAppSetup().key // valid key + authOptions.key = try AblyTests.commonAppSetup(for: test).key // valid key let tokenParams = ARTTokenParams() tokenParams.ttl = 1.0 @@ -3060,9 +3153,10 @@ class AuthTests: XCTestCase { } func test__111__authorize__when_TokenParams_and_AuthOptions_are_provided__should_supersede_configured_AuthOptions__using_authUrl__even_if_arguments_objects_are_empty() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) - let testTokenDetails = try XCTUnwrap(getTestTokenDetails(ttl: 0.1)) + let testTokenDetails = try XCTUnwrap(getTestTokenDetails(for: test, ttl: 0.1)) let tokenRequestData = try XCTUnwrap(createJsonEncoder().encode(testTokenDetails), "Encode failure") let authOptions = ARTAuthOptions() @@ -3149,7 +3243,8 @@ class AuthTests: XCTestCase { } func test__112__authorize__when_TokenParams_and_AuthOptions_are_provided__should_supersede_configured_AuthOptions__using_authCallback__even_if_arguments_objects_are_empty() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let testTokenDetails = ARTTokenDetails(token: "token", expires: Date(), issued: Date(), capability: nil, clientId: nil) var authCallbackHasBeenInvoked = false @@ -3210,7 +3305,8 @@ class AuthTests: XCTestCase { } func test__113__authorize__when_TokenParams_and_AuthOptions_are_provided__should_supersede_configured_params_and_options_even_if_arguments_objects_are_empty() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.key = "xxxx:xxxx" options.clientId = "client_string" let rest = ARTRest(options: options) @@ -3235,7 +3331,7 @@ class AuthTests: XCTestCase { tokenParams.clientId = nil let authOptions = ARTAuthOptions() - authOptions.key = try AblyTests.commonAppSetup().key + authOptions.key = try AblyTests.commonAppSetup(for: test).key authOptions.queryTime = true var serverTimeRequestCount = 0 @@ -3277,7 +3373,8 @@ class AuthTests: XCTestCase { } func test__114__authorize__when_TokenParams_and_AuthOptions_are_provided__example__if_a_client_is_initialised_with_TokenParams_ttl_configured_with_a_custom_value__and_a_TokenParams_object_is_passed_in_as_an_argument_to__authorize_with_a_null_value_for_ttl__then_the_ttl_used_for_every_subsequent_authorization_will_be_null() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.defaultTokenParams = { $0.ttl = 0.1 $0.clientId = "tester" @@ -3332,7 +3429,8 @@ class AuthTests: XCTestCase { // RSA10k func skipped__test__115__authorize__server_time_offset__should_obtain_server_time_once_and_persist_the_offset_from_the_local_clock() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let mockServerDate = Date().addingTimeInterval(120) @@ -3388,7 +3486,8 @@ class AuthTests: XCTestCase { } func test__116__authorize__server_time_offset__should_be_consistent_the_timestamp_request_with_the_server_time() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let mockServerDate = Date().addingTimeInterval(120) @@ -3423,7 +3522,8 @@ class AuthTests: XCTestCase { } func test__117__authorize__server_time_offset__should_be_possible_by_lib_Client_to_discard_the_cached_local_clock_offset() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.queryTime = true let rest = ARTRest(options: options) @@ -3472,7 +3572,8 @@ class AuthTests: XCTestCase { } func test__118__authorize__server_time_offset__should_use_the_local_clock_offset_to_calculate_the_server_time() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let authOptions = ARTAuthOptions() @@ -3500,7 +3601,8 @@ class AuthTests: XCTestCase { } func test__119__authorize__server_time_offset__should_request_server_time_when_queryTime_is_true_even_if_the_time_offset_is_assigned() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) var serverTimeRequestCount = 0 @@ -3531,7 +3633,8 @@ class AuthTests: XCTestCase { } func test__120__authorize__server_time_offset__should_discard_the_time_offset_in_situations_in_which_it_may_have_been_invalidated() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) var discardTimeOffsetCallCount = 0 let hook = rest.auth.internal.testSuite_injectIntoMethod(after: #selector(rest.auth.internal.discardTimeOffset)) { @@ -3561,7 +3664,8 @@ class AuthTests: XCTestCase { } func test__121__authorize__two_consecutive_authorizations__using_REST__should_call_each_authorize_callback() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true let rest = ARTRest(options: options) @@ -3601,7 +3705,8 @@ class AuthTests: XCTestCase { } func test__122__authorize__two_consecutive_authorizations__using_Realtime_and_connection_is_CONNECTING__should_call_each_Realtime_authorize_callback() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true let realtime = AblyTests.newRealtime(options).client defer { realtime.close(); realtime.dispose() } @@ -3648,7 +3753,8 @@ class AuthTests: XCTestCase { } func test__123__authorize__two_consecutive_authorizations__using_Realtime_and_connection_is_CONNECTED__should_call_each_Realtime_authorize_callback() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true let realtime = ARTRealtime(options: options) defer { realtime.close(); realtime.dispose() } @@ -3726,12 +3832,13 @@ class AuthTests: XCTestCase { // RTC8 func test__127__Reauth__should_use_authorize__force__true___to_reauth_with_a_token_with_a_different_set_of_capabilities() throws { - let options = try AblyTests.commonAppSetup() - let initialToken = try getTestToken(clientId: "tester", capability: "{\"restricted\":[\"*\"]}") + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let initialToken = try getTestToken(for: test, clientId: "tester", capability: "{\"restricted\":[\"*\"]}") options.token = initialToken let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } - let channel = realtime.channels.get(uniqueChannelName()) + let channel = realtime.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -3768,7 +3875,8 @@ class AuthTests: XCTestCase { // RTC8 func test__128__Reauth__for_a_token_change_that_fails_due_to_an_incompatible_token__which_should_result_in_the_connection_entering_the_FAILED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "tester" options.useTokenAuth = true let realtime = ARTRealtime(options: options) @@ -3805,7 +3913,8 @@ class AuthTests: XCTestCase { // TK2d func test__129__TokenParams__timestamp_should_not_be_a_member_of_any_default_token_params() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) waitUntil(timeout: testTimeout) { done in rest.auth.authorize(nil, options: nil) { _, error in XCTAssertNil(error) @@ -3948,8 +4057,9 @@ class AuthTests: XCTestCase { } func skipped__test__140__JWT_and_realtime__client_initialized_with_a_JWT_token_in_ClientOptions__with_valid_credentials__pulls_stats_successfully() throws { - let options = try AblyTests.clientOptions() - options.token = try getJWTToken() + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getJWTToken(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } @@ -3962,8 +4072,9 @@ class AuthTests: XCTestCase { } func test__141__JWT_and_realtime__client_initialized_with_a_JWT_token_in_ClientOptions__with_invalid_credentials__fails_to_connect_with_reason__invalid_signature_() throws { - let options = try AblyTests.clientOptions() - options.token = try getJWTToken(invalid: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getJWTToken(for: test, invalid: true) options.autoConnect = false let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } @@ -3984,9 +4095,10 @@ class AuthTests: XCTestCase { // RSA8g RSA8c func test__142__JWT_and_realtime__when_using_authUrl__with_valid_credentials__fetches_a_channels_and_posts_a_message() throws { - let keys = try getKeys() + let test = Test() + let keys = try getKeys(for: test) - let options = try createAuthUrlTestsOptions() + let options = try createAuthUrlTestsOptions(for: test) options.authParams = [URLQueryItem]() options.authParams?.append(URLQueryItem(name: "keyName", value: keys["keyName"])) options.authParams?.append(URLQueryItem(name: "keySecret", value: keys["keySecret"])) @@ -4007,9 +4119,10 @@ class AuthTests: XCTestCase { } func test__143__JWT_and_realtime__when_using_authUrl__with_wrong_credentials__fails_to_connect_with_reason__invalid_signature_() throws { - let keys = try getKeys() + let test = Test() + let keys = try getKeys(for: test) - let options = try createAuthUrlTestsOptions() + let options = try createAuthUrlTestsOptions(for: test) options.authParams = [URLQueryItem]() options.authParams?.append(URLQueryItem(name: "keyName", value: keys["keyName"])) options.authParams?.append(URLQueryItem(name: "keySecret", value: "INVALID")) @@ -4031,11 +4144,12 @@ class AuthTests: XCTestCase { } func test__144__JWT_and_realtime__when_using_authUrl__when_token_expires__receives_a_40142_error_from_the_server() throws { - let keys = try getKeys() + let test = Test() + let keys = try getKeys(for: test) let tokenDuration = 5.0 - let options = try createAuthUrlTestsOptions() + let options = try createAuthUrlTestsOptions(for: test) options.authParams = [URLQueryItem]() options.authParams?.append(URLQueryItem(name: "keyName", value: keys["keyName"])) options.authParams?.append(URLQueryItem(name: "keySecret", value: keys["keySecret"])) @@ -4059,19 +4173,20 @@ class AuthTests: XCTestCase { // RTC8a4 func test__145__JWT_and_realtime__when_using_authUrl__when_the_server_sends_and_AUTH_protocol_message__client_reauths_correctly_without_going_through_a_disconnection() throws { - let keys = try getKeys() + let test = Test() + let keys = try getKeys(for: test) // The server sends an AUTH protocol message 30 seconds before a token expires // We create a token that lasts 35 seconds, so there's room to receive the AUTH message let tokenDuration = 35.0 - let options = try createAuthUrlTestsOptions() + let options = try createAuthUrlTestsOptions(for: test) options.authParams = [URLQueryItem]() options.authParams?.append(URLQueryItem(name: "keyName", value: keys["keyName"])) options.authParams?.append(URLQueryItem(name: "keySecret", value: keys["keySecret"])) options.authParams?.append(URLQueryItem(name: "expiresIn", value: String(UInt(tokenDuration)))) options.autoConnect = false // Prevent auto connection so we can set the transport proxy - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -4094,11 +4209,12 @@ class AuthTests: XCTestCase { // RSA8g func skipped__test__146__JWT_and_realtime__when_using_authCallback__with_valid_credentials__pulls_stats_successfully() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { _, completion in let token: ARTTokenDetails do { - token = .init(token: try getJWTToken()!) + token = .init(token: try getJWTToken(for: test)!) } catch { XCTFail("Failed to get JWT: \(error)") completion(nil, error) @@ -4118,11 +4234,12 @@ class AuthTests: XCTestCase { } func test__147__JWT_and_realtime__when_using_authCallback__with_invalid_credentials__fails_to_connect() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { _, completion in let token: ARTTokenDetails do { - token = .init(token: try getJWTToken(invalid: true)!) + token = .init(token: try getJWTToken(for: test, invalid: true)!) } catch { XCTFail("Failed to get JWT: \(error)") completion(nil, error) @@ -4147,14 +4264,15 @@ class AuthTests: XCTestCase { } func test__148__JWT_and_realtime__when_token_expires_and_has_a_means_to_renew__reconnects_using_authCallback_and_obtains_a_new_token() throws { + let test = Test() let tokenDuration = 3.0 - let options = try AblyTests.clientOptions() + let options = try AblyTests.clientOptions(for: test) options.useTokenAuth = true options.autoConnect = false options.authCallback = { _, completion in let token: ARTTokenDetails do { - token = .init(token: try getJWTToken(expiresIn: Int(tokenDuration))!) + token = .init(token: try getJWTToken(for: test, expiresIn: Int(tokenDuration))!) } catch { XCTFail("Failed to get JWT: \(error)") completion(nil, error) @@ -4186,9 +4304,10 @@ class AuthTests: XCTestCase { } func test__149__JWT_and_realtime__when_the_token_request_includes_a_clientId__the_clientId_is_the_same_specified_in_the_JWT_token_request() throws { + let test = Test() let clientId = "JWTClientId" - let options = try AblyTests.clientOptions() - options.tokenDetails = ARTTokenDetails(token: try getJWTToken(clientId: clientId)!) + let options = try AblyTests.clientOptions(for: test) + options.tokenDetails = ARTTokenDetails(token: try getJWTToken(for: test, clientId: clientId)!) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -4202,9 +4321,10 @@ class AuthTests: XCTestCase { } func test__150__JWT_and_realtime__when_the_token_request_includes_subscribe_only_capabilities__fails_to_publish_to_a_channel_with_subscribe_only_capability() throws { + let test = Test() let capability = "{\"\(channelName)\":[\"subscribe\"]}" - let options = try AblyTests.clientOptions() - options.tokenDetails = ARTTokenDetails(token: try getJWTToken(capability: capability)!) + let options = try AblyTests.clientOptions(for: test) + options.tokenDetails = ARTTokenDetails(token: try getJWTToken(for: test, capability: capability)!) // Prevent channel name to be prefixed by test-* options.testOptions.channelNamePrefix = nil let client = ARTRealtime(options: options) @@ -4223,14 +4343,16 @@ class AuthTests: XCTestCase { // RSA11b func test__151__currentTokenDetails__should_hold_a__TokenDetails__instance_in_which_only_the__token__attribute_is_populated_with_that_token_string() throws { - let token = try getTestToken() + let test = Test() + let token = try getTestToken(for: test) let rest = ARTRest(token: token) XCTAssertEqual(rest.auth.tokenDetails?.token, token) } // RSA11c func test__152__currentTokenDetails__should_be_set_with_the_current_token__if_applicable__on_instantiation_and_each_time_it_is_replaced() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) XCTAssertNil(rest.auth.tokenDetails) var authenticatedTokenDetails: ARTTokenDetails? waitUntil(timeout: testTimeout) { done in @@ -4245,15 +4367,17 @@ class AuthTests: XCTestCase { // RSA11d func test__153__currentTokenDetails__should_be_empty_if_there_is_no_current_token() throws { - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) XCTAssertNil(rest.auth.tokenDetails) } // RSC1 RSC1a RSC1c RSA3d func test__154__JWT_and_rest__when_the_JWT_token_embeds_an_Ably_token__pulls_stats_successfully() throws { - let options = try AblyTests.clientOptions() - options.tokenDetails = ARTTokenDetails(token: try getJWTToken(jwtType: "embedded")!) + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.tokenDetails = ARTTokenDetails(token: try getJWTToken(for: test, jwtType: "embedded")!) let client = ARTRest(options: options) waitUntil(timeout: testTimeout) { done in client.stats { _, error in @@ -4264,8 +4388,9 @@ class AuthTests: XCTestCase { } func test__155__JWT_and_rest__when_the_JWT_token_embeds_an_Ably_token_and_it_is_requested_as_encrypted__pulls_stats_successfully() throws { - let options = try AblyTests.clientOptions() - options.tokenDetails = ARTTokenDetails(token: try getJWTToken(jwtType: "embedded", encrypted: 1)!) + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.tokenDetails = ARTTokenDetails(token: try getJWTToken(for: test, jwtType: "embedded", encrypted: 1)!) let client = ARTRest(options: options) waitUntil(timeout: testTimeout) { done in client.stats { _, error in @@ -4278,7 +4403,8 @@ class AuthTests: XCTestCase { // RSA4f, RSA8c func test__156__JWT_and_rest__when_the_JWT_token_is_returned_with_application_jwt_content_type__the_client_successfully_connects_and_pulls_stats() throws { - let client = try jwtContentTypeTestsSetupDependencies() + let test = Test() + let client = try jwtContentTypeTestsSetupDependencies(for: test) waitUntil(timeout: testTimeout) { done in client.stats { _, error in @@ -4289,13 +4415,14 @@ class AuthTests: XCTestCase { } func test__157__JWT_and_rest__when_the_JWT_token_is_returned_with_application_jwt_content_type__the_client_can_request_a_new_token_to_initilize_another_client_that_connects_and_pulls_stats() throws { - let client = try jwtContentTypeTestsSetupDependencies() + let test = Test() + let client = try jwtContentTypeTestsSetupDependencies(for: test) waitUntil(timeout: testTimeout) { done in client.auth.requestToken(nil, with: nil, callback: { tokenDetails, error in let newClientOptions: ARTClientOptions do { - newClientOptions = try AblyTests.clientOptions() + newClientOptions = try AblyTests.clientOptions(for: test) } catch { XCTFail("Got unexpected error when creating client options: \(error.localizedDescription)") done() @@ -4313,17 +4440,19 @@ class AuthTests: XCTestCase { // https://github.com/ably/ably-cocoa/issues/849 func test__001__should_not_force_token_auth_when_clientId_is_set() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "foo" XCTAssertTrue(options.isBasicAuth()) } // https://github.com/ably/ably-cocoa/issues/1093 func test__002__should_accept_authURL_response_with_timestamp_argument_as_string() throws { + let test = Test() var originalTokenRequest: ARTTokenRequest! - let tmpRest = ARTRest(options: try AblyTests.commonAppSetup()) + let tmpRest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) waitUntil(timeout: testTimeout) { done in let tokenParams = ARTTokenParams() tokenParams.clientId = "john" @@ -4342,7 +4471,7 @@ class AuthTests: XCTestCase { {"keyName":"\(originalTokenRequest.keyName)","timestamp":"\(String(dateToMilliseconds(originalTokenRequest.timestamp))))","clientId":"\(originalTokenRequest.clientId!)","nonce":"\(originalTokenRequest.nonce)","mac":"\(originalTokenRequest.mac)","ttl":"\(String(originalTokenRequest.ttl!.intValue * 1000)))","capability":"\(originalTokenRequest.capability!.replace("\"", withString: "\\\""))"} """ - let options = try AblyTests.clientOptions() + let options = try AblyTests.clientOptions(for: test) options.authUrl = URL(string: "http://auth-test.ably.cocoa") let rest = ARTRest(options: options) @@ -4350,7 +4479,7 @@ class AuthTests: XCTestCase { #if TARGET_OS_IOS XCTAssertNil(rest.device.clientId) #endif - let testHttpExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHttpExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHttpExecutor let channel = rest.channels.get(channelName) diff --git a/Test/Tests/DeltaCodecTests.swift b/Test/Tests/DeltaCodecTests.swift index de0b3b02a..746ee1f45 100644 --- a/Test/Tests/DeltaCodecTests.swift +++ b/Test/Tests/DeltaCodecTests.swift @@ -21,7 +21,8 @@ class DeltaCodecTests: XCTestCase { // RTL19 func test__001__DeltaCodec__decoding__should_decode_vcdiff_encoded_messages() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } @@ -31,7 +32,7 @@ class DeltaCodecTests: XCTestCase { "delta": "vcdiff", ] - let channel = client.channels.get(uniqueChannelName(), options: channelOptions) + let channel = client.channels.get(uniqueChannelName(for: test), options: channelOptions) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -74,12 +75,13 @@ class DeltaCodecTests: XCTestCase { // RTL20 func test__002__DeltaCodec__decoding__should_fail_and_recover_when_the_vcdiff_messages_are_out_of_order() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } let channelOptions = ARTRealtimeChannelOptions() channelOptions.params = ["delta": "vcdiff"] - let channel = client.channels.get(uniqueChannelName(), options: channelOptions) + let channel = client.channels.get(uniqueChannelName(for: test), options: channelOptions) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -133,12 +135,13 @@ class DeltaCodecTests: XCTestCase { // RTL18 func test__003__DeltaCodec__decoding__should_recover_when_the_vcdiff_message_decoding_fails() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } let channelOptions = ARTRealtimeChannelOptions() channelOptions.params = ["delta": "vcdiff"] - let channel = client.channels.get(uniqueChannelName(), options: channelOptions) + let channel = client.channels.get(uniqueChannelName(for: test), options: channelOptions) waitUntil(timeout: testTimeout) { done in channel.attach { error in diff --git a/Test/Tests/ObjectLifetimesTests.swift b/Test/Tests/ObjectLifetimesTests.swift index ea983e977..f72f1a9a9 100644 --- a/Test/Tests/ObjectLifetimesTests.swift +++ b/Test/Tests/ObjectLifetimesTests.swift @@ -77,7 +77,8 @@ class ObjectLifetimesTests: XCTestCase { } func test__004__ObjectLifetimes__when_user_leaves_Realtime_open__still_works() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var client: ARTRealtime? = ARTRealtime(options: options) @@ -85,7 +86,7 @@ class ObjectLifetimesTests: XCTestCase { XCTAssertNotNil(weakClient) defer { client?.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) waitUntil(timeout: testTimeout) { done in client!.channels.get(channelName).subscribe(attachCallback: { _ in client = nil @@ -98,12 +99,13 @@ class ObjectLifetimesTests: XCTestCase { } func test__005__ObjectLifetimes__when_Realtime_is_closed_and_user_loses_its_reference__channels_don_t_leak() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var client: ARTRealtime? = ARTRealtime(options: options) weak var weakClient = client!.internal - var channel: ARTRealtimeChannel? = client!.channels.get(uniqueChannelName()) + var channel: ARTRealtimeChannel? = client!.channels.get(uniqueChannelName(for: test)) weak var weakChannel = channel!.internal waitUntil(timeout: testTimeout) { done in @@ -121,7 +123,7 @@ class ObjectLifetimesTests: XCTestCase { } waitUntil(timeout: testTimeout) { done in - AblyTests.queue.async { + options.internalDispatchQueue.async { client = nil // should enqueue a release channel = nil // should enqueue a release done() @@ -129,7 +131,7 @@ class ObjectLifetimesTests: XCTestCase { } waitUntil(timeout: testTimeout) { done in - AblyTests.queue.async { + options.internalDispatchQueue.async { XCTAssertNil(weakClient) XCTAssertNil(weakChannel) done() diff --git a/Test/Tests/PushAdminTests.swift b/Test/Tests/PushAdminTests.swift index 7a153f8bf..0c25d1267 100644 --- a/Test/Tests/PushAdminTests.swift +++ b/Test/Tests/PushAdminTests.swift @@ -103,14 +103,15 @@ class PushAdminTests: XCTestCase { override class func setUp() { super.setUp() + let test = Test() // a slight abuse of the meaning of Test, but we only have one instance of +setUp so doesn’t seem worth worrying over let options: ARTClientOptions do { - options = try AblyTests.commonAppSetup() + options = try AblyTests.commonAppSetup(for: test) } catch { fatalError("commonAppSetup failed: \(error)") } options.pushFullWait = true - options.dispatchQueue = AblyTests.createUserQueue() + options.dispatchQueue = AblyTests.createUserQueue(for: test) let rest = ARTRest(options: options) rest.internal.storage = MockDeviceStorage() let group = DispatchGroup() @@ -136,13 +137,14 @@ class PushAdminTests: XCTestCase { } override class func tearDown() { + let test = Test() // a slight abuse of the meaning of Test, but we only have one instance of +tearDown so doesn’t seem worth worrying over let options: ARTClientOptions do { - options = try AblyTests.commonAppSetup() + options = try AblyTests.commonAppSetup(for: test) } catch { fatalError("commonAppSetup failed: \(error)") } - options.dispatchQueue = AblyTests.createUserQueue() + options.dispatchQueue = AblyTests.createUserQueue(for: test) let rest = ARTRest(options: options) rest.internal.storage = MockDeviceStorage() let group = DispatchGroup() @@ -221,10 +223,11 @@ class PushAdminTests: XCTestCase { } func skipped__test__002__publish__should_publish_successfully() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } - let channel = realtime.channels.get("pushenabled:\(uniqueChannelName())") // works with pure uniqueChannelName() as well + let channel = realtime.channels.get("pushenabled:\(uniqueChannelName(for: test))") // works with pure uniqueChannelName(for: test) as well let publishObject = ["transportType": "ablyChannel", "channel": channel.name, "ablyKey": options.key!, @@ -254,9 +257,10 @@ class PushAdminTests: XCTestCase { } func skipped__test__003__publish__should_fail_with_a_bad_recipient() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } - let channel = realtime.channels.get("pushenabled:\(uniqueChannelName())") // works with pure uniqueChannelName() as well + let channel = realtime.channels.get("pushenabled:\(uniqueChannelName(for: test))") // works with pure uniqueChannelName(for: test) as well waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -281,9 +285,10 @@ class PushAdminTests: XCTestCase { } func skipped__test__004__publish__should_fail_with_an_empty_recipient() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } - let channel = realtime.channels.get("pushenabled:\(uniqueChannelName())") // works with pure uniqueChannelName() as well + let channel = realtime.channels.get("pushenabled:\(uniqueChannelName(for: test))") // works with pure uniqueChannelName(for: test) as well waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -307,9 +312,10 @@ class PushAdminTests: XCTestCase { } func test__005__publish__should_fail_with_an_empty_payload() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } - let channel = realtime.channels.get("pushenabled:\(uniqueChannelName())") // works with pure uniqueChannelName() as well + let channel = realtime.channels.get("pushenabled:\(uniqueChannelName(for: test))") // works with pure uniqueChannelName(for: test) as well waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -335,7 +341,8 @@ class PushAdminTests: XCTestCase { // RSH1b1 func test__006__Device_Registrations__get__should_return_a_device() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.push.admin.deviceRegistrations.get("testDeviceDetails") { device, error in @@ -350,7 +357,8 @@ class PushAdminTests: XCTestCase { } func test__007__Device_Registrations__get__should_not_return_a_device_if_it_doesnt_exist() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.push.admin.deviceRegistrations.get("madeup") { device, error in @@ -366,7 +374,8 @@ class PushAdminTests: XCTestCase { } func test__008__Device_Registrations__get__push_device_authentication__should_include_DeviceIdentityToken_HTTP_header() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } realtime.internal.rest.httpExecutor = mockHttpExecutor @@ -395,7 +404,8 @@ class PushAdminTests: XCTestCase { } func test__009__Device_Registrations__get__push_device_authentication__should_include_DeviceSecret_HTTP_header() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } realtime.internal.rest.httpExecutor = mockHttpExecutor @@ -414,7 +424,8 @@ class PushAdminTests: XCTestCase { // RSH1b2 func test__010__Device_Registrations__list__should_list_devices_by_id() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.push.admin.deviceRegistrations.list(["deviceId": "testDeviceDetails"]) { result, error in @@ -429,7 +440,8 @@ class PushAdminTests: XCTestCase { } func test__011__Device_Registrations__list__should_list_devices_by_client_id() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.push.admin.deviceRegistrations.list(["clientId": "clientA"]) { result, error in @@ -444,7 +456,8 @@ class PushAdminTests: XCTestCase { } func test__012__Device_Registrations__list__should_list_devices_sorted() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.push.admin.deviceRegistrations.list(["direction": "forwards"]) { result, error in @@ -459,7 +472,8 @@ class PushAdminTests: XCTestCase { } func test__013__Device_Registrations__list__should_return_an_empty_list_when_id_does_not_exist() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.push.admin.deviceRegistrations.list(["deviceId": "madeup"]) { result, error in @@ -476,7 +490,8 @@ class PushAdminTests: XCTestCase { // RSH1b4 func test__014__Device_Registrations__remove__should_unregister_a_device() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.pushFullWait = true let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -498,7 +513,8 @@ class PushAdminTests: XCTestCase { // RSH1b3 func test__015__Device_Registrations__save__should_register_a_device() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.pushFullWait = true let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -518,7 +534,8 @@ class PushAdminTests: XCTestCase { } func test__016__Device_Registrations__save__push_device_authentication__should_include_DeviceIdentityToken_HTTP_header() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.pushFullWait = true let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -551,7 +568,8 @@ class PushAdminTests: XCTestCase { } func test__017__Device_Registrations__save__push_device_authentication__should_include_DeviceSecret_HTTP_header() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.pushFullWait = true let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -574,7 +592,8 @@ class PushAdminTests: XCTestCase { // RSH1b5 func test__018__Device_Registrations__removeWhere__should_unregister_a_device() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.pushFullWait = true let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -650,10 +669,11 @@ class PushAdminTests: XCTestCase { // RSH1c3 func test__019__Channel_Subscriptions__save__should_add_a_subscription() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } - let testProxyHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testProxyHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) realtime.internal.rest.httpExecutor = testProxyHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -671,7 +691,8 @@ class PushAdminTests: XCTestCase { } func test__020__Channel_Subscriptions__save__should_update_a_subscription() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } let updateSubscription = ARTPushChannelSubscription(clientId: subscription.clientId!, channel: "pushenabled:foo") waitUntil(timeout: testTimeout) { done in @@ -683,7 +704,8 @@ class PushAdminTests: XCTestCase { } func test__021__Channel_Subscriptions__save__should_fail_with_a_bad_recipient() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } let invalidSubscription = ARTPushChannelSubscription(deviceId: "madeup", channel: "pushenabled:foo") waitUntil(timeout: testTimeout) { done in @@ -699,7 +721,8 @@ class PushAdminTests: XCTestCase { } func test__022__Channel_Subscriptions__save__push_device_authentication__should_include_DeviceIdentityToken_HTTP_header() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } realtime.internal.rest.httpExecutor = mockHttpExecutor @@ -731,7 +754,8 @@ class PushAdminTests: XCTestCase { } func test__023__Channel_Subscriptions__save__push_device_authentication__should_include_DeviceSecret_HTTP_header() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } realtime.internal.rest.httpExecutor = mockHttpExecutor @@ -753,7 +777,8 @@ class PushAdminTests: XCTestCase { // RSH1c1 func test__024__Channel_Subscriptions__list__should_receive_a_list_of_subscriptions() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.push.admin.channelSubscriptions.save(subscription) { error in @@ -773,7 +798,8 @@ class PushAdminTests: XCTestCase { // RSH1c2 func test__025__Channel_Subscriptions__listChannels__should_receive_a_list_of_subscriptions() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.push.admin.channelSubscriptions.listChannels { result, error in @@ -790,10 +816,11 @@ class PushAdminTests: XCTestCase { // RSH1c4 func test__026__Channel_Subscriptions__remove__should_remove_a_subscription() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } - let testProxyHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testProxyHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) realtime.internal.rest.httpExecutor = testProxyHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -822,7 +849,8 @@ class PushAdminTests: XCTestCase { } func test__027__Channel_Subscriptions__remove__push_device_authentication__should_include_DeviceIdentityToken_HTTP_header() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } realtime.internal.rest.httpExecutor = mockHttpExecutor @@ -854,7 +882,8 @@ class PushAdminTests: XCTestCase { } func test__028__Channel_Subscriptions__remove__push_device_authentication__should_include_DeviceSecret_HTTP_header() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } realtime.internal.rest.httpExecutor = mockHttpExecutor @@ -876,7 +905,8 @@ class PushAdminTests: XCTestCase { // RSH1c5 func test__029__Channel_Subscriptions__removeWhere__should_remove_by_cliendId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.pushFullWait = true let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -931,7 +961,8 @@ class PushAdminTests: XCTestCase { } func test__030__Channel_Subscriptions__removeWhere__should_remove_by_cliendId_and_channel() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.pushFullWait = true let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -976,7 +1007,8 @@ class PushAdminTests: XCTestCase { } func test__031__Channel_Subscriptions__removeWhere__should_remove_by_deviceId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.pushFullWait = true let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } @@ -1021,7 +1053,8 @@ class PushAdminTests: XCTestCase { } func test__032__Channel_Subscriptions__removeWhere__should_not_remove_by_inexistent_deviceId() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } let params = [ diff --git a/Test/Tests/PushChannelTests.swift b/Test/Tests/PushChannelTests.swift index 97ff203f4..d36b4daee 100644 --- a/Test/Tests/PushChannelTests.swift +++ b/Test/Tests/PushChannelTests.swift @@ -2,32 +2,23 @@ import Ably import Nimble import XCTest -private var rest: ARTRest! -private var mockHttpExecutor: MockHTTPExecutor! - class PushChannelTests: XCTestCase { - // XCTest invokes this method before executing the first test in the test suite. We use it to ensure that the global variables are initialized at the same moment, and in the same order, as they would have been when we used the Quick testing framework. - override class var defaultTestSuite: XCTestSuite { - _ = rest - _ = mockHttpExecutor - - return super.defaultTestSuite - } - - private var userQueue: DispatchQueue! - - override func setUp() { - super.setUp() - - mockHttpExecutor = MockHTTPExecutor() - let options = ARTClientOptions(key: "xxxx:xxxx") - userQueue = AblyTests.createUserQueue() - options.dispatchQueue = userQueue - options.internalDispatchQueue = AblyTests.queue - rest = ARTRest(options: options) - rest.internal.options.clientId = "tester" - rest.internal.httpExecutor = mockHttpExecutor - rest.internal.resetDeviceSingleton() + private struct TestEnvironment { + var rest: ARTRest + var mockHttpExecutor: MockHTTPExecutor + var userQueue: DispatchQueue + + init(test: Test) { + mockHttpExecutor = MockHTTPExecutor() + let options = ARTClientOptions(key: "xxxx:xxxx") + userQueue = AblyTests.createUserQueue(for: test) + options.dispatchQueue = userQueue + options.internalDispatchQueue = AblyTests.createInternalQueue(for: test) + rest = ARTRest(options: options) + rest.internal.options.clientId = "tester" + rest.internal.httpExecutor = mockHttpExecutor + rest.internal.resetDeviceSingleton() + } } // RSH7 @@ -36,13 +27,16 @@ class PushChannelTests: XCTestCase { // RSH7a1 func test__001__Push_Channel__subscribeDevice__should_fail_if_the_LocalDevice_doesn_t_have_an_deviceIdentityToken() { - waitUntil(timeout: testTimeout) { [userQueue] done in - rest.channels.get(uniqueChannelName()).push.subscribeDevice { error in + let test = Test() + let testEnvironment = TestEnvironment(test: test) + + waitUntil(timeout: testTimeout) { done in + testEnvironment.rest.channels.get(uniqueChannelName(for: test)).push.subscribeDevice { error in guard let error = error else { fail("Error is nil"); done(); return } expect(error.message).to(contain("cannot use device before device activation has finished")) - XCTAssertTrue(AblyTests.currentQueueLabel() == userQueue!.label) + XCTAssertTrue(AblyTests.currentQueueLabel() == testEnvironment.userQueue.label) done() } } @@ -50,11 +44,15 @@ class PushChannelTests: XCTestCase { // RSH7a2, RSH7a3 func test__002__Push_Channel__subscribeDevice__should_do_a_POST_request_to__push_channelSubscriptions_and_include_device_authentication() throws { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let rest = testEnvironment.rest + let testIdentityTokenDetails = ARTDeviceIdentityTokenDetails(token: "xxxx-xxxx-xxx", issued: Date(), expires: Date.distantFuture, capability: "", clientId: "") rest.device.setAndPersistIdentityTokenDetails(testIdentityTokenDetails) defer { rest.device.setAndPersistIdentityTokenDetails(nil) } - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.push.subscribeDevice { error in XCTAssertNil(error) @@ -62,7 +60,7 @@ class PushChannelTests: XCTestCase { } } - let request = try XCTUnwrap(mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") + let request = try XCTUnwrap(testEnvironment.mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") let url = try XCTUnwrap(request.url, "No request url found") let rawBody = try XCTUnwrap(request.httpBody, "should have a body") let decodedBody = try XCTUnwrap(try rest.internal.defaultEncoder.decode(rawBody), "Decode request body failed") @@ -82,6 +80,10 @@ class PushChannelTests: XCTestCase { // RSH7b1 func test__003__Push_Channel__subscribeClient__should_fail_if_the_LocalDevice_doesn_t_have_a_clientId() { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let rest = testEnvironment.rest + let testIdentityTokenDetails = ARTDeviceIdentityTokenDetails(token: "xxxx-xxxx-xxx", issued: Date(), expires: Date.distantFuture, capability: "", clientId: "") rest.device.setAndPersistIdentityTokenDetails(testIdentityTokenDetails) defer { rest.device.setAndPersistIdentityTokenDetails(nil) } @@ -90,13 +92,13 @@ class PushChannelTests: XCTestCase { rest.device.clientId = nil defer { rest.device.clientId = originalClientId } - waitUntil(timeout: testTimeout) { [userQueue] done in - rest.channels.get(uniqueChannelName()).push.subscribeClient { error in + waitUntil(timeout: testTimeout) { done in + rest.channels.get(uniqueChannelName(for: test)).push.subscribeClient { error in guard let error = error else { fail("Error is nil"); done(); return } expect(error.message).to(contain("null client ID")) - XCTAssertTrue(AblyTests.currentQueueLabel() == userQueue!.label) + XCTAssertTrue(AblyTests.currentQueueLabel() == testEnvironment.userQueue.label) done() } } @@ -104,11 +106,15 @@ class PushChannelTests: XCTestCase { // RSH7b2 func test__004__Push_Channel__subscribeClient__should_do_a_POST_request_to__push_channelSubscriptions() throws { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let rest = testEnvironment.rest + let testIdentityTokenDetails = ARTDeviceIdentityTokenDetails(token: "xxxx-xxxx-xxx", issued: Date(), expires: Date.distantFuture, capability: "", clientId: "") rest.device.setAndPersistIdentityTokenDetails(testIdentityTokenDetails) defer { rest.device.setAndPersistIdentityTokenDetails(nil) } - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.push.subscribeClient { error in XCTAssertNil(error) @@ -116,7 +122,7 @@ class PushChannelTests: XCTestCase { } } - let request = try XCTUnwrap(mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") + let request = try XCTUnwrap(testEnvironment.mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") let url = try XCTUnwrap(request.url, "No request url found") let rawBody = try XCTUnwrap(request.httpBody, "should have a body") let decodedBody = try XCTUnwrap(try rest.internal.defaultEncoder.decode(rawBody), "Decode request body failed") @@ -135,13 +141,16 @@ class PushChannelTests: XCTestCase { // RSH7c1 func test__005__Push_Channel__unsubscribeDevice__should_fail_if_the_LocalDevice_doesn_t_have_a_deviceIdentityToken() { - waitUntil(timeout: testTimeout) { [userQueue] done in - rest.channels.get(uniqueChannelName()).push.unsubscribeDevice { error in + let test = Test() + let testEnvironment = TestEnvironment(test: test) + + waitUntil(timeout: testTimeout) { done in + testEnvironment.rest.channels.get(uniqueChannelName(for: test)).push.unsubscribeDevice { error in guard let error = error else { fail("Error is nil"); done(); return } expect(error.message).to(contain("cannot use device before device activation has finished")) - XCTAssertTrue(AblyTests.currentQueueLabel() == userQueue!.label) + XCTAssertTrue(AblyTests.currentQueueLabel() == testEnvironment.userQueue.label) done() } } @@ -149,11 +158,15 @@ class PushChannelTests: XCTestCase { // RSH7c2, RSH7c3 func test__006__Push_Channel__unsubscribeDevice__should_do_a_DELETE_request_to__push_channelSubscriptions_and_include_device_authentication() throws { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let rest = testEnvironment.rest + let testIdentityTokenDetails = ARTDeviceIdentityTokenDetails(token: "xxxx-xxxx-xxx", issued: Date(), expires: Date.distantFuture, capability: "", clientId: "") rest.device.setAndPersistIdentityTokenDetails(testIdentityTokenDetails) defer { rest.device.setAndPersistIdentityTokenDetails(nil) } - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.push.unsubscribeDevice { error in XCTAssertNil(error) @@ -161,7 +174,7 @@ class PushChannelTests: XCTestCase { } } - let request = try XCTUnwrap(mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") + let request = try XCTUnwrap(testEnvironment.mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") let url = try XCTUnwrap(request.url, "No request url found") let query = try XCTUnwrap(url.query, "should have a query") @@ -179,6 +192,10 @@ class PushChannelTests: XCTestCase { // RSH7d1 func test__007__Push_Channel__unsubscribeClient__should_fail_if_the_LocalDevice_doesn_t_have_a_clientId() { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let rest = testEnvironment.rest + let testIdentityTokenDetails = ARTDeviceIdentityTokenDetails(token: "xxxx-xxxx-xxx", issued: Date(), expires: Date.distantFuture, capability: "", clientId: "") rest.device.setAndPersistIdentityTokenDetails(testIdentityTokenDetails) defer { rest.device.setAndPersistIdentityTokenDetails(nil) } @@ -187,13 +204,13 @@ class PushChannelTests: XCTestCase { rest.device.clientId = nil defer { rest.device.clientId = originalClientId } - waitUntil(timeout: testTimeout) { [userQueue] done in - rest.channels.get(uniqueChannelName()).push.unsubscribeClient { error in + waitUntil(timeout: testTimeout) { done in + rest.channels.get(uniqueChannelName(for: test)).push.unsubscribeClient { error in guard let error = error else { fail("Error is nil"); done(); return } expect(error.message).to(contain("null client ID")) - XCTAssertTrue(AblyTests.currentQueueLabel() == userQueue!.label) + XCTAssertTrue(AblyTests.currentQueueLabel() == testEnvironment.userQueue.label) done() } } @@ -201,11 +218,15 @@ class PushChannelTests: XCTestCase { // RSH7d2 func test__008__Push_Channel__unsubscribeClient__should_do_a_DELETE_request_to__push_channelSubscriptions() throws { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let rest = testEnvironment.rest + let testIdentityTokenDetails = ARTDeviceIdentityTokenDetails(token: "xxxx-xxxx-xxx", issued: Date(), expires: Date.distantFuture, capability: "", clientId: "") rest.device.setAndPersistIdentityTokenDetails(testIdentityTokenDetails) defer { rest.device.setAndPersistIdentityTokenDetails(nil) } - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.push.unsubscribeClient { error in XCTAssertNil(error) @@ -213,7 +234,7 @@ class PushChannelTests: XCTestCase { } } - let request = try XCTUnwrap(mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") + let request = try XCTUnwrap(testEnvironment.mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") let url = try XCTUnwrap(request.url, "No request url found") let query = try XCTUnwrap(url.query, "should have a query") @@ -229,11 +250,15 @@ class PushChannelTests: XCTestCase { // RSH7e func test__009__Push_Channel__listSubscriptions__should_return_a_paginated_result_with_PushChannelSubscription_filtered_by_channel_and_device() throws { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let rest = testEnvironment.rest + let params = [ "deviceId": "111", "channel": "aaa", ] - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in try? channel.push.listSubscriptions(params) { result, error in XCTAssertNil(error) @@ -242,7 +267,7 @@ class PushChannelTests: XCTestCase { } } - let request = try XCTUnwrap(mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") + let request = try XCTUnwrap(testEnvironment.mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") let url = try XCTUnwrap(request.url, "No request url found") let query = try XCTUnwrap(url.query, "should have a query") @@ -254,11 +279,15 @@ class PushChannelTests: XCTestCase { } func test__010__Push_Channel__listSubscriptions__should_return_a_paginated_result_with_PushChannelSubscription_filtered_by_channel_and_client() throws { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let rest = testEnvironment.rest + let params = [ "clientId": "tester", "channel": "aaa", ] - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in try? channel.push.listSubscriptions(params) { result, error in XCTAssertNil(error) @@ -267,7 +296,7 @@ class PushChannelTests: XCTestCase { } } - let request = try XCTUnwrap(mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") + let request = try XCTUnwrap(testEnvironment.mockHttpExecutor.requests.first, "should have a \"/push/channelSubscriptions\" request") let url = try XCTUnwrap(request.url, "No request url found") let query = try XCTUnwrap(url.query, "should have a query") @@ -279,25 +308,34 @@ class PushChannelTests: XCTestCase { } func test__011__Push_Channel__listSubscriptions__should_not_accept_null_deviceId_and_null_clientId() { - let channel = rest.channels.get(uniqueChannelName()) + let test = Test() + let testEnvironment = TestEnvironment(test: test) + + let channel = testEnvironment.rest.channels.get(uniqueChannelName(for: test)) expect { try channel.push.listSubscriptions([:]) { _, _ in } }.to(throwError { (error: NSError) in XCTAssertEqual(error.code, ARTDataQueryError.missingRequiredFields.rawValue) }) } func test__012__Push_Channel__listSubscriptions__should_not_accept_both_deviceId_and_clientId_params_at_the_same_time() { + let test = Test() + let testEnvironment = TestEnvironment(test: test) + let params = [ "deviceId": "x", "clientId": "y", ] - let channel = rest.channels.get(uniqueChannelName()) + let channel = testEnvironment.rest.channels.get(uniqueChannelName(for: test)) expect { try channel.push.listSubscriptions(params) { _, _ in } }.to(throwError { (error: NSError) in XCTAssertEqual(error.code, ARTDataQueryError.invalidParameters.rawValue) }) } func test__013__Push_Channel__listSubscriptions__should_return_a_paginated_result_with_PushChannelSubscription() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let _ = TestEnvironment(test: test) + + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "tester" // Prevent channel name to be prefixed by test-* options.testOptions.channelNamePrefix = nil @@ -309,7 +347,7 @@ class PushChannelTests: XCTestCase { rest.device.setAndPersistIdentityTokenDetails(testIdentityTokenDetails) defer { rest.device.setAndPersistIdentityTokenDetails(nil) } - let channel = rest.channels.get("pushenabled:\(uniqueChannelName())") + let channel = rest.channels.get("pushenabled:\(uniqueChannelName(for: test))") waitUntil(timeout: testTimeout) { done in channel.push.subscribeClient { error in XCTAssertNil(error) diff --git a/Test/Tests/PushTests.swift b/Test/Tests/PushTests.swift index 228c00d7e..3bb1494ef 100644 --- a/Test/Tests/PushTests.swift +++ b/Test/Tests/PushTests.swift @@ -106,11 +106,12 @@ class PushTests: XCTestCase { // https://github.com/ably/ably-cocoa/issues/877 func test__005__activation__should_update_LocalDevice_clientId_when_it_s_null_with_auth_clientId() throws { + let test = Test() let expectedClientId = "foo" - let options = try AblyTests.clientOptions() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { _, completion in - getTestTokenDetails(clientId: expectedClientId, completion: { result in + getTestTokenDetails(for: test, clientId: expectedClientId, completion: { result in guard case .success(let tokenDetails) = result else { fail("TokenDetails are missing"); return } @@ -256,7 +257,7 @@ class PushTests: XCTestCase { func test__013__LocalDevice__when_getting_a_client_ID_from_CONNECTED_message__new_clientID_is_set() { let options = ARTClientOptions(key: "fake:key") options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let realtime = ARTRealtime(options: options) XCTAssertNil(realtime.device.clientId) @@ -380,7 +381,8 @@ class PushTests: XCTestCase { } func test__014__Registerer_Delegate_option__a_successful_activation_should_call_the_correct_registerer_delegate_method() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.key = "xxxx:xxxx" let pushRegistererDelegate = StateMachineDelegate() options.pushRegistererDelegate = pushRegistererDelegate @@ -398,7 +400,8 @@ class PushTests: XCTestCase { } func test__015__Registerer_Delegate_option__registerer_delegate_should_not_hold_a_strong_instance_reference() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.key = "xxxx:xxxx" var pushRegistererDelegate: StateMachineDelegate? = StateMachineDelegate() options.pushRegistererDelegate = pushRegistererDelegate diff --git a/Test/Tests/ReadmeExamplesTests.swift b/Test/Tests/ReadmeExamplesTests.swift index baff9bcd4..b077b98bb 100644 --- a/Test/Tests/ReadmeExamplesTests.swift +++ b/Test/Tests/ReadmeExamplesTests.swift @@ -17,7 +17,8 @@ class ReadmeExamplesTests: XCTestCase { } func test__003__testListenToConnectionStateChanges() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRealtime(options: options) defer { client.close() } @@ -42,11 +43,12 @@ class ReadmeExamplesTests: XCTestCase { } func test__005__testSubscribeAndPublishingToChannel() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRealtime(options: options) defer { client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.subscribe { message in print(message.name as Any) @@ -62,11 +64,12 @@ class ReadmeExamplesTests: XCTestCase { } func test__006__testQueryingTheHistory() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRealtime(options: options) defer { client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.history { messagesPage, _ in let messagesPage = messagesPage! @@ -82,14 +85,15 @@ class ReadmeExamplesTests: XCTestCase { } func test__007__testPresenceOnAChannel() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) options.clientId = "foo" let client = ARTRealtime(options: options) defer { client.close() } client.connection.on { stateChange in if stateChange.current == .connected { - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.presence.enter("john.doe") { _ in channel.presence.get { _, _ in @@ -101,11 +105,12 @@ class ReadmeExamplesTests: XCTestCase { } func test__008__testQueryingThePresenceHistory() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRealtime(options: options) defer { client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.presence.history { presencePage, _ in let presencePage = presencePage! @@ -121,23 +126,26 @@ class ReadmeExamplesTests: XCTestCase { } func test__009__testMakeRestClientAndChannel() { + let test = Test() let client = ARTRest(key: "xxxx:xxxx") - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) _ = channel } func test__010__testRestPublishMessage() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.publish("myEvent", data: "Hello!") } func test__011__testRestQueryingTheHistory() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.history { messagesPage, _ in let messagesPage = messagesPage! @@ -151,9 +159,10 @@ class ReadmeExamplesTests: XCTestCase { } func test__012__testRestPresenceOnAChannel() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.presence.get { membersPage, _ in let membersPage = membersPage! @@ -167,9 +176,10 @@ class ReadmeExamplesTests: XCTestCase { } func test__013__testRestQueryingThePresenceHistory() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.presence.history { presencePage, _ in let presencePage = presencePage! @@ -183,7 +193,8 @@ class ReadmeExamplesTests: XCTestCase { } func test__014__testGenerateToken() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) client.auth.requestToken(nil, with: nil) { tokenDetails, _ in let tokenDetails = tokenDetails! @@ -194,8 +205,9 @@ class ReadmeExamplesTests: XCTestCase { } func test__015__testFetchingStats() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - client.channels.get(uniqueChannelName()).publish("foo", data: "bar") { _ in + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + client.channels.get(uniqueChannelName(for: test)).publish("foo", data: "bar") { _ in client.stats { statsPage, _ in let statsPage = statsPage! print(statsPage.items.first as Any) @@ -207,7 +219,8 @@ class ReadmeExamplesTests: XCTestCase { } func test__016__testFetchingTime() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) client.time { time, _ in print(time as Any) // 2016-02-09 03:59:24 +0000 diff --git a/Test/Tests/RealtimeClientChannelTests.swift b/Test/Tests/RealtimeClientChannelTests.swift index 61397e4b0..3e554619b 100644 --- a/Test/Tests/RealtimeClientChannelTests.swift +++ b/Test/Tests/RealtimeClientChannelTests.swift @@ -25,9 +25,9 @@ private var rtl6c4TestsChannel: ARTRealtimeChannel! private let previousConnectionStateTtl = ARTDefault.connectionStateTtl() -private func setupDependencies() throws { +private func setupDependencies(for test: Test) throws { if options == nil { - options = try AblyTests.commonAppSetup() + options = try AblyTests.commonAppSetup(for: test) options.suspendedRetryTimeout = 0.3 options.autoConnect = false } @@ -44,11 +44,11 @@ private func rtl6c4TestsPublish(_ done: @escaping () -> Void) { This test makes a deep assumption about the content of these two files, specifically the format of the first message in the items array. */ -private func testHandlesDecodingErrorInFixture(_ cryptoFixtureFileName: String, channelName: String) throws { - let options = try AblyTests.commonAppSetup() +private func testHandlesDecodingErrorInFixture(_ cryptoFixtureFileName: String, for test: Test, channelName: String) throws { + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.logHandler = ARTLog(capturingOutput: true) - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -107,13 +107,13 @@ private func testHandlesDecodingErrorInFixture(_ cryptoFixtureFileName: String, } } -private func testWithUntilAttach(_ untilAttach: Bool, channelName: String) throws { - let options = try AblyTests.commonAppSetup() +private func testWithUntilAttach(_ untilAttach: Bool, for test: Test, channelName: String) throws { + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } let channel = client.channels.get(channelName) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.rest.httpExecutor = testHTTPExecutor let query = ARTRealtimeHistoryQuery() @@ -156,11 +156,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL1 func skipped__test__001__Channel__should_process_all_incoming_messages_and_presence_messages_as_soon_as_a_Channel_becomes_attached() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client1 = AblyTests.newRealtime(options).client defer { client1.dispose(); client1.close() } - let roomName = uniqueChannelName(prefix: "room") + let roomName = uniqueChannelName(for: test, prefix: "room") let channel1 = client1.channels.get(roomName) @@ -225,10 +226,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2a func test__003__Channel__EventEmitter__channel_states_and_events__should_implement_the_EventEmitter_and_emit_events_for_state_changes() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(channel.internal.statesEventEmitter).to(beAKindOf(ARTEventEmitter.self)) var channelOnMethodCalled = false @@ -291,11 +293,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2a func test__004__Channel__EventEmitter__channel_states_and_events__should_implement_the_EventEmitter_and_emit_events_for_FAILED_state_changes() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(capability: "{\"secret\":[\"subscribe\"]}") + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, capability: "{\"secret\":[\"subscribe\"]}") let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.on { stateChange in @@ -323,9 +326,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2a func test__005__Channel__EventEmitter__channel_states_and_events__should_implement_the_EventEmitter_and_emit_events_for_SUSPENDED_state_changes() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -347,9 +351,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2g func test__006__Channel__EventEmitter__channel_states_and_events__can_emit_an_UPDATE_event() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -384,11 +389,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2g + https://github.com/ably/ably-cocoa/issues/1088 func test__007__Channel__EventEmitter__channel_states_and_events__should_not_emit_detached_event_on_an_already_detached_channel() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.logLevel = .debug let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.on { stateChange in XCTAssertNotEqual(stateChange.current, stateChange.previous) @@ -422,10 +428,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2b func test__008__Channel__EventEmitter__channel_states_and_events__state_attribute_should_be_the_current_state_of_the_channel() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) channel.attach() @@ -435,9 +442,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2c func test__009__Channel__EventEmitter__channel_states_and_events__should_contain_an_ErrorInfo_object_with_details_when_an_error_occurs() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let pmError = AblyTests.newErrorProtocolMessage() waitUntil(timeout: testTimeout) { done in @@ -449,7 +458,7 @@ class RealtimeClientChannelTests: XCTestCase { XCTAssertEqual(channel.errorReason, pmError.error) done() } - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(pmError) } } @@ -457,9 +466,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2d func test__010__Channel__EventEmitter__channel_states_and_events__a_ChannelStateChange_is_emitted_as_the_first_argument_for_every_channel_state_change() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.on { stateChange in @@ -482,7 +493,7 @@ class RealtimeClientChannelTests: XCTestCase { XCTAssertEqual(stateChange.previous, ARTRealtimeChannelState.attached) done() } - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(AblyTests.newErrorProtocolMessage()) } } @@ -490,11 +501,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2f func test__011__Channel__EventEmitter__channel_states_and_events__ChannelStateChange_will_contain_a_resumed_boolean_attribute_with_value__true__if_the_bit_flag_RESUMED_was_included() throws { - let options = try AblyTests.commonAppSetup() - options.tokenDetails = try getTestTokenDetails(ttl: 5.0) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.tokenDetails = try getTestTokenDetails(for: test, ttl: 5.0) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.on { stateChange in @@ -528,10 +540,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL2f, TR4i func test__012__Channel__EventEmitter__channel_states_and_events__bit_flag_RESUMED_was_included() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.once(.attached) { stateChange in @@ -564,14 +577,15 @@ class RealtimeClientChannelTests: XCTestCase { // RTL3a func test__017__Channel__connection_state__changes_to_FAILED__ATTACHING_channel_should_transition_to_FAILED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.attached] @@ -595,10 +609,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__018__Channel__connection_state__changes_to_FAILED__ATTACHED_channel_should_transition_to_FAILED() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -619,9 +634,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__019__Channel__connection_state__changes_to_FAILED__channel_being_released_waiting_for_DETACH_shouldn_t_crash__issue__918_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -633,7 +649,7 @@ class RealtimeClientChannelTests: XCTestCase { var channel0Name = "" for i in 0 ..< 100 { // We need a few channels to trigger iterator invalidation. - let channelName = uniqueChannelName(prefix: "channel\(i)") + let channelName = uniqueChannelName(for: test, prefix: "channel\(i)") if i == 0 { channel0Name = channelName } let channel = client.channels.get(channelName) channel.attach() // No need to wait; ATTACHING state is good enough. @@ -647,7 +663,7 @@ class RealtimeClientChannelTests: XCTestCase { partialDone() } - AblyTests.queue.async { + options.internalDispatchQueue.async { let pmError = AblyTests.newErrorProtocolMessage() client.internal.onError(pmError) partialDone() @@ -657,12 +673,13 @@ class RealtimeClientChannelTests: XCTestCase { // TO3g func test__020__Channel__connection_state__changes_to_FAILED__should_immediately_fail_if_not_in_the_connected_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.queueMessages = false options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in XCTAssertEqual(client.connection.state, .initialized) channel.publish(nil, data: "message") { error in @@ -686,15 +703,16 @@ class RealtimeClientChannelTests: XCTestCase { // TO3g and https://github.com/ably/ably-cocoa/issues/1004 func test__021__Channel__connection_state__changes_to_FAILED__should_keep_the_channels_attached_when_client_reconnected_successfully_and_queue_messages_is_disabled() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.queueMessages = false options.autoConnect = false - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } client.internal.setReachabilityClass(TestReachability.self) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in client.connection.once(.connected) { _ in @@ -722,7 +740,7 @@ class RealtimeClientChannelTests: XCTestCase { expect(stateChange.reason?.message).to(satisfyAnyOf(contain("unreachable host"), contain("network is down"))) done() } - client.simulateNoInternetConnection(transportFactory: transportFactory) + client.simulateNoInternetConnection(transportFactory: transportFactory, internalQueue: options.internalDispatchQueue) } waitUntil(timeout: testTimeout) { done in @@ -730,7 +748,7 @@ class RealtimeClientChannelTests: XCTestCase { XCTAssertEqual(stateChange.previous, .connecting) done() } - client.simulateRestoreInternetConnection(transportFactory: transportFactory) + client.simulateRestoreInternetConnection(transportFactory: transportFactory, internalQueue: options.internalDispatchQueue) } channel.off() @@ -740,15 +758,16 @@ class RealtimeClientChannelTests: XCTestCase { // RTL3b func test__022__Channel__connection_state__changes_to_CLOSED__ATTACHING_channel_should_transition_to_DETACHED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.attached] @@ -761,11 +780,12 @@ class RealtimeClientChannelTests: XCTestCase { } func test__023__Channel__connection_state__changes_to_CLOSED__ATTACHED_channel_should_transition_to_DETACHED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -778,14 +798,15 @@ class RealtimeClientChannelTests: XCTestCase { // RTL3c func test__024__Channel__connection_state__changes_to_SUSPENDED__ATTACHING_channel_should_transition_to_SUSPENDED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.attached] @@ -797,11 +818,12 @@ class RealtimeClientChannelTests: XCTestCase { } func test__025__Channel__connection_state__changes_to_SUSPENDED__ATTACHED_channel_should_transition_to_SUSPENDED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) client.internal.onSuspended() @@ -809,9 +831,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__026__Channel__connection_state__changes_to_SUSPENDED__channel_being_released_waiting_for_DETACH_shouldn_t_crash__issue__918_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -823,7 +846,7 @@ class RealtimeClientChannelTests: XCTestCase { var channel0Name = "" for i in 0 ..< 100 { // We need a few channels to trigger iterator invalidation. - let channelName = uniqueChannelName(prefix: "channel\(i)") + let channelName = uniqueChannelName(for: test, prefix: "channel\(i)") if i == 0 { channel0Name = channelName } let channel = client.channels.get(channelName) channel.attach() // No need to wait; ATTACHING state is good enough. @@ -837,7 +860,7 @@ class RealtimeClientChannelTests: XCTestCase { partialDone() } - AblyTests.queue.async { + options.internalDispatchQueue.async { client.internal.onSuspended() partialDone() } @@ -846,12 +869,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL3d func test__013__Channel__connection_state__if_the_connection_state_enters_the_CONNECTED_state__then_a_SUSPENDED_channel_will_initiate_an_attach_operation() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.suspendedRetryTimeout = 1.0 let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -875,10 +899,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL3d func test__014__Channel__connection_state__if_the_attach_operation_for_the_channel_times_out_and_the_channel_returns_to_the_SUSPENDED_state() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -896,18 +921,19 @@ class RealtimeClientChannelTests: XCTestCase { // RTL3d - https://github.com/ably/ably-cocoa/issues/881 func test__015__Channel__connection_state__should_attach_successfully_and_remain_attached_when_the_connection_state_without_a_successful_recovery_gets_CONNECTED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.disconnectedRetryTimeout = 0.5 options.suspendedRetryTimeout = 3.0 options.channelRetryTimeout = 0.5 options.autoConnect = false - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) client.internal.setReachabilityClass(TestReachability.self) defer { - client.simulateRestoreInternetConnection(transportFactory: transportFactory) + client.simulateRestoreInternetConnection(transportFactory: transportFactory, internalQueue: options.internalDispatchQueue) client.dispose() client.close() } @@ -916,7 +942,7 @@ class RealtimeClientChannelTests: XCTestCase { let ttlHookToken = client.overrideConnectionStateTTL(3.0) defer { ttlHookToken.remove() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -933,10 +959,10 @@ class RealtimeClientChannelTests: XCTestCase { expect(error.message).to(satisfyAnyOf(contain("network is down"), contain("unreachable host"))) done() } - client.simulateNoInternetConnection(transportFactory: transportFactory) + client.simulateNoInternetConnection(transportFactory: transportFactory, internalQueue: options.internalDispatchQueue) } - AblyTests.queue.async { + options.internalDispatchQueue.async { // Do not resume client.simulateLostConnectionAndState() } @@ -946,7 +972,7 @@ class RealtimeClientChannelTests: XCTestCase { XCTAssertEqual(stateChange.reason?.code, ARTErrorCode.unableToRecoverConnectionExpired.intValue) // didn't resumed done() } - client.simulateRestoreInternetConnection(after: 1.0, transportFactory: transportFactory) + client.simulateRestoreInternetConnection(after: 1.0, transportFactory: transportFactory, internalQueue: options.internalDispatchQueue) } waitUntil(timeout: testTimeout) { done in @@ -967,12 +993,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL3e func test__016__Channel__connection_state__if_the_connection_state_enters_the_DISCONNECTED_state__it_will_have_no_effect_on_the_channel_states() throws { - let options = try AblyTests.commonAppSetup() - options.token = try getTestToken(ttl: 5.0) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.token = try getTestToken(for: test, ttl: 5.0) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.once(.detached) { _ in fail("Should not reach the DETACHED state") @@ -1000,10 +1027,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4a func test__027__Channel__attach__if_already_ATTACHED_or_ATTACHING_nothing_is_done() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach { errorInfo in XCTAssertNil(errorInfo) @@ -1028,11 +1056,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4e func test__028__Channel__attach__if_the_user_does_not_have_sufficient_permissions_to_attach__then_the_channel_will_transition_to_FAILED_and_set_the_errorReason() throws { - let options = try AblyTests.commonAppSetup() - options.token = try getTestToken(key: options.key!, capability: "{\"restricted\":[\"*\"]}") + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.token = try getTestToken(for: test, key: options.key!, capability: "{\"restricted\":[\"*\"]}") let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) @@ -1055,9 +1084,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4g func test__029__Channel__attach__if_the_channel_is_in_the_FAILED_state__the_attach_request_sets_its_errorReason_to_null__and_proceeds_with_a_channel_attach() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -1082,9 +1112,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4b func test__039__Channel__attach__results_in_an_error_if_the_connection_state_is__CLOSING() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -1093,7 +1124,7 @@ class RealtimeClientChannelTests: XCTestCase { let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.closed] - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) client.close() XCTAssertEqual(client.connection.state, ARTRealtimeConnectionState.closing) @@ -1107,10 +1138,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__040__Channel__attach__results_in_an_error_if_the_connection_state_is__CLOSED() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) client.close() expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.closed), timeout: testTimeout) @@ -1124,10 +1156,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__041__Channel__attach__results_in_an_error_if_the_connection_state_is__SUSPENDED() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) client.internal.onSuspended() XCTAssertEqual(client.connection.state, ARTRealtimeConnectionState.suspended) waitUntil(timeout: testTimeout) { done in @@ -1139,10 +1172,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__042__Channel__attach__results_in_an_error_if_the_connection_state_is__FAILED() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) client.internal.onError(AblyTests.newErrorProtocolMessage()) XCTAssertEqual(client.connection.state, ARTRealtimeConnectionState.failed) waitUntil(timeout: testTimeout) { done in @@ -1156,12 +1190,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4i func test__043__Channel__attach__happens_when_connection_is_CONNECTED_if_it_s_currently__INITIALIZED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(client.connection.state, .initialized) waitUntil(timeout: testTimeout) { done in channel.on(.attached) { stateChange in @@ -1176,12 +1211,13 @@ class RealtimeClientChannelTests: XCTestCase { } func test__044__Channel__attach__happens_when_connection_is_CONNECTED_if_it_s_currently__CONNECTING() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in client.connect() @@ -1196,11 +1232,12 @@ class RealtimeClientChannelTests: XCTestCase { } func skipped__test__045__Channel__attach__happens_when_connection_is_CONNECTED_if_it_s_currently__DISCONNECTED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -1218,9 +1255,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4c func test__030__Channel__attach__should_send_an_ATTACH_ProtocolMessage__change_state_to_ATTACHING_and_change_state_to_ATTACHED_after_confirmation() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -1228,7 +1266,7 @@ class RealtimeClientChannelTests: XCTestCase { expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) let transport = client.internal.transport as! TestProxyTransport - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) @@ -1240,12 +1278,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4e func test__031__Channel__attach__should_transition_the_channel_state_to_FAILED_if_the_user_does_not_have_sufficient_permissions() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(capability: "{ \"main\":[\"subscribe\"] }") + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, capability: "{ \"main\":[\"subscribe\"] }") let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() waitUntil(timeout: testTimeout) { done in @@ -1264,7 +1303,8 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4f func test__032__Channel__attach__should_transition_the_channel_state_to_SUSPENDED_if_ATTACHED_ProtocolMessage_is_not_received() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.channelRetryTimeout = 1.0 options.testOptions.realtimeRequestTimeout = 1.0 let client = AblyTests.newRealtime(options).client @@ -1277,7 +1317,7 @@ class RealtimeClientChannelTests: XCTestCase { } transport.actionsIgnored += [.attached] - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { errorInfo in XCTAssertNotNil(errorInfo) @@ -1304,10 +1344,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__033__Channel__attach__if_called_with_a_callback_should_call_it_once_attached() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { errorInfo in @@ -1319,10 +1360,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__034__Channel__attach__if_called_with_a_callback_and_already_attaching_should_call_the_callback_once_attached() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach() @@ -1336,10 +1378,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__035__Channel__attach__if_called_with_a_callback_and_already_attached_should_call_the_callback_with_nil_error() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -1354,10 +1397,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4h func test__036__Channel__attach__if_the_channel_is_in_a_pending_state_ATTACHING__do_the_attach_operation_after_the_completion_of_the_pending_request() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) var attachedCount = 0 channel.on(.attached) { stateChange in @@ -1386,10 +1430,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4h func test__037__Channel__attach__if_the_channel_is_in_a_pending_state_DETACHING__do_the_attach_operation_after_the_completion_of_the_pending_request() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -1429,11 +1474,12 @@ class RealtimeClientChannelTests: XCTestCase { } func test__038__Channel__attach__a_channel_in_DETACHING_can_actually_move_back_to_ATTACHED_if_it_fails_to_detach() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.testOptions.realtimeRequestTimeout = 1.0 let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -1463,9 +1509,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4j func test__046__Channel__attach__attach_resume__should_pass_attach_resume_flag_in_attach_message() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -1504,9 +1551,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4j1 func test__047__Channel__attach__attach_resume__should_have_correct_AttachResume_value() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) // Initialized XCTAssertEqual(channel.internal.attachResume, attachResumeExpectedValues[channel.state]) @@ -1515,7 +1564,7 @@ class RealtimeClientChannelTests: XCTestCase { channel.once(.failed) { _ in done() } - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(AblyTests.newErrorProtocolMessage()) } } @@ -1545,9 +1594,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL4j2 func test__048__Channel__attach__attach_resume__should_encode_correctly_the_AttachResume_flag() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } let channel = client.channels.get(channelName) @@ -1594,10 +1644,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5a func test__049__Channel__detach__if_state_is_INITIALIZED_or_DETACHED_nothing_is_done() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) channel.detach { errorInfo in @@ -1626,10 +1677,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5i func test__050__Channel__detach__if_the_channel_is_in_a_pending_state_DETACHING__do_the_detach_operation_after_the_completion_of_the_pending_request() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -1677,10 +1729,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5i func test__051__Channel__detach__if_the_channel_is_in_a_pending_state_ATTACHING__do_the_detach_operation_after_the_completion_of_the_pending_request() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(3, done: done) @@ -1709,10 +1762,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5b func test__052__Channel__detach__results_in_an_error_if_the_connection_state_is_FAILED() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) client.internal.onError(AblyTests.newErrorProtocolMessage()) XCTAssertEqual(client.connection.state, ARTRealtimeConnectionState.failed) @@ -1726,9 +1780,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5d func test__053__Channel__detach__should_send_a_DETACH_ProtocolMessage__change_state_to_DETACHING_and_change_state_to_DETACHED_after_confirmation() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -1736,7 +1791,7 @@ class RealtimeClientChannelTests: XCTestCase { expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) let transport = client.internal.transport as! TestProxyTransport - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) channel.detach() @@ -1750,10 +1805,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5e func test__054__Channel__detach__if_called_with_a_callback_should_call_it_once_detached() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -1769,10 +1825,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5e func test__055__Channel__detach__if_called_with_a_callback_and_already_detaching_should_call_the_callback_once_detached() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -1790,10 +1847,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5e func test__056__Channel__detach__if_called_with_a_callback_and_already_detached_should_should_call_the_callback_with_nil_error() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -1810,10 +1868,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5f func test__057__Channel__detach__if_a_DETACHED_is_not_received_within_the_default_realtime_request_timeout__the_detach_request_should_be_treated_as_though_it_has_failed_and_the_channel_will_return_to_its_previous_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.testOptions.realtimeRequestTimeout = 1.0 - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -1822,7 +1881,7 @@ class RealtimeClientChannelTests: XCTestCase { let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.detached] - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -1846,9 +1905,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5g func test__059__Channel__detach__results_in_an_error_if_the_connection_state_is__CLOSING() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -1857,7 +1917,7 @@ class RealtimeClientChannelTests: XCTestCase { let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.closed] - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -1873,10 +1933,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__060__Channel__detach__results_in_an_error_if_the_connection_state_is__FAILED() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -1893,12 +1954,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5h func test__061__Channel__detach__happens_when_channel_is_ATTACHED_if_connection_is_currently__INITIALIZED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach() XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) @@ -1914,12 +1976,13 @@ class RealtimeClientChannelTests: XCTestCase { } func test__062__Channel__detach__happens_when_channel_is_ATTACHED_if_connection_is_currently__CONNECTING() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in client.connect() @@ -1935,11 +1998,12 @@ class RealtimeClientChannelTests: XCTestCase { } func test__063__Channel__detach__happens_when_channel_is_ATTACHED_if_connection_is_currently__DISCONNECTED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -1959,9 +2023,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL5j func test__058__Channel__detach__if_the_channel_state_is_SUSPENDED__the__detach__request_transitions_the_channel_immediately_to_the_DETACHED_state() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -1994,11 +2059,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6a func test__064__Channel__publish__should_encode_messages_in_the_same_way_as_the_RestChannel() throws { + let test = Test() let data = ["value": 1] - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) - let rest = ARTRest(options: try AblyTests.commonAppSetup()) + let rest = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let restChannel = rest.channels.get(channelName) var restEncodedMessage: ARTMessage? @@ -2013,7 +2079,7 @@ class RealtimeClientChannelTests: XCTestCase { } } - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.close() } let realtimeChannel = realtime.channels.get(channelName) realtimeChannel.attach() @@ -2042,7 +2108,8 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6b func test__067__Channel__publish__should_invoke_callback__when_the_message_is_successfully_delivered() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in @@ -2051,7 +2118,7 @@ class RealtimeClientChannelTests: XCTestCase { let error = stateChange.reason XCTAssertNil(error) if state == .connected { - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.on { stateChange in if stateChange.current == .attached { channel.publish(nil, data: "message") { errorInfo in @@ -2067,9 +2134,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__068__Channel__publish__should_invoke_callback__upon_failure() throws { - let options = try AblyTests.commonAppSetup() - let channelname = uniqueChannelName() - options.token = try getTestToken(key: options.key, capability: "{ \"\(options.testOptions.channelNamePrefix!)-\(channelname)\":[\"subscribe\"] }") + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelname = uniqueChannelName(for: test) + options.token = try getTestToken(for: test, key: options.key, capability: "{ \"\(options.testOptions.channelNamePrefix!)-\(channelname)\":[\"subscribe\"] }") let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -2100,12 +2168,13 @@ class RealtimeClientChannelTests: XCTestCase { } func test__069__Channel__publish__should_invoke_callback__for_all_messages_published() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) - let channelToSucceedName = uniqueChannelName(prefix: "channelToSucceed") - let channelToFailName = uniqueChannelName(prefix: "channelToFail") + let channelToSucceedName = uniqueChannelName(for: test, prefix: "channelToSucceed") + let channelToFailName = uniqueChannelName(for: test, prefix: "channelToFail") - options.token = try getTestToken(key: options.key, capability: "{ \"\(options.testOptions.channelNamePrefix!)-\(channelToSucceedName)\":[\"subscribe\", \"publish\"], \"\(options.testOptions.channelNamePrefix!)-\(channelToFailName)\":[\"subscribe\"] }") + options.token = try getTestToken(for: test, key: options.key, capability: "{ \"\(options.testOptions.channelNamePrefix!)-\(channelToSucceedName)\":[\"subscribe\", \"publish\"], \"\(options.testOptions.channelNamePrefix!)-\(channelToFailName)\":[\"subscribe\"] }") let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -2157,9 +2226,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6c1 func test__071__Channel__publish__Connection_state_conditions__if_the_connection_is_CONNECTED_and_the_channel_is__ATTACHED_then_the_messages_should_be_published_immediately() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -2175,14 +2245,15 @@ class RealtimeClientChannelTests: XCTestCase { } func test__072__Channel__publish__Connection_state_conditions__if_the_connection_is_CONNECTED_and_the_channel_is__INITIALIZED_then_the_messages_should_be_published_immediately() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in client.connection.once(.connected) { _ in done() } } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) XCTAssertEqual(client.connection.state, ARTRealtimeConnectionState.connected) @@ -2198,9 +2269,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__073__Channel__publish__Connection_state_conditions__if_the_connection_is_CONNECTED_and_the_channel_is__DETACHED_then_the_messages_should_be_published_immediately() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { _ in done() @@ -2226,9 +2298,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__074__Channel__publish__Connection_state_conditions__if_the_connection_is_CONNECTED_and_the_channel_is__ATTACHING_then_the_messages_should_be_published_immediately() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in client.connection.once(.connected) { _ in done() @@ -2253,9 +2326,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__075__Channel__publish__Connection_state_conditions__if_the_connection_is_CONNECTED_and_the_channel_is__DETACHING_then_the_messages_should_be_published_immediately() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { _ in done() @@ -2282,8 +2356,8 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6c2 - func beforeEach__Channel__publish__Connection_state_conditions__the_message(channelName: String) throws { - let options = try AblyTests.commonAppSetup() + func beforeEach__Channel__publish__Connection_state_conditions__the_message(for test: Test, channelName: String) throws { + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true options.autoConnect = false rtl6c2TestsClient = AblyTests.newRealtime(options).client @@ -2294,7 +2368,8 @@ class RealtimeClientChannelTests: XCTestCase { func afterEach__Channel__publish__Connection_state_conditions__the_message() { rtl6c2TestsClient.close() } func test__076__Channel__publish__Connection_state_conditions__the_message__should_be_queued_and_delivered_as_soon_as_the_connection_state_returns_to_CONNECTED_if_the_connection_is__INITIALIZED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__the_message(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__the_message(for: test, channelName: uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in XCTAssertEqual(rtl6c2TestsClient.connection.state, ARTRealtimeConnectionState.initialized) @@ -2307,7 +2382,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__077__Channel__publish__Connection_state_conditions__the_message__should_be_queued_and_delivered_as_soon_as_the_connection_state_returns_to_CONNECTED_if_the_connection_is__CONNECTING() throws { - try beforeEach__Channel__publish__Connection_state_conditions__the_message(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__the_message(for: test, channelName: uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in rtl6c2TestsClient.connect() @@ -2320,7 +2396,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__078__Channel__publish__Connection_state_conditions__the_message__should_be_queued_and_delivered_as_soon_as_the_connection_state_returns_to_CONNECTED_if_the_connection_is__DISCONNECTED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__the_message(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__the_message(for: test, channelName: uniqueChannelName(for: test)) rtl6c2TestsClient.connect() expect(rtl6c2TestsClient.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -2336,7 +2413,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__079__Channel__publish__Connection_state_conditions__the_message__should_NOT_be_queued_instead_it_should_be_published_if_the_channel_is__INITIALIZED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__the_message(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__the_message(for: test, channelName: uniqueChannelName(for: test)) rtl6c2TestsClient.connect() XCTAssertEqual(rtl6c2TestsChannel.state, ARTRealtimeChannelState.initialized) @@ -2353,7 +2431,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__080__Channel__publish__Connection_state_conditions__the_message__should_NOT_be_queued_instead_it_should_be_published_if_the_channel_is__ATTACHING() throws { - try beforeEach__Channel__publish__Connection_state_conditions__the_message(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__the_message(for: test, channelName: uniqueChannelName(for: test)) rtl6c2TestsClient.connect() expect(rtl6c2TestsClient.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -2370,7 +2449,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__081__Channel__publish__Connection_state_conditions__the_message__should_NOT_be_queued_instead_it_should_be_published_if_the_channel_is__ATTACHED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__the_message(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__the_message(for: test, channelName: uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in rtl6c2TestsChannel.attach { error in @@ -2408,8 +2488,8 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6c4 - func beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(channelName: String) throws { - try setupDependencies() + func beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(for test: Test, channelName: String) throws { + try setupDependencies(for: test) ARTDefault.setConnectionStateTtl(0.3) rtl6c4TestsClient = AblyTests.newRealtime(options).client rtl6c4TestsChannel = rtl6c4TestsClient.channels.get(channelName) @@ -2421,7 +2501,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__082__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the__connection_is_SUSPENDED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(for: test, channelName: uniqueChannelName(for: test)) rtl6c4TestsClient.connect() expect(rtl6c4TestsClient.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -2435,7 +2516,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__083__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the__connection_is_CLOSING() throws { - try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(for: test, channelName: uniqueChannelName(for: test)) rtl6c4TestsClient.connect() expect(rtl6c4TestsClient.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -2449,7 +2531,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__084__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the__connection_is_CLOSED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(for: test, channelName: uniqueChannelName(for: test)) rtl6c4TestsClient.connect() expect(rtl6c4TestsClient.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -2463,7 +2546,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__085__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the__connection_is_FAILED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(for: test, channelName: uniqueChannelName(for: test)) rtl6c4TestsClient.connect() expect(rtl6c4TestsClient.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -2477,7 +2561,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__086__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the__channel_is_SUSPENDED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(for: test, channelName: uniqueChannelName(for: test)) rtl6c4TestsClient.connect() rtl6c4TestsChannel.attach() @@ -2492,7 +2577,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__087__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the__channel_is_FAILED() throws { - try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(channelName: uniqueChannelName()) + let test = Test() + try beforeEach__Channel__publish__Connection_state_conditions__will_result_in_an_error_if_the(for: test, channelName: uniqueChannelName(for: test)) rtl6c4TestsClient.connect() rtl6c4TestsChannel.attach() @@ -2509,10 +2595,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6c5 func test__070__Channel__publish__Connection_state_conditions__publish_should_not_trigger_an_implicit_attach() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let protocolError = AblyTests.newErrorProtocolMessage() XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) @@ -2526,7 +2614,7 @@ class RealtimeClientChannelTests: XCTestCase { } } XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(protocolError) } } @@ -2535,11 +2623,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6d func test__088__Channel__publish__message_bundling__Messages_are_delivered_using_a_single_ProtocolMessage_where_possible_by_bundling_in_all_messages_for_that_channel() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) // Test that the initially queued messages are sent together. @@ -2593,11 +2682,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6d1 func test__089__Channel__publish__message_bundling__The_resulting_ProtocolMessage_must_not_exceed_the_maxMessageSize() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) // This amount of messages would be beyond maxMessageSize, if bundled together let messagesToBeSent = 2000 @@ -2625,11 +2715,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6d2 func test__092__Channel__publish__message_bundling__Messages_with_differing_clientId_values_must_not_be_bundled_together__messages_with_different__non_empty__clientIds_are_posted_via_different_protocol_messages() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let clientIDs = ["client1", "client2", "client3"] waitUntil(timeout: testTimeout) { done in @@ -2649,11 +2740,12 @@ class RealtimeClientChannelTests: XCTestCase { } func test__093__Channel__publish__message_bundling__Messages_with_differing_clientId_values_must_not_be_bundled_together__messages_with_mixed_empty_non_empty_clientIds_are_posted_via_different_protocol_messages() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) @@ -2674,11 +2766,12 @@ class RealtimeClientChannelTests: XCTestCase { } func test__094__Channel__publish__message_bundling__Messages_with_differing_clientId_values_must_not_be_bundled_together__messages_bundled_by_the_user_are_posted_in_a_single_protocol_message_even_if_they_have_mixed_clientIds() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) var messages = [ARTMessage]() for i in 1 ... 3 { messages.append(ARTMessage(name: "name\(i)", data: "data\(i)", clientId: "clientId\(i)")) @@ -2699,16 +2792,17 @@ class RealtimeClientChannelTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 func skipped__test__090__Channel__publish__message_bundling__should_only_bundle_messages_when_it_respects_all_of_the_constraints() throws { + let test = Test() let defaultMaxMessageSize = ARTDefault.maxMessageSize() ARTDefault.setMaxMessageSize(256) defer { ARTDefault.setMaxMessageSize(defaultMaxMessageSize) } - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelOne = client.channels.get(uniqueChannelName(prefix: "bundlingOne")) - let channelTwo = client.channels.get(uniqueChannelName(prefix: "bundlingTwo")) + let channelOne = client.channels.get(uniqueChannelName(for: test, prefix: "bundlingOne")) + let channelTwo = client.channels.get(uniqueChannelName(for: test, prefix: "bundlingTwo")) channelTwo.publish("2a", data: ["expectedBundle": 0]) channelOne.publish("a", data: ["expectedBundle": 1]) @@ -2734,7 +2828,7 @@ class RealtimeClientChannelTests: XCTestCase { let expectationMessageBundling = XCTestExpectation(description: "message-bundling") - AblyTests.queue.async { + options.internalDispatchQueue.async { let queue: [ARTQueuedMessage] = client.internal.queuedMessages as! [ARTQueuedMessage] for i in 0 ... 10 { for message in queue[i].msg.messages! { @@ -2770,10 +2864,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__091__Channel__publish__message_bundling__should_publish_only_once_on_multiple_explicit_publish_requests_for_a_given_message_with_client_supplied_ids() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName(prefix: "idempotentRealtimePublishing")) + let channel = client.channels.get(uniqueChannelName(for: test, prefix: "idempotentRealtimePublishing")) waitUntil(timeout: testTimeout) { done in channel.once(.attached) { stateChange in @@ -2808,12 +2903,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6e1 func test__095__Channel__publish__Unidentified_clients_using_Basic_Auth__should_have_the_provided_clientId_on_received_message_when_it_was_published_with_clientId() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } XCTAssertNil(client.auth.clientId) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) var resultClientId: String? @@ -2837,9 +2933,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6f func test__065__Channel__publish__Message_connectionId_should_match_the_current_Connection_id_for_all_published_messages() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.subscribe { message in @@ -2853,13 +2950,14 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6i func test__096__Channel__publish__expect_either__an_array_of_Message_objects() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) typealias JSONObject = NSDictionary var result = [JSONObject]() @@ -2877,9 +2975,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__097__Channel__publish__expect_either__a_name_string_and_data_payload() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let expectedResult = "string_data" var result: String? @@ -2894,13 +2993,14 @@ class RealtimeClientChannelTests: XCTestCase { } func test__098__Channel__publish__expect_either__allows_name_to_be_null() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) let expectedObject = ["data": "message", "connectionId": client.connection.id!] @@ -2932,13 +3032,14 @@ class RealtimeClientChannelTests: XCTestCase { } func test__099__Channel__publish__expect_either__allows_data_to_be_null() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) let expectedObject = ["name": "click", "connectionId": client.connection.id!] @@ -2970,13 +3071,14 @@ class RealtimeClientChannelTests: XCTestCase { } func test__100__Channel__publish__expect_either__allows_name_and_data_to_be_assigned() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) let expectedObject = ["name": "click", "data": "message", "connectionId": client.connection.id!] @@ -3004,14 +3106,15 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6g1a & RTL6g1b func test__105__Channel__publish__Identified_clients_with_clientId__When_publishing_a_Message_with_clientId_set_to_null__should_be_unnecessary_to_set_clientId_of_the_Message_before_publishing_and_have_clientId_value_set_for_the_Message_when_received() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let message = ARTMessage(name: nil, data: "message") XCTAssertNil(message.clientId) @@ -3035,11 +3138,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6g2 func test__101__Channel__publish__Identified_clients_with_clientId__when_publishing_a_Message_with_the_clientId_attribute_value_set_to_the_identified_client_s_clientId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let message = ARTMessage(name: nil, data: "message", clientId: options.clientId!) var resultClientId: String? @@ -3061,11 +3165,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6g3 func test__102__Channel__publish__Identified_clients_with_clientId__when_publishing_a_Message_with_a_different_clientId_attribute_value_from_the_identified_client_s_clientId__it_should_reject_that_publish_operation_immediately() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([ARTMessage(name: nil, data: "message", clientId: "tester")]) { error in @@ -3084,13 +3189,14 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6g4 func test__103__Channel__publish__Identified_clients_with_clientId__message_should_be_published_following_authentication_and_received_back_with_the_clientId_intact() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { _, completion in - getTestTokenDetails(clientId: "john", completion: completion) + getTestTokenDetails(for: test, clientId: "john", completion: completion) } let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let message = ARTMessage(name: nil, data: "message", clientId: "john") waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) @@ -3107,13 +3213,14 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6g4 func test__104__Channel__publish__Identified_clients_with_clientId__message_should_be_rejected_by_the_Ably_service_and_the_message_error_should_contain_the_server_error() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { _, completion in - getTestTokenDetails(clientId: "john", completion: completion) + getTestTokenDetails(for: test, clientId: "john", completion: completion) } let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let message = ARTMessage(name: nil, data: "message", clientId: "tester") waitUntil(timeout: testTimeout) { done in channel.publish([message]) { error in @@ -3125,9 +3232,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL6h func test__066__Channel__publish__should_provide_an_optional_argument_that_allows_the_clientId_value_to_be_specified() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) @@ -3148,10 +3256,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL7a func test__106__Channel__subscribe__with_no_arguments_subscribes_a_listener_to_all_messages() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) var counter = 0 @@ -3169,10 +3278,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL7b func test__107__Channel__subscribe__with_a_single_name_argument_subscribes_a_listener_to_only_messages_whose_name_member_matches_the_string_name() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) var counter = 0 @@ -3191,10 +3301,11 @@ class RealtimeClientChannelTests: XCTestCase { } func test__108__Channel__subscribe__with_a_attach_callback_should_subscribe_and_call_the_callback_when_attached() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let publishedMessage = ARTMessage(name: "foo", data: "bar") @@ -3217,10 +3328,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL7c func test__109__Channel__subscribe__should_implicitly_attach_the_channel() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.subscribe { _ in } @@ -3229,10 +3341,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL7c func test__110__Channel__subscribe__should_result_in_an_error_if_channel_is_in_the_FAILED_state() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.internal.onError(AblyTests.newErrorProtocolMessage()) XCTAssertEqual(channel.state, ARTRealtimeChannelState.failed) @@ -3251,25 +3364,28 @@ class RealtimeClientChannelTests: XCTestCase { // RTL7d func test__112__Channel__subscribe__should_deliver_the_message_even_if_there_is_an_error_while_decoding__using_crypto_data_128() throws { - try testHandlesDecodingErrorInFixture("crypto-data-128", channelName: uniqueChannelName()) + let test = Test() + try testHandlesDecodingErrorInFixture("crypto-data-128", for: test, channelName: uniqueChannelName(for: test)) } func test__113__Channel__subscribe__should_deliver_the_message_even_if_there_is_an_error_while_decoding__using_crypto_data_256() throws { - try testHandlesDecodingErrorInFixture("crypto-data-256", channelName: uniqueChannelName()) + let test = Test() + try testHandlesDecodingErrorInFixture("crypto-data-256", for: test, channelName: uniqueChannelName(for: test)) } // RTL7e func test__114__Channel__subscribe__message_cannot_be_decoded_or_decrypted__should_deliver_with_encoding_attribute_set_indicating_the_residual_encoding_and_error_should_be_emitted() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.logHandler = ARTLog(capturingOutput: true) - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } let channelOptions = ARTRealtimeChannelOptions(cipher: ["key": ARTCrypto.generateRandomKey()] as ARTCipherParamsCompatible) - let channel = client.channels.get(uniqueChannelName(), options: channelOptions) + let channel = client.channels.get(uniqueChannelName(for: test), options: channelOptions) let expectedMessage = ["key": 1] let expectedData = try! JSONSerialization.data(withJSONObject: expectedMessage, options: JSONSerialization.WritingOptions(rawValue: 0)) @@ -3307,7 +3423,8 @@ class RealtimeClientChannelTests: XCTestCase { // RTL7f func test__111__Channel__subscribe__should_exist_ensuring_published_messages_are_not_echoed_back_to_the_subscriber_when_echoMessages_is_false() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client1 = ARTRealtime(options: options) defer { client1.close() } @@ -3315,7 +3432,7 @@ class RealtimeClientChannelTests: XCTestCase { let client2 = ARTRealtime(options: options) defer { client2.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) let channel2 = client2.channels.get(channelName) @@ -3340,10 +3457,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL8a func test__115__Channel__unsubscribe__with_no_arguments_unsubscribes_the_provided_listener_to_all_messages_if_subscribed() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let listener = channel.subscribe { _ in @@ -3362,10 +3480,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL8b func test__116__Channel__unsubscribe__with_a_single_name_argument_unsubscribes_the_provided_listener_if_previously_subscribed_with_a_name_specific_subscription() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let eventAListener = channel.subscribe("eventA") { _ in @@ -3386,15 +3505,16 @@ class RealtimeClientChannelTests: XCTestCase { // RTL10a func test__117__Channel__history__should_support_all_the_same_params_as_Rest() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let realtime = ARTRealtime(options: options) defer { realtime.close() } - let channelRest = rest.channels.get(uniqueChannelName()) - let channelRealtime = realtime.channels.get(uniqueChannelName()) + let channelRest = rest.channels.get(uniqueChannelName(for: test)) + let channelRealtime = realtime.channels.get(uniqueChannelName(for: test)) var restChannelHistoryMethodWasCalled = false @@ -3444,9 +3564,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__124__Channel__history__supports_the_param_untilAttach__should_invoke_an_error_when_the_untilAttach_is_specified_and_the_channel_is_not_attached() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let query = ARTRealtimeHistoryQuery() query.untilAttach = true @@ -3463,15 +3584,18 @@ class RealtimeClientChannelTests: XCTestCase { } func test__125__Channel__history__supports_the_param_untilAttach__where_value_is_true__should_pass_the_querystring_param_fromSerial_with_the_serial_number_assigned_to_the_channel() throws { - try testWithUntilAttach(true, channelName: uniqueChannelName()) + let test = Test() + try testWithUntilAttach(true, for: test, channelName: uniqueChannelName(for: test)) } func test__126__Channel__history__supports_the_param_untilAttach__where_value_is_false__should_pass_the_querystring_param_fromSerial_with_the_serial_number_assigned_to_the_channel() throws { - try testWithUntilAttach(true, channelName: uniqueChannelName()) + let test = Test() + try testWithUntilAttach(true, for: test, channelName: uniqueChannelName(for: test)) } func test__127__Channel__history__supports_the_param_untilAttach__should_retrieve_messages_prior_to_the_moment_that_the_channel_was_attached() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client1 = ARTRealtime(options: options) defer { client1.close() } @@ -3479,7 +3603,7 @@ class RealtimeClientChannelTests: XCTestCase { let client2 = ARTRealtime(options: options) defer { client2.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) channel1.attach() @@ -3540,9 +3664,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL10c func test__118__Channel__history__should_return_a_PaginatedResult_page() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.close() } - let channel = realtime.channels.get(uniqueChannelName()) + let channel = realtime.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "message") { errorInfo in @@ -3569,14 +3694,15 @@ class RealtimeClientChannelTests: XCTestCase { // RTL10d func test__119__Channel__history__should_retrieve_all_available_messages() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client1 = ARTRealtime(options: options) defer { client1.close() } let client2 = ARTRealtime(options: options) defer { client2.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) channel1.attach() @@ -3624,9 +3750,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL12 func test__120__Channel__history__attached_channel_may_receive_an_additional_ATTACHED_ProtocolMessage() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -3685,9 +3812,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL13a func test__128__Channel__history__if_the_channel_receives_a_server_initiated_DETACHED_message_when__the_channel_is_in_the_ATTACHED_states__an_attempt_to_reattach_the_channel_should_be_made_immediately_by_sending_a_new_ATTACH_message_and_the_channel_should_transition_to_the_ATTACHING_state_with_the_error_emitted_in_the_ChannelStateChange_event() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -3724,7 +3852,8 @@ class RealtimeClientChannelTests: XCTestCase { // RTL13a func test__129__Channel__history__if_the_channel_receives_a_server_initiated_DETACHED_message_when__the_channel_is_in_the_SUSPENDED_state__an_attempt_to_reattach_the_channel_should_be_made_immediately_by_sending_a_new_ATTACH_message_and_the_channel_should_transition_to_the_ATTACHING_state_with_the_error_emitted_in_the_ChannelStateChange_event() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.testOptions.realtimeRequestTimeout = 1.0 let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } @@ -3740,7 +3869,7 @@ class RealtimeClientChannelTests: XCTestCase { fail("TestProxyTransport is not set"); return } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) // Timeout transport.actionsIgnored += [.attached] @@ -3777,12 +3906,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL13b func test__130__Channel__history__if_the_channel_receives_a_server_initiated_DETACHED_message_when__if_the_attempt_to_re_attach_fails_the_channel_will_transition_to_the_SUSPENDED_state_and_the_error_will_be_emitted_in_the_ChannelStateChange_event() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.channelRetryTimeout = 1.0 options.testOptions.realtimeRequestTimeout = 1.0 let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -3837,11 +3967,12 @@ class RealtimeClientChannelTests: XCTestCase { // RTL13b func test__131__Channel__history__if_the_channel_receives_a_server_initiated_DETACHED_message_when__if_the_channel_was_already_in_the_ATTACHING_state__the_channel_will_transition_to_the_SUSPENDED_state_and_the_error_will_be_emitted_in_the_ChannelStateChange_event() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.channelRetryTimeout = 1.0 let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let detachedMessageWithError = AblyTests.newErrorProtocolMessage() detachedMessageWithError.action = .detached @@ -3876,12 +4007,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL13b func test__131b__Channel__if_the_channel_receives_a_server_initiated_DETACHED_message_and_if_the_attempt_to_reattach_fails_then_the_channel_will_transition_to_SUSPENDED_state_with_periodic_reattach_with_channelRetryTimeout() throws { + let test = Test() - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) options.channelRetryTimeout = 1.0 options.autoConnect = false options.testOptions.realtimeRequestTimeout = 1.0 - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() @@ -3893,7 +4025,7 @@ class RealtimeClientChannelTests: XCTestCase { expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) @@ -3926,12 +4058,13 @@ class RealtimeClientChannelTests: XCTestCase { // RTL13c func test__132__Channel__history__if_the_channel_receives_a_server_initiated_DETACHED_message_when__if_the_connection_is_no_longer_CONNECTED__then_the_automatic_attempts_to_re_attach_the_channel_must_be_cancelled() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.channelRetryTimeout = 1.0 options.testOptions.realtimeRequestTimeout = 1.0 let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -3981,9 +4114,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL14 func test__121__Channel__history__If_an_ERROR_ProtocolMessage_is_received_for_this_channel_then_the_channel_should_immediately_transition_to_the_FAILED_state__the_errorReason_should_be_set_and_an_error_should_be_emitted_on_the_channel() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -4016,9 +4150,10 @@ class RealtimeClientChannelTests: XCTestCase { // RTL16a func test__133__Channel__history__Channel_options__setOptions__should_send_an_ATTACH_message_with_params___modes_if_the_channel_is_attached() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -4067,7 +4202,8 @@ class RealtimeClientChannelTests: XCTestCase { } func test__134__Channel__history__Channel_options__setOptions__should_send_an_ATTACH_message_with_params___modes_if_the_channel_is_attaching() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in @@ -4086,7 +4222,7 @@ class RealtimeClientChannelTests: XCTestCase { "delta": "vcdiff", ] - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(3, done: done) channel.once(.attaching) { _ in @@ -4124,11 +4260,12 @@ class RealtimeClientChannelTests: XCTestCase { } func test__135__Channel__history__Channel_options__setOptions__should_success_immediately_if_channel_is_not_attaching_or_attached() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let channelOptions = ARTRealtimeChannelOptions() channelOptions.modes = [.subscribe] @@ -4146,11 +4283,12 @@ class RealtimeClientChannelTests: XCTestCase { } func test__136__Channel__history__Channel_options__setOptions__should_fail_if_the_attach_moves_to_FAILED() throws { - let options = try AblyTests.commonAppSetup() - options.token = try getTestToken(capability: "{\"secret\":[\"subscribe\"]}") // access denied + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.token = try getTestToken(for: test, capability: "{\"secret\":[\"subscribe\"]}") // access denied let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in client.connection.once(.connected) { _ in @@ -4196,9 +4334,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__137__Channel__history__Channel_options__setOptions__should_fail_if_the_attach_moves_to_DETACHED() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in client.connection.once(.connected) { _ in @@ -4249,9 +4388,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__Channel_options__setOptions__shouldUpdateOptionsOfRestChannel() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in client.connection.once(.connected) { _ in @@ -4283,10 +4423,11 @@ class RealtimeClientChannelTests: XCTestCase { // RTL17 func test__122__Channel__history__should_not_emit_messages_to_subscribers_if_the_channel_is_in_any_state_other_than_ATTACHED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.close(); client.dispose() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let m1 = ARTMessage(name: "m1", data: "d1") let m2 = ARTMessage(name: "m2", data: "d2") @@ -4329,9 +4470,10 @@ class RealtimeClientChannelTests: XCTestCase { } func test__138__Channel__crypto__if_configured_for_encryption__channels_encrypt_and_decrypt_messages__data() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let clientSender = ARTRealtime(options: options) defer { clientSender.close() } @@ -4342,7 +4484,7 @@ class RealtimeClientChannelTests: XCTestCase { clientReceiver.connect() let key = ARTCrypto.generateRandomKey() - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let sender = clientSender.channels.get(channelName, options: ARTRealtimeChannelOptions(cipherKey: key as ARTCipherKeyCompatible)) let receiver = clientReceiver.channels.get(channelName, options: ARTRealtimeChannelOptions(cipherKey: key as ARTCipherKeyCompatible)) @@ -4414,11 +4556,12 @@ class RealtimeClientChannelTests: XCTestCase { // https://github.com/ably/ably-cocoa/issues/614 func test__002__Channel__should_not_crash_when_an_ATTACH_request_is_responded_with_a_DETACHED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.testOptions.realtimeRequestTimeout = 1.0 let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) guard let transport = client.internal.transport as? TestProxyTransport else { fail("TestProxyTransport is not set"); return @@ -4445,13 +4588,15 @@ class RealtimeClientChannelTests: XCTestCase { // TM2a func test__139__message_attributes__if_the_message_does_not_contain_an_id__it_should_be_set_to_protocolMsgId_index() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } let p = ARTProtocolMessage() p.id = "protocolId" let m = ARTMessage(name: nil, data: "message without ID") p.messages = [m] - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { _ in done() @@ -4462,7 +4607,7 @@ class RealtimeClientChannelTests: XCTestCase { XCTAssertEqual(message.id, "protocolId:0") done() } - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onMessage(p) } } diff --git a/Test/Tests/RealtimeClientChannelsTests.swift b/Test/Tests/RealtimeClientChannelsTests.swift index e342aac53..4c2233926 100644 --- a/Test/Tests/RealtimeClientChannelsTests.swift +++ b/Test/Tests/RealtimeClientChannelsTests.swift @@ -12,13 +12,14 @@ extension ARTRealtimeChannels: Sequence { class RealtimeClientChannelsTests: XCTestCase { // RTS2 func test__001__Channels__should_exist_methods_to_check_if_a_channel_exists_or_iterate_through_the_existing_channels() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } var disposable = [String]() - let channelName1 = uniqueChannelName(prefix: "1") - let channelName2 = uniqueChannelName(prefix: "2") - let channelName3 = uniqueChannelName(prefix: "3") + let channelName1 = uniqueChannelName(for: test, prefix: "1") + let channelName2 = uniqueChannelName(for: test, prefix: "2") + let channelName3 = uniqueChannelName(for: test, prefix: "3") disposable.append(client.channels.get(channelName1).name) disposable.append(client.channels.get(channelName2).name) @@ -37,12 +38,13 @@ class RealtimeClientChannelsTests: XCTestCase { // RTS3a func test__002__Channels__get__should_create_a_new_Channel_if_none_exists_or_return_the_existing_one() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } XCTAssertEqual(client.channels.internal.collection.count, 0) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) XCTAssertEqual(channel.name, "\(options.testOptions.channelNamePrefix!)-\(channelName)") @@ -53,18 +55,20 @@ class RealtimeClientChannelsTests: XCTestCase { // RTS3b func test__003__Channels__get__should_be_possible_to_specify_a_ChannelOptions() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } let options = ARTRealtimeChannelOptions() - let channel = client.channels.get(uniqueChannelName(), options: options) + let channel = client.channels.get(uniqueChannelName(for: test), options: options) XCTAssertTrue(channel.options === options) } // RTS3c func test__004__Channels__get__accessing_an_existing_Channel_with_options_should_update_the_options_and_then_return_the_object() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) XCTAssertNil(client.channels.get(channelName).options) let options = ARTRealtimeChannelOptions() let channel = client.channels.get(channelName, options: options) @@ -74,10 +78,11 @@ class RealtimeClientChannelsTests: XCTestCase { // RTS4 func test__005__Channels__release__should_release_a_channel() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) channel.subscribe { _ in fail("shouldn't happen") diff --git a/Test/Tests/RealtimeClientConnectionTests.swift b/Test/Tests/RealtimeClientConnectionTests.swift index 1b9e7c4c7..3f5c4438c 100644 --- a/Test/Tests/RealtimeClientConnectionTests.swift +++ b/Test/Tests/RealtimeClientConnectionTests.swift @@ -27,7 +27,7 @@ private func testUsesAlternativeHostOnResponse(_ caseTest: FakeNetworkResponse, let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false options.testOptions.realtimeRequestTimeout = 1.0 - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -63,10 +63,10 @@ private func testUsesAlternativeHostOnResponse(_ caseTest: FakeNetworkResponse, XCTAssertTrue(NSRegularExpression.match(urlConnections[1].absoluteString, pattern: "//[a-e].ably-realtime.com")) } -private func testMovesToDisconnectedWithNetworkingError(_ error: Error) throws { - let options = try AblyTests.commonAppSetup() +private func testMovesToDisconnectedWithNetworkingError(_ error: Error, for test: Test) throws { + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = AblyTests.newRealtime(options).client defer { client.dispose() @@ -81,7 +81,7 @@ private func testMovesToDisconnectedWithNetworkingError(_ error: Error) throws { } var _transport: ARTWebSocketTransport? - AblyTests.queue.sync { + options.internalDispatchQueue.sync { _transport = client.internal.transport as? ARTWebSocketTransport } @@ -131,9 +131,9 @@ private func expectDataToMatch(_ message: ARTMessage, _ fixtureMessage: Any) { private var jsonOptions: ARTClientOptions! private var msgpackOptions: ARTClientOptions! -private func setupDependencies() throws { +private func setupDependencies(for test: Test) throws { if jsonOptions == nil { - jsonOptions = try AblyTests.commonAppSetup() + jsonOptions = try AblyTests.commonAppSetup(for: test) jsonOptions.useBinaryProtocol = false // Keep the same key and channel prefix msgpackOptions = (jsonOptions.copy() as! ARTClientOptions) @@ -162,9 +162,10 @@ class RealtimeClientConnectionTests: XCTestCase { // CD2c func test__016__Connection__ConnectionDetails__maxMessageSize_overrides_the_default_maxMessageSize() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) let defaultMaxMessageSize = ARTDefault.maxMessageSize() XCTAssertEqual(defaultMaxMessageSize, 65536) @@ -191,7 +192,7 @@ class RealtimeClientConnectionTests: XCTestCase { func test__017__Connection__url__should_connect_to_the_default_host() { let options = ARTClientOptions(key: "keytest:secret") options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() @@ -205,9 +206,10 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__018__Connection__url__should_connect_with_query_string_params() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() @@ -238,12 +240,13 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__019__Connection__url__should_connect_with_query_string_params_including_clientId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" options.useTokenAuth = true options.autoConnect = false options.echoMessages = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() @@ -276,7 +279,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN3 func test__001__Connection__should_connect_automatically() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var connected = false // Default @@ -300,7 +304,8 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__002__Connection__should_connect_manually() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) @@ -331,7 +336,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN2f func test__003__Connection__API_version_param_must_be_included_in_all_connections() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -357,9 +363,10 @@ class RealtimeClientConnectionTests: XCTestCase { // RSC7d func test__004__Connection__Library_and_version_param__agent__should_include_the__Ably_Agent__header_value() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() @@ -391,7 +398,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN4a func test__020__Connection__event_emitter__should_emit_events_for_state_changes() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) @@ -466,7 +474,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN4h func test__021__Connection__event_emitter__should_never_emit_a_ConnectionState_event_for_a_state_equal_to_the_previous_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -498,7 +507,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN4b func test__022__Connection__event_emitter__should_emit_states_on_a_new_connection() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) @@ -536,7 +546,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN4c func test__023__Connection__event_emitter__should_emit_states_when_connection_is_closed() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) let connection = client.connection defer { client.dispose(); client.close() } var events: [ARTRealtimeConnectionState] = [] @@ -572,7 +583,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN4d func test__024__Connection__event_emitter__should_have_the_current_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -600,7 +612,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN4e func test__025__Connection__event_emitter__should_have_a_ConnectionStateChange_as_first_argument_for_every_connection_state_change() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -618,7 +631,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN4f func test__026__Connection__event_emitter__should_have_the_reason_which_contains_an_ErrorInfo() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } let connection = client.connection @@ -647,7 +661,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN4f func test__027__Connection__event_emitter__any_state_change_triggered_by_a_ProtocolMessage_that_contains_an_Error_member_should_populate_the_Reason_property() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } @@ -685,7 +700,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN5 func test__005__Connection__basic_operations_should_work_simultaneously() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.echoMessages = false var disposable = [ARTRealtime]() let numClients = 50 @@ -748,9 +764,10 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN6 func test__006__Connection__should_have_an_opened_websocket_connection_and_received_a_CONNECTED_ProtocolMessage() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { @@ -788,16 +805,17 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN7a func test__028__Connection__ACK_and_NACK__should_expect_either_an_ACK_or_NACK_to_confirm__successful_receipt_and_acceptance_of_message() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.clientId = "client_string" - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in - publishFirstTestMessage(client, channelName: uniqueChannelName(), completion: { error in + publishFirstTestMessage(client, channelName: uniqueChannelName(for: test), completion: { error in XCTAssertNil(error) done() }) @@ -817,10 +835,11 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__029__Connection__ACK_and_NACK__should_expect_either_an_ACK_or_NACK_to_confirm__successful_receipt_and_acceptance_of_presence() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.clientId = "client_string" - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -831,7 +850,7 @@ class RealtimeClientConnectionTests: XCTestCase { let error = stateChange.reason XCTAssertNil(error) if state == .connected { - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach { error in XCTAssertNil(error) channel.presence.enterClient("client_string", data: nil, callback: { errorInfo in @@ -857,12 +876,13 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__030__Connection__ACK_and_NACK__should_expect_either_an_ACK_or_NACK_to_confirm__message_failure() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) - let channelName = uniqueChannelName() - options.token = try getTestToken(key: options.key, capability: "{ \"\(options.testOptions.channelNamePrefix!)-\(channelName)\":[\"subscribe\"] }") + let channelName = uniqueChannelName(for: test) + options.token = try getTestToken(for: test, key: options.key, capability: "{ \"\(options.testOptions.channelNamePrefix!)-\(channelName)\":[\"subscribe\"] }") options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -888,10 +908,11 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__031__Connection__ACK_and_NACK__should_expect_either_an_ACK_or_NACK_to_confirm__presence_failure() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.clientId = "client_string" - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -902,7 +923,7 @@ class RealtimeClientConnectionTests: XCTestCase { let error = stateChange.reason XCTAssertNil(error) if state == .connected { - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach { error in XCTAssertNil(error) channel.presence.enterClient("invalid", data: nil, callback: { errorInfo in @@ -930,15 +951,16 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN7b func test__032__Connection__ACK_and_NACK__ProtocolMessage__should_contain_unique_serially_incrementing_msgSerial_along_with_the_count() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.clientId = "client_string" - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() waitUntil(timeout: testTimeout) { done in @@ -997,13 +1019,14 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__033__Connection__ACK_and_NACK__ProtocolMessage__should_continue_incrementing_msgSerial_serially_if_the_connection_resumes_successfully() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "tester" - options.tokenDetails = try getTestTokenDetails(key: options.key!, clientId: options.clientId, ttl: 5.0) + options.tokenDetails = try getTestTokenDetails(for: test, key: options.key!, clientId: options.clientId, ttl: 5.0) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "message") { error in XCTAssertNil(error) @@ -1082,12 +1105,13 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__034__Connection__ACK_and_NACK__ProtocolMessage__should_reset_msgSerial_serially_if_the_connection_does_not_resume() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "tester" let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "message") { error in XCTAssertNil(error) @@ -1171,15 +1195,16 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN7c func test__035__Connection__ACK_and_NACK__should_trigger_the_failure_callback_for_the_remaining_pending_messages_if__connection_is_closed() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.clientId = "client_string" - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.ack, .nack] @@ -1209,15 +1234,16 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__036__Connection__ACK_and_NACK__should_trigger_the_failure_callback_for_the_remaining_pending_messages_if__connection_state_enters_FAILED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.clientId = "client_string" - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.ack, .nack] @@ -1237,9 +1263,10 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__037__Connection__ACK_and_NACK__should_trigger_the_failure_callback_for_the_remaining_pending_messages_if__lost_connection_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { @@ -1247,7 +1274,7 @@ class RealtimeClientConnectionTests: XCTestCase { client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let transport = client.internal.transport as! TestProxyTransport transport.actionsIgnored += [.ack, .nack] @@ -1290,7 +1317,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN8a func test__038__Connection__connection_id__should_be_null_until_connected() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) let connection = client.connection defer { @@ -1317,7 +1345,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN8b func test__039__Connection__connection_id__should_have_unique_IDs() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var disposable = [ARTRealtime]() defer { for client in disposable { @@ -1366,7 +1395,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN9a func test__040__Connection__connection_key__should_be_null_until_connected() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose() @@ -1393,7 +1423,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN9b func test__041__Connection__connection_key__should_have_unique_connection_keys() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var disposable = [ARTRealtime]() defer { for client in disposable { @@ -1439,7 +1470,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN10a func test__042__Connection__serial__should_be_minus_1_once_connected() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose() client.close() @@ -1459,12 +1491,13 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN10b func test__043__Connection__serial__should_not_update_when_a_message_is_sent_but_increments_by_one_when_ACK_is_received() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose() client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(client.connection.serial, -1) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -1490,13 +1523,14 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__044__Connection__serial__should_have_last_known_connection_serial_from_restored_connection() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose() client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) // Attach first to avoid bundling publishes in the same ProtocolMessage. @@ -1542,7 +1576,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN11b func test__007__Connection__should_make_a_new_connection_with_a_new_transport_instance_if_the_state_is_CLOSING() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in @@ -1579,7 +1614,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN11b func test__008__Connection__it_should_make_sure_that__when_the_CLOSED_ProtocolMessage_arrives_for_the_old_connection__it_doesn_t_affect_the_new_one() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in @@ -1642,7 +1678,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN12f func test__045__Connection__close__if_CONNECTING__do_the_operation_once_CONNECTED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose() } @@ -1662,9 +1699,10 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN12a func test__046__Connection__close__if_CONNECTED__should_send_a_CLOSE_action__change_state_to_CLOSING_and_receive_a_CLOSED_action() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { @@ -1705,9 +1743,10 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN12b func test__047__Connection__close__should_transition_to_CLOSED_action_when_the_close_process_timeouts() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { @@ -1756,9 +1795,10 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN12c func test__048__Connection__close__transitions_to_the_CLOSING_state_and_then_to_the_CLOSED_state_if_the_transport_is_abruptly_closed() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { @@ -1804,7 +1844,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN12d func test__049__Connection__close__if_DISCONNECTED__aborts_the_retry_and_moves_immediately_to_CLOSED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.disconnectedRetryTimeout = 1.0 let client = ARTRealtime(options: options) defer { @@ -1836,7 +1877,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN12e func test__050__Connection__close__if_SUSPENDED__aborts_the_retry_and_moves_immediately_to_CLOSED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.suspendedRetryTimeout = 1.0 let client = ARTRealtime(options: options) defer { @@ -1870,7 +1912,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN13b func test__051__Connection__ping__fails_if_in_the_INITIALIZED__SUSPENDED__CLOSING__CLOSED_or_FAILED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.suspendedRetryTimeout = 0.1 options.autoConnect = false let client = ARTRealtime(options: options) @@ -1922,7 +1965,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN13a func test__052__Connection__ping__should_send_a_ProtocolMessage_with_action_HEARTBEAT_and_expects_a_HEARTBEAT_message_in_response() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in client.ping { error in @@ -1937,7 +1981,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN13c func test__053__Connection__ping__should_fail_if_a_HEARTBEAT_ProtocolMessage_is_not_received_within_the_default_realtime_request_timeout() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let realtimeRequestTimeout = 3.0 options.testOptions.realtimeRequestTimeout = realtimeRequestTimeout let client = AblyTests.newRealtime(options).client @@ -1971,7 +2016,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN14a func test__009__Connection__should_enter_FAILED_state_when_API_key_is_invalid() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.key = String(options.key!.reversed()) options.autoConnect = false let client = ARTRealtime(options: options) @@ -1999,14 +2045,15 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN14b func test__054__Connection__connection_request_fails__on_DISCONNECTED_after_CONNECTED__should_not_emit_error_with_a_renewable_token() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.authCallback = { tokenParams, callback in - getTestTokenDetails(key: options.key, capability: tokenParams.capability, ttl: tokenParams.ttl as! TimeInterval?, completion: callback) + getTestTokenDetails(for: test, key: options.key, capability: tokenParams.capability, ttl: tokenParams.ttl as! TimeInterval?, completion: callback) } let tokenTtl = 3.0 - options.token = try getTestToken(key: options.key, ttl: tokenTtl) - options.testOptions.transportFactory = TestProxyTransportFactory() + options.token = try getTestToken(for: test, key: options.key, ttl: tokenTtl) + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { @@ -2044,14 +2091,15 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__055__Connection__connection_request_fails__on_token_error_while_CONNECTING__reissues_token_and_reconnects() throws { + let test = Test() var authCallbackCalled = 0 var tokenTTL = 1.0 - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) options.authCallback = { _, callback in authCallbackCalled += 1 - getTestTokenDetails(ttl: tokenTTL) { token, err in + getTestTokenDetails(for: test, ttl: tokenTTL) { token, err in // Let the token expire delay(2.0) { callback(token, err) @@ -2088,11 +2136,12 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__056__Connection__connection_request_fails__should_transition_to_disconnected_when_the_token_renewal_fails() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let tokenTtl = 3.0 - let tokenDetails = try getTestTokenDetails(key: options.key, capability: nil, ttl: tokenTtl) + let tokenDetails = try getTestTokenDetails(for: test, key: options.key, capability: nil, ttl: tokenTtl) options.token = tokenDetails.token options.authCallback = { _, callback in delay(0) { @@ -2126,11 +2175,12 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__057__Connection__connection_request_fails__should_transition_to_Failed_state_because_the_token_is_invalid_and_not_renewable() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false let tokenTtl = 1.0 - options.token = try getTestToken(ttl: tokenTtl) - options.testOptions.transportFactory = TestProxyTransportFactory() + options.token = try getTestToken(for: test, ttl: tokenTtl) + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) // Let the token expire waitUntil(timeout: testTimeout) { done in @@ -2181,7 +2231,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN14c func test__058__Connection__connection_request_fails__connection_attempt_should_fail_if_not_connected_within_the_default_realtime_request_timeout() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.realtimeHost = "10.255.255.1" // non-routable IP address options.autoConnect = false let realtimeRequestTimeout = 0.5 @@ -2209,7 +2260,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN14d func test__059__Connection__connection_request_fails__connection_attempt_fails_for_any_recoverable_reason() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.realtimeHost = "10.255.255.1" // non-routable IP address options.disconnectedRetryTimeout = 1.0 options.autoConnect = false @@ -2263,7 +2315,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN14e func test__060__Connection__connection_request_fails__connection_state_has_been_in_the_DISCONNECTED_state_for_more_than_the_default_connectionStateTtl_should_change_the_state_to_SUSPENDED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.disconnectedRetryTimeout = 0.1 options.suspendedRetryTimeout = 0.5 options.autoConnect = false @@ -2297,17 +2350,18 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN14e - https://github.com/ably/ably-cocoa/issues/913 func test__061__Connection__connection_request_fails__should_change_the_state_to_SUSPENDED_when_the_connection_state_has_been_in_the_DISCONNECTED_state_for_more_than_the_connectionStateTtl() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.disconnectedRetryTimeout = 0.5 options.suspendedRetryTimeout = 2.0 options.autoConnect = false - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) client.internal.setReachabilityClass(TestReachability.self) defer { - client.simulateRestoreInternetConnection(transportFactory: transportFactory) + client.simulateRestoreInternetConnection(transportFactory: transportFactory, internalQueue: options.internalDispatchQueue) client.dispose() client.close() } @@ -2327,7 +2381,7 @@ class RealtimeClientConnectionTests: XCTestCase { client.connection.on { stateChange in events.append(stateChange.current) } - client.simulateNoInternetConnection(transportFactory: transportFactory) + client.simulateNoInternetConnection(transportFactory: transportFactory, internalQueue: options.internalDispatchQueue) expect(events).toEventually(equal([ .disconnected, @@ -2348,7 +2402,7 @@ class RealtimeClientConnectionTests: XCTestCase { ]), timeout: testTimeout) events.removeAll() - client.simulateRestoreInternetConnection(after: 7.0, transportFactory: transportFactory) + client.simulateRestoreInternetConnection(after: 7.0, transportFactory: transportFactory, internalQueue: options.internalDispatchQueue) expect(events).toEventually(equal([ .connecting, // 2.0 - 1 @@ -2368,7 +2422,8 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__062__Connection__connection_request_fails__on_CLOSE_the_connection_should_stop_connection_retries() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) // to avoid waiting for the default 15s before trying a reconnection options.disconnectedRetryTimeout = 0.1 options.suspendedRetryTimeout = 0.5 @@ -2419,13 +2474,14 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15a func test__063__Connection__connection_failures_once_CONNECTED__should_not_receive_published_messages_until_the_connection_reconnects_successfully() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client1 = ARTRealtime(options: options) defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) var states = [ARTRealtimeConnectionState]() @@ -2473,7 +2529,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15a func test__064__Connection__connection_failures_once_CONNECTED__if_a_Connection_transport_is_disconnected_unexpectedly_or_if_a_token_expires__then_the_Connection_manager_will_immediately_attempt_to_reconnect() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -2503,7 +2560,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15b1, RTN15b2 func test__067__Connection__connection_failures_once_CONNECTED__reconnects_to_the_websocket_endpoint_with_additional_querystring_params__resume_is_the_private_connection_key_and_connection_serial_is_the_most_recent_ProtocolMessage_connectionSerial_received() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } @@ -2527,10 +2585,11 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15c1 func test__068__Connection__connection_failures_once_CONNECTED__System_s_response_to_a_resume_request__CONNECTED_ProtocolMessage_with_the_same_connectionId_as_the_current_client__and_no_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) let expectedConnectionId = client.connection.id @@ -2555,10 +2614,11 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15c2 func test__069__Connection__connection_failures_once_CONNECTED__System_s_response_to_a_resume_request__CONNECTED_ProtocolMessage_with_the_same_connectionId_as_the_current_client_and_an_non_fatal_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -2611,10 +2671,11 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15c3 func test__070__Connection__connection_failures_once_CONNECTED__System_s_response_to_a_resume_request__CONNECTED_ProtocolMessage_with_a_new_connectionId_and_an_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -2657,10 +2718,11 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15c4 func test__071__Connection__connection_failures_once_CONNECTED__System_s_response_to_a_resume_request__ERROR_ProtocolMessage_indicating_a_fatal_error_in_the_connection() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -2688,15 +2750,16 @@ class RealtimeClientConnectionTests: XCTestCase { } func skipped__test__072__Connection__connection_failures_once_CONNECTED__System_s_response_to_a_resume_request__should_resume_the_connection_after_an_auth_renewal() throws { - let options = try AblyTests.commonAppSetup() - options.tokenDetails = try getTestTokenDetails(ttl: 5.0) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.tokenDetails = try getTestTokenDetails(for: test, ttl: 5.0) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let restOptions = try AblyTests.clientOptions(key: options.key!) + let restOptions = try AblyTests.clientOptions(for: test, key: options.key!) restOptions.testOptions.channelNamePrefix = options.testOptions.channelNamePrefix let rest = ARTRest(options: restOptions) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -2767,12 +2830,13 @@ class RealtimeClientConnectionTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTN15d func skipped__test__065__Connection__connection_failures_once_CONNECTED__should_recover_from_disconnection_and_messages_should_be_delivered_once_the_connection_is_resumed() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client1 = ARTRealtime(options: options) defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) let client2 = ARTRealtime(options: options) @@ -2811,14 +2875,15 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15e func test__073__Connection__connection_failures_once_CONNECTED__when_a_connection_is_resumed__the_connection_key_may_change_and_will_be_provided_in_the_first_CONNECTED_ProtocolMessage_connectionDetails() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -2845,10 +2910,11 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15f func test__066__Connection__connection_failures_once_CONNECTED__ACK_and_NACK_responses_for_published_messages_can_only_ever_be_received_on_the_transport_connection_on_which_those_messages_were_sent() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) var resumed = false waitUntil(timeout: testTimeout) { done in @@ -2887,7 +2953,7 @@ class RealtimeClientConnectionTests: XCTestCase { fail("Shouldn't be called") } } - AblyTests.queue.async { + options.internalDispatchQueue.async { client.internal.onDisconnected() } client.connection.once(.connected) { _ in @@ -2907,7 +2973,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15g RTN15g1 func skipped__test__074__Connection__connection_failures_once_CONNECTED__when_connection__ttl_plus_idle_interval__period_has_passed_since_last_activity__uses_a_new_connection() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) // We want this to be > than the sum of customTtlInterval and customIdleInterval options.disconnectedRetryTimeout = 5.0 + customTtlInterval + customIdleInterval ttlAndIdleIntervalPassedTestsClient = AblyTests.newRealtime(options).client @@ -2941,13 +3008,14 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15g3 func test__075__Connection__connection_failures_once_CONNECTED__when_connection__ttl_plus_idle_interval__period_has_passed_since_last_activity__reattaches_to_the_same_channels_after_a_new_connection_has_been_established() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) // We want this to be > than the sum of customTtlInterval and customIdleInterval options.disconnectedRetryTimeout = 5.0 ttlAndIdleIntervalPassedTestsClient = AblyTests.newRealtime(options).client ttlAndIdleIntervalPassedTestsClient.internal.shouldImmediatelyReconnect = false defer { ttlAndIdleIntervalPassedTestsClient.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = ttlAndIdleIntervalPassedTestsClient.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -2981,7 +3049,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15g2 func test__076__Connection__connection_failures_once_CONNECTED__when_connection__ttl_plus_idle_interval__period_has_NOT_passed_since_last_activity__uses_the_same_connection() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) ttlAndIdleIntervalNotPassedTestsClient = AblyTests.newRealtime(options).client ttlAndIdleIntervalNotPassedTestsClient.connect() defer { ttlAndIdleIntervalNotPassedTestsClient.close() } @@ -3009,14 +3078,15 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15h func skipped__test__077__Connection__connection_failures_once_CONNECTED__DISCONNECTED_message_contains_a_token_error__if_the_token_is_renewable_then_error_should_not_be_emitted() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.authCallback = { tokenParams, callback in - getTestTokenDetails(key: options.key, capability: tokenParams.capability, ttl: TimeInterval(60 * 60), completion: callback) + getTestTokenDetails(for: test, key: options.key, capability: tokenParams.capability, ttl: TimeInterval(60 * 60), completion: callback) } let tokenTtl = 2.0 - options.token = try getTestToken(key: options.key, ttl: tokenTtl) - options.testOptions.transportFactory = TestProxyTransportFactory() + options.token = try getTestToken(for: test, key: options.key, ttl: tokenTtl) + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { @@ -3062,13 +3132,14 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15h1 func test__078__Connection__connection_failures_once_CONNECTED__DISCONNECTED_message_contains_a_token_error__and_the_library_does_not_have_a_means_to_renew_the_token__the_connection_will_transition_to_the_FAILED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let key = options.key // set the key to nil so that the client can't sign further token requests options.key = nil let tokenTtl = 3.0 - let tokenDetails = try getTestTokenDetails(key: key, ttl: tokenTtl) + let tokenDetails = try getTestTokenDetails(for: test, key: key, ttl: tokenTtl) options.token = tokenDetails.token let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -3085,17 +3156,18 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN15h2 func skipped__test__079__Connection__connection_failures_once_CONNECTED__DISCONNECTED_message_contains_a_token_error__should_transition_to_disconnected_when_the_token_renewal_fails_and_the_error_should_be_emitted() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let tokenTtl = 3.0 - let tokenDetails = try getTestTokenDetails(key: options.key, capability: nil, ttl: tokenTtl) + let tokenDetails = try getTestTokenDetails(for: test, key: options.key, capability: nil, ttl: tokenTtl) options.token = tokenDetails.token options.authCallback = { _, callback in delay(0.1) { callback(tokenDetails, nil) // Return the same expired token again. } } - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { @@ -3131,12 +3203,13 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN16a func test__080__Connection__Connection_recovery__connection_state_should_recover_explicitly_with_a_recover_key() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let clientSend = ARTRealtime(options: options) defer { clientSend.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channelSend = clientSend.channels.get(channelName) let clientReceive = ARTRealtime(options: options) @@ -3179,10 +3252,11 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN16b func test__081__Connection__Connection_recovery__Connection_recoveryKey_should_be_composed_with_the_connection_key_and_latest_serial_received_and_msgSerial() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(3, done: done) client.connection.once(.connected) { _ in @@ -3210,7 +3284,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN16d func test__082__Connection__Connection_recovery__when_a_connection_is_successfully_recovered__Connection_id_will_be_identical_to_the_id_of_the_connection_that_was_recovered_and_Connection_key_will_always_be_updated_to_the_ConnectionDetails_connectionKey_provided_in_the_first_CONNECTED_ProtocolMessage() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let clientOriginal = ARTRealtime(options: options) defer { clientOriginal.close() } @@ -3238,7 +3313,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN16c func skipped__test__083__Connection__Connection_recovery__Connection_recoveryKey_should_become_becomes_null_when_a_connection_is_explicitly_CLOSED_or_CLOSED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in @@ -3256,7 +3332,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN16e func test__084__Connection__Connection_recovery__should_connect_anyway_if_the_recoverKey_is_no_longer_valid() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.recover = "99999!xxxxxx-xxxxxxxxx-xxxxxxxxx:-1" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -3274,7 +3351,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN16f func test__085__Connection__Connection_recovery__should_use_msgSerial_from_recoveryKey_to_set_the_client_internal_msgSerial_but_is_not_sent_to_Ably() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.recover = "99999!xxxxxx-xxxxxxxxx-xxxxxxxxx:-1:7" @@ -3323,6 +3401,7 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN17b @available(*, deprecated, message: "This test is marked as deprecated so as to not trigger a compiler warning for using the -ARTClientOptions.fallbackHostsUseDefault property. Remove this deprecation when removing the property.") func test__086__Connection__Host_Fallback__failing_connections_with_custom_endpoint_should_result_in_an_error_immediately() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.environment = "test" // do not use the default endpoint XCTAssertFalse(options.fallbackHostsUseDefault) @@ -3333,7 +3412,7 @@ class RealtimeClientConnectionTests: XCTestCase { let testEnvironment = AblyTests.newRealtime(options) let client = testEnvironment.client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) testEnvironment.transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3373,6 +3452,7 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN17b @available(*, deprecated, message: "This test is marked as deprecated so as to not trigger a compiler warning for using the -ARTClientOptions.fallbackHostsUseDefault property. Remove this deprecation when removing the property.") func test__087__Connection__Host_Fallback__failing_connections_with_custom_endpoint_should_result_in_time_outs() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.environment = "test" // do not use the default endpoint options.testOptions.realtimeRequestTimeout = 1.0 @@ -3383,7 +3463,7 @@ class RealtimeClientConnectionTests: XCTestCase { let testEnvironment = AblyTests.newRealtime(options) let client = testEnvironment.client defer { client.dispose(); client.close() } - client.channels.get(uniqueChannelName()) + client.channels.get(uniqueChannelName(for: test)) testEnvironment.transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3413,14 +3493,15 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN17b func test__088__Connection__Host_Fallback__applies_when_the_default_realtime_ably_io_endpoint_is_being_used() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false options.testOptions.realtimeRequestTimeout = 1.0 - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - client.channels.get(uniqueChannelName()) + client.channels.get(uniqueChannelName(for: test)) transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3456,15 +3537,16 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__089__Connection__Host_Fallback__applies_when_an_array_of_ClientOptions_fallbackHosts_is_provided() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false options.fallbackHosts = ["f.ably-realtime.com", "g.ably-realtime.com", "h.ably-realtime.com", "i.ably-realtime.com", "j.ably-realtime.com"] options.testOptions.realtimeRequestTimeout = 1.0 - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - client.channels.get(uniqueChannelName()) + client.channels.get(uniqueChannelName(for: test)) transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3501,37 +3583,44 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN17d func skipped__test__097__Connection__Host_Fallback__should_use_an_alternative_host_when___hostUnreachable() { - testUsesAlternativeHostOnResponse(.hostUnreachable, channelName: uniqueChannelName()) + let test = Test() + testUsesAlternativeHostOnResponse(.hostUnreachable, channelName: uniqueChannelName(for: test)) } func skipped__test__098__Connection__Host_Fallback__should_use_an_alternative_host_when___requestTimeout_timeout__0_1_() { - testUsesAlternativeHostOnResponse(.requestTimeout(timeout: 0.1), channelName: uniqueChannelName()) + let test = Test() + testUsesAlternativeHostOnResponse(.requestTimeout(timeout: 0.1), channelName: uniqueChannelName(for: test)) } func skipped__test__099__Connection__Host_Fallback__should_use_an_alternative_host_when___hostInternalError_code__501_() { - testUsesAlternativeHostOnResponse(.hostInternalError(code: 501), channelName: uniqueChannelName()) + let test = Test() + testUsesAlternativeHostOnResponse(.hostInternalError(code: 501), channelName: uniqueChannelName(for: test)) } func test__100__Connection__Host_Fallback__should_move_to_disconnected_when_there_s_no_internet__with_NSPOSIXErrorDomain_with_code_57() throws { - try testMovesToDisconnectedWithNetworkingError(NSError(domain: "NSPOSIXErrorDomain", code: 57, userInfo: [NSLocalizedDescriptionKey: "shouldn't matter"])) + let test = Test() + try testMovesToDisconnectedWithNetworkingError(NSError(domain: "NSPOSIXErrorDomain", code: 57, userInfo: [NSLocalizedDescriptionKey: "shouldn't matter"]), for: test) } func test__101__Connection__Host_Fallback__should_move_to_disconnected_when_there_s_no_internet__with_NSPOSIXErrorDomain_with_code_50() throws { - try testMovesToDisconnectedWithNetworkingError(NSError(domain: "NSPOSIXErrorDomain", code: 50, userInfo: [NSLocalizedDescriptionKey: "shouldn't matter"])) + let test = Test() + try testMovesToDisconnectedWithNetworkingError(NSError(domain: "NSPOSIXErrorDomain", code: 50, userInfo: [NSLocalizedDescriptionKey: "shouldn't matter"]), for: test) } func test__102__Connection__Host_Fallback__should_move_to_disconnected_when_there_s_no_internet__with_any_kCFErrorDomainCFNetwork() throws { - try testMovesToDisconnectedWithNetworkingError(NSError(domain: "kCFErrorDomainCFNetwork", code: 1337, userInfo: [NSLocalizedDescriptionKey: "shouldn't matter"])) + let test = Test() + try testMovesToDisconnectedWithNetworkingError(NSError(domain: "kCFErrorDomainCFNetwork", code: 1337, userInfo: [NSLocalizedDescriptionKey: "shouldn't matter"]), for: test) } func test__090__Connection__Host_Fallback__should_not_use_an_alternative_host_when_the_client_receives_a_bad_request() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false options.testOptions.realtimeRequestTimeout = 1.0 - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) transportFactory.fakeNetworkResponse = .host400BadRequest @@ -3558,14 +3647,15 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN17a func test__091__Connection__Host_Fallback__every_connection_is_first_attempted_to_the_primary_host_realtime_ably_io() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false options.testOptions.realtimeRequestTimeout = 1.0 - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - client.channels.get(uniqueChannelName()) + client.channels.get(uniqueChannelName(for: test)) transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3611,17 +3701,18 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN17c func test__092__Connection__Host_Fallback__should_retry_hosts_in_random_order_after_checkin_if_an_internet_connection_is_available() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false options.testOptions.realtimeRequestTimeout = 5.0 options.testOptions.shuffleArray = shuffleArrayInExpectedHostOrder - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - client.channels.get(uniqueChannelName()) + client.channels.get(uniqueChannelName(for: test)) - let testHttpExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHttpExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.rest.httpExecutor = testHttpExecutor transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3686,17 +3777,18 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN17c func test__093__Connection__Host_Fallback__doesn_t_try_fallback_host_if_Internet_connection_check_fails() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false options.testOptions.realtimeRequestTimeout = 1.0 - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - client.channels.get(uniqueChannelName()) + client.channels.get(uniqueChannelName(for: test)) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) let testHttpExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.rest.httpExecutor = testHttpExecutor @@ -3731,6 +3823,7 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__094__Connection__Host_Fallback__should_retry_custom_fallback_hosts_in_random_order_after_checkin_if_an_internet_connection_is_available() { + let test = Test() let hostPrefixes = Array("fghij") let expectedFallbackHosts = Array(expectedHostOrder.map { "\(hostPrefixes[$0]).ably-realtime.com" }) @@ -3739,13 +3832,13 @@ class RealtimeClientConnectionTests: XCTestCase { options.fallbackHosts = expectedFallbackHosts.sorted() // will be picked "randomly" as of expectedHostOrder options.testOptions.realtimeRequestTimeout = 5.0 options.testOptions.shuffleArray = shuffleArrayInExpectedHostOrder - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - client.channels.get(uniqueChannelName()) + client.channels.get(uniqueChannelName(for: test)) - let testHttpExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHttpExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.rest.httpExecutor = testHttpExecutor transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3806,15 +3899,16 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__095__Connection__Host_Fallback__won_t_use_fallback_hosts_feature_if_an_empty_array_is_provided() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false options.fallbackHosts = [] - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) - let testHttpExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHttpExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.rest.httpExecutor = testHttpExecutor transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3841,13 +3935,14 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN17e func test__096__Connection__Host_Fallback__client_is_connected_to_a_fallback_host_endpoint_should_do_HTTP_requests_to_the_same_data_centre() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.autoConnect = false - let transportFactory = TestProxyTransportFactory() + let transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) options.testOptions.transportFactory = transportFactory let client = ARTRealtime(options: options) - let testHttpExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHttpExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.rest.httpExecutor = testHttpExecutor transportFactory.fakeNetworkResponse = .hostUnreachable @@ -3885,7 +3980,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN19 func test__010__Connection__attributes_within_ConnectionDetails_should_be_used_as_defaults() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let realtime = AblyTests.newRealtime(options).client defer { realtime.close() } @@ -3924,10 +4020,11 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN19a func skipped__test__103__Connection__Transport_disconnected_side_effects__should_resend_any_ProtocolMessage_that_is_awaiting_a_ACK_NACK() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let transport = client.internal.transport as! TestProxyTransport waitUntil(timeout: testTimeout) { done in @@ -3954,7 +4051,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN19b func skipped__test__104__Connection__Transport_disconnected_side_effects__should_resend_the_ATTACH_message_if_there_are_any_pending_channels() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } @@ -3964,7 +4062,7 @@ class RealtimeClientConnectionTests: XCTestCase { fail("TestProxyTransport is not setup"); return } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in transport.ignoreSends = true channel.attach { error in @@ -3982,7 +4080,7 @@ class RealtimeClientConnectionTests: XCTestCase { } XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) transport.ignoreSends = false - AblyTests.queue.async { + options.internalDispatchQueue.async { client.internal.onDisconnected() } } @@ -3990,10 +4088,11 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN19b func skipped__test__105__Connection__Transport_disconnected_side_effects__should_resent_the_DETACH_message_if_there_are_any_pending_channels() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let transport = client.internal.transport as! TestProxyTransport expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -4026,8 +4125,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN20a - func beforeEach__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_change_the_state_to_DISCONNECTED_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_no_longer_available() throws { - let options = try AblyTests.commonAppSetup() + func beforeEach__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_change_the_state_to_DISCONNECTED_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_no_longer_available(for test: Test) throws { + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false internetConnectionNotAvailableTestsClient = ARTRealtime(options: options) internetConnectionNotAvailableTestsClient.internal.setReachabilityClass(TestReachability.self) @@ -4039,7 +4138,8 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__109__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_change_the_state_to_DISCONNECTED_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_no_longer_available__when_CONNECTING() throws { - try beforeEach__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_change_the_state_to_DISCONNECTED_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_no_longer_available() + let test = Test() + try beforeEach__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_change_the_state_to_DISCONNECTED_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_no_longer_available(for: test) waitUntil(timeout: testTimeout) { done in internetConnectionNotAvailableTestsClient.connection.on { stateChange in @@ -4070,7 +4170,8 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__110__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_change_the_state_to_DISCONNECTED_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_no_longer_available__when_CONNECTED() throws { - try beforeEach__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_change_the_state_to_DISCONNECTED_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_no_longer_available() + let test = Test() + try beforeEach__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_change_the_state_to_DISCONNECTED_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_no_longer_available(for: test) waitUntil(timeout: testTimeout) { done in internetConnectionNotAvailableTestsClient.connection.on { stateChange in @@ -4102,8 +4203,9 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN20b func test__106__Connection__Operating_System_events_for_network_internet_connectivity_changes__should_immediately_attempt_to_connect_if_the_operating_system_indicates_that_the_underlying_internet_connection_is_now_available_when_DISCONNECTED_or_SUSPENDED() throws { + let test = Test() var client: ARTRealtime! - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) // Ensure it won't reconnect because of timeouts. options.disconnectedRetryTimeout = testTimeout.incremented(by: 10).toTimeInterval() options.suspendedRetryTimeout = testTimeout.incremented(by: 10).toTimeInterval() @@ -4140,14 +4242,15 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN22 func test__107__Connection__Operating_System_events_for_network_internet_connectivity_changes__Ably_can_request_that_a_connected_client_re_authenticates_by_sending_the_client_an_AUTH_ProtocolMessage() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.useTokenAuth = true - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -4198,7 +4301,7 @@ class RealtimeClientConnectionTests: XCTestCase { fail("Missing accessToken from AUTH ProtocolMessage auth attribute"); return } - let restOptions = try AblyTests.clientOptions(key: options.key!) + let restOptions = try AblyTests.clientOptions(for: test, key: options.key!) restOptions.testOptions.channelNamePrefix = options.testOptions.channelNamePrefix let rest = ARTRest(options: restOptions) @@ -4223,12 +4326,13 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN22a func test__108__Connection__Operating_System_events_for_network_internet_connectivity_changes__re_authenticate_and_resume_the_connection_when_the_client_is_forcibly_disconnected_following_a_DISCONNECTED_message_containing_an_error_code_greater_than_or_equal_to_40140_and_less_than_40150() throws { - let options = try AblyTests.commonAppSetup() - options.token = try getTestToken(key: options.key!, ttl: 5.0) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.token = try getTestToken(for: test, key: options.key!, ttl: 5.0) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -4277,7 +4381,7 @@ class RealtimeClientConnectionTests: XCTestCase { XCTAssertEqual(client.connection.id, initialConnectionId) XCTAssertEqual(authorizeMethodCallCount, 1) - let restOptions = try AblyTests.clientOptions(key: options.key!) + let restOptions = try AblyTests.clientOptions(for: test, key: options.key!) restOptions.testOptions.channelNamePrefix = options.testOptions.channelNamePrefix let rest = ARTRest(options: restOptions) @@ -4302,7 +4406,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN23a func test__011__Connection__should_disconnect_the_transport_when_no_activity_exist() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let realtimeRequestTimeout = 0.5 options.testOptions.realtimeRequestTimeout = realtimeRequestTimeout let client = AblyTests.newRealtime(options).client @@ -4364,7 +4469,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN24 func test__012__Connection__the_client_may_receive_a_CONNECTED_ProtocolMessage_from_Ably_at_any_point_and_should_emit_an_UPDATE_event() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -4400,7 +4506,8 @@ class RealtimeClientConnectionTests: XCTestCase { // RTN24 func test__013__Connection__should_set_the_Connection_reason_attribute_based_on_the_Error_member_of_the_CONNECTED_ProtocolMessage() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useTokenAuth = true let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } @@ -4445,7 +4552,8 @@ class RealtimeClientConnectionTests: XCTestCase { // https://github.com/ably/ably-cocoa/issues/454 func test__014__Connection__should_not_move_to_FAILED_if_received_DISCONNECT_with_an_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose() @@ -4465,11 +4573,12 @@ class RealtimeClientConnectionTests: XCTestCase { // https://github.com/ably/wiki/issues/22 func skipped__test__111__Connection__with_fixture_messages__should_encode_and_decode_fixture_messages_as_expected() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useBinaryProtocol = false let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -4538,7 +4647,8 @@ class RealtimeClientConnectionTests: XCTestCase { } func skipped__test__112__Connection__with_fixture_messages__should_send_messages_through_raw_JSON_POST_and_retrieve_equal_messages_through_MsgPack_and_JSON() throws { - try setupDependencies() + let test = Test() + try setupDependencies(for: test) let restPublishClient = ARTRest(options: jsonOptions) let realtimeSubscribeClientMsgPack = AblyTests.newRealtime(msgpackOptions).client let realtimeSubscribeClientJSON = AblyTests.newRealtime(jsonOptions).client @@ -4547,7 +4657,7 @@ class RealtimeClientConnectionTests: XCTestCase { realtimeSubscribeClientJSON.close() } - let realtimeSubscribeChannelMsgPack = realtimeSubscribeClientMsgPack.channels.get(uniqueChannelName()) + let realtimeSubscribeChannelMsgPack = realtimeSubscribeClientMsgPack.channels.get(uniqueChannelName(for: test)) let realtimeSubscribeChannelJSON = realtimeSubscribeClientJSON.channels.get(realtimeSubscribeChannelMsgPack.name) waitUntil(timeout: testTimeout) { done in @@ -4591,12 +4701,13 @@ class RealtimeClientConnectionTests: XCTestCase { } func skipped__test__113__Connection__with_fixture_messages__should_send_messages_through_MsgPack_and_JSON_and_retrieve_equal_messages_through_raw_JSON_GET() throws { - try setupDependencies() + let test = Test() + try setupDependencies(for: test) let restPublishClientMsgPack = ARTRest(options: msgpackOptions) let restPublishClientJSON = ARTRest(options: jsonOptions) let restRetrieveClient = ARTRest(options: jsonOptions) - let restPublishChannelMsgPack = restPublishClientMsgPack.channels.get(uniqueChannelName()) + let restPublishChannelMsgPack = restPublishClientMsgPack.channels.get(uniqueChannelName(for: test)) let restPublishChannelJSON = restPublishClientJSON.channels.get(restPublishChannelMsgPack.name) let messages = fixtures["messages"] as! [[String: Any]] @@ -4644,7 +4755,8 @@ class RealtimeClientConnectionTests: XCTestCase { } func test__015__Connection__should_abort_reconnection_with_new_token_if_the_server_has_requested_it_to_authorize_and_after_it_the_connection_has_been_closed() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -4656,7 +4768,7 @@ class RealtimeClientConnectionTests: XCTestCase { } client.auth.internal.options.authCallback = { _, completion in - getTestTokenDetails(ttl: 0.1) { tokenDetails, error in + getTestTokenDetails(for: test, ttl: 0.1) { tokenDetails, error in XCTAssertNil(error) guard let tokenDetails = tokenDetails else { fail("TokenDetails is nil"); return diff --git a/Test/Tests/RealtimeClientPresenceTests.swift b/Test/Tests/RealtimeClientPresenceTests.swift index 84854cc9c..54c7c2177 100644 --- a/Test/Tests/RealtimeClientPresenceTests.swift +++ b/Test/Tests/RealtimeClientPresenceTests.swift @@ -4,15 +4,16 @@ import Nimble import XCTest // RTP16c -private func testResultsInErrorWithConnectionState(_ connectionState: ARTRealtimeConnectionState, channelName: String, performMethod: @escaping (ARTRealtime) -> Void) throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) +private func testResultsInErrorWithConnectionState(_ connectionState: ARTRealtimeConnectionState, for test: Test, channelName: String, performMethod: @escaping (ARTRealtime, ARTClientOptions) -> Void) throws { + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } let channel = client.channels.get(channelName) XCTAssertTrue(client.internal.options.queueMessages) waitUntil(timeout: testTimeout) { done in channel.attach { _ in - performMethod(client) + performMethod(client, options) done() } } @@ -29,8 +30,8 @@ private func testResultsInErrorWithConnectionState(_ connectionState: ARTRealtim } } -private func getSuspendedChannel(named: String) throws -> (ARTRealtimeChannel, ARTRealtime) { - let options = try AblyTests.commonAppSetup() +private func getSuspendedChannel(named: String, for test: Test) throws -> (ARTRealtimeChannel, ARTRealtime) { + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) let channel = client.channels.get(named) @@ -45,8 +46,8 @@ private func getSuspendedChannel(named: String) throws -> (ARTRealtimeChannel, A return (channel, client) } -private func testSuspendedStateResultsInError(channelName: String, _ getPresence: (ARTRealtimeChannel, @escaping ([ARTPresenceMessage]?, ARTErrorInfo?) -> Void) -> Void) throws { - let (channel, client) = try getSuspendedChannel(named: channelName) +private func testSuspendedStateResultsInError(for test: Test, channelName: String, _ getPresence: (ARTRealtimeChannel, @escaping ([ARTPresenceMessage]?, ARTErrorInfo?) -> Void) -> Void) throws { + let (channel, client) = try getSuspendedChannel(named: channelName, for: test) defer { client.dispose(); client.close() } getPresence(channel) { result, err in @@ -107,13 +108,14 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 func skipped__test__009__Presence__ProtocolMessage_bit_flag__when_no_members_are_present() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) @@ -128,7 +130,8 @@ class RealtimeClientPresenceTests: XCTestCase { } func skipped__test__010__Presence__ProtocolMessage_bit_flag__when_members_are_present() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var disposable = [ARTRealtime]() defer { @@ -138,11 +141,11 @@ class RealtimeClientPresenceTests: XCTestCase { } } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) disposable += [AblyTests.addMembersSequentiallyToChannel(channelName, members: 250, options: options)] options.autoConnect = false - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) client.connect() defer { client.dispose(); client.close() } @@ -169,10 +172,11 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP18a, RTP18b func skipped__test__011__Presence__realtime_system_reserves_the_right_to_initiate_a_sync_of_the_presence_members_at_any_point_once_a_channel_is_attached__should_do_a_new_sync_whenever_a_SYNC_ProtocolMessage_is_received_with_a_channel_attribute_and_a_new_sync_sequence_identifier_in_the_channelSerial_attribute() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -252,10 +256,11 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP18c, RTP18b func skipped__test__012__Presence__realtime_system_reserves_the_right_to_initiate_a_sync_of_the_presence_members_at_any_point_once_a_channel_is_attached__when_a_SYNC_is_sent_with_no_channelSerial_attribute_then_the_sync_data_is_entirely_contained_within_that_ProtocolMessage() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in channel.attach { error in @@ -315,8 +320,9 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP19 func skipped__test__013__Presence__PresenceMap_has_existing_members_when_a_SYNC_is_started__should_ensure_that_members_no_longer_present_on_the_channel_are_removed_from_the_local_PresenceMap_once_the_sync_is_complete() throws { - let options = try AblyTests.commonAppSetup() - let channelName = uniqueChannelName() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 2, options: options) @@ -385,10 +391,11 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP19a func skipped__test__014__Presence__PresenceMap_has_existing_members_when_a_SYNC_is_started__should_emit_a_LEAVE_event_for_each_existing_member_if_the_PresenceMap_has_existing_members_when_an_ATTACHED_message_is_received_without_a_HAS_PRESENCE_flag() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) // Inject local members @@ -435,11 +442,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP4 func skipped__test__002__Presence__should_receive_all_250_members() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var clientSource: ARTRealtime! defer { clientSource.dispose(); clientSource.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) clientSource = AblyTests.addMembersSequentiallyToChannel(channelName, members: 250, options: options) let clientTarget = ARTRealtime(options: options) @@ -474,12 +482,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP6a func test__015__Presence__subscribe__with_no_arguments_should_subscribe_a_listener_to_all_presence_messages() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client1 = AblyTests.newRealtime(options).client defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) // We want to make sure that the ENTER presence action that we publish // gets sent by Realtime as a PRESENCE protocol message, and not in the @@ -528,9 +537,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP7a func test__016__Presence__unsubscribe__with_no_arguments_unsubscribes_the_listener_if_previously_subscribed_with_an_action_specific_subscription() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let listener = channel.presence.subscribe { _ in }! XCTAssertEqual(channel.internal.presenceEventEmitter.anyListeners.count, 1) @@ -543,9 +553,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP5a func test__018__Presence__Channel_state_change_side_effects__if_the_channel_enters_the_FAILED_state__all_queued_presence_messages_should_fail_immediately() throws{ - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let protocolError = AblyTests.newErrorProtocolMessage() @@ -562,9 +573,11 @@ class RealtimeClientPresenceTests: XCTestCase { } func skipped__test__019__Presence__Channel_state_change_side_effects__if_the_channel_enters_the_FAILED_state__should_clear_the_PresenceMap_including_local_members_and_does_not_emit_any_presence_events() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) channel.presence.enterClient("user", data: nil) { error in @@ -592,7 +605,7 @@ class RealtimeClientPresenceTests: XCTestCase { expect(channel.internal.presenceMap.localMembers).to(beEmpty()) done() } - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(AblyTests.newErrorProtocolMessage()) } } @@ -601,9 +614,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP5a func test__020__Presence__Channel_state_change_side_effects__if_the_channel_enters_the_DETACHED_state__all_queued_presence_messages_should_fail_immediately() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.once(.attaching) { _ in @@ -618,9 +632,10 @@ class RealtimeClientPresenceTests: XCTestCase { } func test__021__Presence__Channel_state_change_side_effects__if_the_channel_enters_the_DETACHED_state__should_clear_the_PresenceMap_including_local_members_and_does_not_emit_any_presence_events() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) channel.presence.enterClient("user", data: nil) { error in @@ -655,11 +670,12 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP5b func skipped__test__017__Presence__Channel_state_change_side_effects__if_a_channel_enters_the_ATTACHED_state_then_all_queued_presence_messages_will_be_sent_immediately_and_a_presence_SYNC_may_be_initiated() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client1 = AblyTests.newRealtime(options).client defer { client1.dispose(); client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -709,10 +725,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP5f func test__022__Presence__Channel_state_change_side_effects__channel_enters_the_SUSPENDED_state__all_queued_presence_messages_should_fail_immediately() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -742,15 +759,16 @@ class RealtimeClientPresenceTests: XCTestCase { } func test__023__Presence__Channel_state_change_side_effects__channel_enters_the_SUSPENDED_state__should_maintain_the_PresenceMap_and_any_members_present_before_and_after_the_sync_should_not_emit_presence_events() throws { - let options = try AblyTests.commonAppSetup() - let channelName = uniqueChannelName() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime? clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 3, options: options) defer { clientMembers?.dispose(); clientMembers?.close() } options.clientId = "tester" - options.tokenDetails = try getTestTokenDetails(key: options.key!, clientId: options.clientId, ttl: 5.0) + options.tokenDetails = try getTestTokenDetails(for: test, key: options.key!, clientId: options.clientId, ttl: 5.0) let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } let channel = client.channels.get(channelName) @@ -827,13 +845,14 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8a func skipped__test__024__Presence__enter__should_enter_the_current_client__optionally_with_the_data_provided() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client1 = ARTRealtime(options: options) defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) let client2 = ARTRealtime(options: options) @@ -857,9 +876,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP7b func test__025__Presence__unsubscribe__with_a_single_action_argument_unsubscribes_the_provided_listener_to_all_presence_messages_for_that_action() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let listener = channel.presence.subscribe(.present) { _ in }! XCTAssertEqual(channel.internal.presenceEventEmitter.listeners.count, 1) @@ -871,9 +891,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP6c func test__026__Presence__subscribe__should_implicitly_attach_the_channel() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) channel.presence.subscribe { _ in } @@ -890,10 +911,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP6c func test__027__Presence__subscribe__should_result_in_an_error_if_the_channel_is_in_the_FAILED_state() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.internal.onError(AblyTests.newErrorProtocolMessage()) XCTAssertEqual(channel.state, ARTRealtimeChannelState.failed) @@ -911,9 +933,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP6c func test__028__Presence__subscribe__should_result_in_an_error_if_the_channel_moves_to_the_FAILED_state() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let error = AblyTests.newErrorProtocolMessage() @@ -925,7 +949,7 @@ class RealtimeClientPresenceTests: XCTestCase { done() }) { _ in } }) { _ in } - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(error) } } @@ -935,12 +959,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP6b func test__029__Presence__subscribe__with_a_single_action_argument() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client1 = ARTRealtime(options: options) defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) let client2 = ARTRealtime(options: options) @@ -976,13 +1001,14 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP8b func skipped__test__030__Presence__enter__optionally_a_callback_can_be_provided_that_is_called_for_success() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client1 = ARTRealtime(options: options) defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) let client2 = ARTRealtime(options: options) @@ -1004,13 +1030,14 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP8b func skipped__test__031__Presence__enter__optionally_a_callback_can_be_provided_that_is_called_for_failure() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client1 = ARTRealtime(options: options) defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) let client2 = ARTRealtime(options: options) @@ -1034,11 +1061,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8c func test__032__Presence__enter__entering_without_an_explicit_PresenceMessage_clientId_should_implicitly_use_the_clientId_of_the_current_connection() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) // We want to make sure that the ENTER presence action that we publish // gets sent by Realtime as a PRESENCE protocol message, and not in the // channel’s initial post-attach SYNC. So, we wait for any initial SYNC @@ -1072,9 +1100,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8j (former RTP8f) func test__033__Presence__enter__should_result_in_an_error_immediately_if_the_connection_state_is_connected_and_the_client_is_anonymous() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected)) @@ -1088,11 +1117,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8j func test__033__Presence__enter__should_result_in_an_error_immediately_if_the_connection_state_is_connected_and_the_client_is_wildcard() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) options.clientId = "*" defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected)) @@ -1106,11 +1136,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8g func test__034__Presence__enter__should_result_in_an_error_immediately_if_the_channel_is_DETACHED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { _ in @@ -1130,14 +1161,15 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8g func test__035__Presence__enter__should_result_in_an_error_immediately_if_the_channel_is_FAILED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(AblyTests.newErrorProtocolMessage()) done() } @@ -1155,9 +1187,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8i func test__036__Presence__enter__should_result_in_an_error_if_Ably_service_determines_that_the_client_is_unidentified() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter(nil) { error in @@ -1171,12 +1204,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9a func test__037__Presence__update__should_update_the_data_for_the_present_member_with_a_value() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) // We want to make sure that the ENTER presence action that we publish // gets sent by Realtime as a PRESENCE protocol message, and not in the // channel’s initial post-attach SYNC. So, we wait for any initial SYNC @@ -1202,11 +1236,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9a func skipped__test__038__Presence__update__should_update_the_data_for_the_present_member_with_null() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.subscribe(.enter) { member in @@ -1230,11 +1265,12 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP9b func skipped__test__039__Presence__update__should_enter_current_client_into_the_channel_if_the_client_was_not_already_entered() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.internal.presenceMap.members.count, 0) waitUntil(timeout: testTimeout) { done in @@ -1251,11 +1287,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9c func test__040__Presence__update__optionally_a_callback_can_be_provided_that_is_called_for_success() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.update("online") { error in @@ -1267,16 +1304,17 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9c func test__041__Presence__update__optionally_a_callback_can_be_provided_that_is_called_for_failure() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let protocolError = AblyTests.newErrorProtocolMessage() channel.once(.attaching) { _ in - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(protocolError) } } @@ -1290,11 +1328,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9d func test__042__Presence__update__update_without_an_explicit_PresenceMessage_clientId_should_implicitly_use_the_clientId_of_the_current_connection() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter("online") { error in @@ -1321,11 +1360,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10a func skipped__test__043__Presence__leave__should_leave_the_current_client_from_the_channel_and_the_data_will_be_updated_with_the_value_provided() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.subscribe(.enter) { member in @@ -1350,11 +1390,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10a func skipped__test__044__Presence__leave__should_leave_the_current_client_with_no_data() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.subscribe(.enter) { member in @@ -1375,11 +1416,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2 func skipped__test__003__Presence__should_be_used_a_PresenceMap_to_maintain_a_list_of_members() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var clientSecondary: ARTRealtime! defer { clientSecondary.dispose(); clientSecondary.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) clientSecondary = AblyTests.addMembersSequentiallyToChannel(channelName, members: 100, options: options) let client = AblyTests.newRealtime(options).client @@ -1411,10 +1453,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2a func skipped__test__045__Presence__PresenceMap__all_incoming_presence_messages_must_be_compared_for_newness_with_the_matching_member_already_in_the_PresenceMap() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -1465,9 +1508,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2b1 func test__053__Presence__PresenceMap__compare_for_newness__presence_message_has_a_connectionId_which_is_not_an_initial_substring_of_its_id__compares_them_by_timestamp_numerically() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let now = NSDate() - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 101, options: options) @@ -1544,9 +1588,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2b2 func test__052__Presence__PresenceMap__compare_for_newness__split_the_id_of_both_presence_messages() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let now = NSDate() - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 101, options: options) @@ -1625,9 +1670,10 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 func skipped__test__054__Presence__PresenceMap__all_presence_messages_from_a_SYNC_must_also_be_compared_for_newness_in_the_same_way_as_they_would_from_a_PRESENCE__discard_members_where_messages_have_arrived_before_the_SYNC() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let timeBeforeSync = NSDate() - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 120, options: options) @@ -1679,8 +1725,9 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 func skipped__test__055__Presence__PresenceMap__all_presence_messages_from_a_SYNC_must_also_be_compared_for_newness_in_the_same_way_as_they_would_from_a_PRESENCE__accept_members_where_message_have_arrived_after_the_SYNC() throws { - let options = try AblyTests.commonAppSetup() - let channelName = uniqueChannelName() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 120, options: options) @@ -1731,10 +1778,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2d func skipped__test__046__Presence__PresenceMap__if_action_of_ENTER_arrives__it_should_be_added_to_the_presence_map_with_the_action_set_to_PRESENT() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -1755,10 +1803,11 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP2d func skipped__test__047__Presence__PresenceMap__if_action_of_UPDATE_arrives__it_should_be_added_to_the_presence_map_with_the_action_set_to_PRESENT() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -1783,8 +1832,9 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2d func test__048__Presence__PresenceMap__if_action_of_PRESENT_arrives__it_should_be_added_to_the_presence_map_with_the_action_set_to_PRESENT() throws { - let options = try AblyTests.commonAppSetup() - let channelName = uniqueChannelName() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime! defer { clientMembers.dispose(); clientMembers.close() } clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 1, options: options) @@ -1810,11 +1860,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2e func skipped__test__049__Presence__PresenceMap__if_a_SYNC_is_not_in_progress__then_when_a_presence_message_with_an_action_of_LEAVE_arrives__that_memberKey_should_be_deleted_from_the_presence_map__if_present() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 20, options: options) let client = AblyTests.newRealtime(options).client @@ -1855,8 +1906,9 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2f func skipped__test__050__Presence__PresenceMap__if_a_SYNC_is_in_progress__then_when_a_presence_message_with_an_action_of_LEAVE_arrives__it_should_be_stored_in_the_presence_map_with_the_action_set_to_ABSENT() throws { - let options = try AblyTests.commonAppSetup() - let channelName = uniqueChannelName() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } @@ -1918,10 +1970,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP2g func skipped__test__051__Presence__PresenceMap__any_incoming_presence_message_that_passes_the_newness_check_should_be_emitted_on_the_Presence_object__with_an_event_name_set_to_its_original_action() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -1945,12 +1998,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8h func test__056__Presence__enter__should_result_in_an_error_if_the_client_does_not_have_required_presence_permission() throws { - let options = try AblyTests.commonAppSetup() - options.token = try getTestToken(clientId: "john", capability: "{ \"cannotpresence:john\":[\"publish\"] }") + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.token = try getTestToken(for: test, clientId: "john", capability: "{ \"cannotpresence:john\":[\"publish\"] }") options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter(nil) { error in @@ -1967,9 +2021,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9e func test__057__Presence__update__should_result_in_an_error_immediately_if_the_client_is_anonymous() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.update(nil) { error in @@ -1981,11 +2036,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9e func test__058__Presence__update__should_result_in_an_error_immediately_if_the_channel_is_DETACHED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.attach() channel.detach() @@ -2001,13 +2057,14 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9e func test__059__Presence__update__should_result_in_an_error_immediately_if_the_channel_is_FAILED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(AblyTests.newErrorProtocolMessage()) } @@ -2021,12 +2078,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9e func test__060__Presence__update__should_result_in_an_error_if_the_client_does_not_have_required_presence_permission() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(clientId: "john", capability: "{ \"cannotpresence:john\":[\"publish\"] }") + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, clientId: "john", capability: "{ \"cannotpresence:john\":[\"publish\"] }") options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.update(nil) { error in @@ -2041,9 +2099,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP9e func test__061__Presence__update__should_result_in_an_error_if_Ably_service_determines_that_the_client_is_unidentified() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.update(nil) { error in @@ -2057,11 +2116,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10b func test__062__Presence__leave__optionally_a_callback_can_be_provided_that_is_called_for_success() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter("online") { error in @@ -2080,11 +2140,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10b func test__063__Presence__leave__optionally_a_callback_can_be_provided_that_is_called_for_failure() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter("online") { error in @@ -2106,10 +2167,11 @@ class RealtimeClientPresenceTests: XCTestCase { } func test__064__Presence__leave__should_raise_an_error_if_client_is_not_present() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.leave("offline") { error in XCTAssertEqual(error?.code, Int(ARTErrorCode.invalidClientId.rawValue)) @@ -2120,11 +2182,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10c func test__065__Presence__leave__entering_without_an_explicit_PresenceMessage_clientId_should_implicitly_use_the_clientId_of_the_current_connection() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter("online") { error in @@ -2150,12 +2213,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10d func test__066__Presence__leave__if_the_client_is_not_currently_ENTERED__Ably_will_respond_with_an_ACK_and_the_request_will_succeed() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) waitUntil(timeout: testTimeout) { done in @@ -2183,12 +2247,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8d func test__067__Presence__enter__implicitly_attaches_the_Channel() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) waitUntil(timeout: testTimeout) { done in @@ -2203,14 +2268,15 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8d func test__068__Presence__enter__should_result_in_an_error_if_the_channel_is_in_the_FAILED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(AblyTests.newErrorProtocolMessage()) } @@ -2225,12 +2291,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8d func test__069__Presence__enter__should_result_in_an_error_if_the_channel_is_in_the_DETACHED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) @@ -2257,9 +2324,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10e func test__070__Presence__leave__should_result_in_an_error_immediately_if_the_client_is_anonymous() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.leave(nil) { error in @@ -2271,11 +2339,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10e func test__071__Presence__leave__should_result_in_an_error_immediately_if_the_channel_is_DETACHED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter(nil) { error in @@ -2296,11 +2365,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10e func test__072__Presence__leave__should_result_in_an_error_immediately_if_the_channel_is_FAILED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter(nil) { error in @@ -2309,7 +2379,7 @@ class RealtimeClientPresenceTests: XCTestCase { } } - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(AblyTests.newErrorProtocolMessage()) } @@ -2323,12 +2393,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10e func test__073__Presence__leave__should_result_in_an_error_if_the_client_does_not_have_required_presence_permission() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(clientId: "john", capability: "{ \"cannotpresence:other\":[\"publish\"] }") + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, clientId: "john", capability: "{ \"cannotpresence:other\":[\"publish\"] }") options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.leaveClient("other", data: nil) { error in @@ -2340,9 +2411,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP10e func test__074__Presence__leave__should_result_in_an_error_if_Ably_service_determines_that_the_client_is_unidentified() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.leave(nil) { error in @@ -2356,9 +2428,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP6c func test__075__Presence__subscribe__should_implicitly_attach_the_channel() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) channel.presence.subscribe { _ in } @@ -2375,12 +2448,14 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP6c func test__076__Presence__subscribe__should_result_in_an_error_if_the_channel_is_in_the_FAILED_state() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let protocolError = AblyTests.newErrorProtocolMessage() - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(protocolError) } @@ -2397,9 +2472,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP6c func test__077__Presence__subscribe__should_result_in_an_error_if_the_channel_moves_to_the_FAILED_state() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let error = AblyTests.newErrorProtocolMessage() @@ -2410,7 +2487,7 @@ class RealtimeClientPresenceTests: XCTestCase { }, callback: { _ in fail("Should not be called") }) - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(error) } } @@ -2420,13 +2497,14 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8e func test__078__Presence__enter__optional_data_can_be_included_when_entering_a_channel() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client1 = AblyTests.newRealtime(options).client defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) // We want to make sure that the ENTER presence action that we publish // gets sent by Realtime as a PRESENCE protocol message, and not in the @@ -2456,13 +2534,14 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP8e func test__079__Presence__enter__should_emit_the_data_attribute_in_the_LEAVE_event_when_data_is_provided_when_entering_but_no_data_is_provided_when_leaving() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client1 = ARTRealtime(options: options) defer { client1.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel1 = client1.channels.get(channelName) options.clientId = "mary" @@ -2499,8 +2578,9 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP17 func skipped__test__080__Presence__private_and_internal_PresenceMap_containing_only_members_that_match_the_current_connectionId__any_ENTER__PRESENT__UPDATE_or_LEAVE_event_that_matches_the_current_connectionId_should_be_applied_to_this_object() throws { - let options = try AblyTests.commonAppSetup() - let channelName = uniqueChannelName() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelName = uniqueChannelName(for: test) options.clientId = "a" let clientA = ARTRealtime(options: options) @@ -2630,10 +2710,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP17a func skipped__test__081__Presence__private_and_internal_PresenceMap_containing_only_members_that_match_the_current_connectionId__all_members_belonging_to_the_current_connection_are_published_as_a_PresenceMessage_on_the_Channel_by_the_server_irrespective_of_whether_the_client_has_permission_to_subscribe_or_the_Channel_is_configured_to_publish_presence_events() throws { - let options = try AblyTests.commonAppSetup() - let channelName = uniqueChannelName() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelName = uniqueChannelName(for: test) let clientId = NSUUID().uuidString - options.tokenDetails = try getTestTokenDetails(clientId: clientId, capability: "{\"\(channelName)\":[\"presence\",\"publish\"]}") + options.tokenDetails = try getTestTokenDetails(for: test, clientId: clientId, capability: "{\"\(channelName)\":[\"presence\",\"publish\"]}") // Prevent channel name to be prefixed by test-* options.testOptions.channelNamePrefix = nil let client = ARTRealtime(options: options) @@ -2668,11 +2749,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP17b func skipped__test__082__Presence__private_and_internal_PresenceMap_containing_only_members_that_match_the_current_connectionId__events_applied_to_presence_map__should_be_applied_to_ENTER__PRESENT_or_UPDATE_events_with_a_connectionId_that_matches_the_current_client_s_connectionId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) channel.presence.subscribe(.enter) { presence in @@ -2766,12 +2848,13 @@ class RealtimeClientPresenceTests: XCTestCase { } func skipped__test__083__Presence__private_and_internal_PresenceMap_containing_only_members_that_match_the_current_connectionId__events_applied_to_presence_map__should_be_applied_to_any_LEAVE_event_with_a_connectionId_that_matches_the_current_client_s_connectionId_and_is_not_a_synthesized() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) client.internal.shouldImmediatelyReconnect = false defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let partialDone = AblyTests.splitDone(2, done: done) channel.presence.subscribe(.enter) { presence in @@ -2819,10 +2902,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP15d func test__004__Presence__callback_can_be_provided_that_will_be_called_upon_success() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enterClient("Client 1", data: nil) { errorInfo in @@ -2834,11 +2918,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP15d func test__005__Presence__callback_can_be_provided_that_will_be_called_upon_failure() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(capability: "{ \"room\":[\"subscribe\"] }") + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, capability: "{ \"room\":[\"subscribe\"] }") let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enterClient("Client 1", data: nil) { errorInfo in @@ -2854,11 +2939,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP15c func test__006__Presence__should_also_ensure_that_using_updateClient_has_no_side_effects_on_a_client_that_has_entered_normally_using_Presence_enter() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter(nil) { error in @@ -2885,13 +2971,13 @@ class RealtimeClientPresenceTests: XCTestCase { } // RTP15e - func reusableTestsTestPresencePerformMethod(testCase: TestCase_ReusableTestsTestPresencePerformMethod, beforeEach contextBeforeEach: (() -> Void)? = nil, afterEach contextAfterEach: (() -> Void)? = nil, _ performMethod: @escaping (ARTRealtimePresence, ((ARTErrorInfo?) -> Void)?) -> Void) throws { + func reusableTestsTestPresencePerformMethod(for test: Test, testCase: TestCase_ReusableTestsTestPresencePerformMethod, beforeEach contextBeforeEach: (() -> Void)? = nil, afterEach contextAfterEach: (() -> Void)? = nil, _ performMethod: @escaping (ARTRealtimePresence, ((ARTErrorInfo?) -> Void)?) -> Void) throws { func test__should_implicitly_attach_the_Channel() throws { contextBeforeEach?() - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) waitUntil(timeout: testTimeout) { done in @@ -2910,12 +2996,13 @@ class RealtimeClientPresenceTests: XCTestCase { func test__should_result_in_an_error_if_the_channel_is_in_the_FAILED_state() throws { contextBeforeEach?() - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let expectedErrorMessage = "Something has failed" - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(AblyTests.newErrorProtocolMessage(message: expectedErrorMessage)) } @@ -2938,14 +3025,15 @@ class RealtimeClientPresenceTests: XCTestCase { func test__should_result_in_an_error_if_the_channel_moves_to_the_FAILED_state() throws { contextBeforeEach?() - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let options = try AblyTests.commonAppSetup(for: test) + let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let error = AblyTests.newErrorProtocolMessage() channel.once(.attaching) { _ in - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(error) } } @@ -2971,7 +3059,8 @@ class RealtimeClientPresenceTests: XCTestCase { } func reusableTestsWrapper__Presence__enterClient__reusableTestsTestPresencePerformMethod(testCase: TestCase_ReusableTestsTestPresencePerformMethod) throws { - try reusableTestsTestPresencePerformMethod(testCase: testCase) { $0.enterClient("john", data: nil, callback: $1) } + let test = Test() + try reusableTestsTestPresencePerformMethod(for: test, testCase: testCase) { $0.enterClient("john", data: nil, callback: $1) } } func test__084__Presence__enterClient__should_implicitly_attach_the_Channel() throws { @@ -2987,7 +3076,8 @@ class RealtimeClientPresenceTests: XCTestCase { } func reusableTestsWrapper__Presence__updateClient__reusableTestsTestPresencePerformMethod(testCase: TestCase_ReusableTestsTestPresencePerformMethod) throws { - try reusableTestsTestPresencePerformMethod(testCase: testCase) { $0.updateClient("john", data: nil, callback: $1) } + let test = Test() + try reusableTestsTestPresencePerformMethod(for: test, testCase: testCase) { $0.updateClient("john", data: nil, callback: $1) } } func test__087__Presence__updateClient__should_implicitly_attach_the_Channel() throws { @@ -3003,7 +3093,8 @@ class RealtimeClientPresenceTests: XCTestCase { } func reusableTestsWrapper__Presence__leaveClient__reusableTestsTestPresencePerformMethod(testCase: TestCase_ReusableTestsTestPresencePerformMethod) throws { - try reusableTestsTestPresencePerformMethod(testCase: testCase) { $0.leaveClient("john", data: nil, callback: $1) } + let test = Test() + try reusableTestsTestPresencePerformMethod(for: test, testCase: testCase) { $0.leaveClient("john", data: nil, callback: $1) } } func test__090__Presence__leaveClient__should_implicitly_attach_the_Channel() throws { @@ -3020,11 +3111,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP15f func test__007__Presence__should_indicate_an_error_if_the_client_is_identified_and_has_a_valid_clientId_and_the_clientId_argument_does_not_match_the_client_s_clientId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enter("browser") { error in @@ -3048,9 +3140,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP16a func test__093__Presence__Connection_state_conditions__all_presence_messages_are_published_immediately_if_the_connection_is_CONNECTED() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.presence.enterClient("user", data: nil) { error in @@ -3066,10 +3159,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP16b func test__094__Presence__Connection_state_conditions__all_presence_messages_will_be_queued_and_delivered_as_soon_as_the_connection_state_returns_to_CONNECTED() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertTrue(client.internal.options.queueMessages) waitUntil(timeout: testTimeout) { done in @@ -3093,11 +3187,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP16b func test__095__Presence__Connection_state_conditions__all_presence_messages_will_be_lost_if_queueMessages_has_been_explicitly_set_to_false() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.queueMessages = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertFalse(client.internal.options.queueMessages) expect(client.connection.state).toEventually(equal(ARTRealtimeConnectionState.connected), timeout: testTimeout) @@ -3120,12 +3215,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP16c func test__096__Presence__Connection_state_conditions__should_result_in_an_error_if_the_connection_state_is_INITIALIZED_and_queueMessages_has_been_explicitly_set_to_false() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.queueMessages = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(client.connection.state, ARTRealtimeConnectionState.initialized) @@ -3140,22 +3236,25 @@ class RealtimeClientPresenceTests: XCTestCase { } func test__097__Presence__Connection_state_conditions__should_result_in_an_error_if_the_connection_state_is__suspended() throws { - try testResultsInErrorWithConnectionState(.suspended, channelName: uniqueChannelName()) { client in - AblyTests.queue.async { + let test = Test() + try testResultsInErrorWithConnectionState(.suspended, for: test, channelName: uniqueChannelName(for: test)) { client, options in + options.internalDispatchQueue.async { client.internal.onSuspended() } } } func test__098__Presence__Connection_state_conditions__should_result_in_an_error_if_the_connection_state_is__closed() throws { - try testResultsInErrorWithConnectionState(.closed, channelName: uniqueChannelName()) { client in + let test = Test() + try testResultsInErrorWithConnectionState(.closed, for: test, channelName: uniqueChannelName(for: test)) { client, _ in client.close() } } func test__099__Presence__Connection_state_conditions__should_result_in_an_error_if_the_connection_state_is__failed() throws { - try testResultsInErrorWithConnectionState(.failed, channelName: uniqueChannelName()) { client in - AblyTests.queue.async { + let test = Test() + try testResultsInErrorWithConnectionState(.failed, for: test, channelName: uniqueChannelName(for: test)) { client, options in + options.internalDispatchQueue.async { client.internal.onError(AblyTests.newErrorProtocolMessage()) } } @@ -3170,7 +3269,8 @@ class RealtimeClientPresenceTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // RTP11a func skipped__test__100__Presence__get__should_return_a_list_of_current_members_on_the_channel() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var disposable = [ARTRealtime]() defer { @@ -3182,7 +3282,7 @@ class RealtimeClientPresenceTests: XCTestCase { let expectedData = "online" - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) disposable += [AblyTests.addMembersSequentiallyToChannel(channelName, members: 150, data: expectedData as AnyObject?, options: options)] let client = ARTRealtime(options: options) @@ -3213,9 +3313,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11b func test__101__Presence__get__should_implicitly_attach_the_channel() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) waitUntil(timeout: testTimeout) { done in @@ -3231,12 +3332,14 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11b func test__102__Presence__get__should_result_in_an_error_if_the_channel_is_in_the_FAILED_state() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let pm = AblyTests.newErrorProtocolMessage() - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(pm) } @@ -3262,9 +3365,11 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11b func test__103__Presence__get__should_result_in_an_error_if_the_channel_moves_to_the_FAILED_state() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let pm = AblyTests.newErrorProtocolMessage() @@ -3273,7 +3378,7 @@ class RealtimeClientPresenceTests: XCTestCase { } (client.internal.transport as! TestProxyTransport).actionsIgnored += [.attached] channel.once(.attaching) { _ in - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onError(pm) } } @@ -3292,9 +3397,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11b func test__104__Presence__get__should_result_in_an_error_if_the_channel_is_in_the_DETACHED_state() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach() @@ -3316,7 +3422,8 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11b func test__105__Presence__get__should_result_in_an_error_if_the_channel_moves_to_the_DETACHED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -3324,7 +3431,7 @@ class RealtimeClientPresenceTests: XCTestCase { var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 120, options: options) let channel = client.channels.get(channelName) @@ -3350,13 +3457,15 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11d func test__107__Presence__get__If_the_Channel_is_in_the_SUSPENDED_state_then__by_default__results_in_an_error() throws { - try testSuspendedStateResultsInError(channelName: uniqueChannelName()) { channel, callback in + let test = Test() + try testSuspendedStateResultsInError(for: test, channelName: uniqueChannelName(for: test)) { channel, callback in channel.presence.get(callback) } } func test__108__Presence__get__If_the_Channel_is_in_the_SUSPENDED_state_then__if_waitForSync_is_true__results_in_an_error() throws { - try testSuspendedStateResultsInError(channelName: uniqueChannelName()) { channel, callback in + let test = Test() + try testSuspendedStateResultsInError(for: test, channelName: uniqueChannelName(for: test)) { channel, callback in let params = ARTRealtimePresenceQuery() params.waitForSync = true channel.presence.get(params, callback: callback) @@ -3364,7 +3473,8 @@ class RealtimeClientPresenceTests: XCTestCase { } func test__109__Presence__get__If_the_Channel_is_in_the_SUSPENDED_state_then__if_waitForSync_is_false__returns_the_members_in_the_current_PresenceMap() throws { - let (channel, client) = try getSuspendedChannel(named: uniqueChannelName()) + let test = Test() + let (channel, client) = try getSuspendedChannel(named: uniqueChannelName(for: test), for: test) defer { client.dispose(); client.close() } var msgs = [String: ARTPresenceMessage]() @@ -3392,11 +3502,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11c1 func skipped__test__110__Presence__get__Query__set_of_params___waitForSync_is_true__should_wait_until_SYNC_is_complete_before_returning_a_list_of_members() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var clientSecondary: ARTRealtime! defer { clientSecondary.dispose(); clientSecondary.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) clientSecondary = AblyTests.addMembersSequentiallyToChannel(channelName, members: 150, options: options) let client = AblyTests.newRealtime(options).client @@ -3431,11 +3542,12 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11c1 func test__111__Presence__get__Query__set_of_params___waitForSync_is_false__should_return_immediately_the_known_set_of_presence_members() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var clientSecondary: ARTRealtime! defer { clientSecondary.dispose(); clientSecondary.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) clientSecondary = AblyTests.addMembersSequentiallyToChannel(channelName, members: 150, options: options) let client = AblyTests.newRealtime(options).client @@ -3483,12 +3595,13 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11c2 func test__112__Presence__get__Query__set_of_params___should_return_members_filtered_by_clientId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let now = NSDate() let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) let presenceData: [ARTPresenceMessage] = [ @@ -3542,9 +3655,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP11c3 func test__113__Presence__get__Query__set_of_params___should_return_members_filtered_by_connectionId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let now = NSDate() - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) var clientMembers: ARTRealtime? defer { clientMembers?.dispose(); clientMembers?.close() } clientMembers = AblyTests.addMembersSequentiallyToChannel(channelName, members: 101, options: options) @@ -3624,14 +3738,15 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP12a func test__114__Presence__history__should_support_all_the_same_params_as_Rest() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let realtime = ARTRealtime(options: options) defer { realtime.dispose(); realtime.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channelRest = rest.channels.get(channelName) let channelRealtime = realtime.channels.get(channelName) @@ -3679,7 +3794,8 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP12c, RTP12d func test__115__Presence__history__should_return_a_PaginatedResult_page() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var clientSecondary: ARTRealtime! defer { clientSecondary.dispose(); clientSecondary.close() } @@ -3687,7 +3803,7 @@ class RealtimeClientPresenceTests: XCTestCase { let expectedData = ["x", "y"] let expectedPattern = "^user(\\d+)$" - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) clientSecondary = AblyTests.addMembersSequentiallyToChannel(channelName, members: 150, data: expectedData as AnyObject?, options: options) let client = ARTRealtime(options: options) @@ -3736,7 +3852,8 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP13 func skipped__test__008__Presence__Presence_syncComplete_returns_true_if_the_initial_SYNC_operation_has_completed() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) var disposable = [ARTRealtime]() defer { @@ -3746,7 +3863,7 @@ class RealtimeClientPresenceTests: XCTestCase { } } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) disposable += [AblyTests.addMembersSequentiallyToChannel(channelName, members: 250, options: options)] let client = AblyTests.newRealtime(options).client @@ -3772,9 +3889,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP14a, RTP14b, RTP14c, RTP14d func skipped__test__116__Presence__enterClient__enters_into_presence_on_a_channel_on_behalf_of_another_clientId() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) XCTAssertEqual(channel.internal.presenceMap.members.count, 0) let expectedData = ["test": 1] @@ -3821,9 +3939,10 @@ class RealtimeClientPresenceTests: XCTestCase { // RTP14d func test__117__Presence__enterClient__should_be_present_all_the_registered_members_on_a_presence_channel() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) let john = "john" @@ -3862,7 +3981,8 @@ class RealtimeClientPresenceTests: XCTestCase { // TP3a func test__118__Presence__presence_message_attributes__if_the_presence_message_does_not_contain_an_id__it_should_be_set_to_protocolMsgId_index() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -3881,7 +4001,7 @@ class RealtimeClientPresenceTests: XCTestCase { XCTAssertEqual(message.id, "protocolId:0") done() } - AblyTests.queue.async { + options.internalDispatchQueue.async { channel.internal.onPresence(protocolMessage) } } diff --git a/Test/Tests/RealtimeClientTests.swift b/Test/Tests/RealtimeClientTests.swift index 717bb817f..20720e639 100644 --- a/Test/Tests/RealtimeClientTests.swift +++ b/Test/Tests/RealtimeClientTests.swift @@ -39,9 +39,10 @@ class RealtimeClientTests: XCTestCase { // G4 func test__001__RealtimeClient__All_WebSocket_connections_should_include_the_current_API_version() throws { - let client = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let client = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "message") { error in XCTAssertNil(error) @@ -59,7 +60,8 @@ class RealtimeClientTests: XCTestCase { // RTC1 func test__013__RealtimeClient__options__should_support_the_same_options_as_the_Rest_client() throws { - let options = try AblyTests.commonAppSetup() // Same as Rest + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) // Same as Rest options.clientId = "client_string" let client = ARTRealtime(options: options) @@ -97,7 +99,8 @@ class RealtimeClientTests: XCTestCase { // RTC1c func test__016__RealtimeClient__options__should_attempt_to_recover_the_connection_state_if_recover_string_is_assigned() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" // First connection @@ -175,7 +178,8 @@ class RealtimeClientTests: XCTestCase { // RTC1e func test__018__RealtimeClient__options__should_modify_both_the_REST_and_realtime_endpoint_if_environment_string_is_assigned() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let oldRestHost = options.restHost let oldRealtimeHost = options.realtimeHost @@ -192,7 +196,8 @@ class RealtimeClientTests: XCTestCase { // RTC1f func test__019__RealtimeClient__options__url_should_contains_transport_params() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.transportParams = [ "tpBool": .init(bool: true), "tpInt": .init(number: .init(value: 12)), @@ -233,7 +238,8 @@ class RealtimeClientTests: XCTestCase { // RTC2 func test__002__RealtimeClient__should_have_access_to_the_underlying_Connection_object() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) expect(client.connection).to(beAKindOf(ARTConnection.self)) @@ -241,13 +247,14 @@ class RealtimeClientTests: XCTestCase { // RTC3 func test__003__RealtimeClient__should_provide_access_to_the_underlying_Channels_object() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) client.channels.get(channelName).subscribe { _ in // Attached @@ -258,7 +265,8 @@ class RealtimeClientTests: XCTestCase { // RTC4 func test__020__RealtimeClient__Auth_object__should_provide_access_to_the_Auth_object() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.close() } XCTAssertEqual(client.auth.internal.options.key, options.key) @@ -266,7 +274,8 @@ class RealtimeClientTests: XCTestCase { // RTC4a func test__021__RealtimeClient__Auth_object__clientId_may_be_populated_when_the_connection_is_established() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client_string" let client = ARTRealtime(options: options) defer { client.close() } @@ -292,7 +301,8 @@ class RealtimeClientTests: XCTestCase { // RTC5a func test__022__RealtimeClient__stats__should_present_an_async_interface() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.close() } // Async waitUntil(timeout: testTimeout) { done in @@ -308,7 +318,8 @@ class RealtimeClientTests: XCTestCase { // RTC5b func skipped__test__023__RealtimeClient__stats__should_accept_all_the_same_params_as_RestClient() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.close() } var paginatedResult: ARTPaginatedResult? waitUntil(timeout: testTimeout) { done in @@ -352,7 +363,8 @@ class RealtimeClientTests: XCTestCase { // RTC6a func test__024__RealtimeClient__time__should_present_an_async_interface() throws { - let client = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.close() } // Async waitUntil(timeout: testTimeout) { done in @@ -366,7 +378,8 @@ class RealtimeClientTests: XCTestCase { // RTC7 func test__004__RealtimeClient__should_use_the_configured_timeouts_specified() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.suspendedRetryTimeout = 6.0 let client = ARTRealtime(options: options) @@ -416,10 +429,11 @@ class RealtimeClientTests: XCTestCase { // RTC8a func test__025__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__in_the_CONNECTED_state_and_auth_authorize_is_called__the_client_must_obtain_a_new_token__send_an_AUTH_ProtocolMessage_with_an_auth_attribute() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.useTokenAuth = true - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -472,11 +486,12 @@ class RealtimeClientTests: XCTestCase { // RTC8a1 - part 1 func test__026__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__when_the_authentication_token_change_is_successful__then_the_client_should_receive_a_new_CONNECTED_ProtocolMessage() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - let testToken = try getTestToken() + let testToken = try getTestToken(for: test) options.token = testToken - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -532,11 +547,12 @@ class RealtimeClientTests: XCTestCase { // RTC8a1 - part 2 func test__027__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__performs_an_upgrade_of_capabilities_without_any_loss_of_continuity_or_connectivity_during_the_upgrade_process() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - let testToken = try getTestToken(capability: "{\"test\":[\"subscribe\"]}") + let testToken = try getTestToken(for: test, capability: "{\"test\":[\"subscribe\"]}") options.token = testToken - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -548,7 +564,7 @@ class RealtimeClientTests: XCTestCase { client.connect() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.once(.failed) { stateChange in guard let error = stateChange.reason else { @@ -623,15 +639,16 @@ class RealtimeClientTests: XCTestCase { // RTC8a1 - part 3 func test__028__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__when_capabilities_are_downgraded__client_should_receive_an_ERROR_ProtocolMessage_with_a_channel_property() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - let testToken = try getTestToken() + let testToken = try getTestToken(for: test) options.token = testToken - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in client.connect() channel.attach { error in @@ -684,11 +701,12 @@ class RealtimeClientTests: XCTestCase { // RTC8a2 func test__029__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__when_the_authentication_token_change_fails__client_should_receive_an_ERROR_ProtocolMessage_triggering_the_connection_to_transition_to_the_FAILED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.clientId = "ios" options.useTokenAuth = true - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -734,8 +752,9 @@ class RealtimeClientTests: XCTestCase { } func test__030__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__authorize_call_should_complete_with_an_error_if_the_request_fails() throws { - let options = try AblyTests.clientOptions() - let testToken = try getTestToken() + let test = Test() + let options = try AblyTests.clientOptions(for: test) + let testToken = try getTestToken(for: test) options.token = testToken let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -776,10 +795,11 @@ class RealtimeClientTests: XCTestCase { // RTC8a3 func test__031__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__authorize_call_should_be_indicated_as_completed_with_the_new_token_or_error_only_once_realtime_has_responded_to_the_AUTH_with_either_a_CONNECTED_or_ERROR_respectively() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.useTokenAuth = true - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -810,10 +830,11 @@ class RealtimeClientTests: XCTestCase { // RTC8b func test__032__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__when_connection_is_CONNECTING__all_current_connection_attempts_should_be_halted__and_after_obtaining_a_new_token_the_library_should_immediately_initiate_a_connection_attempt_using_the_new_token() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.useTokenAuth = true - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -835,7 +856,7 @@ class RealtimeClientTests: XCTestCase { let authOptions = ARTAuthOptions() do { - authOptions.key = try AblyTests.commonAppSetup().key + authOptions.key = try AblyTests.commonAppSetup(for: test).key } catch { fail("commonAppSetup failed: \(error)") } @@ -866,9 +887,10 @@ class RealtimeClientTests: XCTestCase { // RTC8b1 - part 1 func test__033__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__authorize_call_should_complete_with_the_new_token_once_the_connection_has_moved_to_the_CONNECTED_state() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.autoConnect = false - let testToken = try getTestToken() + let testToken = try getTestToken(for: test) options.token = testToken let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -876,7 +898,7 @@ class RealtimeClientTests: XCTestCase { waitUntil(timeout: testTimeout) { done in let authOptions = ARTAuthOptions() do { - authOptions.key = try AblyTests.commonAppSetup().key + authOptions.key = try AblyTests.commonAppSetup(for: test).key } catch { fail("commonAppSetup failed: \(error)") } @@ -896,10 +918,11 @@ class RealtimeClientTests: XCTestCase { // RTC8b1 - part 2 func test__034__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__authorize_call_should_complete_with_an_error_if_the_connection_moves_to_the_FAILED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.useTokenAuth = true - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -946,10 +969,11 @@ class RealtimeClientTests: XCTestCase { // RTC8b1 - part 3 func test__035__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__authorize_call_should_complete_with_an_error_if_the_connection_moves_to_the_SUSPENDED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.useTokenAuth = true - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -988,7 +1012,8 @@ class RealtimeClientTests: XCTestCase { // RTC8b1 - part 4 func skipped__test__036__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__authorize_call_should_complete_with_an_error_if_the_connection_moves_to_the_CLOSED_state() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false options.useTokenAuth = true let client = ARTRealtime(options: options) @@ -1031,11 +1056,12 @@ class RealtimeClientTests: XCTestCase { // RTC8c - part 1 func test__037__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__when_the_connection_is_in_the_SUSPENDED_state_when_auth_authorize_is_called__after_obtaining_a_token_the_library_should_move_to_the_CONNECTING_state_and_initiate_a_connection_attempt_using_the_new_token() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - let testToken = try getTestToken() + let testToken = try getTestToken(for: test) options.token = testToken - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -1086,11 +1112,12 @@ class RealtimeClientTests: XCTestCase { // RTC8c - part 2 func test__038__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__when_the_connection_is_in_the_CLOSED_state_when_auth_authorize_is_called__after_obtaining_a_token_the_library_should_move_to_the_CONNECTING_state_and_initiate_a_connection_attempt_using_the_new_token() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - let testToken = try getTestToken() + let testToken = try getTestToken(for: test) options.token = testToken - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -1141,11 +1168,12 @@ class RealtimeClientTests: XCTestCase { // RTC8c - part 3 func test__039__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__when_the_connection_is_in_the_DISCONNECTED_state_when_auth_authorize_is_called__after_obtaining_a_token_the_library_should_move_to_the_CONNECTING_state_and_initiate_a_connection_attempt_using_the_new_token() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - let testToken = try getTestToken() + let testToken = try getTestToken(for: test) options.token = testToken - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -1196,11 +1224,12 @@ class RealtimeClientTests: XCTestCase { // RTC8c - part 4 func test__040__RealtimeClient__Auth_authorize_should_upgrade_the_connection_with_current_token__when_the_connection_is_in_the_FAILED_state_when_auth_authorize_is_called__after_obtaining_a_token_the_library_should_move_to_the_CONNECTING_state_and_initiate_a_connection_attempt_using_the_new_token() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false - let testToken = try getTestToken() + let testToken = try getTestToken(for: test) options.token = testToken - options.testOptions.transportFactory = TestProxyTransportFactory() + options.testOptions.transportFactory = TestProxyTransportFactory(internalQueue: options.internalDispatchQueue) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -1252,18 +1281,19 @@ class RealtimeClientTests: XCTestCase { // FIXME: Fix flaky presence tests and re-enable. See https://ably-real-time.slack.com/archives/C030C5YLY/p1623172436085700 // https://github.com/ably/ably-cocoa/issues/577 func skipped__test__005__RealtimeClient__background_behaviour() { + let test = Test() waitUntil(timeout: testTimeout) { done in URLSession.shared.dataTask(with: URL(string: "https://ably.io")!) { _, _, _ in let realtime: ARTRealtime do { - realtime = .init(options: try AblyTests.commonAppSetup()) + realtime = .init(options: try AblyTests.commonAppSetup(for: test)) } catch { XCTFail("commonAppSetup failed: \(error)") return } - realtime.channels.get(uniqueChannelName()).attach { error in + realtime.channels.get(uniqueChannelName(for: test)).attach { error in XCTAssertNil(error) realtime.close() done() @@ -1273,9 +1303,10 @@ class RealtimeClientTests: XCTestCase { } func test__006__RealtimeClient__should_accept_acks_with_different_order() throws { - let realtime = AblyTests.newRealtime(try AblyTests.commonAppSetup()).client + let test = Test() + let realtime = AblyTests.newRealtime(try AblyTests.commonAppSetup(for: test)).client defer { realtime.dispose(); realtime.close() } - let channel = realtime.channels.get(uniqueChannelName()) + let channel = realtime.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in XCTAssertNil(error) @@ -1323,7 +1354,8 @@ class RealtimeClientTests: XCTestCase { } func test__007__RealtimeClient__transport_should_guarantee_the_incoming_message_order() throws { - let realtime = ARTRealtime(options: try AblyTests.commonAppSetup()) + let test = Test() + let realtime = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { realtime.dispose(); realtime.close() } waitUntil(timeout: testTimeout) { done in realtime.connection.on(.connected) { _ in @@ -1360,7 +1392,8 @@ class RealtimeClientTests: XCTestCase { } func test__008__RealtimeClient__subscriber_should_receive_messages_in_the_same_order_in_which_they_have_been_sent() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let realtime1 = ARTRealtime(options: options) let realtime2 = ARTRealtime(options: options) defer { @@ -1368,7 +1401,7 @@ class RealtimeClientTests: XCTestCase { realtime2.dispose(); realtime2.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let subscribeChannel = realtime1.channels.get(channelName) let sendChannel = realtime2.channels.get(channelName) @@ -1399,10 +1432,13 @@ class RealtimeClientTests: XCTestCase { // Issue https://github.com/ably/ably-cocoa/issues/640 func test__009__RealtimeClient__should_dispatch_in_user_queue_when_removing_an_observer() { + let test = Test() + let channelName = uniqueChannelName(for: test) class Foo { - static let channelName = uniqueChannelName(testIdentifier: "test__009__RealtimeClient__should_dispatch_in_user_queue_when_removing_an_observer") - init() { - AblyManager.sharedClient.channels.get(Self.channelName).subscribe { _ in + private let channelName: String + init(channelName: String) { + self.channelName = channelName + AblyManager.sharedClient.channels.get(channelName).subscribe { _ in // keep reference self.update() } @@ -1411,18 +1447,19 @@ class RealtimeClientTests: XCTestCase { func update() {} deinit { - AblyManager.sharedClient.channels.get(Self.channelName).unsubscribe() + AblyManager.sharedClient.channels.get(channelName).unsubscribe() } } - var foo: Foo? = Foo() + var foo: Foo? = Foo(channelName: channelName) XCTAssertNotNil(foo) foo = nil - AblyManager.sharedClient.channels.get(Foo.channelName).unsubscribe() + AblyManager.sharedClient.channels.get(channelName).unsubscribe() } func test__010__RealtimeClient__should_never_register_any_connection_listeners_for_internal_use_with_the_public_EventEmitter() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.autoConnect = false let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } @@ -1440,11 +1477,12 @@ class RealtimeClientTests: XCTestCase { } func test__011__RealtimeClient__should_never_register_any_message_and_channel_listeners_for_internal_use_with_the_public_EventEmitter() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { _ in done() @@ -1475,11 +1513,12 @@ class RealtimeClientTests: XCTestCase { } func skipped__test__012__RealtimeClient__moves_to_DISCONNECTED_on_an_unexpected_normal_WebSocket_close() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) defer { client.dispose(); client.close() } - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) var received = false client.channels.get(channelName).subscribe { _ in @@ -1502,9 +1541,10 @@ class RealtimeClientTests: XCTestCase { // RSL1i func test__041__If_the_total_size_of_message_s__exceeds_the_maxMessageSize__the_client_library_should_reject_the_publish_and_indicate_an_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRealtime(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let messages = buildMessagesThatExceedMaxMessageSize() defer { client.dispose(); client.close() } @@ -1520,10 +1560,11 @@ class RealtimeClientTests: XCTestCase { } func test__042__If_the_total_size_of_message_s__exceeds_the_maxMessageSize__the_client_library_should_reject_also_presence_messages__enter_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = clientId let client = ARTRealtime(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout, action: { done in @@ -1537,10 +1578,11 @@ class RealtimeClientTests: XCTestCase { } func test__043__If_the_total_size_of_message_s__exceeds_the_maxMessageSize__the_client_library_should_reject_also_presence_messages__leave_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = clientId let client = ARTRealtime(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout, action: { done in @@ -1554,10 +1596,11 @@ class RealtimeClientTests: XCTestCase { } func test__044__If_the_total_size_of_message_s__exceeds_the_maxMessageSize__the_client_library_should_reject_also_presence_messages__update_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = clientId let client = ARTRealtime(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout, action: { done in @@ -1571,10 +1614,11 @@ class RealtimeClientTests: XCTestCase { } func test__045__If_the_total_size_of_message_s__exceeds_the_maxMessageSize__the_client_library_should_reject_also_presence_messages__updateClient_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = clientId let client = ARTRealtime(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout, action: { done in @@ -1588,10 +1632,11 @@ class RealtimeClientTests: XCTestCase { } func test__046__If_the_total_size_of_message_s__exceeds_the_maxMessageSize__the_client_library_should_reject_also_presence_messages__leaveClient_() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = clientId let client = ARTRealtime(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout, action: { done in diff --git a/Test/Tests/RestClientChannelTests.swift b/Test/Tests/RestClientChannelTests.swift index 572bd3a73..716d2fe96 100644 --- a/Test/Tests/RestClientChannelTests.swift +++ b/Test/Tests/RestClientChannelTests.swift @@ -3,9 +3,6 @@ import Foundation import Nimble import XCTest -private var client: ARTRest! -private var testHTTPExecutor: TestProxyHTTPExecutor! - private func assertMessagePayloadId(id: String?, expectedSerial: String) { guard let id = id else { fail("Message.id from payload is nil"); return @@ -37,8 +34,8 @@ private let dictionary = ["number": 3, "name": "John"] as [String: Any] private let array = ["John", "Mary"] private let binaryData = "123456".data(using: .utf8)! -private func testSupportsAESEncryptionWithKeyLength(_ encryptionKeyLength: UInt, channelName: String) throws { - let options = try AblyTests.commonAppSetup() +private func testSupportsAESEncryptionWithKeyLength(_ encryptionKeyLength: UInt, for test: Test, channelName: String, testHTTPExecutor: TestProxyHTTPExecutor) throws { + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) client.internal.httpExecutor = testHTTPExecutor @@ -111,8 +108,6 @@ struct ExpectedModel: Codable, Equatable { class RestClientChannelTests: XCTestCase { // XCTest invokes this method before executing the first test in the test suite. We use it to ensure that the global variables are initialized at the same moment, and in the same order, as they would have been when we used the Quick testing framework. override class var defaultTestSuite: XCTestSuite { - _ = client - _ = testHTTPExecutor _ = presenceFixtures _ = text _ = integer @@ -134,23 +129,29 @@ class RestClientChannelTests: XCTestCase { let expected: ExpectedModel } - override func setUpWithError() throws { - try super.setUpWithError() + struct TestEnvironment { + var client: ARTRest + var testHTTPExecutor: TestProxyHTTPExecutor - let options = try AblyTests.commonAppSetup() - client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + init(test: Test) throws { + let options = try AblyTests.commonAppSetup(for: test) + client = ARTRest(options: options) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) + } } // RSL1 // RSL1b - func test__005__publish__with_name_and_data_arguments__publishes_the_message_and_invokes_callback_with_success() { + func test__005__publish__with_name_and_data_arguments__publishes_the_message_and_invokes_callback_with_success() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + var publishError: ARTErrorInfo? = ARTErrorInfo.create(from: NSError(domain: "", code: -1, userInfo: nil)) var publishedMessage: ARTMessage? - let channel = client.channels.get(uniqueChannelName()) + let channel = testEnvironment.client.channels.get(uniqueChannelName(for: test)) channel.publish(PublishArgs.name, data: PublishArgs.data) { error in publishError = error @@ -166,11 +167,14 @@ class RestClientChannelTests: XCTestCase { // RSL1b, RSL1e - func test__006__publish__with_name_only__publishes_the_message_and_invokes_callback_with_success() { + func test__006__publish__with_name_only__publishes_the_message_and_invokes_callback_with_success() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + var publishError: ARTErrorInfo? = ARTErrorInfo.create(from: NSError(domain: "io.ably.XCTest", code: -1, userInfo: nil)) var publishedMessage: ARTMessage? - let channel = client.channels.get(uniqueChannelName()) + let channel = testEnvironment.client.channels.get(uniqueChannelName(for: test)) channel.publish(PublishArgs.name, data: nil) { error in publishError = error @@ -186,11 +190,14 @@ class RestClientChannelTests: XCTestCase { // RSL1b, RSL1e - func test__007__publish__with_data_only__publishes_the_message_and_invokes_callback_with_success() { + func test__007__publish__with_data_only__publishes_the_message_and_invokes_callback_with_success() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + var publishError: ARTErrorInfo? = ARTErrorInfo.create(from: NSError(domain: "", code: -1, userInfo: nil)) var publishedMessage: ARTMessage? - let channel = client.channels.get(uniqueChannelName()) + let channel = testEnvironment.client.channels.get(uniqueChannelName(for: test)) channel.publish(nil, data: PublishArgs.data) { error in publishError = error @@ -206,11 +213,14 @@ class RestClientChannelTests: XCTestCase { // RSL1b, RSL1e - func test__008__publish__with_neither_name_nor_data__publishes_the_message_and_invokes_callback_with_success() { + func test__008__publish__with_neither_name_nor_data__publishes_the_message_and_invokes_callback_with_success() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + var publishError: ARTErrorInfo? = ARTErrorInfo.create(from: NSError(domain: "", code: -1, userInfo: nil)) var publishedMessage: ARTMessage? - let channel = client.channels.get(uniqueChannelName()) + let channel = testEnvironment.client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: nil) { error in @@ -227,11 +237,14 @@ class RestClientChannelTests: XCTestCase { XCTAssertNil(publishedMessage?.data) } - func test__009__publish__with_a_Message_object__publishes_the_message_and_invokes_callback_with_success() { + func test__009__publish__with_a_Message_object__publishes_the_message_and_invokes_callback_with_success() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + var publishError: ARTErrorInfo? = ARTErrorInfo.create(from: NSError(domain: "", code: -1, userInfo: nil)) var publishedMessage: ARTMessage? - let channel = client.channels.get(uniqueChannelName()) + let channel = testEnvironment.client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([ARTMessage(name: PublishArgs.name, data: PublishArgs.data)]) { error in @@ -250,7 +263,12 @@ class RestClientChannelTests: XCTestCase { // RSL1c - func test__010__publish__with_an_array_of_Message_objects__publishes_the_messages_in_a_single_request_and_invokes_callback_with_success() { + func test__010__publish__with_an_array_of_Message_objects__publishes_the_messages_in_a_single_request_and_invokes_callback_with_success() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + let oldExecutor = client.internal.httpExecutor defer { client.internal.httpExecutor = oldExecutor } client.internal.httpExecutor = testHTTPExecutor @@ -263,7 +281,7 @@ class RestClientChannelTests: XCTestCase { ARTMessage(name: "bat", data: "baz"), ] - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.publish(messages) { error in publishError = error @@ -288,8 +306,9 @@ class RestClientChannelTests: XCTestCase { // RSL1f1 func test__011__publish__Unidentified_clients_using_Basic_Auth__should_publish_message_with_the_provided_clientId() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([ARTMessage(name: nil, data: "message", clientId: "tester")]) { error in XCTAssertNil(error) @@ -313,12 +332,13 @@ class RestClientChannelTests: XCTestCase { // RSA7e1 func test__012__publish__ClientOptions_clientId__should_include_the_clientId_as_a_querystring_parameter_in_realtime_connection_requests() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john-doe" let client = AblyTests.newRealtime(options).client defer { client.dispose(); client.close() } waitUntil(timeout: testTimeout) { done in - client.channels.get(uniqueChannelName(prefix: "RSA7e1")) + client.channels.get(uniqueChannelName(for: test, prefix: "RSA7e1")) .publish(nil, data: "foo") { error in XCTAssertNil(error) guard let connection = client.internal.transport as? TestProxyTransport else { @@ -333,13 +353,14 @@ class RestClientChannelTests: XCTestCase { // RSA7e2 func test__013__publish__ClientOptions_clientId__should_include_an_X_Ably_ClientId_header_with_value_set_to_the_clientId_as_Base64_encoded_string_in_REST_connection_requests() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john-doe" let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - client.channels.get(uniqueChannelName(prefix: "RSA7e1")) + client.channels.get(uniqueChannelName(for: test, prefix: "RSA7e1")) .publish(nil, data: "foo") { error in XCTAssertNil(error) guard let request = testHTTPExecutor.requests.first else { @@ -359,14 +380,15 @@ class RestClientChannelTests: XCTestCase { // RSL1m1 func test__014__publish__Message_clientId__publishing_with_no_clientId_when_the_clientId_is_set_to_some_value_in_the_client_options_should_result_in_a_message_received_with_the_clientId_property_set_to_that_value() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client-rest" let expectedClientId = options.clientId let rest = ARTRest(options: options) options.clientId = "client-realtime" let realtime = ARTRealtime(options: options) - let chanelName = uniqueChannelName(prefix: "ch1") + let chanelName = uniqueChannelName(for: test, prefix: "ch1") let subscriber = realtime.channels.get(chanelName) waitUntil(timeout: testTimeout) { done in @@ -390,14 +412,15 @@ class RestClientChannelTests: XCTestCase { // RSL1m2 func test__015__publish__Message_clientId__publishing_with_a_clientId_set_to_the_same_value_as_the_clientId_in_the_client_options_should_result_in_a_message_received_with_the_clientId_property_set_to_that_value() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client-rest" let expectedClientId = options.clientId! let rest = ARTRest(options: options) options.clientId = "client-realtime" let realtime = ARTRealtime(options: options) - let chanelName = uniqueChannelName(prefix: "ch1") + let chanelName = uniqueChannelName(for: test, prefix: "ch1") let subscriber = realtime.channels.get(chanelName) waitUntil(timeout: testTimeout) { done in @@ -421,12 +444,13 @@ class RestClientChannelTests: XCTestCase { // RSL1m3 func test__016__publish__Message_clientId__publishing_with_a_clientId_set_to_a_value_from_an_unidentified_client_should_result_in_a_message_received_with_the_clientId_property_set_to_that_value() throws { + let test = Test() let expectedClientId = "client-rest" - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) let realtime = ARTRealtime(options: options) - let chanelName = uniqueChannelName(prefix: "ch1") + let chanelName = uniqueChannelName(for: test, prefix: "ch1") let subscriber = realtime.channels.get(chanelName) waitUntil(timeout: testTimeout) { done in @@ -450,13 +474,14 @@ class RestClientChannelTests: XCTestCase { // RSL1m4 func test__017__publish__Message_clientId__publishing_with_a_clientId_set_to_a_different_value_from_the_clientId_in_the_client_options_should_result_in_a_message_being_rejected_by_the_server() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "client-rest" let rest = ARTRest(options: options) options.clientId = "client-realtime" let realtime = ARTRealtime(options: options) - let chanelName = uniqueChannelName(prefix: "ch1") + let chanelName = uniqueChannelName(for: test, prefix: "ch1") let subscriber = realtime.channels.get(chanelName) waitUntil(timeout: testTimeout) { done in @@ -479,9 +504,10 @@ class RestClientChannelTests: XCTestCase { // https://github.com/ably/ably-cocoa/issues/1074 and related with RSL1m func test__001__publish__should_not_fail_sending_a_message_with_no_clientId_in_the_client_options_and_credentials_that_can_assume_any_clientId() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.authCallback = { _, callback in - getTestTokenDetails(clientId: "*") { result in + getTestTokenDetails(for: test, clientId: "*") { result in switch result { case .success(let tokenDetails): callback(tokenDetails, nil) @@ -492,7 +518,7 @@ class RestClientChannelTests: XCTestCase { } let rest = ARTRest(options: options) - let channel = rest.channels.get(uniqueChannelName(prefix: "issue-1074")) + let channel = rest.channels.get(uniqueChannelName(for: test, prefix: "issue-1074")) waitUntil(timeout: testTimeout) { done in // The first attempt encodes the message before requesting auth credentials so there's no clientId @@ -512,10 +538,11 @@ class RestClientChannelTests: XCTestCase { // RSL1h func test__002__publish__should_provide_an_optional_argument_that_allows_the_clientId_value_to_be_specified() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "john" let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish("name", data: "some data", clientId: "tester") { error in expect(error!.message).to(contain("invalid clientId")) @@ -526,11 +553,12 @@ class RestClientChannelTests: XCTestCase { // RSL1h, RSL6a2 func test__003__publish__should_provide_an_optional_argument_that_allows_the_extras_value_to_be_specified() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) // Prevent channel name to be prefixed by test-* options.testOptions.channelNamePrefix = nil let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName(prefix: "pushenabled:test")) + let channel = client.channels.get(uniqueChannelName(for: test, prefix: "pushenabled:test")) let extras = ["push": ["notification": ["title": "Hello from Ably!"]]] as ARTJsonCompatible XCTAssertTrue((client.internal.encoders["application/json"] as! ARTJsonLikeEncoder).message(from: [ @@ -567,9 +595,10 @@ class RestClientChannelTests: XCTestCase { // RSL1i func test__018__publish__If_the_total_size_of_message_s__exceeds_the_maxMessageSize__the_client_library_should_reject_the_publish_and_indicate_an_error() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let messages = buildMessagesThatExceedMaxMessageSize() waitUntil(timeout: testTimeout) { done in @@ -581,9 +610,10 @@ class RestClientChannelTests: XCTestCase { } func test__019__publish__If_the_total_size_of_message_s__exceeds_the_maxMessageSize__also_when_using_publish_data_clientId_extras() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let name = buildStringThatExceedMaxMessageSize() waitUntil(timeout: testTimeout) { done in @@ -598,6 +628,8 @@ class RestClientChannelTests: XCTestCase { // TO3n func test__020__publish__idempotent_publishing__idempotentRestPublishing_option() throws { + let test = Test() + XCTAssertEqual(ARTClientOptions.getDefaultIdempotentRestPublishing(forVersion: "2"), true) XCTAssertEqual(ARTClientOptions.getDefaultIdempotentRestPublishing(forVersion: "2.0.0"), true) XCTAssertEqual(ARTClientOptions.getDefaultIdempotentRestPublishing(forVersion: "1.1"), false) @@ -610,13 +642,14 @@ class RestClientChannelTests: XCTestCase { XCTAssertEqual(ARTClientOptions.getDefaultIdempotentRestPublishing(forVersion: "0.9.1"), false) // Current version - let options = try AblyTests.clientOptions() + let options = try AblyTests.clientOptions(for: test) XCTAssertEqual(options.idempotentRestPublishing, true) } // RSL1k1 func test__027__publish__idempotent_publishing__random_idempotent_publish_id__should_generate_for_one_message_with_empty_id() throws { + let test = Test() let message = ARTMessage(name: nil, data: "foo") XCTAssertNil(message.id) @@ -624,7 +657,7 @@ class RestClientChannelTests: XCTestCase { rest.internal.options.idempotentRestPublishing = true let mockHTTPExecutor = MockHTTPExecutor() rest.internal.httpExecutor = mockHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([message]) { error in @@ -645,6 +678,7 @@ class RestClientChannelTests: XCTestCase { } func test__028__publish__idempotent_publishing__random_idempotent_publish_id__should_generate_for_multiple_messages_with_empty_id() throws { + let test = Test() let message1 = ARTMessage(name: nil, data: "foo1") XCTAssertNil(message1.id) let message2 = ARTMessage(name: "john", data: "foo2") @@ -654,7 +688,7 @@ class RestClientChannelTests: XCTestCase { rest.internal.options.idempotentRestPublishing = true let mockHTTPExecutor = MockHTTPExecutor() rest.internal.httpExecutor = mockHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([message1, message2]) { error in @@ -679,6 +713,7 @@ class RestClientChannelTests: XCTestCase { // RSL1k2 func test__021__publish__idempotent_publishing__should_not_generate_for_message_with_a_non_empty_id() throws { + let test = Test() let message = ARTMessage(name: nil, data: "foo") message.id = "123" @@ -686,7 +721,7 @@ class RestClientChannelTests: XCTestCase { rest.internal.options.idempotentRestPublishing = true let mockHTTPExecutor = MockHTTPExecutor() rest.internal.httpExecutor = mockHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([message]) { error in @@ -706,11 +741,12 @@ class RestClientChannelTests: XCTestCase { } func test__022__publish__idempotent_publishing__should_generate_for_internal_message_that_is_created_in_publish_name_data___method() throws { + let test = Test() let rest = ARTRest(key: "xxxx:xxxx") rest.internal.options.idempotentRestPublishing = true let mockHTTPExecutor = MockHTTPExecutor() rest.internal.httpExecutor = mockHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish("john", data: "foo") { error in @@ -730,6 +766,7 @@ class RestClientChannelTests: XCTestCase { // RSL1k3 func test__023__publish__idempotent_publishing__should_not_generate_for_multiple_messages_with_a_non_empty_id() throws { + let test = Test() let message1 = ARTMessage(name: nil, data: "foo1") XCTAssertNil(message1.id) let message2 = ARTMessage(name: "john", data: "foo2") @@ -739,7 +776,7 @@ class RestClientChannelTests: XCTestCase { rest.internal.options.idempotentRestPublishing = true let mockHTTPExecutor = MockHTTPExecutor() rest.internal.httpExecutor = mockHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([message1, message2]) { error in @@ -758,6 +795,7 @@ class RestClientChannelTests: XCTestCase { } func test__024__publish__idempotent_publishing__should_not_generate_when_idempotentRestPublishing_flag_is_off() throws { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.idempotentRestPublishing = false @@ -769,7 +807,7 @@ class RestClientChannelTests: XCTestCase { let rest = ARTRest(options: options) let mockHTTPExecutor = MockHTTPExecutor() rest.internal.httpExecutor = mockHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([message1, message2]) { error in @@ -789,7 +827,12 @@ class RestClientChannelTests: XCTestCase { // RSL1k4 @available(*, deprecated, message: "This test is marked as deprecated so as to not trigger a compiler warning for using the -ARTClientOptions.fallbackHostsUseDefault property. Remove this deprecation when removing the property.") - func test__025__publish__idempotent_publishing__should_have_only_one_published_message() { + func test__025__publish__idempotent_publishing__should_have_only_one_published_message() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + client.internal.options.idempotentRestPublishing = true client.internal.httpExecutor = testHTTPExecutor client.internal.options.fallbackHostsUseDefault = true @@ -810,7 +853,7 @@ class RestClientChannelTests: XCTestCase { ARTMessage(name: nil, data: "test3"), ] - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(messages) { error in @@ -835,10 +878,11 @@ class RestClientChannelTests: XCTestCase { // RSL1k5 func test__026__publish__idempotent_publishing__should_publish_a_message_with_implicit_Id_only_once() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) rest.internal.options.idempotentRestPublishing = true - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) let message = ARTMessage(name: "unique", data: "foo") message.id = "123" @@ -867,12 +911,13 @@ class RestClientChannelTests: XCTestCase { // RSL1j func test__004__publish__should_include_attributes_supplied_by_the_caller_in_the_encoded_message() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let proxyHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let proxyHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = proxyHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) let message = ARTMessage(name: nil, data: "") message.id = "123" message.name = "tester" @@ -903,8 +948,9 @@ class RestClientChannelTests: XCTestCase { // RSL2a func test__029__history__should_return_a_PaginatedResult_page_containing_the_first_page_of_messages() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish([ @@ -980,8 +1026,9 @@ class RestClientChannelTests: XCTestCase { // RSL2b1 func test__030__history__query_arguments__start_and_end_should_filter_messages_between_those_two_times() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) let query = ARTDataQuery() XCTAssertEqual(query.direction, ARTQueryDirection.backwards) @@ -1039,8 +1086,9 @@ class RestClientChannelTests: XCTestCase { // RSL2b1 func test__031__history__query_arguments__start_must_be_equal_to_or_less_than_end_and_is_unaffected_by_the_request_direction() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) let query = ARTDataQuery() query.direction = .backwards @@ -1060,8 +1108,9 @@ class RestClientChannelTests: XCTestCase { // RSL2b2 func test__032__history__query_arguments__direction_backwards_or_forwards() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) let query = ARTDataQuery() XCTAssertEqual(query.direction, ARTQueryDirection.backwards) @@ -1101,8 +1150,9 @@ class RestClientChannelTests: XCTestCase { // RSL2b3 func test__033__history__query_arguments__limit_items_result() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) let query = ARTDataQuery() XCTAssertEqual(query.limit, 100) @@ -1139,8 +1189,9 @@ class RestClientChannelTests: XCTestCase { // RSL2b3 func test__034__history__query_arguments__limit_supports_up_to_1000_items() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) let query = ARTDataQuery() XCTAssertEqual(query.limit, 100) @@ -1157,9 +1208,10 @@ class RestClientChannelTests: XCTestCase { // RSP3 func skipped__test__035__presence__get__should_return_presence_fixture_data() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.testOptions.channelNamePrefix = nil - client = ARTRest(options: options) + let client = ARTRest(options: options) let key = appSetupModel.cipher.key let cipherParams = ARTCipherParams( algorithm: appSetupModel.cipher.algorithm, @@ -1197,7 +1249,12 @@ class RestClientChannelTests: XCTestCase { // RSL4 // RSL4a - func test__036__message_encoding__payloads_should_be_binary__strings__or_objects_capable_of_JSON_representation() { + func test__036__message_encoding__payloads_should_be_binary__strings__or_objects_capable_of_JSON_representation() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + let validCases: [TestCase] = [ TestCase(value: nil, expected: .with([:] as [String: Any])), TestCase(value: text, expected: .with(["data": text])), @@ -1211,7 +1268,7 @@ class RestClientChannelTests: XCTestCase { client.internal.options.idempotentRestPublishing = false client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) validCases.forEach { caseTest in waitUntil(timeout: testTimeout) { done in @@ -1252,7 +1309,12 @@ class RestClientChannelTests: XCTestCase { } // RSL4b - func test__037__message_encoding__encoding_attribute_should_represent_the_encoding_s__applied_in_right_to_left() { + func test__037__message_encoding__encoding_attribute_should_represent_the_encoding_s__applied_in_right_to_left() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + let encodingCases = [ TestCase(value: text, expected: .init(encoding: nil)), TestCase(value: dictionary, expected: .init(encoding: "json")), @@ -1262,7 +1324,7 @@ class RestClientChannelTests: XCTestCase { client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) encodingCases.forEach { caseItem in waitUntil(timeout: testTimeout) { done in @@ -1289,9 +1351,14 @@ class RestClientChannelTests: XCTestCase { // RSL4d1 func test__038__message_encoding__json__binary_payload_should_be_encoded_as_Base64_and_represented_as_a_JSON_string() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: binaryData, callback: { error in @@ -1310,10 +1377,15 @@ class RestClientChannelTests: XCTestCase { } // RSL4d - func test__039__message_encoding__json__string_payload_should_be_represented_as_a_JSON_string() { + func test__039__message_encoding__json__string_payload_should_be_represented_as_a_JSON_string() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: text, callback: { error in @@ -1334,10 +1406,15 @@ class RestClientChannelTests: XCTestCase { // RSL4d3 - func test__041__message_encoding__json__json_payload_should_be_stringified_either__as_a_JSON_Array() { + func test__041__message_encoding__json__json_payload_should_be_stringified_either__as_a_JSON_Array() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) // JSON Array waitUntil(timeout: testTimeout) { done in @@ -1360,10 +1437,15 @@ class RestClientChannelTests: XCTestCase { } } - func test__042__message_encoding__json__json_payload_should_be_stringified_either__as_a_JSON_Object() { + func test__042__message_encoding__json__json_payload_should_be_stringified_either__as_a_JSON_Object() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) // JSON Object waitUntil(timeout: testTimeout) { done in @@ -1387,10 +1469,13 @@ class RestClientChannelTests: XCTestCase { } // RSL4d4 - func test__040__message_encoding__json__messages_received_should_be_decoded_based_on_the_encoding_field() { + func test__040__message_encoding__json__messages_received_should_be_decoded_based_on_the_encoding_field() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let cases = [text, integer, decimal, dictionary, array, binaryData] as [Any] - let channel = client.channels.get(uniqueChannelName()) + let channel = testEnvironment.client.channels.get(uniqueChannelName(for: test)) cases.forEach { caseTest in waitUntil(timeout: testTimeout) { done in @@ -1435,21 +1520,26 @@ class RestClientChannelTests: XCTestCase { // RSL5b func test__043__message_payload_encryption__should_support_AES_encryption__128_CBC_mode() throws { - try testSupportsAESEncryptionWithKeyLength(128, channelName: uniqueChannelName()) + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + try testSupportsAESEncryptionWithKeyLength(128, for: test, channelName: uniqueChannelName(for: test), testHTTPExecutor: testEnvironment.testHTTPExecutor) } func test__044__message_payload_encryption__should_support_AES_encryption__256_CBC_mode() throws { - try testSupportsAESEncryptionWithKeyLength(256, channelName: uniqueChannelName()) + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + try testSupportsAESEncryptionWithKeyLength(256, for: test, channelName: uniqueChannelName(for: test), testHTTPExecutor: testEnvironment.testHTTPExecutor) } // RSL6 // RSL6b func test__045__message_decoding__should_deliver_with_a_binary_payload_when_the_payload_was_successfully_decoded_but_it_could_not_be_decrypted() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let clientEncrypted = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channelOptions = ARTChannelOptions(cipher: ["key": ARTCrypto.generateRandomKey()] as ARTCipherParamsCompatible) let channelEncrypted = clientEncrypted.channels.get(channelName, options: channelOptions) @@ -1482,12 +1572,16 @@ class RestClientChannelTests: XCTestCase { // RSL6b func test__046__message_decoding__should_deliver_with_encoding_attribute_set_indicating_the_residual_encoding_and_error_should_be_emitted() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let testHTTPExecutor = testEnvironment.testHTTPExecutor + + let options = try AblyTests.commonAppSetup(for: test) options.useBinaryProtocol = false options.logHandler = ARTLog(capturingOutput: true) let client = ARTRest(options: options) let channelOptions = ARTChannelOptions(cipher: ["key": ARTCrypto.generateRandomKey()] as ARTCipherParamsCompatible) - let channel = client.channels.get(uniqueChannelName(), options: channelOptions) + let channel = client.channels.get(uniqueChannelName(for: test), options: channelOptions) client.internal.httpExecutor = testHTTPExecutor let expectedMessage = ["something": 1] @@ -1526,11 +1620,12 @@ class RestClientChannelTests: XCTestCase { // RSL8a, CHD2b, CHS2b, CHO2a func test__047__status__with_subscribers__returns_a_channel_details_object_populated_with_channel_metrics() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.clientId = "Client 1" let rest = ARTRest(options: options) let realtime = ARTRealtime(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let realtimeChannel = realtime.channels.get(channelName) let restChannel = rest.channels.get(channelName) @@ -1559,8 +1654,13 @@ class RestClientChannelTests: XCTestCase { } func test__48__channel_name_can_contain_slash_character_which_is_url_encoded_in_the_rest_request_path() throws { + let test = Test() + let testEnvironment = try TestEnvironment(test: test) + let client = testEnvironment.client + let testHTTPExecutor = testEnvironment.testHTTPExecutor + client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName(prefix: "beforeSlash/afterSlash")) + let channel = client.channels.get(uniqueChannelName(for: test, prefix: "beforeSlash/afterSlash")) channel.publish(nil, data: nil) diff --git a/Test/Tests/RestClientPresenceTests.swift b/Test/Tests/RestClientPresenceTests.swift index cde0843b0..743392a5b 100644 --- a/Test/Tests/RestClientPresenceTests.swift +++ b/Test/Tests/RestClientPresenceTests.swift @@ -7,9 +7,10 @@ class RestClientPresenceTests: XCTestCase { // RSP3a func skipped__test__002__Presence__get__should_return_a_PaginatedResult_page_containing_the_first_page_of_members() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) var disposable = [ARTRealtime]() @@ -65,8 +66,9 @@ class RestClientPresenceTests: XCTestCase { // RSP3a1 func test__003__Presence__get__limit_should_support_up_to_1000_items() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) let query = ARTPresenceQuery() XCTAssertEqual(query.limit, 100) @@ -80,8 +82,9 @@ class RestClientPresenceTests: XCTestCase { // RSP3a2 func test__004__Presence__get__clientId_should_filter_members_by_the_provided_clientId() throws { - let options = try AblyTests.commonAppSetup() - let channelName = uniqueChannelName() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let channelName = uniqueChannelName(for: test) let client = ARTRest(options: options) let channel = client.channels.get(channelName) @@ -115,10 +118,11 @@ class RestClientPresenceTests: XCTestCase { // RSP3a3 func test__005__Presence__get__connectionId_should_filter_members_by_the_provided_connectionId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) var disposable = [ARTRealtime]() @@ -160,10 +164,11 @@ class RestClientPresenceTests: XCTestCase { // RSP4a func test__006__Presence__history__should_return_a_PaginatedResult_page_containing_the_first_page_of_members() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) var realtime: ARTRealtime! @@ -221,10 +226,11 @@ class RestClientPresenceTests: XCTestCase { // Disabled because there's something wrong in the Sandbox. // More info at https://ably-real-time.slack.com/archives/C030C5YLY/p1614269570000400 func skipped__test__007__Presence__history__query_argument__direction_should_change_the_order_of_the_members() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) var disposable = [ARTRealtime]() @@ -275,10 +281,11 @@ class RestClientPresenceTests: XCTestCase { // RSP4b3 func test__009__Presence__history__query_argument__limit_supports_up_to_1000_members() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) var realtime: ARTRealtime! @@ -310,10 +317,11 @@ class RestClientPresenceTests: XCTestCase { // RSP3a3 func test__008__Presence__history__connectionId_should_filter_members_by_the_provided_connectionId() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) var disposable = [ARTRealtime]() @@ -357,10 +365,11 @@ class RestClientPresenceTests: XCTestCase { // RSP4b1 func test__010__Presence__history__query_argument__start_and_end_should_filter_members_between_those_two_times() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) var disposable = [ARTRealtime]() @@ -412,8 +421,9 @@ class RestClientPresenceTests: XCTestCase { // RSP4b1 func test__011__Presence__history__query_argument__start_must_be_equal_to_or_less_than_end_and_is_unaffected_by_the_request_direction() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) - let channel = client.channels.get(uniqueChannelName()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) + let channel = client.channels.get(uniqueChannelName(for: test)) let query = ARTDataQuery() query.direction = .backwards @@ -433,10 +443,11 @@ class RestClientPresenceTests: XCTestCase { // RSP5 func test__001__Presence__presence_messages_retrieved_are_decoded_in_the_same_way_that_messages_are_decoded() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) let channel = client.channels.get(channelName) let expectedData = ["test": 1] diff --git a/Test/Tests/RestClientStatsTests.swift b/Test/Tests/RestClientStatsTests.swift index 66e3635a5..ff67d4d64 100644 --- a/Test/Tests/RestClientStatsTests.swift +++ b/Test/Tests/RestClientStatsTests.swift @@ -3,12 +3,12 @@ import Foundation import Nimble import XCTest -private func postTestStats(_ stats: [[String: Any]]) throws -> ARTClientOptions { - let options = try AblyTests.commonAppSetup(forceNewApp: true) +private func postTestStats(_ stats: [[String: Any]], for test: Test) throws -> ARTClientOptions { + let options = try AblyTests.commonAppSetup(for: test, forceNewApp: true) let keyBase64 = encodeBase64(options.key ?? "") - let request = NSMutableURLRequest(url: URL(string: "\(try AblyTests.clientOptions().restUrl().absoluteString)/stats")!) + let request = NSMutableURLRequest(url: URL(string: "\(try AblyTests.clientOptions(for: test).restUrl().absoluteString)/stats")!) request.httpMethod = "POST" request.httpBody = try JSONUtility.serialize(stats) @@ -95,12 +95,13 @@ class RestClientStatsTests: XCTestCase { // RSC6a - func beforeEach__RestClient__stats__result() throws { - statsOptions = try postTestStats(statsFixtures) + func beforeEach__RestClient__stats__result(for test: Test) throws { + statsOptions = try postTestStats(statsFixtures, for: test) } func skipped__test__001__RestClient__stats__result__should_match_minute_level_inbound_and_outbound_fixture_data__forwards_() throws { - try beforeEach__RestClient__stats__result() + let test = Test() + try beforeEach__RestClient__stats__result(for: test) let client = ARTRest(options: statsOptions) let query = ARTStatsQuery() @@ -122,7 +123,8 @@ class RestClientStatsTests: XCTestCase { } func test__002__RestClient__stats__result__should_match_hour_level_inbound_and_outbound_fixture_data__forwards_() throws { - try beforeEach__RestClient__stats__result() + let test = Test() + try beforeEach__RestClient__stats__result(for: test) let client = ARTRest(options: statsOptions) let query = ARTStatsQuery() @@ -144,7 +146,8 @@ class RestClientStatsTests: XCTestCase { } func test__003__RestClient__stats__result__should_match_day_level_inbound_and_outbound_fixture_data__forwards_() throws { - try beforeEach__RestClient__stats__result() + let test = Test() + try beforeEach__RestClient__stats__result(for: test) let client = ARTRest(options: statsOptions) let query = ARTStatsQuery() @@ -162,7 +165,8 @@ class RestClientStatsTests: XCTestCase { } func skipped__test__004__RestClient__stats__result__should_match_month_level_inbound_and_outbound_fixture_data__forwards_() throws { - try beforeEach__RestClient__stats__result() + let test = Test() + try beforeEach__RestClient__stats__result(for: test) let client = ARTRest(options: statsOptions) let query = ARTStatsQuery() @@ -180,7 +184,8 @@ class RestClientStatsTests: XCTestCase { } func skipped__test__005__RestClient__stats__result__should_contain_only_one_item_when_limit_is_1__backwards() throws { - try beforeEach__RestClient__stats__result() + let test = Test() + try beforeEach__RestClient__stats__result(for: test) let client = ARTRest(options: statsOptions) let query = ARTStatsQuery() @@ -197,7 +202,8 @@ class RestClientStatsTests: XCTestCase { } func test__006__RestClient__stats__result__should_contain_only_one_item_when_limit_is_1__forwards() throws { - try beforeEach__RestClient__stats__result() + let test = Test() + try beforeEach__RestClient__stats__result(for: test) let client = ARTRest(options: statsOptions) let query = ARTStatsQuery() @@ -215,7 +221,8 @@ class RestClientStatsTests: XCTestCase { } func test__007__RestClient__stats__result__should_be_paginated_according_to_the_limit__backwards() throws { - try beforeEach__RestClient__stats__result() + let test = Test() + try beforeEach__RestClient__stats__result(for: test) let client = ARTRest(options: statsOptions) let query = ARTStatsQuery() @@ -263,7 +270,8 @@ class RestClientStatsTests: XCTestCase { } func skipped__test__008__RestClient__stats__result__should_be_paginated_according_to_the_limit__fowards_() throws { - try beforeEach__RestClient__stats__result() + let test = Test() + try beforeEach__RestClient__stats__result(for: test) let client = ARTRest(options: statsOptions) let query = ARTStatsQuery() diff --git a/Test/Tests/RestClientTests.swift b/Test/Tests/RestClientTests.swift index 65faa7528..417fb48fb 100644 --- a/Test/Tests/RestClientTests.swift +++ b/Test/Tests/RestClientTests.swift @@ -23,11 +23,11 @@ private let shuffleArrayInExpectedHostOrder = { (array: NSMutableArray) in private let _fallbackHosts = ["f.ably-realtime.com", "g.ably-realtime.com", "h.ably-realtime.com", "i.ably-realtime.com", "j.ably-realtime.com"] -private func testUsesAlternativeHost(_ caseTest: FakeNetworkResponse, channelName: String) { +private func testUsesAlternativeHost(_ caseTest: FakeNetworkResponse, for test: Test, channelName: String) { let options = ARTClientOptions(key: "xxxx:xxxx") let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: caseTest, resetAfter: 1) @@ -47,11 +47,11 @@ private func testUsesAlternativeHost(_ caseTest: FakeNetworkResponse, channelNam XCTAssertTrue(NSRegularExpression.match(testHTTPExecutor.requests[1].url!.absoluteString, pattern: "//[a-e].ably-realtime.com")) } -private func testStoresSuccessfulFallbackHostAsDefaultHost(_ caseTest: FakeNetworkResponse, channelName: String) { +private func testStoresSuccessfulFallbackHostAsDefaultHost(_ caseTest: FakeNetworkResponse, for test: Test, channelName: String) { let options = ARTClientOptions(key: "xxxx:xxxx") let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: caseTest, resetAfter: 1) @@ -83,13 +83,13 @@ private func testStoresSuccessfulFallbackHostAsDefaultHost(_ caseTest: FakeNetwo XCTAssertEqual(usedFallbackURL.host, reusedURL.host) } -private func testRestoresDefaultPrimaryHostAfterTimeoutExpires(_ caseTest: FakeNetworkResponse, channelName: String) { +private func testRestoresDefaultPrimaryHostAfterTimeoutExpires(_ caseTest: FakeNetworkResponse, for test: Test, channelName: String) { let options = ARTClientOptions(key: "xxxx:xxxx") options.logLevel = .debug options.fallbackRetryTimeout = 1 let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: caseTest, resetAfter: 1) @@ -113,13 +113,13 @@ private func testRestoresDefaultPrimaryHostAfterTimeoutExpires(_ caseTest: FakeN XCTAssertEqual(testHTTPExecutor.requests[2].url!.host, "rest.ably.io") } -private func testUsesAnotherFallbackHost(_ caseTest: FakeNetworkResponse, channelName: String) { +private func testUsesAnotherFallbackHost(_ caseTest: FakeNetworkResponse, for test: Test, channelName: String) { let options = ARTClientOptions(key: "xxxx:xxxx") options.fallbackRetryTimeout = 10 options.logLevel = .debug let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: caseTest, resetAfter: 2) @@ -149,11 +149,12 @@ class RestClientTests: XCTestCase { // G4 func test__001__RestClient__All_REST_requests_should_include_the_current_API_version() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "message") { error in XCTAssertNil(error) @@ -171,12 +172,13 @@ class RestClientTests: XCTestCase { // RSC1 func test__015__RestClient__initializer__should_accept_an_API_key() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(key: options.key!) client.internal.prioritizedHost = options.restHost - let publishTask = publishTestMessage(client, channelName: uniqueChannelName()) + let publishTask = publishTestMessage(client, channelName: uniqueChannelName(for: test)) expect(publishTask.error).toEventually(beNil(), timeout: testTimeout) } @@ -186,46 +188,51 @@ class RestClientTests: XCTestCase { } func test__017__RestClient__initializer__should_result_in_error_status_when_provided_a_bad_key() { + let test = Test() let client = ARTRest(key: "fake:key") - let publishTask = publishTestMessage(client, channelName: uniqueChannelName(), failOnError: false) + let publishTask = publishTestMessage(client, channelName: uniqueChannelName(for: test), failOnError: false) expect(publishTask.error?.code).toEventually(equal(ARTErrorCode.invalidCredential.intValue), timeout: testTimeout) } func test__018__RestClient__initializer__should_accept_a_token() throws { + let test = Test() ARTClientOptions.setDefaultEnvironment(getEnvironment()) defer { ARTClientOptions.setDefaultEnvironment(nil) } - let client = ARTRest(token: try getTestToken()) - let publishTask = publishTestMessage(client, channelName: uniqueChannelName()) + let client = ARTRest(token: try getTestToken(for: test)) + let publishTask = publishTestMessage(client, channelName: uniqueChannelName(for: test)) expect(publishTask.error).toEventually(beNil(), timeout: testTimeout) } func test__019__RestClient__initializer__should_accept_an_options_object() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - let publishTask = publishTestMessage(client, channelName: uniqueChannelName()) + let publishTask = publishTestMessage(client, channelName: uniqueChannelName(for: test)) expect(publishTask.error).toEventually(beNil(), timeout: testTimeout) } func test__020__RestClient__initializer__should_accept_an_options_object_with_token_authentication() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) let client = ARTRest(options: options) - let publishTask = publishTestMessage(client, channelName: uniqueChannelName()) + let publishTask = publishTestMessage(client, channelName: uniqueChannelName(for: test)) expect(publishTask.error).toEventually(beNil(), timeout: testTimeout) } func test__021__RestClient__initializer__should_result_in_error_status_when_provided_a_bad_token() throws { - let options = try AblyTests.clientOptions() + let test = Test() + let options = try AblyTests.clientOptions(for: test) options.token = "invalid_token" let client = ARTRest(options: options) - let publishTask = publishTestMessage(client, channelName: uniqueChannelName(), failOnError: false) + let publishTask = publishTestMessage(client, channelName: uniqueChannelName(for: test), failOnError: false) expect(publishTask.error?.code).toEventually(equal(ARTErrorCode.invalidCredential.intValue), timeout: testTimeout) } @@ -254,7 +261,8 @@ class RestClientTests: XCTestCase { // RSC3 func test__023__RestClient__logging__should_have_a_mutable_log_level() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.logHandler = ARTLog(capturingOutput: true) let client = ARTRest(options: options) client.internal.logger_onlyForUseInClassMethodsAndTests.logLevel = .error @@ -268,6 +276,8 @@ class RestClientTests: XCTestCase { // RSC4 func test__024__RestClient__logging__should_accept_a_custom_logger() throws { + let test = Test() + enum Log { static var interceptedLog: (String, ARTLogLevel) = ("", .none) } @@ -277,7 +287,7 @@ class RestClientTests: XCTestCase { } } - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) let customLogger = MyLogger() options.logHandler = customLogger options.logLevel = .verbose @@ -295,62 +305,67 @@ class RestClientTests: XCTestCase { // RSC11a func test__025__RestClient__endpoint__should_accept_a_custom_host_and_send_requests_to_the_specified_host() { + let test = Test() let options = ARTClientOptions(key: "fake:key") options.restHost = "fake.ably.io" let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor - publishTestMessage(client, channelName: uniqueChannelName(), failOnError: false) + publishTestMessage(client, channelName: uniqueChannelName(for: test), failOnError: false) expect(testHTTPExecutor.requests.first?.url?.host).toEventually(equal("fake.ably.io"), timeout: testTimeout) } func test__026__RestClient__endpoint__should_ignore_an_environment_when_restHost_is_customized() { + let test = Test() let options = ARTClientOptions(key: "fake:key") options.environment = "test" options.restHost = "fake.ably.io" let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor - publishTestMessage(client, channelName: uniqueChannelName(), failOnError: false) + publishTestMessage(client, channelName: uniqueChannelName(for: test), failOnError: false) expect(testHTTPExecutor.requests.first?.url?.host).toEventually(equal("fake.ably.io"), timeout: testTimeout) } // RSC11b func test__027__RestClient__endpoint__should_accept_an_environment_when_restHost_is_left_unchanged() { + let test = Test() let options = ARTClientOptions(key: "fake:key") options.environment = "myEnvironment" let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor - publishTestMessage(client, channelName: uniqueChannelName(), failOnError: false) + publishTestMessage(client, channelName: uniqueChannelName(for: test), failOnError: false) expect(testHTTPExecutor.requests.first?.url?.host).toEventually(equal("myEnvironment-rest.ably.io"), timeout: testTimeout) } func test__028__RestClient__endpoint__should_default_to_https___rest_ably_io() { + let test = Test() let options = ARTClientOptions(key: "fake:key") let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test),logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor - publishTestMessage(client, channelName: uniqueChannelName(), failOnError: false) + publishTestMessage(client, channelName: uniqueChannelName(for: test), failOnError: false) expect(testHTTPExecutor.requests.first?.url?.absoluteString).toEventually(beginWith("https://rest.ably.io"), timeout: testTimeout) } func test__029__RestClient__endpoint__should_connect_over_plain_http____when_tls_is_off() throws { - let options = try AblyTests.clientOptions(requestToken: true) + let test = Test() + let options = try AblyTests.clientOptions(for: test, requestToken: true) options.tls = false let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor - publishTestMessage(client, channelName: uniqueChannelName(), failOnError: false) + publishTestMessage(client, channelName: uniqueChannelName(for: test), failOnError: false) expect(testHTTPExecutor.requests.first?.url?.scheme).toEventually(equal("http"), timeout: testTimeout) } @@ -367,12 +382,13 @@ class RestClientTests: XCTestCase { // RSC13 func test__031__RestClient__should_use_the_the_connection_and_request_timeouts_specified__timeout_for_any_single_HTTP_request_and_response() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.restHost = "10.255.255.1" // non-routable IP address XCTAssertEqual(options.httpRequestTimeout, 10.0) // Seconds options.httpRequestTimeout = 1.0 let client = ARTRest(options: options) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let start = NSDate() channel.publish(nil, data: "message") { error in @@ -388,12 +404,13 @@ class RestClientTests: XCTestCase { } func test__032__RestClient__should_use_the_the_connection_and_request_timeouts_specified__max_number_of_fallback_hosts() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") XCTAssertEqual(options.httpMaxRetryCount, 3) options.httpMaxRetryCount = 1 let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) @@ -405,7 +422,7 @@ class RestClientTests: XCTestCase { } } - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in done() @@ -415,16 +432,17 @@ class RestClientTests: XCTestCase { } func test__033__RestClient__should_use_the_the_connection_and_request_timeouts_specified__max_elapsed_time_in_which_fallback_host_retries_for_HTTP_requests_will_be_attempted() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") XCTAssertEqual(options.httpMaxRetryDuration, 15.0) // Seconds options.httpMaxRetryDuration = 1.0 let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .requestTimeout(timeout: 0.1)) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in let start = Date() channel.publish(nil, data: "nil") { _ in @@ -437,7 +455,8 @@ class RestClientTests: XCTestCase { // RSC5 func test__002__RestClient__should_provide_access_to_the_AuthOptions_object_passed_in_ClientOptions() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) let authOptions = client.auth.internal.options @@ -447,15 +466,16 @@ class RestClientTests: XCTestCase { // RSC12 func test__003__RestClient__REST_endpoint_host_should_be_configurable_in_the_Client_constructor_with_the_option_restHost() throws { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") XCTAssertEqual(options.restHost, "rest.ably.io") options.restHost = "rest.ably.test" XCTAssertEqual(options.restHost, "rest.ably.test") let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: AblyTests.createInternalQueue(for: test), logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - client.channels.get(uniqueChannelName()).publish(nil, data: "message") { error in + client.channels.get(uniqueChannelName(for: test)).publish(nil, data: "message") { error in XCTAssertNotNil(error) done() } @@ -469,7 +489,8 @@ class RestClientTests: XCTestCase { // RSC16 func test__034__RestClient__time__should_return_server_time() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) var time: NSDate? @@ -483,13 +504,14 @@ class RestClientTests: XCTestCase { // RSC7, RSC18 func test__004__RestClient__should_send_requests_over_http_and_https() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let clientHttps = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) clientHttps.internal.httpExecutor = testHTTPExecutor - let channelName = uniqueChannelName() + let channelName = uniqueChannelName(for: test) waitUntil(timeout: testTimeout) { done in publishTestMessage(clientHttps, channelName: channelName) { _ in @@ -505,7 +527,7 @@ class RestClientTests: XCTestCase { options.useTokenAuth = true options.tls = false let clientHttp = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) clientHttp.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -520,8 +542,9 @@ class RestClientTests: XCTestCase { // RSC9 func test__005__RestClient__should_use_Auth_to_manage_authentication() throws { - let options = try AblyTests.clientOptions() - let testTokenDetails = try getTestTokenDetails() + let test = Test() + let options = try AblyTests.clientOptions(for: test) + let testTokenDetails = try getTestTokenDetails(for: test) options.tokenDetails = testTokenDetails options.authCallback = { _, completion in completion(testTokenDetails, nil) @@ -550,16 +573,17 @@ class RestClientTests: XCTestCase { // RSC10 func test__006__RestClient__should_request_another_token_after_current_one_is_no_longer_valid() throws { - let options = try AblyTests.commonAppSetup() - options.token = try getTestToken(ttl: 0.5) + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + options.token = try getTestToken(for: test, ttl: 0.5) let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor let auth = client.auth waitUntil(timeout: testTimeout) { done in delay(1.0) { - client.channels.get(uniqueChannelName()).history { result, error in + client.channels.get(uniqueChannelName(for: test)).history { result, error in XCTAssertNil(error) XCTAssertNotNil(result) @@ -579,14 +603,15 @@ class RestClientTests: XCTestCase { // RSC10 func test__007__RestClient__should_result_in_an_error_when_user_does_not_have_sufficient_permissions() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(capability: "{ \"main\":[\"subscribe\"] }") + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, capability: "{ \"main\":[\"subscribe\"] }") let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - client.channels.get(uniqueChannelName()).history { result, error in + client.channels.get(uniqueChannelName(for: test)).history { result, error in guard let errorCode = error?.code else { fail("Error is empty"); done() return @@ -608,7 +633,8 @@ class RestClientTests: XCTestCase { // RSC14a func test__035__RestClient__Authentication__should_support_basic_authentication_when_an_API_key_is_provided_with_the_key_option() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) guard let components = options.key?.components(separatedBy: ":"), let keyName = components.first, let keySecret = components.last else { fail("Invalid API key: \(options.key ?? "nil")"); return } @@ -618,7 +644,7 @@ class RestClientTests: XCTestCase { } let rest = ARTRest(key: "\(keyName):\(keySecret)") waitUntil(timeout: testTimeout) { done in - rest.channels.get(uniqueChannelName()).publish(nil, data: "testing") { error in + rest.channels.get(uniqueChannelName(for: test)).publish(nil, data: "testing") { error in XCTAssertNil(error) done() } @@ -658,7 +684,8 @@ class RestClientTests: XCTestCase { // RSC14c func test__036__RestClient__Authentication__should_error_when_expired_token_and_no_means_to_renew() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let auth = client.auth let tokenParams = ARTTokenParams() @@ -680,7 +707,7 @@ class RestClientTests: XCTestCase { let options: ARTClientOptions do { - options = try AblyTests.clientOptions() + options = try AblyTests.clientOptions(for: test) } catch { XCTFail(error.localizedDescription) value(nil) @@ -703,14 +730,14 @@ class RestClientTests: XCTestCase { } let rest = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in // Delay for token expiration delay(TimeInterval(truncating: tokenParams.ttl!)) { // [40140, 40150) - token expired and will not recover because authUrl is invalid - publishTestMessage(rest, channelName: uniqueChannelName()) { error in + publishTestMessage(rest, channelName: uniqueChannelName(for: test)) { error in guard let errorCode = testHTTPExecutor.responses.first?.value(forHTTPHeaderField: "X-Ably-Errorcode") else { fail("expected X-Ably-Errorcode header in request") return @@ -726,7 +753,8 @@ class RestClientTests: XCTestCase { // RSC14d func test__037__RestClient__Authentication__should_renew_the_token_when_it_has_expired() throws { - let client = ARTRest(options: try AblyTests.commonAppSetup()) + let test = Test() + let client = ARTRest(options: try AblyTests.commonAppSetup(for: test)) let auth = client.auth let tokenParams = ARTTokenParams() @@ -748,7 +776,7 @@ class RestClientTests: XCTestCase { let options: ARTClientOptions do { - options = try AblyTests.clientOptions() + options = try AblyTests.clientOptions(for: test) } catch { XCTFail(error.localizedDescription) done() @@ -766,13 +794,13 @@ class RestClientTests: XCTestCase { ) let rest = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor // Delay for token expiration delay(TimeInterval(truncating: tokenParams.ttl!)) { // [40140, 40150) - token expired and will not recover because authUrl is invalid - publishTestMessage(rest, channelName: uniqueChannelName()) { error in + publishTestMessage(rest, channelName: uniqueChannelName(for: test)) { error in guard let errorCode = testHTTPExecutor.responses.first?.value(forHTTPHeaderField: "X-Ably-Errorcode") else { fail("expected X-Ably-Errorcode header in request") return @@ -862,14 +890,15 @@ class RestClientTests: XCTestCase { // RSC15b1 func test__055__RestClient__Host_Fallback__Fallback_behavior__should_be_applied_when_restHost__port_and_tlsPort_has_not_been_set_to_an_explicit_value() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable, resetAfter: 2) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -888,15 +917,16 @@ class RestClientTests: XCTestCase { // RSC15b1 func test__056__RestClient__Host_Fallback__Fallback_behavior__should_NOT_be_applied_when_ClientOptions_restHost_has_been_set() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.restHost = "fake.ably.io" let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -913,16 +943,17 @@ class RestClientTests: XCTestCase { // RSC15b1 func test__057__RestClient__Host_Fallback__Fallback_behavior__should_NOT_be_applied_when_ClientOptions_port_has_been_set() { + let test = Test() let options = ARTClientOptions(token: "xxxx") options.tls = false options.port = 999 let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -939,15 +970,16 @@ class RestClientTests: XCTestCase { // RSC15b1 func test__058__RestClient__Host_Fallback__Fallback_behavior__should_NOT_be_applied_when_ClientOptions_tlsPort_has_been_set() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.tlsPort = 999 let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -964,15 +996,16 @@ class RestClientTests: XCTestCase { // RSC15b2 func test__059__RestClient__Host_Fallback__Fallback_behavior__should_be_applied_when_ClientOptions_fallbackHosts_is_provided() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.fallbackHosts = ["a.cocoa.ably", "b.cocoa.ably"] let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -991,15 +1024,16 @@ class RestClientTests: XCTestCase { // RSC15b3, RSC15g4 @available(*, deprecated, message: "This test is marked as deprecated so as to not trigger a compiler warning for using the -ARTClientOptions.fallbackHostsUseDefault property. Remove this deprecation when removing the property.") func test__060__RestClient__Host_Fallback__Fallback_behavior__should_be_applied_when_ClientOptions_fallbackHosts_is_not_provided_and_deprecated_fallbackHostsUseDefault_is_on() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.fallbackHostsUseDefault = true let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable, resetAfter: 2) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -1017,15 +1051,16 @@ class RestClientTests: XCTestCase { // RSC15k func test__045__RestClient__Host_Fallback__failing_HTTP_requests_with_custom_endpoint_should_result_in_an_error_immediately() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.restHost = "fake.ably.io" let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "message") { error in expect(error?.message).to(contain("hostname could not be found")) @@ -1039,15 +1074,16 @@ class RestClientTests: XCTestCase { // RSC15g1 func test__061__RestClient__Host_Fallback__fallback_hosts_list_and_priorities__should_use_ClientOptions_fallbackHosts_when_list_is_provided() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.fallbackHosts = ["f.ably-realtime.com"] let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -1064,15 +1100,16 @@ class RestClientTests: XCTestCase { // RSC15g2 func test__062__RestClient__Host_Fallback__fallback_hosts_list_and_priorities__should_use_environment_fallback_hosts_when_ClientOptions_environment_is_set_to_a_value_other_than__production__and_ClientOptions_fallbackHosts_is_not_set() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.environment = "test" let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable, resetAfter: 2) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -1090,15 +1127,16 @@ class RestClientTests: XCTestCase { // RSC15g2 func test__063__RestClient__Host_Fallback__fallback_hosts_list_and_priorities__should_NOT_use_environment_fallback_hosts_when_ClientOptions_environment_is_set_to__production_() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.environment = "production" let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -1117,15 +1155,16 @@ class RestClientTests: XCTestCase { // RSC15g3 func test__064__RestClient__Host_Fallback__fallback_hosts_list_and_priorities__should_use_default_fallback_hosts_when_both_ClientOptions_fallbackHosts_and_ClientOptions_environment_are_not_set() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.environment = "" let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "") { error in @@ -1145,16 +1184,17 @@ class RestClientTests: XCTestCase { // RSC15g4 @available(*, deprecated, message: "This test is marked as deprecated so as to not trigger a compiler warning for using the -ARTClientOptions.fallbackHostsUseDefault property. Remove this deprecation when removing the property.") func test__046__RestClient__Host_Fallback__applies_when_ClientOptions_fallbackHostsUseDefault_is_true() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.environment = "test" options.fallbackHostsUseDefault = true let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable, resetAfter: 1) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { error in @@ -1170,15 +1210,16 @@ class RestClientTests: XCTestCase { // RSC15g1 func test__047__RestClient__Host_Fallback__won_t_apply_fallback_hosts_if_ClientOptions_fallbackHosts_array_is_empty() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.fallbackHosts = [] // to test TO3k6 let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1193,15 +1234,16 @@ class RestClientTests: XCTestCase { // RSC15g3 func test__048__RestClient__Host_Fallback__won_t_apply_custom_fallback_hosts_if_ClientOptions_fallbackHosts_and_ClientOptions_environment_are_not_set__use_defaults_instead() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.fallbackHosts = nil let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable, resetAfter: 1) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1220,16 +1262,17 @@ class RestClientTests: XCTestCase { // RSC15e func test__049__RestClient__Host_Fallback__every_new_HTTP_request_is_first_attempted_to_the_default_primary_host_rest_ably_io() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.httpMaxRetryCount = 1 options.fallbackRetryTimeout = 1 // RSC15j exception let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable, resetAfter: 1) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1273,16 +1316,17 @@ class RestClientTests: XCTestCase { } func test__067__RestClient__Host_Fallback__retry_hosts_in_random_order__until_httpMaxRetryCount_has_been_reached() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.testOptions.shuffleArray = shuffleArrayInExpectedHostOrder let client = ARTRest(options: options) options.httpMaxRetryCount = 3 let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1302,6 +1346,7 @@ class RestClientTests: XCTestCase { } func test__068__RestClient__Host_Fallback__retry_hosts_in_random_order__use_custom_fallback_hosts_if_set() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.httpMaxRetryCount = 10 let customFallbackHosts = ["j.ably-realtime.com", @@ -1313,11 +1358,11 @@ class RestClientTests: XCTestCase { options.testOptions.shuffleArray = shuffleArrayInExpectedHostOrder let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1337,16 +1382,17 @@ class RestClientTests: XCTestCase { } func test__069__RestClient__Host_Fallback__retry_hosts_in_random_order__until_all_fallback_hosts_have_been_tried() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.httpMaxRetryCount = 10 options.testOptions.shuffleArray = shuffleArrayInExpectedHostOrder let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1366,6 +1412,7 @@ class RestClientTests: XCTestCase { } func test__070__RestClient__Host_Fallback__retry_hosts_in_random_order__until_httpMaxRetryCount_has_been_reached__if_custom_fallback_hosts_are_provided_in_ClientOptions_fallbackHosts__then_they_will_be_used_instead() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.httpMaxRetryCount = 4 options.fallbackHosts = _fallbackHosts @@ -1373,11 +1420,11 @@ class RestClientTests: XCTestCase { let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1398,6 +1445,7 @@ class RestClientTests: XCTestCase { } func test__071__RestClient__Host_Fallback__retry_hosts_in_random_order__until_all_fallback_hosts_have_been_tried__if_custom_fallback_hosts_are_provided_in_ClientOptions_fallbackHosts__then_they_will_be_used_instead() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.httpMaxRetryCount = 10 options.fallbackHosts = _fallbackHosts @@ -1405,11 +1453,11 @@ class RestClientTests: XCTestCase { let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1430,17 +1478,18 @@ class RestClientTests: XCTestCase { } func test__072__RestClient__Host_Fallback__retry_hosts_in_random_order__all_fallback_requests_headers_should_contain__Host__header_with_fallback_host_address() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.httpMaxRetryCount = 10 options.fallbackHosts = _fallbackHosts let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1462,17 +1511,18 @@ class RestClientTests: XCTestCase { } func test__073__RestClient__Host_Fallback__retry_hosts_in_random_order__if_an_empty_array_of_fallback_hosts_is_provided__then_fallback_host_functionality_is_disabled() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.httpMaxRetryCount = 5 options.fallbackHosts = [] let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1487,27 +1537,31 @@ class RestClientTests: XCTestCase { // RSC15d func test__074__RestClient__Host_Fallback__should_use_an_alternative_host_when___hostUnreachable() { - testUsesAlternativeHost(.hostUnreachable, channelName: uniqueChannelName()) + let test = Test() + testUsesAlternativeHost(.hostUnreachable, for: test, channelName: uniqueChannelName(for: test)) } func test__075__RestClient__Host_Fallback__should_use_an_alternative_host_when___requestTimeout_timeout__0_1_() { - testUsesAlternativeHost(.requestTimeout(timeout: 0.1), channelName: uniqueChannelName()) + let test = Test() + testUsesAlternativeHost(.requestTimeout(timeout: 0.1), for: test, channelName: uniqueChannelName(for: test)) } func test__076__RestClient__Host_Fallback__should_use_an_alternative_host_when___hostInternalError_code__501_() { - testUsesAlternativeHost(.hostInternalError(code: 501), channelName: uniqueChannelName()) + let test = Test() + testUsesAlternativeHost(.hostInternalError(code: 501), for: test, channelName: uniqueChannelName(for: test)) } // RSC15d func test__050__RestClient__Host_Fallback__should_not_use_an_alternative_host_when_the_client_receives_an_bad_request() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .host400BadRequest, resetAfter: 1) - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "nil") { _ in @@ -1522,51 +1576,61 @@ class RestClientTests: XCTestCase { // RSC15f func test__077__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host___hostUnreachable() { - testStoresSuccessfulFallbackHostAsDefaultHost(.hostUnreachable, channelName: uniqueChannelName()) + let test = Test() + testStoresSuccessfulFallbackHostAsDefaultHost(.hostUnreachable, for: test, channelName: uniqueChannelName(for: test)) } func test__078__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host___requestTimeout_timeout__0_1_() { - testStoresSuccessfulFallbackHostAsDefaultHost(.requestTimeout(timeout: 0.1), channelName: uniqueChannelName()) + let test = Test() + testStoresSuccessfulFallbackHostAsDefaultHost(.requestTimeout(timeout: 0.1), for: test, channelName: uniqueChannelName(for: test)) } func test__079__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host___hostInternalError_code__501_() { - testStoresSuccessfulFallbackHostAsDefaultHost(.hostInternalError(code: 501), channelName: uniqueChannelName()) + let test = Test() + testStoresSuccessfulFallbackHostAsDefaultHost(.hostInternalError(code: 501), for: test, channelName: uniqueChannelName(for: test)) } func test__080__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host__should_restore_default_primary_host_after_fallbackRetryTimeout_expired___hostUnreachable() { - testRestoresDefaultPrimaryHostAfterTimeoutExpires(.hostUnreachable, channelName: uniqueChannelName()) + let test = Test() + testRestoresDefaultPrimaryHostAfterTimeoutExpires(.hostUnreachable, for: test, channelName: uniqueChannelName(for: test)) } func test__081__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host__should_restore_default_primary_host_after_fallbackRetryTimeout_expired___requestTimeout_timeout__0_1_() { - testRestoresDefaultPrimaryHostAfterTimeoutExpires(.requestTimeout(timeout: 0.1), channelName: uniqueChannelName()) + let test = Test() + testRestoresDefaultPrimaryHostAfterTimeoutExpires(.requestTimeout(timeout: 0.1), for: test, channelName: uniqueChannelName(for: test)) } func test__082__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host__should_restore_default_primary_host_after_fallbackRetryTimeout_expired___hostInternalError_code__501_() { - testRestoresDefaultPrimaryHostAfterTimeoutExpires(.hostInternalError(code: 501), channelName: uniqueChannelName()) + let test = Test() + testRestoresDefaultPrimaryHostAfterTimeoutExpires(.hostInternalError(code: 501), for: test, channelName: uniqueChannelName(for: test)) } func test__083__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host__should_use_another_fallback_host_if_previous_fallback_request_failed_and_store_it_as_default_if_current_fallback_request_succseeded___hostUnreachable() { - testUsesAnotherFallbackHost(.hostUnreachable, channelName: uniqueChannelName()) + let test = Test() + testUsesAnotherFallbackHost(.hostUnreachable, for: test, channelName: uniqueChannelName(for: test)) } func test__084__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host__should_use_another_fallback_host_if_previous_fallback_request_failed_and_store_it_as_default_if_current_fallback_request_succseeded___requestTimeout_timeout__0_1_() { - testUsesAnotherFallbackHost(.requestTimeout(timeout: 0.1), channelName: uniqueChannelName()) + let test = Test() + testUsesAnotherFallbackHost(.requestTimeout(timeout: 0.1), for: test, channelName: uniqueChannelName(for: test)) } func test__085__RestClient__Host_Fallback__should_store_successful_fallback_host_as_default_host__should_use_another_fallback_host_if_previous_fallback_request_failed_and_store_it_as_default_if_current_fallback_request_succseeded___hostInternalError_code__501_() { - testUsesAnotherFallbackHost(.hostInternalError(code: 501), channelName: uniqueChannelName()) + let test = Test() + testUsesAnotherFallbackHost(.hostInternalError(code: 501), for: test, channelName: uniqueChannelName(for: test)) } // RSC8a func test__008__RestClient__should_use_MsgPack_binary_protocol() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) XCTAssertTrue(options.useBinaryProtocol) let rest = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - rest.channels.get(uniqueChannelName(prefix: "rest")).publish(nil, data: "message") { _ in + rest.channels.get(uniqueChannelName(for: test, prefix: "rest")).publish(nil, data: "message") { _ in done() } } @@ -1582,7 +1646,7 @@ class RestClientTests: XCTestCase { let realtime = AblyTests.newRealtime(options).client defer { realtime.close() } waitUntil(timeout: testTimeout) { done in - realtime.channels.get(uniqueChannelName(prefix: "realtime")).publish(nil, data: "message") { _ in + realtime.channels.get(uniqueChannelName(for: test, prefix: "realtime")).publish(nil, data: "message") { _ in done() } } @@ -1596,14 +1660,15 @@ class RestClientTests: XCTestCase { // RSC8b func test__009__RestClient__should_use_JSON_text_protocol() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.useBinaryProtocol = false let rest = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - rest.channels.get(uniqueChannelName(prefix: "rest")).publish(nil, data: "message") { _ in + rest.channels.get(uniqueChannelName(for: test, prefix: "rest")).publish(nil, data: "message") { _ in done() } } @@ -1619,7 +1684,7 @@ class RestClientTests: XCTestCase { let realtime = AblyTests.newRealtime(options).client defer { realtime.close() } waitUntil(timeout: testTimeout) { done in - realtime.channels.get(uniqueChannelName(prefix: "realtime")).publish(nil, data: "message") { _ in + realtime.channels.get(uniqueChannelName(for: test, prefix: "realtime")).publish(nil, data: "message") { _ in done() } } @@ -1631,12 +1696,13 @@ class RestClientTests: XCTestCase { // RSC7a func test__010__RestClient__X_Ably_Version_must_be_included_in_all_REST_requests() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor waitUntil(timeout: testTimeout) { done in - client.channels.get(uniqueChannelName()).publish(nil, data: "message") { error in + client.channels.get(uniqueChannelName(for: test)).publish(nil, data: "message") { error in XCTAssertNil(error) guard let headerAblyVersion = testHTTPExecutor.requests.first?.allHTTPHeaderFields?["X-Ably-Version"] else { fail("X-Ably-Version header not found"); done() @@ -1656,11 +1722,12 @@ class RestClientTests: XCTestCase { // RSC7d func test__011__RestClient__The_Agent_library_identifier_is_composed_of_a_series_of_key__value__entries_joined_by_spaces() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let client = ARTRest(options: options) - testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) client.internal.httpExecutor = testHTTPExecutor - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "message") { error in XCTAssertNil(error) @@ -1675,12 +1742,13 @@ class RestClientTests: XCTestCase { // https://github.com/ably/ably-cocoa/issues/117 func test__012__RestClient__should_indicate_an_error_if_there_is_no_way_to_renew_the_token() throws { - let options = try AblyTests.clientOptions() - options.token = try getTestToken(ttl: 0.1) + let test = Test() + let options = try AblyTests.clientOptions(for: test) + options.token = try getTestToken(for: test, ttl: 0.1) let client = ARTRest(options: options) waitUntil(timeout: testTimeout) { done in delay(0.1) { - client.channels.get(uniqueChannelName()).publish(nil, data: "message") { error in + client.channels.get(uniqueChannelName(for: test)).publish(nil, data: "message") { error in guard let error = error else { fail("Error is empty"); done() return @@ -1695,11 +1763,12 @@ class RestClientTests: XCTestCase { // https://github.com/ably/ably-cocoa/issues/577 func test__013__RestClient__background_behaviour() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) waitUntil(timeout: testTimeout) { done in URLSession.shared.dataTask(with: URL(string: "https://ably.io")!) { _, _, _ in let rest = ARTRest(options: options) - rest.channels.get(uniqueChannelName()).history { _, _ in + rest.channels.get(uniqueChannelName(for: test)).history { _, _ in done() } }.resume() @@ -1874,9 +1943,10 @@ class RestClientTests: XCTestCase { } func test__092__RestClient__request__method_signature_and_arguments__should_do_a_request_and_receive_a_valid_response() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish("a", data: nil) { error in XCTAssertNil(error) @@ -1884,7 +1954,7 @@ class RestClientTests: XCTestCase { } } - let proxyHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let proxyHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = proxyHTTPExecutor var httpPaginatedResponse: ARTHTTPPaginatedResponse! @@ -1923,9 +1993,10 @@ class RestClientTests: XCTestCase { } func test__093__RestClient__request__method_signature_and_arguments__should_handle_response_failures() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish("a", data: nil) { error in XCTAssertNil(error) @@ -1933,7 +2004,7 @@ class RestClientTests: XCTestCase { } } - let proxyHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let proxyHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = proxyHTTPExecutor waitUntil(timeout: testTimeout) { done in @@ -1968,8 +2039,9 @@ class RestClientTests: XCTestCase { // RSA4e func test__094__RestClient__if_in_the_course_of_a_REST_request_an_attempt_to_authenticate_using_authUrl_fails_due_to_a_timeout__the_request_should_result_in_an_error_with_code_40170__statusCode_401__and_a_suitable_error_message() throws { - let options = try AblyTests.commonAppSetup() - let token = try getTestToken() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) + let token = try getTestToken(for: test) options.httpRequestTimeout = 3 // short timeout to make it fail faster options.authUrl = URL(string: "http://10.255.255.1")! options.authParams = [URLQueryItem]() @@ -1978,7 +2050,7 @@ class RestClientTests: XCTestCase { let client = ARTRest(options: options) waitUntil(timeout: testTimeout) { done in - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) channel.publish("test", data: "test-data") { error in guard let error = error else { fail("Error should not be empty") @@ -1996,6 +2068,7 @@ class RestClientTests: XCTestCase { // RSC7c func test__095__RestClient__request_IDs__should_add__request_id__query_parameter() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.addRequestIds = true @@ -2003,7 +2076,7 @@ class RestClientTests: XCTestCase { let mockHttpExecutor = MockHTTPExecutor() restA.internal.httpExecutor = mockHttpExecutor waitUntil(timeout: testTimeout) { done in - restA.channels.get(uniqueChannelName()).publish(nil, data: "something") { error in + restA.channels.get(uniqueChannelName(for: test)).publish(nil, data: "something") { error in XCTAssertNil(error) guard let url = mockHttpExecutor.requests.first?.url else { fail("No requests found") @@ -2020,7 +2093,7 @@ class RestClientTests: XCTestCase { let restB = ARTRest(options: options) restB.internal.httpExecutor = mockHttpExecutor waitUntil(timeout: testTimeout) { done in - restB.channels.get(uniqueChannelName()).publish(nil, data: "something") { error in + restB.channels.get(uniqueChannelName(for: test)).publish(nil, data: "something") { error in XCTAssertNil(error) XCTAssertEqual(mockHttpExecutor.requests.count, 1) guard let url = mockHttpExecutor.requests.first?.url else { @@ -2034,6 +2107,7 @@ class RestClientTests: XCTestCase { } func test__096__RestClient__request_IDs__should_remain_the_same_if_a_request_is_retried_to_a_fallback_host() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.httpMaxRetryCount = 5 options.addRequestIds = true @@ -2041,7 +2115,7 @@ class RestClientTests: XCTestCase { let client = ARTRest(options: options) let internalLog = InternalLog(clientOptions: options) - let mockHTTP = MockHTTP(logger: internalLog) + let mockHTTP = MockHTTP(queue: AblyTests.createInternalQueue(for: test), logger: internalLog) testHTTPExecutor = TestProxyHTTPExecutor(http: mockHTTP, logger: internalLog) client.internal.httpExecutor = testHTTPExecutor mockHTTP.setNetworkState(network: .hostUnreachable) @@ -2054,7 +2128,7 @@ class RestClientTests: XCTestCase { } var requestId: String = "" - let channel = client.channels.get(uniqueChannelName()) + let channel = client.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish(nil, data: "something") { error in guard let error = error else { @@ -2074,6 +2148,7 @@ class RestClientTests: XCTestCase { } func test__097__RestClient__request_IDs__ErrorInfo_should_have__requestId__property() { + let test = Test() let options = ARTClientOptions(key: "xxxx:xxxx") options.addRequestIds = true @@ -2083,7 +2158,7 @@ class RestClientTests: XCTestCase { rest.internal.httpExecutor = mockHttpExecutor waitUntil(timeout: testTimeout) { done in - rest.channels.get(uniqueChannelName()).publish(nil, data: "something") { error in + rest.channels.get(uniqueChannelName(for: test)).publish(nil, data: "something") { error in XCTAssertNotNil(error) XCTAssertNotNil(error?.requestId) done() diff --git a/Test/Tests/UtilitiesTests.swift b/Test/Tests/UtilitiesTests.swift index 860403b90..299081a09 100644 --- a/Test/Tests/UtilitiesTests.swift +++ b/Test/Tests/UtilitiesTests.swift @@ -5,7 +5,7 @@ import XCTest private var jsonEncoder: ARTJsonLikeEncoder! -private var eventEmitter = ARTInternalEventEmitter(queue: AblyTests.queue) +private var eventEmitter: ARTInternalEventEmitter! private var receivedFoo1: Int? private var receivedFoo2: Int? private var receivedBar: Int? @@ -38,6 +38,8 @@ class UtilitiesTests: XCTestCase { return super.defaultTestSuite } + private var eventEmitterQueue: DispatchQueue! + func beforeEach__Utilities__JSON_Encoder() { jsonEncoder = ARTJsonLikeEncoder() jsonEncoder.delegate = ARTJsonEncoder() @@ -105,12 +107,13 @@ class UtilitiesTests: XCTestCase { } func test__005__Utilities__JSON_Encoder__in_Realtime__should_handle_and_emit_the_invalid_data_error() throws { + let test = Test() beforeEach__Utilities__JSON_Encoder() - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) let realtime = ARTRealtime(options: options) defer { realtime.close() } - let channel = realtime.channels.get(uniqueChannelName()) + let channel = realtime.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish("test", data: NSDate()) { error in guard let error = error else { @@ -134,12 +137,13 @@ class UtilitiesTests: XCTestCase { } func test__006__Utilities__JSON_Encoder__in_Realtime__should_ignore_invalid_transport_message() throws { + let test = Test() beforeEach__Utilities__JSON_Encoder() - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) let realtime = ARTRealtime(options: options) defer { realtime.close() } - let channel = realtime.channels.get(uniqueChannelName()) + let channel = realtime.channels.get(uniqueChannelName(for: test)) // Garbage values (whatever is on the heap) let bytes = UnsafeMutablePointer.allocate(capacity: 1) @@ -171,11 +175,12 @@ class UtilitiesTests: XCTestCase { } func test__007__Utilities__JSON_Encoder__in_Rest__should_handle_and_emit_the_invalid_data_error() throws { + let test = Test() beforeEach__Utilities__JSON_Encoder() - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.publish("test", data: NSDate()) { error in guard let error = error else { @@ -199,13 +204,14 @@ class UtilitiesTests: XCTestCase { } func test__008__Utilities__JSON_Encoder__in_Rest__should_ignore_invalid_response_payload() throws { + let test = Test() beforeEach__Utilities__JSON_Encoder() - let options = try AblyTests.commonAppSetup() + let options = try AblyTests.commonAppSetup(for: test) let rest = ARTRest(options: options) - let testHTTPExecutor = TestProxyHTTPExecutor(logger: .init(clientOptions: options)) + let testHTTPExecutor = TestProxyHTTPExecutor(queue: options.internalDispatchQueue, logger: .init(clientOptions: options)) rest.internal.httpExecutor = testHTTPExecutor - let channel = rest.channels.get(uniqueChannelName()) + let channel = rest.channels.get(uniqueChannelName(for: test)) // Garbage values (whatever is on the heap) let bytes = UnsafeMutablePointer.allocate(capacity: 1) @@ -232,8 +238,9 @@ class UtilitiesTests: XCTestCase { } } - func beforeEach__Utilities__EventEmitter() { - eventEmitter = ARTInternalEventEmitter(queue: AblyTests.queue) + func beforeEach__Utilities__EventEmitter(for test: Test) { + eventEmitterQueue = AblyTests.createInternalQueue(for: test) + eventEmitter = ARTInternalEventEmitter(queue: eventEmitterQueue) receivedFoo1 = nil receivedFoo2 = nil receivedBar = nil @@ -248,7 +255,8 @@ class UtilitiesTests: XCTestCase { } func test__009__Utilities__EventEmitter__should_emit_events_to_all_relevant_listeners() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) eventEmitter.emit("foo", with: 123 as AnyObject?) @@ -270,7 +278,8 @@ class UtilitiesTests: XCTestCase { } func test__010__Utilities__EventEmitter__should_only_call_once_listeners_once_for_its_event() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) eventEmitter.emit("foo", with: 123 as AnyObject?) @@ -289,7 +298,8 @@ class UtilitiesTests: XCTestCase { } func test__011__Utilities__EventEmitter__calling_off_with_a_single_listener_argument__should_stop_receiving_events_when_calling_off_with_a_single_listener_argument() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) eventEmitter.off(listenerFoo1!) eventEmitter.emit("foo", with: 123 as AnyObject?) @@ -310,21 +320,23 @@ class UtilitiesTests: XCTestCase { } func test__012__Utilities__EventEmitter__calling_off_with_a_single_listener_argument__should_remove_the_timeout() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) listenerFoo1!.setTimer(0.1, onTimeout: { fail("onTimeout callback shouldn't have been called") }).startTimer() eventEmitter.off(listenerFoo1!) - waitUntil(timeout: testTimeout) { done in - AblyTests.queue.asyncAfter(deadline: DispatchTime.now() + 0.3) { + waitUntil(timeout: testTimeout) { [eventEmitterQueue] done in + eventEmitterQueue!.asyncAfter(deadline: DispatchTime.now() + 0.3) { done() } } } func test__013__Utilities__EventEmitter__calling_off_with_listener_and_event_arguments__should_still_receive_events_if_off_doesn_t_match_the_listener_s_criteria() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) eventEmitter.off("foo", listener: listenerAll!) eventEmitter.emit("foo", with: 111 as AnyObject?) @@ -334,7 +346,8 @@ class UtilitiesTests: XCTestCase { } func test__014__Utilities__EventEmitter__calling_off_with_listener_and_event_arguments__should_stop_receive_events_if_off_matches_the_listener_s_criteria() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) eventEmitter.off("foo", listener: listenerFoo1!) eventEmitter.emit("foo", with: 111 as AnyObject?) @@ -344,7 +357,8 @@ class UtilitiesTests: XCTestCase { } func test__015__Utilities__EventEmitter__calling_off_with_no_arguments__should_remove_all_listeners() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) eventEmitter.off() eventEmitter.emit("foo", with: 111 as AnyObject?) @@ -361,7 +375,8 @@ class UtilitiesTests: XCTestCase { } func test__016__Utilities__EventEmitter__calling_off_with_no_arguments__should_allow_listening_again() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) eventEmitter.off() eventEmitter.on("foo", callback: { receivedFoo1 = $0 as? Int }) @@ -370,7 +385,8 @@ class UtilitiesTests: XCTestCase { } func test__017__Utilities__EventEmitter__calling_off_with_no_arguments__should_remove_all_timeouts() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) listenerFoo1!.setTimer(0.1, onTimeout: { fail("onTimeout callback shouldn't have been called") @@ -379,23 +395,24 @@ class UtilitiesTests: XCTestCase { fail("onTimeout callback shouldn't have been called") }).startTimer() eventEmitter.off() - waitUntil(timeout: DispatchTimeInterval.milliseconds(300)) { done in - AblyTests.queue.asyncAfter(deadline: .now() + 0.15) { + waitUntil(timeout: DispatchTimeInterval.milliseconds(300)) { [eventEmitterQueue] done in + eventEmitterQueue!.asyncAfter(deadline: .now() + 0.15) { done() } } } func test__018__Utilities__EventEmitter__the_timed_method__should_not_call_onTimeout_if_the_deadline_isn_t_reached() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) weak var timer = listenerFoo1!.setTimer(0.2, onTimeout: { fail("onTimeout callback shouldn't have been called") }) - waitUntil(timeout: DispatchTimeInterval.seconds(1)) { done in + waitUntil(timeout: DispatchTimeInterval.seconds(1)) { [eventEmitterQueue] done in timer?.startTimer() eventEmitter.emit("foo", with: 123 as AnyObject?) - AblyTests.queue.asyncAfter(deadline: .now() + 0.3) { + eventEmitterQueue!.asyncAfter(deadline: .now() + 0.3) { XCTAssertNotNil(receivedFoo1) done() } @@ -403,7 +420,8 @@ class UtilitiesTests: XCTestCase { } func test__019__Utilities__EventEmitter__the_timed_method__should_call_onTimeout_and_off_the_listener_if_the_deadline_is_reached() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) var calledOnTimeout = false let beforeEmitting = NSDate() @@ -411,8 +429,8 @@ class UtilitiesTests: XCTestCase { calledOnTimeout = true expect(NSDate()).to(beCloseTo(beforeEmitting.addingTimeInterval(0.3), within: 0.2)) }).startTimer() - waitUntil(timeout: DispatchTimeInterval.milliseconds(500)) { done in - AblyTests.queue.asyncAfter(deadline: .now() + 0.35) { + waitUntil(timeout: DispatchTimeInterval.milliseconds(500)) { [eventEmitterQueue] done in + eventEmitterQueue!.asyncAfter(deadline: .now() + 0.35) { XCTAssertTrue(calledOnTimeout) eventEmitter.emit("foo", with: 123 as AnyObject?) XCTAssertNil(receivedFoo1) @@ -423,7 +441,8 @@ class UtilitiesTests: XCTestCase { // RTE6a func test__020__Utilities__EventEmitter__set_of_listeners__should_not_change_over_the_course_of_the_emit() { - beforeEach__Utilities__EventEmitter() + let test = Test() + beforeEach__Utilities__EventEmitter(for: test) var firstCallbackCalled = false var secondCallbackCalled = false @@ -439,11 +458,12 @@ class UtilitiesTests: XCTestCase { } func test__021__Utilities__Logger__should_have_a_history_of_logs() throws { - let options = try AblyTests.commonAppSetup() + let test = Test() + let options = try AblyTests.commonAppSetup(for: test) options.logLevel = .verbose let realtime = ARTRealtime(options: options) defer { realtime.close() } - let channel = realtime.channels.get(uniqueChannelName()) + let channel = realtime.channels.get(uniqueChannelName(for: test)) waitUntil(timeout: testTimeout) { done in channel.attach { error in diff --git a/fastlane/Scanfile b/fastlane/Scanfile index fea35296b..da002c455 100644 --- a/fastlane/Scanfile +++ b/fastlane/Scanfile @@ -1,8 +1,10 @@ open_report false -clean true +clean false skip_slack true ensure_devices_found true output_types "junit" # I'm being explicit about this because I want to make sure it's being used, to make sure that trainer is used to generate the JUnit report xcodebuild_formatter "xcbeautify" result_bundle true +# Just for printing inside these loop jobs +buildlog_path "xcodebuild_output"