Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add safety fallback when we are unable to unarchive requests #1368

Merged
merged 7 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions Branch-TestBed/Branch-SDK-Tests/BNCClassSerializationTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//
// BNCClassSerializationTests.m
// Branch-SDK-Tests
//
// Created by Ernest Cho on 3/28/24.
// Copyright © 2024 Branch, Inc. All rights reserved.
//

#import <XCTest/XCTest.h>
#import "BranchEvent.h"
#import "BranchOpenRequest.h"
#import "BranchInstallRequest.h"

@interface BranchEvent()
echo-branch marked this conversation as resolved.
Show resolved Hide resolved
// private BranchEvent methods used to build a BranchEventRequest
- (NSDictionary *)buildEventDictionary;
@end

@interface BNCClassSerializationTests : XCTestCase

@end

// Test serialization of replayable requests
@implementation BNCClassSerializationTests

- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
gdeluna-branch marked this conversation as resolved.
Show resolved Hide resolved
}

- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

// BranchEventRequest is creation is tightly coupled with the BranchEvent class
// In order to test building it, we need to expose some private methods. :(
- (BranchEventRequest *)buildBranchEventRequest {
BranchEvent *event = [BranchEvent standardEvent:BranchStandardEventPurchase];
NSURL *url = [NSURL URLWithString:@"https://api3.branch.io/v2/event/standard"];
NSDictionary *eventDictionary = [event buildEventDictionary];

BranchEventRequest *request = [[BranchEventRequest alloc] initWithServerURL:url eventDictionary:eventDictionary completion:nil];
return request;
}

- (void)testBranchEventRequestArchive {
BranchEventRequest *request = [self buildBranchEventRequest];

// archive the event
NSError *error = nil;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:request requiringSecureCoding:YES error:&error];
echo-branch marked this conversation as resolved.
Show resolved Hide resolved
XCTAssertNil(error);
XCTAssertNotNil(data);

// unarchive the event
id object = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[BranchEventRequest.class]] fromData:data error:&error];
XCTAssertNil(error);
XCTAssertNotNil(object);

// check object
XCTAssertTrue([object isKindOfClass:BranchEventRequest.class]);
BranchEventRequest *unarchivedRequest = (BranchEventRequest *)object;

XCTAssertTrue([request.serverURL.absoluteString isEqualToString:unarchivedRequest.serverURL.absoluteString]);
XCTAssertTrue(request.eventDictionary.count == unarchivedRequest.eventDictionary.count);
XCTAssertNil(unarchivedRequest.completion);
}

- (void)testBranchOpenRequestArchive {
BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:nil];
request.urlString = @"https://branch.io";

// archive the event
NSError *error = nil;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:request requiringSecureCoding:YES error:&error];
XCTAssertNil(error);
XCTAssertNotNil(data);

// unarchive the event
id object = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[BranchOpenRequest.class]] fromData:data error:&error];
XCTAssertNil(error);
XCTAssertNotNil(object);

// check object
XCTAssertTrue([object isKindOfClass:BranchOpenRequest.class]);
BranchOpenRequest *unarchivedRequest = (BranchOpenRequest *)object;

// Should the urlString be restored? Probably not.
//XCTAssertTrue([request.urlString isEqualToString:unarchivedRequest.urlString]);
XCTAssertNil(unarchivedRequest.callback);
}

- (void)testBranchInstallRequestArchive {
BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:nil];
request.urlString = @"https://branch.io";

// archive the event
NSError *error = nil;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:request requiringSecureCoding:YES error:&error];
XCTAssertNil(error);
XCTAssertNotNil(data);

// unarchive the event
id object = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[BranchInstallRequest.class]] fromData:data error:&error];
XCTAssertNil(error);
XCTAssertNotNil(object);

// check object
XCTAssertTrue([object isKindOfClass:BranchInstallRequest.class]);
BranchInstallRequest *unarchivedRequest = (BranchInstallRequest *)object;

// Should the urlString be restored? Probably not.
//XCTAssertTrue([request.urlString isEqualToString:unarchivedRequest.urlString]);
XCTAssertNil(unarchivedRequest.callback);
XCTAssertTrue([@"install" isEqualToString:[unarchivedRequest getActionName]]);
}

