Skip to content

Commit

Permalink
Refactoring and tests for app group message storage
Browse files Browse the repository at this point in the history
  • Loading branch information
kas-kad committed May 30, 2017
1 parent 7524d01 commit 62a9a71
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 57 deletions.
20 changes: 11 additions & 9 deletions Example/MobileMessagingExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

/* Begin PBXBuildFile section */
2499E18FB6EBAD6C8F7A7620 /* Pods_MobileMessagingExample_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F5E69FCAC421EB2E25ED816 /* Pods_MobileMessagingExample_Tests.framework */; };
5000030C1CCB7B2F00C91479 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
5000030D1CCB7B2F00C91479 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
500003101CCB7B3C00C91479 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
500003111CCB7B3C00C91479 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
5000030C1CCB7B2F00C91479 /* (null) in Resources */ = {isa = PBXBuildFile; };
5000030D1CCB7B2F00C91479 /* (null) in Resources */ = {isa = PBXBuildFile; };
500003101CCB7B3C00C91479 /* (null) in Resources */ = {isa = PBXBuildFile; };
500003111CCB7B3C00C91479 /* (null) in Resources */ = {isa = PBXBuildFile; };
502129431CEEF450007CEF8E /* MessagesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502129421CEEF450007CEF8E /* MessagesManager.swift */; };
5087EDA71CEEF82500B85546 /* MessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5087EDA61CEEF82500B85546 /* MessageCell.swift */; };
5087EDB01CEF067100B85546 /* InfoTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5087EDAC1CEF067100B85546 /* InfoTableViewController.swift */; };
Expand Down Expand Up @@ -560,14 +560,14 @@
buildActionMask = 2147483647;
files = (
A0DB0FBD1E2F8FC0005F5979 /* mocks in Resources */,
500003111CCB7B3C00C91479 /* BuildFile in Resources */,
500003111CCB7B3C00C91479 /* (null) in Resources */,
50B8C10D1CAD3362000FB79A /* Images.xcassets in Resources */,
500003101CCB7B3C00C91479 /* BuildFile in Resources */,
500003101CCB7B3C00C91479 /* (null) in Resources */,
A0953C291CAD1C660076488D /* Main.storyboard in Resources */,
8EC5E6061CEB4A36008D53A3 /* MobileMessagingExample_Tests_Device-Info.plist in Resources */,
5000030D1CCB7B2F00C91479 /* BuildFile in Resources */,
5000030D1CCB7B2F00C91479 /* (null) in Resources */,
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */,
5000030C1CCB7B2F00C91479 /* BuildFile in Resources */,
5000030C1CCB7B2F00C91479 /* (null) in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1030,6 +1030,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = MobileMessagingExample/MobileMessagingExample.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1460136653767;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = T6U248P7YM;
Expand All @@ -1048,7 +1049,7 @@
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\"";
PRODUCT_BUNDLE_IDENTIFIER = com.infobip.mobilemessaging.example;
PRODUCT_NAME = MobileMessagingExample;
PROVISIONING_PROFILE = "4aaea8b9-b39c-4690-9571-86af1428dcaf";
PROVISIONING_PROFILE = "e8f44623-f9be-445a-bfdc-8f5df6053ef5";
PROVISIONING_PROFILE_SPECIFIER = "Mobile Messaging Example - Development";
SWIFT_VERSION = 3.0.1;
};
Expand Down Expand Up @@ -1193,6 +1194,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_ENTITLEMENTS = NotificationServiceExtension/NotificationServiceExtension.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = T6U248P7YM;
FRAMEWORK_SEARCH_PATHS = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ class NotificationService: UNNotificationServiceExtension {
}
}
}

91 changes: 85 additions & 6 deletions Example/Tests/MobileMessagingTests/MessageStorageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import XCTest
import UserNotifications
@testable import MobileMessaging

class MockMessageStorage: NSObject, MessageStorage {
Expand All @@ -18,21 +19,21 @@ class MockMessageStorage: NSObject, MessageStorage {
var queue: DispatchQueue {
return DispatchQueue.main
}
var mtMessages = [String]()
var moMessages = [String]()
var mtMessages = [MTMessage]()
var moMessages = [MOMessage]()
func insert(incoming messages: [MTMessage]) {
messages.forEach { (message) in
self.mtMessages.append(message.messageId)
self.mtMessages.append(message)
}
}
func insert(outgoing messages: [MOMessage]) {
messages.forEach { (message) in
self.moMessages.append(message.messageId)
self.moMessages.append(message)
}
}
func findMessage(withId messageId: MessageId) -> BaseMessage? {
if let idx = moMessages.index(where: { $0 == messageId }) {
return BaseMessage(messageId: moMessages[idx], direction: .MO, originalPayload: ["messageId": moMessages[idx]], createdDate: Date())
if let idx = moMessages.index(where: { $0.messageId == messageId }) {
return BaseMessage(messageId: moMessages[idx].messageId, direction: .MO, originalPayload: ["messageId": moMessages[idx].messageId], createdDate: Date())
} else {
return nil
}
Expand Down Expand Up @@ -273,8 +274,86 @@ class MessageStorageTests: MMTestCase {
self.waitForExpectations(timeout: 60, handler: nil)
}

@available(iOS 10.0, *)
func testThatMessageStorageIsBeingPopulatedWithNotificationExtensionHandledMessages() {
guard #available(iOS 10.0, *) else {
return
}

cleanUpAndStop()

let content = UNMutableNotificationContent()
content.userInfo = [
"messageId": "mid1",
"aps": ["alert": ["title": "msg_title", "body": "msg_body"], "badge": 6, "sound": "default", "mutable-content": 1]
]
let request = UNNotificationRequest(identifier: "id1", content: content, trigger: nil)
let contentHandler: (UNNotificationContent) -> Void = { content in

}
let sharedStorageMock = SharedMessageStorageMock(applicationCode: "appCode", appGroupId: "groupId")!


MobileMessagingNotificationServiceExtension.startWithApplicationCode("appCode", appGroupId: "groupId")
MobileMessagingNotificationServiceExtension.sharedInstance?.deliveryReporter = SuccessfullDeliveryReporterMock(applicationCode: "appCode", baseUrl: "groupId")
MobileMessagingNotificationServiceExtension.sharedInstance?.sharedNotificationExtensionStorage = sharedStorageMock
MobileMessagingNotificationServiceExtension.didReceive(request, withContentHandler: contentHandler)

XCTAssertEqual(sharedStorageMock.retrieveMessages().count, 1)

let mockMessageStorage = MockMessageStorage()
XCTAssertEqual(mockMessageStorage.mtMessages.count, 0)

let mm = mockedMMInstanceWithApplicationCode(MMTestConstants.kTestCorrectApplicationCode)!.withMessageStorage(mockMessageStorage)
mm.sharedNotificationExtensionStorage = sharedStorageMock
mm.start()

weak var expectation = self.expectation(description: "")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1)) {
mm.cleanUpAndStop()
XCTAssertEqual(sharedStorageMock.retrieveMessages().count, 0)

expectation?.fulfill()
}
self.waitForExpectations(timeout: 60, handler: { _ in
XCTAssertEqual(mockMessageStorage.mtMessages.count, 1)
})
}

override func tearDown() {
self.defaultMessageStorage?.coreDataStorage?.drop()
super.tearDown()
}
}

class SuccessfullDeliveryReporterMock: DeliveryReporting {
required init(applicationCode: String, baseUrl: String) {

}

func report(messageIds: [String], completion: @escaping (Result<DeliveryReportResponse>) -> Void) {
completion(Result.Success(DeliveryReportResponse.init()))
}
}

class SharedMessageStorageMock: AppGroupMessageStorage {
var inMemStorage = [String: Any]()
let applicationCode: String
required init?(applicationCode: String, appGroupId: String) {
self.applicationCode = applicationCode
}

func save(message: MTMessage, isDelivered: Bool) {
var msgs = (inMemStorage[applicationCode] as? [MTMessage]) ?? [MTMessage]()
msgs.append(message)
inMemStorage[applicationCode] = msgs
}

func retrieveMessages() -> [MTMessage] {
return (inMemStorage[applicationCode] as? [MTMessage]) ?? [MTMessage]()
}

func cleanupMessages() {
inMemStorage[applicationCode] = nil
}
}
1 change: 0 additions & 1 deletion Example/Tests/MobileMessagingTests/RegistrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ final class RegistrationTests: MMTestCase {
self.waitForExpectations(timeout: 60) { _ in
let ctx = (self.mobileMessagingInstance.internalStorage.mainThreadManagedObjectContext!)
if let installation = InstallationManagedObject.MM_findFirstInContext(ctx) {

XCTAssertTrue(installation.dirtyAttributesSet.contains(AttributesSet.deviceToken), "Dirty flag may be false only after success registration")
XCTAssertEqual(installation.internalUserId, nil, "Internal id must be nil, server denied the application code")
XCTAssertEqual(installation.deviceToken, "someToken".mm_toHexademicalString, "Device token must be mocked properly. (current is \(String(describing: installation.deviceToken)))")
Expand Down
8 changes: 6 additions & 2 deletions Pod/Classes/Core/MobileMessaging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ public final class MobileMessaging: NSObject {
return self
}

@available(iOS 10.0, *)
public func withAppGroupId(_ appGroupId: String) -> MobileMessaging {
self.appGroupId = appGroupId
self.sharedNotificationExtensionStorage = DefaultSharedDataStorage(applicationCode: applicationCode, appGroupId: appGroupId)
return self
}

Expand Down Expand Up @@ -280,7 +282,7 @@ public final class MobileMessaging: NSObject {
func cleanUpAndStop(_ clearKeychain: Bool = true) {
MMLogDebug("Cleaning up MobileMessaging service...")
if #available(iOS 10.0, *) {
UserDefaults.cleanupNotificationServiceExtensionContainer(forApplicationCode: applicationCode)
sharedNotificationExtensionStorage?.cleanupMessages()
}
MMCoreDataStorage.dropStorages(internalStorage: internalStorage, messageStorage: messageStorage as? MMDefaultMessageStorage)
if (clearKeychain) {
Expand Down Expand Up @@ -418,9 +420,11 @@ public final class MobileMessaging: NSObject {
lazy var application: MMApplication! = UIApplication.shared
lazy var reachabilityManager: ReachabilityManagerProtocol! = MMNetworkReachabilityManager.sharedInstance
lazy var keychain: MMKeychain! = MMKeychain()
var appGroupId: String?

static var date: MMDate = MMDate() // testability

var appGroupId: String?
var sharedNotificationExtensionStorage: AppGroupMessageStorage?
}

extension UIApplication: MMApplication {}
Expand Down
7 changes: 5 additions & 2 deletions Pod/Classes/Core/MobileMessagingAppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@ open class MobileMessagingAppDelegate: UIResponder, UIApplicationDelegate {
public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
if !isTestingProcessRunning {
var session = MobileMessaging.withApplicationCode(applicationCode, notificationType: userNotificationType)
if let appGroupId = appGroupId {
session = session?.withAppGroupId(appGroupId)

if #available(iOS 10.0, *) {
if let appGroupId = appGroupId {
session = session?.withAppGroupId(appGroupId)
}
}
session?.start()
}
Expand Down
11 changes: 1 addition & 10 deletions Pod/Classes/Core/Operations/MMMessageHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,10 @@ final class MMMessageHandler: MobileMessagingService {

@available(iOS 10.0, *)
func handleStorageFromNotificationServiceExtensionGroupContainer() {
guard let ud = UserDefaults.notificationServiceExtensionContainer, let mm = MobileMessaging.sharedInstance, let messageDataDicts = ud.array(forKey: mm.applicationCode) as? [StringKeyPayload] else
guard let mm = MobileMessaging.sharedInstance, let messages = mm.sharedNotificationExtensionStorage?.retrieveMessages() else
{
return
}
let messages = messageDataDicts.flatMap({ messageDataTuple -> MTMessage? in
guard let payload = messageDataTuple["p"] as? StringKeyPayload, let date = messageDataTuple["d"] as? Date, let dlrSent = messageDataTuple["dlr"] as? Bool else {
return nil
}
let newMessage = MTMessage(payload: payload, createdDate: date)
newMessage?.isDeliveryReportSent = dlrSent
return newMessage
})
ud.removeObject(forKey: mm.applicationCode)
handleMTMessages(messages, notificationTapped: false, completion: nil)
}

Expand Down
15 changes: 0 additions & 15 deletions Pod/Classes/MessageStorage/StorageProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,6 @@ public typealias FetchResultBlock = ([BaseMessage]?) -> Void
func update(messageSentStatus status: MOMessageSentStatus, for messageId: MessageId)
}

extension UserDefaults {
@available(iOS 10.0, *)
class var notificationServiceExtensionContainer: UserDefaults? {
guard let appGroupId = MobileMessagingNotificationServiceExtension.sharedInstance?.appGroupId ?? MobileMessaging.sharedInstance?.appGroupId else {
return nil
}
return UserDefaults.init(suiteName: appGroupId)
}

@available(iOS 10.0, *)
class func cleanupNotificationServiceExtensionContainer(forApplicationCode: String) {
UserDefaults.notificationServiceExtensionContainer?.removeObject(forKey: forApplicationCode)
}
}

/// The adapter dispatches all adaptee method calls into the adaptee's queue,
/// and checks for existing messages to avoid duplications, that's all.
class MMMessageStorageQueuedAdapter: MessageStorage {
Expand Down
Loading

0 comments on commit 62a9a71

Please sign in to comment.