amplify-swift/AmplifyPlugins/Analytics/AWSPinpointAnalyticsPluginT.../AWSPinpointAnalyticsPluginC...

433 lines
19 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import Amplify
import AWSPinpoint
@testable import AWSPinpointAnalyticsPlugin
@testable import AmplifyTestCommon
import XCTest
// swiftlint:disable:next type_name type_body_length
class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginTestBase {
let testName = "testName"
let testIdentityId = "identityId"
let testEmail = "testEmail"
let testPlan = "testPlan"
let testProperties: [String: AnalyticsPropertyValue] = ["keyString": "value",
"keyInt": 123,
"keyDouble": 1.2,
"keyBool": true]
let testLocation = AnalyticsUserProfile.Location(latitude: 12,
longitude: 34,
postalCode: "98122",
city: "Seattle",
region: "WA",
country: "USA")
// MARK: IdentifyUser API
/// Given: A fully populated AnalyticsUserProfile
/// When: AnalyticsPlugin.identifyUser is invoked with the user profile
/// Then: AWSPinpoint.currentEndpoint and updateEndpoint methods are called
/// and Hub Analytics.identifyUser event is dispatched with the input data
func testIdentifyUser() {
let analyticsEventReceived = expectation(description: "Analytics event was received on the hub plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
print(payload)
if payload.eventName == HubPayload.EventName.Analytics.identifyUser {
analyticsEventReceived.fulfill()
guard let data = payload.data as? (String, AnalyticsUserProfile?) else {
XCTFail("Missing data")
return
}
XCTAssertNotNil(data)
XCTAssertEqual(data.0, self.testIdentityId)
}
}
let userProfile = AnalyticsUserProfile(name: testName,
email: testEmail,
plan: testPlan,
location: testLocation,
properties: testProperties)
let expectedEndpointProfile = AWSPinpointEndpointProfile()
expectedEndpointProfile.addIdentityId(testIdentityId)
expectedEndpointProfile.addUserProfile(userProfile)
analyticsPlugin.identifyUser(testIdentityId, withProfile: userProfile)
mockPinpoint.verifyCurrentEndpointProfile()
mockPinpoint.verifyUpdate(expectedEndpointProfile)
waitForExpectations(timeout: 1)
}
/// Given: AnalyticsPlugin is disabled
/// When: AnalyticsPlugin.identifyUser is invoked
/// Then: AWSPinpoint.currentEndpointProfile and updateEndpointProfile methods are not called
func testIdentifyUserDispatchesErrorForIsEnabledFalse() {
analyticsPlugin.isEnabled = false
analyticsPlugin.identifyUser(testIdentityId, withProfile: nil)
XCTAssertEqual(mockPinpoint.currentEndpointProfileCalled, 0)
XCTAssertEqual(mockPinpoint.updateEndpointProfileCalled, 0)
}
/// Given: An expected error from AWSPinpoint.updateEndpointProfile method call
/// When: AnalyticsPlugin.identifyUser is invoked with the user profile
/// Then: AWSPinpoint.currentEndpoint and updateEndpoint methods are called
/// and Hub Analytics.identifyUser event is dispatched with an error
func testIdentifyUserDispatchesErrorForPinpointError() {
mockPinpoint.updateEndpointProfileResult = AWSTask<AnyObject>.init(error: NSError(domain: "domain",
code: 1,
userInfo: nil))
let analyticsEventReceived = expectation(description: "Analytics event was received on the hub plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
print(payload)
if payload.eventName == HubPayload.EventName.Analytics.identifyUser {
analyticsEventReceived.fulfill()
guard let error = payload.data as? AnalyticsError else {
XCTFail("Missing error")
return
}
XCTAssertNotNil(error)
}
}
let userProfile = AnalyticsUserProfile(name: testName,
email: testEmail,
plan: testPlan,
location: testLocation,
properties: testProperties)
let expectedEndpointProfile = AWSPinpointEndpointProfile()
expectedEndpointProfile.addIdentityId(testIdentityId)
expectedEndpointProfile.addUserProfile(userProfile)
analyticsPlugin.identifyUser(testIdentityId, withProfile: userProfile)
mockPinpoint.verifyCurrentEndpointProfile()
mockPinpoint.verifyUpdate(expectedEndpointProfile)
waitForExpectations(timeout: 1)
}
// MARK: RecordEvent API
/// Given: A fully populated BasicAnalyticsEvent
/// When: AnalyticsPlugin.record is invoked with the basic event
/// Then: AWSPinpoint.createEvent and record methods are called
/// and Hub Analytics.record event is dispatched with the input data
func testRecordEvent() {
let expectedPinpointEvent = AWSPinpointEvent(eventType: testName, session: AWSPinpointSession())
mockPinpoint.createEventResult = expectedPinpointEvent
expectedPinpointEvent.addProperties(testProperties)
let event = BasicAnalyticsEvent(name: testName, properties: testProperties)
let analyticsEventReceived = expectation(description: "Analytics event was received on the hub plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
print(payload)
if payload.eventName == HubPayload.EventName.Analytics.record {
analyticsEventReceived.fulfill()
guard let data = payload.data as? AnalyticsEvent else {
XCTFail("Missing data")
return
}
XCTAssertNotNil(data)
}
}
analyticsPlugin.record(event: event)
mockPinpoint.verifyCreateEvent(withEventType: testName)
mockPinpoint.verifyRecord(expectedPinpointEvent)
waitForExpectations(timeout: 1)
}
/// Given: AnalyticsPlugin is disabled
/// When: AnalyticsPlugin.record is invoked
/// Then: AWSPinpoint.record is not called
func testRecordEventDispatchesErrorForIsEnabledFalse() {
analyticsPlugin.isEnabled = false
let event = BasicAnalyticsEvent(name: testName, properties: testProperties)
analyticsPlugin.record(event: event)
XCTAssertEqual(mockPinpoint.recordCalled, 0)
}
/// Given: An expected error from AWSPinpoint.record method call
/// When: AnalyticsPlugin.record is invoked with the basic event
/// Then: AWSPinpoint.createEvent and record methods are called
/// and Hub Analytics.record event is dispatched with a error
func testRecordEventDispatchesErrorForPinpointError() {
mockPinpoint.recordResult = AWSTask<AnyObject>.init(error: NSError(domain: "domain",
code: 1,
userInfo: nil))
let expectedPinpointEvent = AWSPinpointEvent(eventType: testName, session: AWSPinpointSession())
mockPinpoint.createEventResult = expectedPinpointEvent
expectedPinpointEvent.addProperties(testProperties)
let event = BasicAnalyticsEvent(name: testName, properties: testProperties)
let analyticsEventReceived = expectation(description: "Analytics event was received on the hub plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
print(payload)
if payload.eventName == HubPayload.EventName.Analytics.record {
analyticsEventReceived.fulfill()
guard let error = payload.data as? AnalyticsError else {
XCTFail("Missing error")
return
}
XCTAssertNotNil(error)
}
}
analyticsPlugin.record(event: event)
mockPinpoint.verifyCreateEvent(withEventType: testName)
mockPinpoint.verifyRecord(expectedPinpointEvent)
waitForExpectations(timeout: 1)
}
// MARK: RecordEventWithName API
/// Given: An event with name
/// When: AnalyticsPlugin.record is invoked with the event name
/// Then: AWSPinpoint.createEvent and record methods are called
/// and Hub Analytics.record event is dispatched with the input data
func testRecordEventWithName() {
let expectedPinpointEvent = AWSPinpointEvent(eventType: testName, session: AWSPinpointSession())
mockPinpoint.createEventResult = expectedPinpointEvent
let analyticsEventReceived = expectation(description: "Analytics event was received on the hub plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
print(payload)
if payload.eventName == HubPayload.EventName.Analytics.record {
analyticsEventReceived.fulfill()
guard let data = payload.data as? AnalyticsEvent else {
XCTFail("Missing data")
return
}
XCTAssertNotNil(data)
}
}
analyticsPlugin.record(eventWithName: testName)
mockPinpoint.verifyCreateEvent(withEventType: testName)
mockPinpoint.verifyRecord(expectedPinpointEvent)
waitForExpectations(timeout: 1)
}
/// AnalyticsPlugin is disabled
/// When: AnalyticsPlugin.record is invoked
/// Then: AWSPinpoint.record is not called
func testRecordEventWithNameDispatchesErrorForIsEnabledFalse() {
analyticsPlugin.isEnabled = false
analyticsPlugin.record(eventWithName: testName)
XCTAssertEqual(mockPinpoint.recordCalled, 0)
}
/// Given: An expected error from AWSPinpoint.record method call
/// When: AnalyticsPlugin.record is invoked with the event name
/// Then: AWSPinpoint.createEvent and record methods are called
/// and Hub Analytics.record event is dispatched with a error
func testRecordEventWithNameDispatchesErrorForPinpointError() {
mockPinpoint.recordResult = AWSTask<AnyObject>.init(error: NSError(domain: "domain",
code: 1,
userInfo: nil))
let expectedPinpointEvent = AWSPinpointEvent(eventType: testName, session: AWSPinpointSession())
mockPinpoint.createEventResult = expectedPinpointEvent
let analyticsEventReceived = expectation(description: "Analytics event was received on the hub plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
print(payload)
if payload.eventName == HubPayload.EventName.Analytics.record {
analyticsEventReceived.fulfill()
guard let error = payload.data as? AnalyticsError else {
XCTFail("Missing error")
return
}
XCTAssertNotNil(error)
}
}
analyticsPlugin.record(eventWithName: testName)
mockPinpoint.verifyCreateEvent(withEventType: testName)
mockPinpoint.verifyRecord(expectedPinpointEvent)
waitForExpectations(timeout: 1)
}
// MARK: RegisterGlobalProperties API
/// Given: A dictionary of properties with different AnalyticsPropertyValue subclasses
/// When: AnalyticsPlugin.registerGlobalProperties is invoked with the properties
/// Then: The properties are set on the AnalyticsPlugin.globalProperties
func testRegisterGlobalProperties() {
analyticsPlugin.registerGlobalProperties(testProperties)
XCTAssertEqual(analyticsPlugin.globalProperties.count, testProperties.count)
XCTAssertTrue(mockPinpoint.addGlobalMetricCalled > 0)
XCTAssertTrue(mockPinpoint.addGlobalAttributeCalled > 0)
}
/// Given: An invalid property key with length greater than 50
/// When: AnalyticsPlugin.registerGlobalProperties is invoked
/// Then: PreconditionFailure is thrown for invalid key
func testRegisterGlobalPropertiesWithInvalidKeys() throws {
let keyTooLong = String(repeating: "1", count: 51)
let properties = [keyTooLong: "value"]
try XCTAssertThrowFatalError {
self.analyticsPlugin.registerGlobalProperties(properties)
}
}
// MARK: UnregisterGlobalProperties API
/// Given: A dictionary of properties with different AnalyticsPropertyValue subclasses
/// When: AnalyticsPlugin.unregisterGlobalProperties is invoked with some property keys
/// Then: The corresponding property keys are removed from the AnalyticsPlugin.globalProperties
func testUnregisterGlobalProperties() {
analyticsPlugin.globalProperties = testProperties
analyticsPlugin.unregisterGlobalProperties(Set<String>(testProperties.keys))
XCTAssertEqual(analyticsPlugin.globalProperties.count, 0)
XCTAssertTrue(mockPinpoint.removeGlobalMetricCalled > 0)
XCTAssertTrue(mockPinpoint.removeGlobalAttributeCalled > 0)
}
/// Given: globalProperties set on the AnalyticsPlugin
/// When: AnalyticsPlugin.unregisterGlobalProperties is invoked with no properties
/// Then: All of the global properties are removed
func testAllUnregisterGlobalProperties() {
analyticsPlugin.globalProperties = testProperties
analyticsPlugin.unregisterGlobalProperties(nil)
XCTAssertEqual(analyticsPlugin.globalProperties.count, 0)
XCTAssertTrue(mockPinpoint.removeGlobalMetricCalled > 0)
XCTAssertTrue(mockPinpoint.removeGlobalAttributeCalled > 0)
}
// MARK: FlushEvents API
/// When: AnalyticsPlugin.flushEvents is invoked
/// Then: AWSPinpoint.submitEvents is invoked
/// and Hub Analytics.flushEvents event is dispatched with submitted events
func testFlushEvents() {
mockPinpoint.submitEventsResult = AWSTask<AnyObject>.init(result: [AWSPinpointEvent(),
AWSPinpointEvent()] as AnyObject)
let methodWasInvokedOnPlugin = expectation(description: "method was invoked on plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
if payload.eventName == HubPayload.EventName.Analytics.flushEvents {
methodWasInvokedOnPlugin.fulfill()
guard let pinpointEvents = payload.data as? [AWSPinpointEvent] else {
XCTFail("Missing data")
return
}
XCTAssertNotNil(pinpointEvents)
}
}
analyticsPlugin.flushEvents()
mockPinpoint.verifySubmitEvents()
waitForExpectations(timeout: 1)
}
/// Given: AWSPinpoint.submitEvents returns a "No events to submit." error
/// When: AnalyticsPlugin.flushEvents is invoked
/// Then: AWSPinpoint.submitEvents is invoked
/// and Hub Analytics.flushEvents event is dispatched with an empty array of events
func testFlushEvents_noEvents() {
let error = NSError(domain: AWSPinpointAnalyticsErrorDomain,
code: AWSPinpointAnalyticsErrorType.unknown.rawValue,
userInfo: [NSLocalizedDescriptionKey: "No events to submit."])
mockPinpoint.submitEventsResult = AWSTask<AnyObject>.init(error: error)
let methodWasInvokedOnPlugin = expectation(description: "method was invoked on plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
if payload.eventName == HubPayload.EventName.Analytics.flushEvents {
methodWasInvokedOnPlugin.fulfill()
guard let pinpointEvents = payload.data as? [AWSPinpointEvent] else {
XCTFail("Missing data")
return
}
XCTAssertTrue(pinpointEvents.isEmpty)
}
}
analyticsPlugin.flushEvents()
mockPinpoint.verifySubmitEvents()
waitForExpectations(timeout: 1)
}
/// Given: AnalyticsPlugin is disabled
/// When: AnalyticsPlugin.flushEvents is invoked
/// Then: AWSPinpoint.submitEvents is not called
func testFlushEventsDispatchesErrorForIsEnableFalse() {
analyticsPlugin.isEnabled = false
analyticsPlugin.flushEvents()
XCTAssertEqual(mockPinpoint.submitEventsCalled, 0)
}
/// Given: An expected error from AWSPinpoint.submitEvents method call
/// When: AnalyticsPlugin.flushEvents is invoked
/// Then: AWSPinpoint.submitEvents is invoked
/// and Hub Analytics.flushEvents event is dispatched with error
func testFlushEventsDispatchesErrorForPinpointError() {
mockPinpoint.submitEventsResult = AWSTask<AnyObject>.init(error: NSError(domain: "domain",
code: 1,
userInfo: nil))
let methodWasInvokedOnPlugin = expectation(description: "method was invoked on plugin")
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
if payload.eventName == HubPayload.EventName.Analytics.flushEvents {
methodWasInvokedOnPlugin.fulfill()
guard let error = payload.data as? AnalyticsError else {
XCTFail("Missing error")
return
}
XCTAssertNotNil(error)
}
}
analyticsPlugin.flushEvents()
mockPinpoint.verifySubmitEvents()
waitForExpectations(timeout: 1)
}
// MARK: Enable API
func testEnable() {
analyticsPlugin.enable()
XCTAssertTrue(analyticsPlugin.isEnabled)
}
// MARK: Disable API
func testDisable() {
analyticsPlugin.disable()
XCTAssertFalse(analyticsPlugin.isEnabled)
}
} // swiftlint:disable:this file_length