@end
4 changes: 4 additions & 0 deletions Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
5F644C482B7AA811000DCD78 /* BNCCallbackMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F644BB72B7AA811000DCD78 /* BNCCallbackMap.m */; };
5F644C492B7AA811000DCD78 /* BNCEventUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F644BB82B7AA811000DCD78 /* BNCEventUtils.m */; };
5F67F48E228F535500067429 /* BNCEncodingUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F67F48D228F535500067429 /* BNCEncodingUtilsTests.m */; };
5F6D86D92BB5E9650068B536 /* BNCClassSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F6D86D82BB5E9650068B536 /* BNCClassSerializationTests.m */; };
5F83B9ED2433BAAA0054A022 /* BNCServerInterface.Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16837E2098C901008819E3 /* BNCServerInterface.Test.m */; };
5F86501A2B76DA3200364BDE /* NSMutableDictionaryBranchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F8650192B76DA3200364BDE /* NSMutableDictionaryBranchTests.m */; };
5F892EC5236116CD0023AEC1 /* NSErrorBranchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F892EC4236116CC0023AEC1 /* NSErrorBranchTests.m */; };
Expand Down Expand Up @@ -496,6 +497,7 @@
5F644BB72B7AA811000DCD78 /* BNCCallbackMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCCallbackMap.m; sourceTree = "<group>"; };
5F644BB82B7AA811000DCD78 /* BNCEventUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCEventUtils.m; sourceTree = "<group>"; };
5F67F48D228F535500067429 /* BNCEncodingUtilsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BNCEncodingUtilsTests.m; sourceTree = "<group>"; };
5F6D86D82BB5E9650068B536 /* BNCClassSerializationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BNCClassSerializationTests.m; sourceTree = "<group>"; };
5F73FC8023314697000EBD32 /* BNCJSONUtilityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BNCJSONUtilityTests.m; sourceTree = "<group>"; };
5F8650192B76DA3200364BDE /* NSMutableDictionaryBranchTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSMutableDictionaryBranchTests.m; sourceTree = "<group>"; };
5F892EC4236116CC0023AEC1 /* NSErrorBranchTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSErrorBranchTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -681,6 +683,7 @@
5F892EC4236116CC0023AEC1 /* NSErrorBranchTests.m */,
5F8650192B76DA3200364BDE /* NSMutableDictionaryBranchTests.m */,
4D16839E2098C901008819E3 /* NSStringBranchTests.m */,
5F6D86D82BB5E9650068B536 /* BNCClassSerializationTests.m */,
);
path = "Branch-SDK-Tests";
sourceTree = "<group>";
Expand Down Expand Up @@ -1409,6 +1412,7 @@
5F83B9ED2433BAAA0054A022 /* BNCServerInterface.Test.m in Sources */,
5F205D0823186AF700C776D1 /* BNCUserAgentCollectorTests.m in Sources */,
5FCF7EAD29DC96A7008D629E /* BNCURLFilterSkiplistUpgradeTests.m in Sources */,
5F6D86D92BB5E9650068B536 /* BNCClassSerializationTests.m in Sources */,
E7A728BD2AA9A112009343B7 /* BNCAPIServerTest.m in Sources */,
4D1683C12098C902008819E3 /* BNCApplicationTests.m in Sources */,
4D1683B92098C902008819E3 /* BNCSystemObserverTests.m in Sources */,
Expand Down
18 changes: 16 additions & 2 deletions Sources/BranchSDK/BNCServerRequestQueue.m
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,19 @@ - (void)retrieve {
}
}

// It's been reported that unarchive can fail in some situations. In that case, remove the queued requests file.
- (void)removeSaveFile {
NSURL *fileURL = [BNCServerRequestQueue URLForQueueFile];
if (fileURL) {
NSError *error;
[NSFileManager.defaultManager removeItemAtURL:fileURL error:&error];

if (error) {
[[BranchLogger shared] logError:@"Failed to remove archived queue" error:error];
gdeluna-branch marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

- (NSMutableArray<BNCServerRequest *> *)unarchiveQueueFromData:(NSData *)data {
NSMutableArray<BNCServerRequest *> *queue = [NSMutableArray new];

Expand Down Expand Up @@ -317,7 +330,8 @@ - (id)unarchiveObjectFromData:(NSData *)data {
id object = [NSKeyedUnarchiver unarchivedObjectOfClasses:[BNCServerRequestQueue encodableClasses] fromData:data error:&error];

if (error) {
[[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Failed to unarchive: %@", error]];
[[BranchLogger shared] logError:@"Failed to unarchive" error:error];
[self removeSaveFile];
}

return object;
Expand All @@ -331,7 +345,7 @@ - (id)unarchiveObjectFromData:(NSData *)data {
NSArray *tmp = @[
[BranchOpenRequest class],
[BranchInstallRequest class],
[BranchEventRequest class],
[BranchEventRequest class]
];
requestClasses = [NSSet setWithArray:tmp];
});
Expand Down
7 changes: 5 additions & 2 deletions Sources/BranchSDK/BranchEvent.m
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,11 @@ - (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) return self;

self.serverURL = [decoder decodeObjectOfClass:NSString.class forKey:@"serverURL"];
self.eventDictionary = [decoder decodeObjectOfClass:NSDictionary.class forKey:@"eventDictionary"];
echo-branch marked this conversation as resolved.
Show resolved Hide resolved
self.serverURL = [decoder decodeObjectOfClass:NSURL.class forKey:@"serverURL"];
echo-branch marked this conversation as resolved.
Show resolved Hide resolved

NSSet *classes = [NSSet setWithArray:@[NSDictionary.class, NSArray.class, NSString.class, NSNumber.class]];
self.eventDictionary = [decoder decodeObjectOfClasses:classes forKey:@"eventDictionary"];

return self;
}

Expand Down
Loading