Skip to content

Commit 7d5cad6

Browse files
lawmichadiegocstn
andauthored
test(DataStore): Add V2 Connection Integration tests (#1557)
* test: Add V2 Connection schema and files * Blog Post Comment 6 V2 - integration tests * Blog Post Comment 7 V2 - integration tests * Project1V2 Team1V2 hasOne Implicit * Project2V2 Team2V2 hasOne Explicit * Comment3aV2 Post3aV2 HasMany Implicit and Explicit * Post5V2 User5V2 ManyToMany * Comment4V2 Post4V2 Bi-directional Has Many * Model with Secondary Index Model With Custom Timestamps Model with Default Value * Add code compiling for BelongsTo Implicit and Explicit (Project4aV2 Project4bV2 Team4aV2 Team4bV2 * Blog7V2 Post7V2 to latest codegen - compiling * clean up - rename folder, remove dedup schema file * Blog6V2 Post6V2 Comment6V2 cascade delete Blog deletes post and comments * Team1V2 Project1V2 cascade delete test - disabled * CustomerSecondaryIndexV2 add update and delete test * TodoWithDefaultValueV2 test without explicit content * TodoCustomTimestampV2 with failing update and passing delete * Project1V2 Team1V2 Has One (Implicit) DataStoreConnectionScenario1V2Tests update test with sync for updated and deleted models * Project1/1V2/2/2V2 Add unit test showcasing cascade delete is not working * CRUD with cascade tests in 3aV2 (implicit has-many) 3V2 (explicit has-many) and 5V2 (many-to-many) * CRUD with cacade tests in 4V2 DataStoreConnectionScenario4V2Tests * CRUD with cascade test in 7V2 DataStoreConnectionScenario7V2Tests * add github issue related to DataStoreModelWithCustomTimestampTests missing id in update mutation * latest codegen changes for Project4aV2 Project4bV2 * DataStoreConnectionScenario8V2Tests for use case 13 * Update AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/TransformerV2/DataStoreModelWithDefaultValueTests.swift Co-authored-by: Diego Costantino <[email protected]> * Update AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/TransformerV2/DataStoreModelWithDefaultValueTests.swift Co-authored-by: Diego Costantino <[email protected]> * Update AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/TransformerV2/DataStoreModelWithSecondaryIndexTests.swift Co-authored-by: Diego Costantino <[email protected]> * update readme * fix podfile.lock * schema update Co-authored-by: Diego Costantino <[email protected]>
1 parent 2c57ccc commit 7d5cad6

File tree

82 files changed

+8220
-16
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+8220
-16
lines changed

Amplify.xcodeproj/project.pbxproj

Lines changed: 340 additions & 10 deletions
Large diffs are not rendered by default.

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/Connection/DataStoreConnectionScenario1Tests.swift

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,48 @@ class DataStoreConnectionScenario1Tests: SyncEngineIntegrationTestBase {
185185
wait(for: [queriedProjectCompleted, syncUpdatedProjectReceived], timeout: networkTimeout)
186186
}
187187

188-
func testDeleteAndGetProject() throws {
188+
func testDeleteAndGetProjectReturnsNilWithSync() throws {
189189
try startAmplifyAndWaitForSync()
190190
guard let team = saveTeam(name: "name"),
191191
let project = saveProject(teamID: team.id, team: team) else {
192192
XCTFail("Could not save team and project")
193193
return
194194
}
195+
let createReceived = expectation(description: "received created items from cloud")
196+
createReceived.expectedFulfillmentCount = 2 // 1 project and 1 team
197+
let deleteReceived = expectation(description: "Delete notification received")
198+
deleteReceived.expectedFulfillmentCount = 2 // 1 project and 1 team
199+
let hubListener = Amplify.Hub.listen(to: .dataStore,
200+
eventName: HubPayload.EventName.DataStore.syncReceived) { payload in
201+
guard let mutationEvent = payload.data as? MutationEvent else {
202+
XCTFail("Could not cast payload to mutation event")
203+
return
204+
}
205+
206+
if let projectEvent = try? mutationEvent.decodeModel() as? Project1,
207+
projectEvent.id == project.id {
208+
if mutationEvent.mutationType == GraphQLMutationType.create.rawValue {
209+
XCTAssertEqual(mutationEvent.version, 1)
210+
createReceived.fulfill()
211+
} else if mutationEvent.mutationType == GraphQLMutationType.delete.rawValue {
212+
deleteReceived.fulfill()
213+
}
214+
215+
} else if let teamEvent = try? mutationEvent.decodeModel() as? Team1, teamEvent.id == team.id {
216+
if mutationEvent.mutationType == GraphQLMutationType.create.rawValue {
217+
XCTAssertEqual(mutationEvent.version, 1)
218+
createReceived.fulfill()
219+
} else if mutationEvent.mutationType == GraphQLMutationType.delete.rawValue {
220+
deleteReceived.fulfill()
221+
}
222+
}
223+
224+
}
225+
guard try HubListenerTestUtilities.waitForListener(with: hubListener, timeout: 5.0) else {
226+
XCTFail("Listener not registered for hub")
227+
return
228+
}
229+
wait(for: [createReceived], timeout: TestCommonConstants.networkTimeout)
195230

196231
let deleteProjectSuccessful = expectation(description: "delete project")
197232
Amplify.DataStore.delete(project) { result in
@@ -203,6 +238,20 @@ class DataStoreConnectionScenario1Tests: SyncEngineIntegrationTestBase {
203238
}
204239
}
205240
wait(for: [deleteProjectSuccessful], timeout: TestCommonConstants.networkTimeout)
241+
242+
// TODO: Delete Team should not be necessary, cascade delete should delete the team when deleting the project.
243+
// Once cascade works for hasOne, the following code can be removed.
244+
let deleteTeamSuccessful = expectation(description: "delete team")
245+
Amplify.DataStore.delete(team) { result in
246+
switch result {
247+
case .success:
248+
deleteTeamSuccessful.fulfill()
249+
case .failure(let error):
250+
XCTFail("\(error)")
251+
}
252+
}
253+
wait(for: [deleteTeamSuccessful, deleteReceived], timeout: TestCommonConstants.networkTimeout)
254+
206255
let getProjectAfterDeleteCompleted = expectation(description: "get project after deleted complete")
207256
Amplify.DataStore.query(Project1.self, byId: project.id) { result in
208257
switch result {

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/Connection/DataStoreConnectionScenario2Tests.swift

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,48 @@ class DataStoreConnectionScenario2Tests: SyncEngineIntegrationTestBase {
183183
wait(for: [queriedProjectCompleted, syncUpdatedProjectReceived], timeout: networkTimeout)
184184
}
185185

186-
func testDeleteAndGetProject() throws {
186+
func testDeleteAndGetProjectReturnsNilWithSync() throws {
187187
try startAmplifyAndWaitForSync()
188188
guard let team = saveTeam(name: "name"),
189189
let project = saveProject(teamID: team.id, team: team) else {
190190
XCTFail("Could not save team and project")
191191
return
192192
}
193+
let createReceived = expectation(description: "received created items from cloud")
194+
createReceived.expectedFulfillmentCount = 2 // 1 project and 1 team
195+
let deleteReceived = expectation(description: "Delete notification received")
196+
deleteReceived.expectedFulfillmentCount = 2 // 1 project and 1 team
197+
let hubListener = Amplify.Hub.listen(to: .dataStore,
198+
eventName: HubPayload.EventName.DataStore.syncReceived) { payload in
199+
guard let mutationEvent = payload.data as? MutationEvent else {
200+
XCTFail("Could not cast payload to mutation event")
201+
return
202+
}
203+
204+
if let projectEvent = try? mutationEvent.decodeModel() as? Project2,
205+
projectEvent.id == project.id {
206+
if mutationEvent.mutationType == GraphQLMutationType.create.rawValue {
207+
XCTAssertEqual(mutationEvent.version, 1)
208+
createReceived.fulfill()
209+
} else if mutationEvent.mutationType == GraphQLMutationType.delete.rawValue {
210+
deleteReceived.fulfill()
211+
}
212+
213+
} else if let teamEvent = try? mutationEvent.decodeModel() as? Team2, teamEvent.id == team.id {
214+
if mutationEvent.mutationType == GraphQLMutationType.create.rawValue {
215+
XCTAssertEqual(mutationEvent.version, 1)
216+
createReceived.fulfill()
217+
} else if mutationEvent.mutationType == GraphQLMutationType.delete.rawValue {
218+
deleteReceived.fulfill()
219+
}
220+
}
221+
222+
}
223+
guard try HubListenerTestUtilities.waitForListener(with: hubListener, timeout: 5.0) else {
224+
XCTFail("Listener not registered for hub")
225+
return
226+
}
227+
wait(for: [createReceived], timeout: TestCommonConstants.networkTimeout)
193228

194229
let deleteProjectSuccessful = expectation(description: "delete project")
195230
Amplify.DataStore.delete(project) { result in
@@ -201,6 +236,20 @@ class DataStoreConnectionScenario2Tests: SyncEngineIntegrationTestBase {
201236
}
202237
}
203238
wait(for: [deleteProjectSuccessful], timeout: TestCommonConstants.networkTimeout)
239+
240+
// TODO: Delete Team should not be necessary, cascade delete should delete the team when deleting the project.
241+
// Once cascade works for hasOne, the following code can be removed.
242+
let deleteTeamSuccessful = expectation(description: "delete team")
243+
Amplify.DataStore.delete(team) { result in
244+
switch result {
245+
case .success:
246+
deleteTeamSuccessful.fulfill()
247+
case .failure(let error):
248+
XCTFail("\(error)")
249+
}
250+
}
251+
wait(for: [deleteTeamSuccessful, deleteReceived], timeout: TestCommonConstants.networkTimeout)
252+
204253
let getProjectAfterDeleteCompleted = expectation(description: "get project after deleted complete")
205254
Amplify.DataStore.query(Project2.self, byId: project.id) { result in
206255
switch result {

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/Connection/DataStoreConnectionScenario3Tests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import AWSMobileClient
1414
@testable import AWSDataStoreCategoryPlugin
1515

1616
/*
17-
(HasMany) A Post that can have many comments
17+
(HasMany) A Post that can have many comments (Explicit)
1818
```
1919
type Post3 @model {
2020
id: ID!

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ type CustomerOrder @model
234234
orderId: String!
235235
email: String!
236236
}
237+
237238
```
238239
3. `amplify push`
239240

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import XCTest
9+
10+
import AmplifyPlugins
11+
import AWSMobileClient
12+
13+
@testable import Amplify
14+
@testable import AmplifyTestCommon
15+
@testable import AWSDataStoreCategoryPlugin
16+
17+
class SyncEngineIntegrationV2TestBase: DataStoreTestBase {
18+
19+
static let amplifyConfigurationFile = "testconfiguration/AWSDataStoreCategoryPluginIntegrationV2Tests-amplifyconfiguration"
20+
21+
static let networkTimeout = TimeInterval(180)
22+
let networkTimeout = SyncEngineIntegrationTestBase.networkTimeout
23+
24+
// Convenience property to obtain a handle to the underlying storage adapter implementation, for use in asserting
25+
// database behaviors. Full of force-unwrapped badness.
26+
// swiftlint:disable force_try
27+
// swiftlint:disable force_cast
28+
var storageAdapter: SQLiteStorageEngineAdapter {
29+
let plugin = try! Amplify.DataStore.getPlugin(for: "awsDataStorePlugin") as! AWSDataStorePlugin
30+
let storageEngine = plugin.storageEngine as! StorageEngine
31+
let storageAdapter = storageEngine.storageAdapter as! SQLiteStorageEngineAdapter
32+
return storageAdapter
33+
}
34+
// swiftlint:enable force_try
35+
// swiftlint:enable force_cast
36+
37+
override func setUp() {
38+
super.setUp()
39+
40+
continueAfterFailure = false
41+
42+
Amplify.reset()
43+
Amplify.Logging.logLevel = .verbose
44+
45+
do {
46+
try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: TestModelV2Registration()))
47+
try Amplify.add(plugin: AWSDataStorePlugin(modelRegistration: TestModelV2Registration()))
48+
} catch {
49+
XCTFail(String(describing: error))
50+
return
51+
}
52+
}
53+
54+
func stopDataStore() {
55+
let stopped = expectation(description: "DataStore stopped")
56+
Amplify.DataStore.stop { result in
57+
switch result {
58+
case .success:
59+
stopped.fulfill()
60+
case .failure(let error):
61+
XCTFail("\(error)")
62+
}
63+
}
64+
wait(for: [stopped], timeout: 2)
65+
}
66+
67+
func clearDataStore() {
68+
let cleared = expectation(description: "DataStore cleared")
69+
Amplify.DataStore.clear { result in
70+
switch result {
71+
case .success:
72+
cleared.fulfill()
73+
case .failure(let error):
74+
XCTFail("\(error)")
75+
}
76+
}
77+
wait(for: [cleared], timeout: 2)
78+
}
79+
80+
func startAmplify(_ completion: BasicClosure? = nil) throws {
81+
let amplifyConfig = try TestConfigHelper.retrieveAmplifyConfiguration(forResource: Self.amplifyConfigurationFile)
82+
83+
DispatchQueue.global().async {
84+
do {
85+
try Amplify.configure(amplifyConfig)
86+
completion?()
87+
} catch {
88+
XCTFail(String(describing: error))
89+
}
90+
}
91+
}
92+
93+
func startAmplifyAndWaitForSync() throws {
94+
try startAmplifyAndWait(for: HubPayload.EventName.DataStore.syncStarted)
95+
}
96+
97+
func startAmplifyAndWaitForReady() throws {
98+
try startAmplifyAndWait(for: HubPayload.EventName.DataStore.ready)
99+
}
100+
101+
private func startAmplifyAndWait(for eventName: String) throws {
102+
let eventReceived = expectation(description: "DataStore \(eventName) event")
103+
104+
var token: UnsubscribeToken!
105+
token = Amplify.Hub.listen(to: .dataStore,
106+
eventName: eventName) { _ in
107+
eventReceived.fulfill()
108+
Amplify.Hub.removeListener(token)
109+
}
110+
111+
guard try HubListenerTestUtilities.waitForListener(with: token, timeout: 5.0) else {
112+
XCTFail("Hub Listener not registered")
113+
return
114+
}
115+
116+
try startAmplify {
117+
Amplify.DataStore.start { result in
118+
if case .failure(let error) = result {
119+
XCTFail("\(error)")
120+
}
121+
}
122+
}
123+
124+
wait(for: [eventReceived], timeout: 100.0)
125+
}
126+
127+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Amplify
9+
import AmplifyTestCommon
10+
11+
struct TestModelV2Registration: AmplifyModelRegistration {
12+
13+
func registerModels(registry: ModelRegistry.Type) {
14+
registry.register(modelType: Project1V2.self)
15+
registry.register(modelType: Team1V2.self)
16+
registry.register(modelType: Project2V2.self)
17+
registry.register(modelType: Team2V2.self)
18+
registry.register(modelType: Post3aV2.self)
19+
registry.register(modelType: Comment3aV2.self)
20+
registry.register(modelType: Post3V2.self)
21+
registry.register(modelType: Comment3V2.self)
22+
registry.register(modelType: Post4V2.self)
23+
registry.register(modelType: Comment4V2.self)
24+
registry.register(modelType: Post5V2.self)
25+
registry.register(modelType: PostEditor5V2.self)
26+
registry.register(modelType: User5V2.self)
27+
registry.register(modelType: Blog6V2.self)
28+
registry.register(modelType: Post6V2.self)
29+
registry.register(modelType: Comment6V2.self)
30+
registry.register(modelType: Blog7V2.self)
31+
registry.register(modelType: Post7V2.self)
32+
registry.register(modelType: Comment7V2.self)
33+
registry.register(modelType: Meeting8V2.self)
34+
registry.register(modelType: Attendee8V2.self)
35+
registry.register(modelType: Registration8V2.self)
36+
37+
registry.register(modelType: CustomerSecondaryIndexV2.self)
38+
registry.register(modelType: TodoWithDefaultValueV2.self)
39+
registry.register(modelType: TodoCustomTimestampV2.self)
40+
}
41+
42+
let version: String = "1"
43+
44+
}

0 commit comments

Comments
 (0)