From 6a625dbc019ab2c6166dbf85678e703f19d0b779 Mon Sep 17 00:00:00 2001 From: Anthony Miller Date: Mon, 30 Sep 2024 15:52:50 -0700 Subject: [PATCH] Remove server integration tests (apollographql/apollo-ios-dev#497) --- .github/workflows/ci-tests-xcode-beta.yml | 5 +- .github/workflows/ci-tests.yml | 77 +-- .github/workflows/release-check.yml | 143 ----- SimpleUploadServer/.gitignore | 3 - SimpleUploadServer/.nvmrc | 1 - SimpleUploadServer/file-utils.js | 50 -- SimpleUploadServer/index.js | 71 --- SimpleUploadServer/package.json | 21 - ...tInterceptorProviderIntegrationTests.swift | 79 --- Tests/ApolloServerIntegrationTests/Info.plist | 22 - ...aRegistryApolloSchemaDownloaderTests.swift | 39 -- .../StarWarsApolloSchemaDownloaderTests.swift | 45 -- .../StarWarsServerCachingRoundtripTests.swift | 102 ---- .../StarWarsServerTests.swift | 266 -------- .../StarWarsSubscriptionTests.swift | 569 ------------------ .../StarWarsWebSocketTests.swift | 351 ----------- .../SubscriptionTests.swift | 58 -- .../TestHelpers/HTTPBinAPI.swift | 59 -- .../TestHelpers/TestConfigs.swift | 47 -- .../TestHelpers/TestServerURLs.swift | 15 - .../UploadTests.swift | 302 ---------- ...stall-apollo-server-docs-example-server.sh | 9 - scripts/install-node-v12.sh | 8 - scripts/install-or-update-starwars-server.sh | 10 - 24 files changed, 2 insertions(+), 2350 deletions(-) delete mode 100644 SimpleUploadServer/.gitignore delete mode 100644 SimpleUploadServer/.nvmrc delete mode 100644 SimpleUploadServer/file-utils.js delete mode 100644 SimpleUploadServer/index.js delete mode 100644 SimpleUploadServer/package.json delete mode 100644 Tests/ApolloServerIntegrationTests/DefaultInterceptorProviderIntegrationTests.swift delete mode 100644 Tests/ApolloServerIntegrationTests/Info.plist delete mode 100644 Tests/ApolloServerIntegrationTests/SchemaRegistryApolloSchemaDownloaderTests.swift delete mode 100644 Tests/ApolloServerIntegrationTests/StarWarsApolloSchemaDownloaderTests.swift delete mode 100644 Tests/ApolloServerIntegrationTests/StarWarsServerCachingRoundtripTests.swift delete mode 100644 Tests/ApolloServerIntegrationTests/StarWarsServerTests.swift delete mode 100644 Tests/ApolloServerIntegrationTests/StarWarsSubscriptionTests.swift delete mode 100755 Tests/ApolloServerIntegrationTests/StarWarsWebSocketTests.swift delete mode 100644 Tests/ApolloServerIntegrationTests/SubscriptionTests.swift delete mode 100644 Tests/ApolloServerIntegrationTests/TestHelpers/HTTPBinAPI.swift delete mode 100644 Tests/ApolloServerIntegrationTests/TestHelpers/TestConfigs.swift delete mode 100644 Tests/ApolloServerIntegrationTests/TestHelpers/TestServerURLs.swift delete mode 100644 Tests/ApolloServerIntegrationTests/UploadTests.swift delete mode 100755 scripts/install-apollo-server-docs-example-server.sh delete mode 100755 scripts/install-node-v12.sh delete mode 100755 scripts/install-or-update-starwars-server.sh diff --git a/.github/workflows/ci-tests-xcode-beta.yml b/.github/workflows/ci-tests-xcode-beta.yml index 836e65437..40eee7507 100644 --- a/.github/workflows/ci-tests-xcode-beta.yml +++ b/.github/workflows/ci-tests-xcode-beta.yml @@ -23,8 +23,7 @@ jobs: filters: | ios: - 'apollo-ios/**' - - 'Tests/ApolloInternalTestHelpers/**' - - 'Tests/ApolloServerIntegrationTests/**' + - 'Tests/ApolloInternalTestHelpers/**' - 'Tests/ApolloTests/**' codegen: - 'apollo-ios-codegen/**' @@ -246,5 +245,3 @@ jobs: - name: Run CocoaPods Integration Tests id: run-cocoapods-integration-tests uses: ./.github/actions/run-cocoapods-integration-tests - - # IntegrationTests removed because source is not compatible with Sendable yet. diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index e4f5849e1..bbf8c288f 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -23,8 +23,7 @@ jobs: filters: | ios: - 'apollo-ios/**' - - 'Tests/ApolloInternalTestHelpers/**' - - 'Tests/ApolloServerIntegrationTests/**' + - 'Tests/ApolloInternalTestHelpers/**' - 'Tests/ApolloTests/**' codegen: - 'apollo-ios-codegen/**' @@ -259,77 +258,3 @@ jobs: - name: Run CocoaPods Integration Tests id: run-cocoapods-integration-tests uses: ./.github/actions/run-cocoapods-integration-tests - - run-integration-tests: - runs-on: macos-13 - needs: [tuist-generation, changes] - if: ${{ needs.changes.outputs.ios == 'true' }} - timeout-minutes: 20 - name: Apollo Integration Tests - macOS - steps: - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: 15.2 - - name: Checkout Repo - uses: actions/checkout@v3 - - name: Setup Node 12.22.10 - uses: actions/setup-node@v3 - with: - node-version: 12.22.10 - - name: Setup Upload Server - shell: bash - run: | - sudo chmod -R +rwx SimpleUploadServer - cd SimpleUploadServer && npm install && npm start & - - name: Setup Node 18.15.0 - uses: actions/setup-node@v3 - with: - node-version: 18.15.0 - - name: Setup Subscription Server - shell: bash - run: | - sh ./scripts/install-apollo-server-docs-example-server.sh - cd ../docs-examples/apollo-server/v3/subscriptions-graphql-ws && npm start & - - name: Setup Star Wars Server - shell: bash - run: | - sh ./scripts/install-or-update-starwars-server.sh - cd ../starwars-server && npm start & - - name: Retrieve Build Cache - uses: actions/cache@v3 - with: - path: | - ./ApolloDev.xcodeproj - ./ApolloDev.xcworkspace - ./Derived/* - key: ${{ github.run_id }}-dependencies - fail-on-cache-miss: true - - name: Build and Test - uses: ./.github/actions/build-and-run-unit-tests - with: - destination: platform=macOS,arch=x86_64 - scheme: ApolloServerIntegrationTests - test-plan: Apollo-IntegrationTestPlan - - name: Save xcodebuild logs - uses: actions/upload-artifact@v3 - with: - name: macOS-Integration-logs - path: | - DerivedData/Logs/Build - - name: Save crash logs - uses: actions/upload-artifact@v3 - with: - name: macOS-Integration-crashes - path: | - ~/Library/Logs/DiagnosticReports - - name: Zip Result Bundle - shell: bash - working-directory: TestResults - run: | - zip -r ResultBundle.zip ResultBundle.xcresult - - name: Save test results - uses: actions/upload-artifact@v3 - with: - name: macOS-Integration-results - path: | - TestResults/ResultBundle.zip diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml index e4218a0fa..8bb33ec14 100644 --- a/.github/workflows/release-check.yml +++ b/.github/workflows/release-check.yml @@ -147,76 +147,6 @@ jobs: path: | TestResults/ResultBundle.zip - # legacy-unit-test: - # runs-on: macos-11 - # needs: tuist-generation - # timeout-minutes: 20 - # strategy: - # fail-fast: false - # matrix: - # include: - # # iOS 14.4 - # - destination: platform=iOS Simulator,OS=14.4,name=iPhone 12 - # scheme: ApolloTests - # test-plan: Apollo-CITestPlan - # name: Apollo Unit Tests - iOS 14.4 - # name: ${{ matrix.name }} - # steps: - # - name: Checkout Repo - # uses: actions/checkout@v3 - # # Caching for apollo-ios and apollo-ios-codegen SPM dependencies - # # - uses: actions/cache@v3 - # # with: - # # path: ./DerivedData/SourcePackages - # # key: ${{ runner.os }}-spm-${{ hashFiles('./apollo-ios/Package.resolved') }}-${{ hashFiles('./apollo-ios-codegen/Package.resolved') }} - # - name: Retrieve Build Cache - # uses: actions/cache@v3 - # with: - # path: | - # ./ApolloDev.xcodeproj - # ./ApolloDev.xcworkspace - # ./Derived/* - # key: ${{ github.run_id }}-dependencies - # fail-on-cache-miss: true - # - uses: maxim-lobanov/setup-xcode@v1 - # with: - # xcode-version: 12.4.0 - # - name: Build and Test - # uses: ./.github/actions/build-and-run-unit-tests - # with: - # destination: ${{ matrix.destination }} - # scheme: ${{ matrix.scheme }} - # test-plan: ${{ matrix.test-plan }} - # - name: Run-JS-Tests - # if: ${{ matrix.run-js-tests == true }} - # shell: bash - # working-directory: apollo-ios-codegen/Sources/GraphQLCompiler/JavaScript/ - # run: | - # npm install && npm test - # - name: Save xcodebuild logs - # uses: actions/upload-artifact@v3 - # with: - # name: ${{ matrix.name }}-logs - # path: | - # DerivedData/Logs/Build - # - name: Save crash logs - # uses: actions/upload-artifact@v3 - # with: - # name: ${{ matrix.name }}-crashes - # path: | - # ~/Library/Logs/DiagnosticReports - # - name: Zip Result Bundle - # shell: bash - # working-directory: TestResults - # run: | - # zip -r ResultBundle.zip ResultBundle.xcresult - # - name: Save test results - # uses: actions/upload-artifact@v3 - # with: - # name: ${{ matrix.name }}-results - # path: | - # TestResults/ResultBundle.zip - run-codegen-test-configurations: runs-on: macos-latest timeout-minutes: 20 @@ -251,76 +181,3 @@ jobs: - name: Run CocoaPods Integration Tests id: run-cocoapods-integration-tests uses: ./.github/actions/run-cocoapods-integration-tests - - run-integration-tests: - runs-on: macos-13 - needs: tuist-generation - timeout-minutes: 20 - name: Apollo Integration Tests - macOS - steps: - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: 15.2 - - name: Checkout Repo - uses: actions/checkout@v3 - - name: Setup Node 12.22.10 - uses: actions/setup-node@v3 - with: - node-version: 12.22.10 - - name: Setup Upload Server - shell: bash - run: | - sudo chmod -R +rwx SimpleUploadServer - cd SimpleUploadServer && npm install && npm start & - - name: Setup Node 18.15.0 - uses: actions/setup-node@v3 - with: - node-version: 18.15.0 - - name: Setup Subscription Server - shell: bash - run: | - sh ./scripts/install-apollo-server-docs-example-server.sh - cd ../docs-examples/apollo-server/v3/subscriptions-graphql-ws && npm start & - - name: Setup Star Wars Server - shell: bash - run: | - sh ./scripts/install-or-update-starwars-server.sh - cd ../starwars-server && npm start & - - name: Retrieve Build Cache - uses: actions/cache@v3 - with: - path: | - ./ApolloDev.xcodeproj - ./ApolloDev.xcworkspace - ./Derived/* - key: ${{ github.run_id }}-dependencies - fail-on-cache-miss: true - - name: Build and Test - uses: ./.github/actions/build-and-run-unit-tests - with: - destination: platform=macOS,arch=x86_64 - scheme: ApolloServerIntegrationTests - test-plan: Apollo-IntegrationTestPlan - - name: Save xcodebuild logs - uses: actions/upload-artifact@v3 - with: - name: macOS-Integration-logs - path: | - DerivedData/Logs/Build - - name: Save crash logs - uses: actions/upload-artifact@v3 - with: - name: macOS-Integration-crashes - path: | - ~/Library/Logs/DiagnosticReports - - name: Zip Result Bundle - shell: bash - working-directory: TestResults - run: | - zip -r ResultBundle.zip ResultBundle.xcresult - - name: Save test results - uses: actions/upload-artifact@v3 - with: - name: macOS-Integration-results - path: | - TestResults/ResultBundle.zip diff --git a/SimpleUploadServer/.gitignore b/SimpleUploadServer/.gitignore deleted file mode 100644 index 98f86d850..000000000 --- a/SimpleUploadServer/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -uploads -node_modules -db.json \ No newline at end of file diff --git a/SimpleUploadServer/.nvmrc b/SimpleUploadServer/.nvmrc deleted file mode 100644 index 08a9a3768..000000000 --- a/SimpleUploadServer/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -12.22.12 \ No newline at end of file diff --git a/SimpleUploadServer/file-utils.js b/SimpleUploadServer/file-utils.js deleted file mode 100644 index 4ec0a2926..000000000 --- a/SimpleUploadServer/file-utils.js +++ /dev/null @@ -1,50 +0,0 @@ -const fs = require("fs"); -const lowdb = require("lowdb"); -const FileSync = require("lowdb/adapters/FileSync"); -const mkdirp = require("mkdirp"); -const shortid = require("shortid"); - -const UPLOAD_DIR = "./uploads"; -const db = lowdb(new FileSync("db.json")); - -// Seed an empty DB. -db.defaults({ uploads: [] }).write(); - -// Ensure upload directory exists. -mkdirp.sync(UPLOAD_DIR); - -const storeFS = ({ stream, filename }) => { - const id = shortid.generate(); - const path = `${UPLOAD_DIR}/${id}-${filename}`; - return new Promise((resolve, reject) => - stream - .on("error", error => { - if (stream.truncated) - // Delete the truncated file. - fs.unlinkSync(path); - reject(error); - }) - .pipe(fs.createWriteStream(path)) - .on("error", error => reject(error)) - .on("finish", () => resolve({ id, path })) - ); -}; - -const storeDB = file => - db - .get("uploads") - .push(file) - .last() - .write(); - -const processUpload = async upload => { - const { createReadStream, filename, mimetype } = await upload; - const stream = createReadStream(); - const { id, path } = await storeFS({ stream, filename }); - return storeDB({ id, filename, mimetype, path }); -}; - -module.exports = { - db, - processUpload -}; diff --git a/SimpleUploadServer/index.js b/SimpleUploadServer/index.js deleted file mode 100644 index fed3f0b44..000000000 --- a/SimpleUploadServer/index.js +++ /dev/null @@ -1,71 +0,0 @@ -const { ApolloServer, gql, GraphQLUpload } = require("apollo-server"); -const promisesAll = require("promises-all"); -const { db, processUpload } = require("./file-utils"); - -const typeDefs = gql` - type File { - id: ID! - path: String! - filename: String! - mimetype: String! - } - type Query { - uploads: [File] - } - type Mutation { - singleUpload(file: Upload!): File! - multipleUpload(files: [Upload!]!): [File!]! - multipleParameterUpload(singleFile: Upload!, multipleFiles: [Upload!]!): [File!]! - } -`; - -const resolvers = { - Upload: GraphQLUpload, - Query: { - uploads: () => db.get("uploads").value() - }, - Mutation: { - singleUpload: (obj, { file }) => processUpload(file), - async multipleUpload(obj, { files }) { - const { resolve, reject } = await promisesAll.all( - files.map(processUpload) - ); - - if (reject.length) - reject.forEach(({ name, message }) => - // eslint-disable-next-line no-console - console.error(`${name}: ${message}`) - ); - - return resolve; - }, - async multipleParameterUpload(obj, { singleFile, multipleFiles }) { - const { resolve, reject } = await promisesAll.all( - [singleFile, ...multipleFiles].map(processUpload) - ); - - if (reject.length) - reject.forEach(({ name, message }) => - // eslint-disable-next-line no-console - console.error(`${name}: ${message}`) - ); - - return resolve; - } - } -}; - -const server = new ApolloServer({ - typeDefs, - resolvers, - uploads: { - maxFileSize: 10000000, // 10 MB - maxFiles: 20 - } -}); - -server.listen({ - port: 4001 -}).then(({ url }) => { - console.info(`Upload server started at ${url}`); -}); diff --git a/SimpleUploadServer/package.json b/SimpleUploadServer/package.json deleted file mode 100644 index 5c6a5f40a..000000000 --- a/SimpleUploadServer/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "uploads", - "version": "1.0.0", - "description": "", - "main": "index.js", - "dependencies": { - "apollo-server": "^2.16.1", - "graphql": "^14.7.0", - "lowdb": "^1.0.0", - "mkdirp": "^0.5.5", - "promises-all": "^1.0.0", - "shortid": "^2.2.15" - }, - "devDependencies": {}, - "scripts": { - "start": "node index.js" - }, - "keywords": [], - "author": "", - "license": "ISC" -} diff --git a/Tests/ApolloServerIntegrationTests/DefaultInterceptorProviderIntegrationTests.swift b/Tests/ApolloServerIntegrationTests/DefaultInterceptorProviderIntegrationTests.swift deleted file mode 100644 index 40825d9a7..000000000 --- a/Tests/ApolloServerIntegrationTests/DefaultInterceptorProviderIntegrationTests.swift +++ /dev/null @@ -1,79 +0,0 @@ -import Apollo -import XCTest -import StarWarsAPI - -/// Tests that the `DefaultInterceptorProvider` configures an `ApolloClient` that successfully -/// communicates with an external Apollo Server. -/// -/// - Precondition: These tests will only pass if a local instance of the Star Wars server is -/// running on port 8080. -/// This server can be found at https://github.com/apollographql/starwars-server -class DefaultInterceptorProviderIntegrationTests: XCTestCase { - - var client: ApolloClient! - - override func setUp() { - let url = TestServerURL.starWarsServer.url - let store = ApolloStore() - let provider = DefaultInterceptorProvider(store: store) - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: url) - - client = ApolloClient(networkTransport: transport, store: store) - } - - override func tearDown() { - client = nil - - super.tearDown() - } - - func testLoading() { - let expectation = self.expectation(description: "loaded with default client") - client.fetch(query: HeroNameQuery(episode: nil)) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - - } - expectation.fulfill() - } - - self.wait(for: [expectation], timeout: 10) - } - - func testInitialLoadFromNetworkAndSecondaryLoadFromCache() { - let initialLoadExpectation = self.expectation(description: "loaded with default client") - client.fetch(query: HeroNameQuery(episode: nil)) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - - } - initialLoadExpectation.fulfill() - } - - self.wait(for: [initialLoadExpectation], timeout: 10) - - let secondLoadExpectation = self.expectation(description: "loaded with default client") - client.fetch(query: HeroNameQuery(episode: nil)) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - - } - secondLoadExpectation.fulfill() - } - - self.wait(for: [secondLoadExpectation], timeout: 10) - } -} diff --git a/Tests/ApolloServerIntegrationTests/Info.plist b/Tests/ApolloServerIntegrationTests/Info.plist deleted file mode 100644 index 64d65ca49..000000000 --- a/Tests/ApolloServerIntegrationTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Tests/ApolloServerIntegrationTests/SchemaRegistryApolloSchemaDownloaderTests.swift b/Tests/ApolloServerIntegrationTests/SchemaRegistryApolloSchemaDownloaderTests.swift deleted file mode 100644 index ffa0fa5aa..000000000 --- a/Tests/ApolloServerIntegrationTests/SchemaRegistryApolloSchemaDownloaderTests.swift +++ /dev/null @@ -1,39 +0,0 @@ -#if os(macOS) -import XCTest -import ApolloInternalTestHelpers -import ApolloCodegenInternalTestHelpers -@testable import ApolloCodegenLib -@testable import GraphQLCompiler - -class SchemaRegistryApolloSchemaDownloaderTests: XCTestCase { - func testDownloadingSchema_fromSchemaRegistry_shouldOutputSDL() async throws { - let fileManager = try testIsolatedFileManager() - let testOutputFolderURL = fileManager.directoryURL - - XCTAssertFalse(ApolloFileManager.default.doesFileExist(atPath: testOutputFolderURL.path)) - - guard let apiKey = ProcessInfo.processInfo.environment["REGISTRY_API_KEY"] else { - throw XCTSkip("No API key could be fetched from the environment to test downloading from the schema registry") - } - - let settings = ApolloSchemaDownloadConfiguration.DownloadMethod.ApolloRegistrySettings( - apiKey: apiKey, - graphID: "Apollo-Fullstack-8zo5jl" - ) - let configuration = ApolloSchemaDownloadConfiguration( - using: .apolloRegistry(settings), - outputPath: testOutputFolderURL.path - ) - - try await ApolloSchemaDownloader.fetch(configuration: configuration) - XCTAssertTrue(ApolloFileManager.default.doesFileExist(atPath: configuration.outputPath)) - - // Can it be turned into the expected schema? - let frontend = try await GraphQLJSFrontend() - let source = try await frontend.makeSource(from: URL(fileURLWithPath: configuration.outputPath)) - let schema = try await frontend.loadSchema(from: [source]) - let rocketType = try await schema.getType(named: "Rocket") - XCTAssertEqual(rocketType?.name.schemaName, "Rocket") - } -} -#endif diff --git a/Tests/ApolloServerIntegrationTests/StarWarsApolloSchemaDownloaderTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsApolloSchemaDownloaderTests.swift deleted file mode 100644 index af0f2cc08..000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsApolloSchemaDownloaderTests.swift +++ /dev/null @@ -1,45 +0,0 @@ -#if os(macOS) -import XCTest -import ApolloInternalTestHelpers -import ApolloCodegenInternalTestHelpers -@testable import ApolloCodegenLib -@testable import GraphQLCompiler - -class StarWarsApolloSchemaDownloaderTests: XCTestCase { - - func testDownloadingSchema_usingIntrospection_shouldOutputSDL() async throws { - let fileManager = try testIsolatedFileManager() - - let configuration = ApolloSchemaDownloadConfiguration( - using: .introspection(endpointURL: TestServerURL.starWarsServer.url), - outputPath: fileManager.filePathBuilder.schemaOutputURL.path - ) - - XCTAssertFalse(ApolloFileManager.default.doesFileExist(atPath: configuration.outputPath)) - - try await ApolloSchemaDownloader.fetch(configuration: configuration) - - // Does the file now exist? - XCTAssertTrue(ApolloFileManager.default.doesFileExist(atPath: configuration.outputPath)) - - // Is it non-empty? - let data = try Data(contentsOf: URL(fileURLWithPath: configuration.outputPath)) - XCTAssertFalse(data.isEmpty) - - // It should not be JSON - XCTAssertNil(try? JSONSerialization.jsonObject(with: data, options: []) as? [AnyHashable:Any]) - - // Can it be turned into the expected schema? - let frontend = try await GraphQLJSFrontend() - let source = try await frontend.makeSource(from: URL(fileURLWithPath: configuration.outputPath)) - let schema = try await frontend.loadSchema(from: [source]) - let episodeType = try await schema.getType(named: "Episode") - XCTAssertEqual(episodeType?.name.schemaName, "Episode") - - // OK delete it now - try ApolloFileManager.default.deleteFile(atPath: configuration.outputPath) - XCTAssertFalse(ApolloFileManager.default.doesFileExist(atPath: configuration.outputPath)) - } - -} -#endif diff --git a/Tests/ApolloServerIntegrationTests/StarWarsServerCachingRoundtripTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsServerCachingRoundtripTests.swift deleted file mode 100644 index e47cb2b32..000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsServerCachingRoundtripTests.swift +++ /dev/null @@ -1,102 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloInternalTestHelpers -import StarWarsAPI -import ApolloAPI - -class SQLiteStarWarsServerCachingRoundtripTests: StarWarsServerCachingRoundtripTests { - override var cacheType: any TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class StarWarsServerCachingRoundtripTests: XCTestCase, CacheDependentTesting { - var cacheType: any TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 5 - - var cache: (any NormalizedCache)! - var store: ApolloStore! - var client: ApolloClient! - - override func setUp() async throws { - try await super.setUp() - - cache = try await makeNormalizedCache() - store = ApolloStore(cache: cache) - let provider = DefaultInterceptorProvider(store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestServerURL.starWarsServer.url) - - client = ApolloClient(networkTransport: network, store: store) - } - - override func tearDownWithError() throws { - cache = nil - store = nil - client = nil - - try super.tearDownWithError() - } - - func testHeroAndFriendsNamesQuery() { - let query = HeroAndFriendsNamesQuery(episode: nil) - - fetchAndLoadFromStore(query: query) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - func testHeroAndFriendsNamesQueryWithVariable() { - let query = HeroAndFriendsNamesQuery(episode: .init(.jedi)) - - fetchAndLoadFromStore(query: query) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - func testHeroAndFriendsNamesWithIDsQuery() { - let query = HeroAndFriendsNamesWithIDsQuery(episode: nil) - - fetchAndLoadFromStore(query: query) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - // MARK: - Helpers - - private func fetchAndLoadFromStore(query: Query, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Query.Data) -> Void) { - let fetchedFromServerExpectation = expectation(description: "Fetched query from server") - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData) { result in - defer { fetchedFromServerExpectation.fulfill() } - XCTAssertSuccessResult(result, file: file, line: line) - } - - wait(for: [fetchedFromServerExpectation], timeout: Self.defaultWaitTimeout) - - let resultObserver = makeResultObserver(for: query, file: file, line: line) - - let loadedFromStoreExpectation = resultObserver.expectation(description: "Loaded query from store", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - store.load(query, resultHandler: resultObserver.handler) - - wait(for: [loadedFromStoreExpectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloServerIntegrationTests/StarWarsServerTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsServerTests.swift deleted file mode 100644 index 775c9cd57..000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsServerTests.swift +++ /dev/null @@ -1,266 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloInternalTestHelpers -import StarWarsAPI -import ApolloAPI - -class StarWarsServerAPQsGetMethodTests: StarWarsServerTests { - override func setUp() { - super.setUp() - config = APQsWithGetMethodConfig() - } -} - -class StarWarsServerAPQsTests: StarWarsServerTests { - override func setUp() { - super.setUp() - config = APQsConfig() - } -} - -class SQLiteStarWarsServerAPQsGetMethodTests: StarWarsServerAPQsGetMethodTests { - override var cacheType: any TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class SQLiteStarWarsServerAPQsTests: StarWarsServerAPQsTests { - override var cacheType: any TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class SQLiteStarWarsServerTests: StarWarsServerTests { - override var cacheType: any TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class StarWarsServerTests: XCTestCase, CacheDependentTesting { - var config: (any TestConfig)! - - var cacheType: any TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 5 - - var cache: (any NormalizedCache)! - var client: ApolloClient! - - override func setUp() async throws { - try await super.setUp() - - config = DefaultConfig() - - cache = try await makeNormalizedCache() - let store = ApolloStore(cache: cache) - - client = ApolloClient(networkTransport: config.network(store: store), store: store) - } - - override func tearDownWithError() throws { - cache = nil - client = nil - config = nil - - try super.tearDownWithError() - } - - // MARK: Queries - - func testHeroNameQuery() { - fetch(query: HeroNameQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - - func testHeroNameQueryWithVariable() { - fetch(query: HeroNameQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - } - - func testHeroAppearsInQuery() { - fetch(query: HeroAppearsInQuery()) { data in - XCTAssertEqual(data.hero?.appearsIn, [.init(.newhope), .init(.empire), .init(.jedi)]) - } - } - - func testHeroAndFriendsNamesQuery() { - fetch(query: HeroAndFriendsNamesQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - func testHeroFriendsOfFriendsNamesQuery() { - fetch(query: HeroFriendsOfFriendsNamesQuery(episode: nil)) { data in - let friendsOfFirstFriendNames = data.hero?.friends?.first??.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsOfFirstFriendNames, ["Han Solo", "Leia Organa", "C-3PO", "R2-D2"]) - } - } - - func testHumanQueryWithNullMass() { - fetch(query: HumanQuery(id: "1004")) { data in - XCTAssertEqual(data.human?.name, "Wilhuff Tarkin") - XCTAssertNil(data.human?.mass) - } - } - - func testHumanQueryWithNullResult() { - fetch(query: HumanQuery(id: "9999")) { data in - XCTAssertNil(data.human) - } - } - - func testHeroDetailsQueryDroid() { - fetch(query: HeroDetailsQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - - guard let droid = data.hero?.asDroid else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - } - - func testHeroDetailsQueryHuman() { - fetch(query: HeroDetailsQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - - guard let human = data.hero?.asHuman else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(human.height, 1.72) - } - } - - func testHeroDetailsWithFragmentQueryDroid() { - fetch(query: HeroDetailsWithFragmentQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.fragments.heroDetails.name, "R2-D2") - - guard let droid = data.hero?.fragments.heroDetails.asDroid else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - } - - func testHeroDetailsWithFragmentQueryHuman() { - fetch(query: HeroDetailsWithFragmentQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.fragments.heroDetails.name, "Luke Skywalker") - - guard let human = data.hero?.fragments.heroDetails.asHuman else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(human.height, 1.72) - } - } - - func testDroidDetailsWithFragmentQueryDroid() { - fetch(query: DroidDetailsWithFragmentQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.asDroid?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.primaryFunction, "Astromech") - } - } - - func testDroidDetailsWithFragmentQueryHuman() { - fetch(query: DroidDetailsWithFragmentQuery(episode: .init(.empire))) { data in - XCTAssertNil(data.hero?.asDroid) - } - } - - - func testHeroTypeDependentAliasedFieldDroid() { - fetch(query: HeroTypeDependentAliasedFieldQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.asDroid?.property, "Astromech") - XCTAssertNil(data.hero?.asHuman?.property) - } - } - - func testHeroTypeDependentAliasedFieldHuman() { - fetch(query: HeroTypeDependentAliasedFieldQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.asHuman?.property, "Tatooine") - XCTAssertNil(data.hero?.asDroid?.property) - } - } - - func testHeroParentTypeDependentFieldDroid() { - fetch(query: HeroParentTypeDependentFieldQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.asDroid?.friends?.first??.asHuman?.height, 1.72) - } - } - - func testHeroParentTypeDependentFieldHuman() { - fetch(query: HeroParentTypeDependentFieldQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.asHuman?.friends?.first??.asHuman?.height, 5.905512) - } - } - - func testStarshipCoordinates() { - fetch(query: StarshipQuery()) { data in - XCTAssertEqual(data.starship?.coordinates?[0], [1, 2]) - XCTAssertEqual(data.starship?.coordinates?[1], [3, 4]) - } - } - - // MARK: Mutations - - func testCreateReviewForEpisode() { - perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.jedi), - review: ReviewInput(stars: 5, commentary: "This is a great movie!")) - ) { data in - XCTAssertEqual(data.createReview?.stars, 5) - XCTAssertEqual(data.createReview?.commentary, "This is a great movie!") - } - } - - // MARK: - Helpers - - private func fetch(query: Query, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Query.Data) -> Void) { - let resultObserver = makeResultObserver(for: query, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Fetched query from server", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } - - private func perform(mutation: Mutation, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Mutation.Data) -> Void) { - let resultObserver = makeResultObserver(for: mutation, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Performing mutation on server", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - client.perform(mutation: mutation, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloServerIntegrationTests/StarWarsSubscriptionTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsSubscriptionTests.swift deleted file mode 100644 index d91cc88f3..000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsSubscriptionTests.swift +++ /dev/null @@ -1,569 +0,0 @@ -import XCTest -import Apollo -import ApolloInternalTestHelpers -@testable import ApolloWebSocket -import StarWarsAPI -import ApolloAPI - -class StarWarsSubscriptionTests: XCTestCase { - var concurrentQueue: DispatchQueue! - var client: ApolloClient! - var webSocketTransport: WebSocketTransport! - - var connectionStartedExpectation: XCTestExpectation? - var disconnectedExpectation: XCTestExpectation? - var reconnectedExpectation: XCTestExpectation? - - override func setUp() { - super.setUp() - - concurrentQueue = DispatchQueue(label: "com.apollographql.test.\(self.name)", attributes: .concurrent) - - connectionStartedExpectation = self.expectation(description: "Web socket connected") - - webSocketTransport = WebSocketTransport( - websocket: WebSocket( - request: URLRequest(url: TestServerURL.starWarsWebSocket.url), - protocol: .graphql_ws - ), - store: ApolloStore() - ) - webSocketTransport.delegate = self - client = ApolloClient(networkTransport: webSocketTransport, store: ApolloStore()) - - self.wait(for: [self.connectionStartedExpectation!], timeout: 5) - } - - override func tearDownWithError() throws { - client = nil - webSocketTransport = nil - connectionStartedExpectation = nil - disconnectedExpectation = nil - reconnectedExpectation = nil - concurrentQueue = nil - - try super.tearDownWithError() - } - - private func waitForSubscriptionsToStart(for delay: TimeInterval = 0.1, on queue: DispatchQueue = .main) { - /// This method works around changes to the subscriptions package which mean that subscriptions do not start passing on data the absolute instant they are created. - let waitExpectation = self.expectation(description: "Waited!") - - queue.asyncAfter(deadline: .now() + delay) { - waitExpectation.fulfill() - } - - self.wait(for: [waitExpectation], timeout: delay + 1) - } - - // MARK: Subscriptions - - func testSubscribeReviewJediEpisode() { - let expectation = self.expectation(description: "Subscribe single review") - - let sub = client.subscribe(subscription: ReviewAddedSubscription(episode: .init(.jedi))) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - guard let data = graphQLResult.data else { - XCTFail("No subscription result data") - return - } - - XCTAssertEqual(data.reviewAdded?.episode, .init(.jedi)) - XCTAssertEqual(data.reviewAdded?.stars, 6) - XCTAssertEqual(data.reviewAdded?.commentary, "This is the greatest movie!") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForSubscriptionsToStart() - - client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.jedi), - review: ReviewInput(stars: 6, commentary: "This is the greatest movie!") - )) - - waitForExpectations(timeout: 10, handler: nil) - sub.cancel() - } - - func testSubscribeReviewAnyEpisode() { - let expectation = self.expectation(description: "Subscribe any episode") - - let sub = client.subscribe(subscription: ReviewAddedSubscription(episode: nil)) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - guard let data = graphQLResult.data else { - XCTFail("No subscription result data") - return - } - - XCTAssertEqual(data.reviewAdded?.stars, 13) - XCTAssertEqual(data.reviewAdded?.commentary, "This is an even greater movie!") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForSubscriptionsToStart() - - client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.empire), - review: ReviewInput(stars: 13, commentary: "This is an even greater movie!") - )) - - waitForExpectations(timeout: 2, handler: nil) - sub.cancel() - } - - func testSubscribeReviewDifferentEpisode() { - let expectation = self.expectation(description: "Subscription to specific episode - expecting timeout") - expectation.isInverted = true - - let sub = client.subscribe(subscription: ReviewAddedSubscription( - episode: .init(.jedi) - )) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - guard let data = graphQLResult.data else { - XCTFail("No subscription result data") - return - } - - XCTAssertNotEqual(data.reviewAdded?.episode, .init(.jedi)) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForSubscriptionsToStart() - - client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.empire), - review: ReviewInput(stars: 10, commentary: "This is an even greater movie!") - )) - - waitForExpectations(timeout: 3, handler: nil) - sub.cancel() - } - - func testSubscribeThenCancel() { - let expectation = self.expectation(description: "Subscription then cancel - expecting timeout") - expectation.isInverted = true - - let sub = client.subscribe(subscription: ReviewAddedSubscription( - episode: .init(.jedi) - )) { _ in - XCTFail("Received subscription after cancel") - } - - self.waitForSubscriptionsToStart() - - sub.cancel() - - client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.jedi), - review: ReviewInput(stars: 10, commentary: "This is an even greater movie!") - )) - - waitForExpectations(timeout: 3, handler: nil) - } - - func testSubscribeMultipleReviews() { - let count = 50 - let expectation = self.expectation(description: "Multiple reviews") - expectation.expectedFulfillmentCount = count - - let sub = client.subscribe(subscription: ReviewAddedSubscription( - episode: .init(.empire) - )) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - guard let data = graphQLResult.data else { - XCTFail("No subscription result data") - return - } - - XCTAssertEqual(data.reviewAdded?.episode, .init(.empire)) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForSubscriptionsToStart() - - for i in 1...count { - let review = ReviewInput(stars: i, commentary: "The greatest movie ever!") - _ = client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.empire), - review: review - )) - } - - waitForExpectations(timeout: 10, handler: nil) - sub.cancel() - } - - func testMultipleSubscriptions() { - // Multiple subscriptions, one for any episode and one for each of the episode - // We send count reviews and expect to receive twice that number of subscriptions - - let count = 20 - - let expectation = self.expectation(description: "Multiple reviews") - expectation.expectedFulfillmentCount = count * 2 - - var allFulfilledCount = 0 - var newHopeFulfilledCount = 0 - var empireFulfilledCount = 0 - var jediFulfilledCount = 0 - - let subAll = client.subscribe(subscription: ReviewAddedSubscription(episode: nil)) { result in - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - XCTAssertNotNil(graphQLResult.data) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - expectation.fulfill() - allFulfilledCount += 1 - } - - let subEmpire = client.subscribe(subscription: ReviewAddedSubscription( - episode: .init(.empire) - )) { result in - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - XCTAssertNotNil(graphQLResult.data) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - expectation.fulfill() - empireFulfilledCount += 1 - } - - let subJedi = client.subscribe(subscription: ReviewAddedSubscription( - episode: .init(.jedi) - )) { result in - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - XCTAssertNotNil(graphQLResult.data) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - expectation.fulfill() - jediFulfilledCount += 1 - } - - let subNewHope = client.subscribe(subscription: ReviewAddedSubscription( - episode: .init(.newhope) - )) { result in - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - XCTAssertNotNil(graphQLResult.data) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - expectation.fulfill() - newHopeFulfilledCount += 1 - } - - self.waitForSubscriptionsToStart() - - let episodes : [Episode] = [.empire, .jedi, .newhope] - - var selectedEpisodes = [Episode]() - for i in 1...count { - let review = ReviewInput(stars: i, commentary: "The greatest movie ever!") - let episode = episodes.randomElement()! - selectedEpisodes.append(episode) - _ = client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(episode), - review: review - )) - } - - waitForExpectations(timeout: 10, handler: nil) - XCTAssertEqual( - allFulfilledCount, - count, - "All not fulfilled proper number of times. Expected \(count), got \(allFulfilledCount)" - ) - let expectedNewHope = selectedEpisodes.filter { $0 == .init(.newhope) }.count - XCTAssertEqual( - newHopeFulfilledCount, - expectedNewHope, - "New Hope not fulfilled proper number of times. Expected \(expectedNewHope), got \(newHopeFulfilledCount)" - ) - let expectedEmpire = selectedEpisodes.filter { $0 == .init(.empire) }.count - XCTAssertEqual( - empireFulfilledCount, - expectedEmpire, - "Empire not fulfilled proper number of times. Expected \(expectedEmpire), got \(empireFulfilledCount)" - ) - let expectedJedi = selectedEpisodes.filter { $0 == .init(.jedi) }.count - XCTAssertEqual( - jediFulfilledCount, - expectedJedi, - "Jedi not fulfilled proper number of times. Expected \(expectedJedi), got \(jediFulfilledCount)" - ) - - subAll.cancel() - subEmpire.cancel() - subJedi.cancel() - subNewHope.cancel() - } - - // MARK: Data races tests - - func testConcurrentSubscribing() { - let firstSubscription = ReviewAddedSubscription(episode: .init(.empire)) - let secondSubscription = ReviewAddedSubscription(episode: .init(.empire)) - - let expectation = self.expectation(description: "Subscribers connected and received events") - expectation.expectedFulfillmentCount = 2 - - var sub1: (any Cancellable)? - var sub2: (any Cancellable)? - - concurrentQueue.async { - sub1 = self.client.subscribe(subscription: firstSubscription) { _ in - expectation.fulfill() - } - } - - concurrentQueue.async { - sub2 = self.client.subscribe(subscription: secondSubscription) { _ in - expectation.fulfill() - } - } - - self.waitForSubscriptionsToStart(on: concurrentQueue) - - // dispatched with a barrier flag to make sure - // this is performed after subscription calls - concurrentQueue.sync(flags: .barrier) { - // dispatched on the processing queue with barrier flag to make sure - // this is performed after subscribers are processed - self.webSocketTransport.processingQueue.async(flags: .barrier) { - _ = self.client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.empire), - review: ReviewInput(stars: 5, commentary: "The greatest movie ever!") - )) - } - } - - waitForExpectations(timeout: 10, handler: nil) - sub1?.cancel() - sub2?.cancel() - } - - func testConcurrentSubscriptionCancellations() { - let firstSubscription = ReviewAddedSubscription(episode: .init(.empire)) - let secondSubscription = ReviewAddedSubscription(episode: .init(.empire)) - - let expectation = self.expectation(description: "Subscriptions cancelled") - expectation.expectedFulfillmentCount = 2 - let invertedExpectation = self.expectation(description: "Subscription received callback - expecting timeout") - invertedExpectation.isInverted = true - - let sub1 = client.subscribe(subscription: firstSubscription) { _ in - invertedExpectation.fulfill() - } - let sub2 = client.subscribe(subscription: secondSubscription) { _ in - invertedExpectation.fulfill() - } - - self.waitForSubscriptionsToStart(on: concurrentQueue) - - concurrentQueue.async { - sub1.cancel() - expectation.fulfill() - } - concurrentQueue.async { - sub2.cancel() - expectation.fulfill() - } - - wait(for: [expectation], timeout: 10) - - _ = self.client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.empire), - review: ReviewInput(stars: 5, commentary: "The greatest movie ever!") - )) - - wait(for: [invertedExpectation], timeout: 2) - } - - func testConcurrentSubscriptionAndConnectionClose() { - let empireReviewSubscription = ReviewAddedSubscription(episode: .init(.empire)) - let expectation = self.expectation(description: "Connection closed") - let invertedExpectation = self.expectation(description: "Subscription received callback - expecting timeout") - invertedExpectation.isInverted = true - - let sub = self.client.subscribe(subscription: empireReviewSubscription) { _ in - invertedExpectation.fulfill() - } - - self.waitForSubscriptionsToStart(on: concurrentQueue) - - concurrentQueue.async { - sub.cancel() - } - concurrentQueue.async { - self.webSocketTransport.closeConnection() - expectation.fulfill() - } - - wait(for: [expectation], timeout: 10) - - _ = self.client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.empire), - review: ReviewInput(stars: 5, commentary: "The greatest movie ever!") - )) - - wait(for: [invertedExpectation], timeout: 2) - } - - func testConcurrentConnectAndCloseConnection() { - let webSocketTransport = WebSocketTransport( - websocket: MockWebSocket( - request: URLRequest(url: TestServerURL.starWarsWebSocket.url), - protocol: .graphql_ws - ), - store: ApolloStore() - ) - - let expectation = self.expectation(description: "Connection closed") - expectation.expectedFulfillmentCount = 2 - - concurrentQueue.async { - if let websocket = webSocketTransport.websocket as? MockWebSocket { - websocket.reportDidConnect() - expectation.fulfill() - } - } - - concurrentQueue.async { - webSocketTransport.closeConnection() - expectation.fulfill() - } - - waitForExpectations(timeout: 10, handler: nil) - } - - func testPausingAndResumingWebSocketConnection() { - let subscription = ReviewAddedSubscription(episode: nil) - let reviewMutation = CreateAwesomeReviewMutation() - - // Send the mutations via a separate transport so they can still be sent when the websocket is disconnected - let store = ApolloStore() - let interceptorProvider = DefaultInterceptorProvider(store: store) - let alternateTransport = RequestChainNetworkTransport( - interceptorProvider: interceptorProvider, - endpointURL: TestServerURL.starWarsServer.url - ) - let alternateClient = ApolloClient(networkTransport: alternateTransport, store: store) - - func sendReview() { - let reviewSentExpectation = self.expectation(description: "review sent") - alternateClient.perform(mutation: reviewMutation) { mutationResult in - switch mutationResult { - case .success: - break - case .failure(let error): - XCTFail("Unexpected error sending review: \(error)") - } - - reviewSentExpectation.fulfill() - } - self.wait(for: [reviewSentExpectation], timeout: 10) - } - - let subscriptionExpectation = self.expectation(description: "Received review") - // This should get hit twice - once before we pause the web socket and once after. - subscriptionExpectation.expectedFulfillmentCount = 2 - let reviewAddedSubscription = self.client.subscribe(subscription: subscription) { subscriptionResult in - switch subscriptionResult { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.reviewAdded?.episode, .init(.jedi)) - subscriptionExpectation.fulfill() - case .failure(let error): - if let wsError = error as? WebSocket.WSError { - // This is an expected error on disconnection, ignore it. - XCTAssertEqual(wsError.code, 1000) - } else { - XCTFail("Unexpected error receiving subscription: \(error)") - subscriptionExpectation.fulfill() - } - } - } - - self.waitForSubscriptionsToStart() - sendReview() - - self.disconnectedExpectation = self.expectation(description: "Web socket disconnected") - webSocketTransport.pauseWebSocketConnection() - self.wait(for: [self.disconnectedExpectation!], timeout: 10) - - // This should not go through since the socket is paused - sendReview() - - self.reconnectedExpectation = self.expectation(description: "Web socket reconnected") - webSocketTransport.resumeWebSocketConnection() - self.wait(for: [self.reconnectedExpectation!], timeout: 10) - self.waitForSubscriptionsToStart() - - // Now that we've reconnected, this should go through to the same subscription. - sendReview() - - self.wait(for: [subscriptionExpectation], timeout: 10) - - // Cancel subscription so it doesn't keep receiving from other tests. - reviewAddedSubscription.cancel() - } -} - -extension StarWarsSubscriptionTests: WebSocketTransportDelegate { - - func webSocketTransportDidConnect(_ webSocketTransport: WebSocketTransport) { - self.connectionStartedExpectation?.fulfill() - } - - func webSocketTransportDidReconnect(_ webSocketTransport: WebSocketTransport) { - self.reconnectedExpectation?.fulfill() - } - - func webSocketTransport(_ webSocketTransport: WebSocketTransport, didDisconnectWithError error: (any Error)?) { - self.disconnectedExpectation?.fulfill() - } -} diff --git a/Tests/ApolloServerIntegrationTests/StarWarsWebSocketTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsWebSocketTests.swift deleted file mode 100755 index 380c1247a..000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsWebSocketTests.swift +++ /dev/null @@ -1,351 +0,0 @@ -import XCTest -import Apollo -import ApolloInternalTestHelpers -@testable import ApolloWebSocket -import StarWarsAPI -import ApolloAPI - -class StarWarsWebSocketTests: XCTestCase, CacheDependentTesting { - - var cacheType: any TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 5 - - var cache: (any NormalizedCache)! - var client: ApolloClient! - - override func setUp() async throws { - try await super.setUp() - - cache = try await makeNormalizedCache() - let store = ApolloStore(cache: cache) - - let networkTransport = WebSocketTransport( - websocket: WebSocket(request: URLRequest(url: TestServerURL.starWarsWebSocket.url), - protocol: .graphql_ws), - store: store - ) - - client = ApolloClient(networkTransport: networkTransport, store: store) - } - - override func tearDownWithError() throws { - cache = nil - client = nil - - try super.tearDownWithError() - } - - // MARK: Queries - - func testHeroNameQuery() { - fetch(query: HeroNameQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - - func testHeroNameQueryWithVariable() { - fetch(query: HeroNameQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - } - - func testHeroAppearsInQuery() { - fetch(query: HeroAppearsInQuery()) { data in - XCTAssertEqual(data.hero?.appearsIn, [.init(.newhope), .init(.empire), .init(.jedi)]) - } - } - - func testHeroAndFriendsNamesQuery() { - fetch(query: HeroAndFriendsNamesQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - func testHeroFriendsOfFriendsNamesQuery() { - fetch(query: HeroFriendsOfFriendsNamesQuery(episode: nil)) { data in - let friendsOfFirstFriendNames = data.hero?.friends?.first??.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsOfFirstFriendNames, ["Han Solo", "Leia Organa", "C-3PO", "R2-D2"]) - } - } - - func testHumanQueryWithNullMass() { - fetch(query: HumanQuery(id: "1004")) { data in - XCTAssertEqual(data.human?.name, "Wilhuff Tarkin") - XCTAssertNil(data.human?.mass) - } - } - - func testHumanQueryWithNullResult() { - fetch(query: HumanQuery(id: "9999")) { data in - XCTAssertNil(data.human) - } - } - - func testHeroDetailsQueryDroid() { - fetch(query: HeroDetailsQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - - guard let droid = data.hero?.asDroid else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - } - - func testHeroDetailsQueryHuman() { - fetch(query: HeroDetailsQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - - guard let human = data.hero?.asHuman else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(human.height, 1.72) - } - } - - func testHeroDetailsWithFragmentQueryDroid() { - fetch(query: HeroDetailsWithFragmentQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.fragments.heroDetails.name, "R2-D2") - - guard let droid = data.hero?.fragments.heroDetails.asDroid else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - } - - func testHeroDetailsWithFragmentQueryHuman() { - fetch(query: HeroDetailsWithFragmentQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.fragments.heroDetails.name, "Luke Skywalker") - - guard let human = data.hero?.fragments.heroDetails.asHuman else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(human.height, 1.72) - } - } - - func testDroidDetailsWithFragmentQueryDroid() { - fetch(query: DroidDetailsWithFragmentQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.asDroid?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.primaryFunction, "Astromech") - } - } - - func testDroidDetailsWithFragmentQueryHuman() { - fetch(query: DroidDetailsWithFragmentQuery(episode: .init(.empire))) { data in - XCTAssertNil(data.hero?.asDroid) - } - } - - - func testHeroTypeDependentAliasedFieldDroid() { - fetch(query: HeroTypeDependentAliasedFieldQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.asDroid?.property, "Astromech") - XCTAssertNil(data.hero?.asHuman?.property) - } - } - - func testHeroTypeDependentAliasedFieldHuman() { - fetch(query: HeroTypeDependentAliasedFieldQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.asHuman?.property, "Tatooine") - XCTAssertNil(data.hero?.asDroid?.property) - } - } - - func testHeroParentTypeDependentFieldDroid() { - fetch(query: HeroParentTypeDependentFieldQuery(episode: nil)) { data in - XCTAssertEqual(data.hero?.asDroid?.friends?.first??.asHuman?.height, 1.72) - } - } - - func testHeroParentTypeDependentFieldHuman() { - fetch(query: HeroParentTypeDependentFieldQuery(episode: .init(.empire))) { data in - XCTAssertEqual(data.hero?.asHuman?.friends?.first??.asHuman?.height, 5.905512) - } - } - - func testStarshipCoordinates() { - fetch(query: StarshipQuery()) { data in - XCTAssertEqual(data.starship?.coordinates?[0], [1, 2]) - XCTAssertEqual(data.starship?.coordinates?[1], [3, 4]) - } - } - - // MARK: @skip / @include directives - - func testHeroNameConditionalExclusion() { - fetch(query: HeroNameConditionalExclusionQuery(skipName: false)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalExclusionQuery(skipName: true)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalInclusion() { - fetch(query: HeroNameConditionalInclusionQuery(includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalInclusionQuery(includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalBoth() { - fetch(query: HeroNameConditionalBothQuery(skipName: false, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothQuery(skipName: true, includeName: true)) { data in - XCTAssertNil(data.hero?.name) - } - - fetch(query: HeroNameConditionalBothQuery(skipName: false, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - - fetch(query: HeroNameConditionalBothQuery(skipName: true, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalBothSeparate() { - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: false, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: true, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: false, includeName: false)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: true, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroDetailsInlineConditionalInclusion() { - fetch(query: HeroDetailsInlineConditionalInclusionQuery(includeDetails: true)) { data in - XCTAssertEqual(data.hero?.ifIncludeDetails?.name, "R2-D2") - XCTAssertEqual(data.hero?.ifIncludeDetails?.appearsIn, [.init(.newhope), .init(.empire), .init(.jedi)]) - } - - fetch(query: HeroDetailsInlineConditionalInclusionQuery(includeDetails: false)) { data in - XCTAssertNil(data.hero?.ifIncludeDetails?.name) - XCTAssertNil(data.hero?.ifIncludeDetails?.appearsIn) - } - } - - func testHeroDetailsFragmentConditionalInclusion() { - fetch(query: HeroDetailsFragmentConditionalInclusionQuery(includeDetails: true)) { data in - XCTAssertEqual(data.hero?.ifIncludeDetails?.name, "R2-D2") - XCTAssertEqual(data.hero?.ifIncludeDetails?.fragments.heroDetails.asDroid?.primaryFunction, "Astromech") - } - - fetch(query: HeroDetailsFragmentConditionalInclusionQuery(includeDetails: false)) { data in - XCTAssertNil(data.hero?.ifIncludeDetails?.name) - XCTAssertNil(data.hero?.ifIncludeDetails?.fragments.heroDetails.asDroid?.primaryFunction) - } - } - - func testHeroNameTypeSpecificConditionalInclusion() { - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery( - episode: nil, - includeName: true - )) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.name, "R2-D2") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery( - episode: nil, - includeName: false - )) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.name, "R2-D2") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery( - episode: .init(.empire), - includeName: true - )) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery( - episode: .init(.empire), - includeName: false - )) { data in - XCTAssertNil(data.hero?.name) - } - } - - // MARK: Mutations - - func testCreateReviewForEpisode() { - perform(mutation: CreateReviewForEpisodeMutation( - episode: .init(.jedi), - review: ReviewInput(stars: 5, commentary: "This is a great movie!") - )) { data in - XCTAssertEqual(data.createReview?.stars, 5) - XCTAssertEqual(data.createReview?.commentary, "This is a great movie!") - } - } - - // MARK: - Helpers - - private func fetch(query: Query, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Query.Data) -> Void) { - let resultObserver = makeResultObserver(for: query, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Fetched query from server", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } - - private func perform(mutation: Mutation, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Mutation.Data) -> Void) { - let resultObserver = makeResultObserver(for: mutation, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Performing mutation on server", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - client.perform(mutation: mutation, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloServerIntegrationTests/SubscriptionTests.swift b/Tests/ApolloServerIntegrationTests/SubscriptionTests.swift deleted file mode 100644 index 354961a74..000000000 --- a/Tests/ApolloServerIntegrationTests/SubscriptionTests.swift +++ /dev/null @@ -1,58 +0,0 @@ -import XCTest -import Apollo -import SubscriptionAPI -import ApolloWebSocket -import SQLite -import Nimble - -class SubscriptionTests: XCTestCase { - enum Connection: Equatable { - case disconnected - case connected - } - - var connectionState: Connection = .disconnected - var resultNumber: Int? = nil - - func test_subscribe_givenSubscription_shouldReceiveSuccessResult_andCancelSubscription() { - // given - let store = ApolloStore() - let webSocketTransport = WebSocketTransport( - websocket: WebSocket(url: TestServerURL.subscriptionWebSocket.url, protocol: .graphql_transport_ws), - store: store - ) - webSocketTransport.delegate = self - let client = ApolloClient(networkTransport: webSocketTransport, store: store) - - expect(self.connectionState).toEventually(equal(Connection.connected), timeout: .seconds(1)) - - // when - let subject = client.subscribe(subscription: IncrementingSubscription()) { result in - switch result { - case let .failure(error): - XCTFail("Expected .success, got \(error.localizedDescription)") - - case let .success(graphqlResult): - expect(graphqlResult.errors).to(beNil()) - self.resultNumber = graphqlResult.data?.numberIncremented - } - } - - // then - expect(self.resultNumber).toEventuallyNot(beNil(), timeout: .seconds(2)) - - subject.cancel() - webSocketTransport.closeConnection() - expect(self.connectionState).toEventually(equal(.disconnected), timeout: .seconds(2)) - } -} - -extension SubscriptionTests: WebSocketTransportDelegate { - func webSocketTransportDidConnect(_ webSocketTransport: WebSocketTransport) { - connectionState = .connected - } - - func webSocketTransport(_ webSocketTransport: WebSocketTransport, didDisconnectWithError error: (any Error)?) { - connectionState = .disconnected - } -} diff --git a/Tests/ApolloServerIntegrationTests/TestHelpers/HTTPBinAPI.swift b/Tests/ApolloServerIntegrationTests/TestHelpers/HTTPBinAPI.swift deleted file mode 100644 index 2229569dc..000000000 --- a/Tests/ApolloServerIntegrationTests/TestHelpers/HTTPBinAPI.swift +++ /dev/null @@ -1,59 +0,0 @@ -import Foundation - -enum HTTPBinAPI { - static let baseURL = URL(string: "https://httpbin.org")! - enum Endpoint { - case bytes(count: Int) - case get - case getWithIndex(index: Int) - case headers - case image - case post - - var toString: String { - - switch self { - case .bytes(let count): - return "bytes/\(count)" - case .get, - .getWithIndex: - return "get" - case .headers: - return "headers" - case .image: - return "image/jpeg" - case .post: - return "post" - } - } - - var queryParams: [URLQueryItem]? { - switch self { - case .getWithIndex(let index): - return [URLQueryItem(name: "index", value: "\(index)")] - default: - return nil - } - } - - var toURL: URL { - var components = URLComponents(url: HTTPBinAPI.baseURL, resolvingAgainstBaseURL: false)! - components.path = "/\(self.toString)" - components.queryItems = self.queryParams - - return components.url! - } - } -} - -struct HTTPBinResponse: Codable { - - let headers: [String: String] - let url: String - let json: [String: String]? - let args: [String: String]? - - init(data: Data) throws { - self = try JSONDecoder().decode(Self.self, from: data) - } -} diff --git a/Tests/ApolloServerIntegrationTests/TestHelpers/TestConfigs.swift b/Tests/ApolloServerIntegrationTests/TestHelpers/TestConfigs.swift deleted file mode 100644 index cfaf86023..000000000 --- a/Tests/ApolloServerIntegrationTests/TestHelpers/TestConfigs.swift +++ /dev/null @@ -1,47 +0,0 @@ -@testable import Apollo - -protocol TestConfig { - func network(store: ApolloStore) -> any NetworkTransport -} - -class DefaultConfig: TestConfig { - - func transport(with store: ApolloStore) -> any NetworkTransport { - let provider = DefaultInterceptorProvider(store: store) - return RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestServerURL.starWarsServer.url) - } - - func network(store: ApolloStore) -> any NetworkTransport { - return transport(with: store) - } -} - -class APQsConfig: TestConfig { - - func transport(with store: ApolloStore) -> any NetworkTransport { - let provider = DefaultInterceptorProvider(store: store) - return RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestServerURL.starWarsServer.url, - autoPersistQueries: true) - } - - func network(store: ApolloStore) -> any NetworkTransport { - return transport(with: store) - } -} - -class APQsWithGetMethodConfig: TestConfig { - - func transport(with store: ApolloStore) -> any NetworkTransport { - let provider = DefaultInterceptorProvider(store: store) - return RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestServerURL.starWarsServer.url, - autoPersistQueries: true, - useGETForPersistedQueryRetry: true) - } - - func network(store: ApolloStore) -> any NetworkTransport { - return transport(with: store) - } -} diff --git a/Tests/ApolloServerIntegrationTests/TestHelpers/TestServerURLs.swift b/Tests/ApolloServerIntegrationTests/TestHelpers/TestServerURLs.swift deleted file mode 100644 index 95c504bd1..000000000 --- a/Tests/ApolloServerIntegrationTests/TestHelpers/TestServerURLs.swift +++ /dev/null @@ -1,15 +0,0 @@ -/// Local URLs for servers used in integration testing -import Foundation - -public enum TestServerURL: String { - case mockServer = "http://localhost/dummy_url" - case starWarsServer = "http://localhost:8080/graphql" - case starWarsWebSocket = "ws://localhost:8080/websocket" - case uploadServer = "http://localhost:4001" - case subscriptionServer = "http://localhost:4000/graphql" - case subscriptionWebSocket = "ws://localhost:4000/graphql" - - public var url: URL { - return URL(string: self.rawValue)! - } -} diff --git a/Tests/ApolloServerIntegrationTests/UploadTests.swift b/Tests/ApolloServerIntegrationTests/UploadTests.swift deleted file mode 100644 index d04bc5fbe..000000000 --- a/Tests/ApolloServerIntegrationTests/UploadTests.swift +++ /dev/null @@ -1,302 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloInternalTestHelpers -import UploadAPI -import StarWarsAPI - -class UploadTests: XCTestCase { - - static let uploadClientURL = TestServerURL.uploadServer.url - - var client: ApolloClient! - - override func setUp() { - super.setUp() - - client = { - let store = ApolloStore() - let provider = DefaultInterceptorProvider(store: store) - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.uploadClientURL, - additionalHeaders: ["headerKey": "headerValue"]) - transport.clientName = "test" - transport.clientVersion = "test" - - return ApolloClient(networkTransport: transport, store: store) - }() - } - - override func tearDown() { - client = nil - - super.tearDown() - } - - override class func tearDown() { - // Recreate the uploads folder at the end of all tests in this suite to avoid having one billion files in there - recreateUploadsFolder() - super.tearDown() - } - - private static func recreateUploadsFolder() { - let uploadsFolderURL = TestFileHelper.uploadsFolder() - try? FileManager.default.removeItem(at: uploadsFolderURL) - - try? FileManager.default.createDirectory(at: uploadsFolderURL, withIntermediateDirectories: false) - } - - private func compareInitialFile(at initialFileURL: URL, - toUploadedFileAt path: String?, - file: StaticString = #filePath, - line: UInt = #line) { - guard let path = path else { - XCTFail("Path was nil!", - file: file, - line: line) - return - } - - let sanitizedPath = String(path.dropFirst(2)) // Gets rid of the ./ returned by the server - - let uploadedFileURL = TestFileHelper.uploadServerFolder() - .appendingPathComponent(sanitizedPath) - - do { - let initialData = try Data(contentsOf: initialFileURL) - let uploadedData = try Data(contentsOf: uploadedFileURL) - XCTAssertFalse(initialData.isEmpty, - "Initial data was empty at \(initialFileURL)", - file: file, - line: line) - XCTAssertFalse(uploadedData.isEmpty, - "Uploaded data was empty at \(uploadedFileURL)", - file: file, - line: line) - XCTAssertEqual(initialData, - uploadedData, - "Initial data at \(initialFileURL) was not equal to data uploaded at \(uploadedFileURL)", - file: file, - line: line) - } catch { - XCTFail("Unexpected error loading data to compare: \(error)", - file: file, - line: line) - } - } - - func testUploadingASingleFile() throws { - let fileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let file = try GraphQLFile(fieldName: "file", - originalName: "a.txt", - fileURL: fileURL) - - let upload = UploadOneFileMutation(file: "a.txt") - - let expectation = self.expectation(description: "File upload complete") - self.client.upload(operation: upload, files: [file]) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.singleUpload.filename, "a.txt") - self.compareInitialFile(at: fileURL, toUploadedFileAt: graphQLResult.data?.singleUpload.path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testUploadingMultipleFilesWithTheSameFieldName() throws { - let firstFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let firstFile = try GraphQLFile(fieldName: "files", - originalName: "a.txt", - fileURL: firstFileURL) - - let secondFileURL = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - - let secondFile = try GraphQLFile(fieldName: "files", - originalName: "b.txt", - fileURL: secondFileURL) - - let files = [firstFile, secondFile] - - let upload = UploadMultipleFilesToTheSameParameterMutation(files: files.map { $0.originalName }) - - let expectation = self.expectation(description: "File upload complete") - self.client.upload(operation: upload, files: files) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - guard let uploads = graphQLResult.data?.multipleUpload else { - XCTFail("NOPE") - return - } - - XCTAssertEqual(uploads.count, 2) - let sortedUploads = uploads.sorted { $0.filename < $1.filename } - XCTAssertEqual(sortedUploads[0].filename, "a.txt") - XCTAssertEqual(sortedUploads[1].filename, "b.txt") - self.compareInitialFile(at: firstFileURL, toUploadedFileAt: sortedUploads[0].path) - self.compareInitialFile(at: secondFileURL, toUploadedFileAt: sortedUploads[1].path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testUploadingMultipleFilesWithDifferentFieldNames() throws { - let firstFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let firstFile = try GraphQLFile(fieldName: "singleFile", - originalName: "a.txt", - fileURL: firstFileURL) - - let secondFileURL = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - - let secondFile = try GraphQLFile(fieldName: "multipleFiles", - originalName: "b.txt", - fileURL: secondFileURL) - - let thirdFileURL = TestFileHelper.fileURLForFile(named: "c", extension: "txt") - - let thirdFile = try GraphQLFile(fieldName: "multipleFiles", - originalName: "c.txt", - fileURL: thirdFileURL) - - // This is the array of Files for the `multipleFiles` parameter only - let multipleFiles = [secondFile, thirdFile] - - let upload = UploadMultipleFilesToDifferentParametersMutation(singleFile: firstFile.originalName, multipleFiles: multipleFiles.map { $0.originalName }) - - let expectation = self.expectation(description: "File upload complete") - - // This is the array of Files for all parameters - let allFiles = [firstFile, secondFile, thirdFile] - self.client.upload(operation: upload, files: allFiles) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - guard let uploads = graphQLResult.data?.multipleParameterUpload else { - XCTFail("NOPE") - return - } - - XCTAssertEqual(uploads.count, 3) - let sortedUploads = uploads.sorted { $0.filename < $1.filename } - XCTAssertEqual(sortedUploads[0].filename, "a.txt") - XCTAssertEqual(sortedUploads[1].filename, "b.txt") - XCTAssertEqual(sortedUploads[2].filename, "c.txt") - self.compareInitialFile(at: firstFileURL, toUploadedFileAt: sortedUploads[0].path) - self.compareInitialFile(at: secondFileURL, toUploadedFileAt: sortedUploads[1].path) - self.compareInitialFile(at: thirdFileURL, toUploadedFileAt: sortedUploads [2].path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testUploadingASingleFileInAnArray() throws { - let fileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let file = try GraphQLFile(fieldName: "files", - originalName: "a.txt", - fileURL: fileURL) - - let filesArray = [file] - - let uploadMutation = UploadMultipleFilesToTheSameParameterMutation(files: filesArray.map { $0.originalName }) - - let expectation = self.expectation(description: "File upload complete") - self.client.upload(operation: uploadMutation, files: filesArray) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - guard let uploads = graphQLResult.data?.multipleUpload else { - XCTFail("NOPE") - return - } - - XCTAssertEqual(uploads.count, 1) - guard let uploadedFile = uploads.first else { - XCTFail("Could not access uploaded file!") - return - } - - XCTAssertEqual(uploadedFile.filename, "a.txt") - self.compareInitialFile(at: fileURL, toUploadedFileAt: uploadedFile.path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testUploadingSingleFileInAnArrayWithAnotherFileForAnotherField() throws { - let firstFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let firstFile = try GraphQLFile(fieldName: "singleFile", - originalName: "a.txt", - fileURL: firstFileURL) - - let secondFileURL = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - - let secondFile = try GraphQLFile(fieldName: "multipleFiles", - originalName: "b.txt", - fileURL: secondFileURL) - - // This is the array of Files for the `multipleFiles` parameter only - let multipleFiles = [secondFile] - - let upload = UploadMultipleFilesToDifferentParametersMutation(singleFile: firstFile.originalName, multipleFiles: multipleFiles.map { $0.originalName }) - - let expectation = self.expectation(description: "File upload complete") - - // This is the array of Files for all parameters - let allFiles = [firstFile, secondFile] - self.client.upload(operation: upload, files: allFiles) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - guard let uploads = graphQLResult.data?.multipleParameterUpload else { - XCTFail("NOPE") - return - } - - XCTAssertEqual(uploads.count, 2) - let sortedUploads = uploads.sorted { $0.filename < $1.filename } - XCTAssertEqual(sortedUploads[0].filename, "a.txt") - XCTAssertEqual(sortedUploads[1].filename, "b.txt") - self.compareInitialFile(at: firstFileURL, toUploadedFileAt: sortedUploads[0].path) - self.compareInitialFile(at: secondFileURL, toUploadedFileAt: sortedUploads[1].path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - -} diff --git a/scripts/install-apollo-server-docs-example-server.sh b/scripts/install-apollo-server-docs-example-server.sh deleted file mode 100755 index db81cfc94..000000000 --- a/scripts/install-apollo-server-docs-example-server.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -cd $(dirname "$0")/../.. - -git clone https://github.com/apollographql/docs-examples.git - -cd docs-examples/apollo-server/v3/subscriptions-graphql-ws - -npm install diff --git a/scripts/install-node-v12.sh b/scripts/install-node-v12.sh deleted file mode 100755 index 45da71fec..000000000 --- a/scripts/install-node-v12.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -#touch $GITHUB_ENV -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash -echo 'export NVM_DIR="$HOME/.nvm"<> $GITHUB_ENV -echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"<> $GITHUB_ENV -echo nvm install v12.22.10 >> $GITHUB_ENV -echo nvm use v18.15.0 >> $GITHUB_ENV diff --git a/scripts/install-or-update-starwars-server.sh b/scripts/install-or-update-starwars-server.sh deleted file mode 100755 index 8e1678134..000000000 --- a/scripts/install-or-update-starwars-server.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -cd $(dirname "$0")/../.. - -git -C starwars-server pull || git clone https://github.com/apollographql/starwars-server - -cd starwars-server - -npm install -npm prune