Skip to content

Commit 980a0d5

Browse files
authored
Merge pull request #1368 from BranchMetrics/SDK-2263
Add safety fallback when we are unable to unarchive requests
2 parents 1435b6b + 104c760 commit 980a0d5

File tree

5 files changed

+161
-4
lines changed

5 files changed

+161
-4
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//
2+
// BNCClassSerializationTests.m
3+
// Branch-SDK-Tests
4+
//
5+
// Created by Ernest Cho on 3/28/24.
6+
// Copyright © 2024 Branch, Inc. All rights reserved.
7+
//
8+
9+
#import <XCTest/XCTest.h>
10+
#import "BranchEvent.h"
11+
#import "BranchOpenRequest.h"
12+
#import "BranchInstallRequest.h"
13+
14+
@interface BranchEvent()
15+
// private BranchEvent methods used to build a BranchEventRequest
16+
- (NSDictionary *)buildEventDictionary;
17+
@end
18+
19+
@interface BranchOpenRequest()
20+
- (NSString *)getActionName;
21+
@end
22+
23+
@interface BNCClassSerializationTests : XCTestCase
24+
25+
@end
26+
27+
// Test serialization of replayable requests
28+
@implementation BNCClassSerializationTests
29+
30+
- (void)setUp {
31+
// Put setup code here. This method is called before the invocation of each test method in the class.
32+
}
33+
34+
- (void)tearDown {
35+
// Put teardown code here. This method is called after the invocation of each test method in the class.
36+
}
37+
38+
// BranchEventRequest is creation is tightly coupled with the BranchEvent class
39+
// In order to test building it, we need to expose some private methods. :(
40+
- (BranchEventRequest *)buildBranchEventRequest {
41+
BranchEvent *event = [BranchEvent standardEvent:BranchStandardEventPurchase];
42+
NSURL *url = [NSURL URLWithString:@"https://api3.branch.io/v2/event/standard"];
43+
NSDictionary *eventDictionary = [event buildEventDictionary];
44+
45+
BranchEventRequest *request = [[BranchEventRequest alloc] initWithServerURL:url eventDictionary:eventDictionary completion:nil];
46+
return request;
47+
}
48+
49+
- (void)testBranchEventRequestArchive {
50+
BranchEventRequest *request = [self buildBranchEventRequest];
51+
52+
// archive the event
53+
NSError *error = nil;
54+
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:request requiringSecureCoding:YES error:&error];
55+
XCTAssertNil(error);
56+
XCTAssertNotNil(data);
57+
58+
// unarchive the event
59+
id object = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[BranchEventRequest.class]] fromData:data error:&error];
60+
XCTAssertNil(error);
61+
XCTAssertNotNil(object);
62+
63+
// check object
64+
XCTAssertTrue([object isKindOfClass:BranchEventRequest.class]);
65+
BranchEventRequest *unarchivedRequest = (BranchEventRequest *)object;
66+
67+
XCTAssertTrue([request.serverURL.absoluteString isEqualToString:unarchivedRequest.serverURL.absoluteString]);
68+
XCTAssertTrue(request.eventDictionary.count == unarchivedRequest.eventDictionary.count);
69+
XCTAssertNil(unarchivedRequest.completion);
70+
}
71+
72+
- (void)testBranchOpenRequestArchive {
73+
BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:nil];
74+
request.urlString = @"https://branch.io";
75+
76+
// archive the event
77+
NSError *error = nil;
78+
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:request requiringSecureCoding:YES error:&error];
79+
XCTAssertNil(error);
80+
XCTAssertNotNil(data);
81+
82+
// unarchive the event
83+
id object = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[BranchOpenRequest.class]] fromData:data error:&error];
84+
XCTAssertNil(error);
85+
XCTAssertNotNil(object);
86+
87+
// check object
88+
XCTAssertTrue([object isKindOfClass:BranchOpenRequest.class]);
89+
BranchOpenRequest *unarchivedRequest = (BranchOpenRequest *)object;
90+
91+
XCTAssertTrue([request.urlString isEqualToString:unarchivedRequest.urlString]);
92+
XCTAssertNil(unarchivedRequest.callback);
93+
XCTAssertTrue([@"open" isEqualToString:[unarchivedRequest getActionName]]);
94+
}
95+
96+
- (void)testBranchInstallRequestArchive {
97+
BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:nil];
98+
request.urlString = @"https://branch.io";
99+
100+
// archive the event
101+
NSError *error = nil;
102+
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:request requiringSecureCoding:YES error:&error];
103+
XCTAssertNil(error);
104+
XCTAssertNotNil(data);
105+
106+
// unarchive the event
107+
id object = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[BranchInstallRequest.class]] fromData:data error:&error];
108+
XCTAssertNil(error);
109+
XCTAssertNotNil(object);
110+
111+
// check object
112+
XCTAssertTrue([object isKindOfClass:BranchInstallRequest.class]);
113+
BranchInstallRequest *unarchivedRequest = (BranchInstallRequest *)object;
114+
115+
XCTAssertTrue([request.urlString isEqualToString:unarchivedRequest.urlString]);
116+
XCTAssertNil(unarchivedRequest.callback);
117+
XCTAssertTrue([@"install" isEqualToString:[unarchivedRequest getActionName]]);
118+
}
119+
120+
@end

Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@
187187
5F644C482B7AA811000DCD78 /* BNCCallbackMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F644BB72B7AA811000DCD78 /* BNCCallbackMap.m */; };
188188
5F644C492B7AA811000DCD78 /* BNCEventUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F644BB82B7AA811000DCD78 /* BNCEventUtils.m */; };
189189
5F67F48E228F535500067429 /* BNCEncodingUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F67F48D228F535500067429 /* BNCEncodingUtilsTests.m */; };
190+
5F6D86D92BB5E9650068B536 /* BNCClassSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F6D86D82BB5E9650068B536 /* BNCClassSerializationTests.m */; };
191+
5F83B9ED2433BAAA0054A022 /* BNCServerInterface.Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16837E2098C901008819E3 /* BNCServerInterface.Test.m */; };
190192
5F86501A2B76DA3200364BDE /* NSMutableDictionaryBranchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F8650192B76DA3200364BDE /* NSMutableDictionaryBranchTests.m */; };
191193
5F892EC5236116CD0023AEC1 /* NSErrorBranchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F892EC4236116CC0023AEC1 /* NSErrorBranchTests.m */; };
192194
5F8B7B4021B5F5CD009CE0A6 /* libBranch.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 466B58381B17773000A69EDE /* libBranch.a */; };
@@ -475,6 +477,7 @@
475477
5F644BB72B7AA811000DCD78 /* BNCCallbackMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCCallbackMap.m; sourceTree = "<group>"; };
476478
5F644BB82B7AA811000DCD78 /* BNCEventUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCEventUtils.m; sourceTree = "<group>"; };
477479
5F67F48D228F535500067429 /* BNCEncodingUtilsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BNCEncodingUtilsTests.m; sourceTree = "<group>"; };
480+
5F6D86D82BB5E9650068B536 /* BNCClassSerializationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BNCClassSerializationTests.m; sourceTree = "<group>"; };
478481
5F73FC8023314697000EBD32 /* BNCJSONUtilityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BNCJSONUtilityTests.m; sourceTree = "<group>"; };
479482
5F8650192B76DA3200364BDE /* NSMutableDictionaryBranchTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSMutableDictionaryBranchTests.m; sourceTree = "<group>"; };
480483
5F892EC4236116CC0023AEC1 /* NSErrorBranchTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSErrorBranchTests.m; sourceTree = "<group>"; };
@@ -648,6 +651,7 @@
648651
5F892EC4236116CC0023AEC1 /* NSErrorBranchTests.m */,
649652
5F8650192B76DA3200364BDE /* NSMutableDictionaryBranchTests.m */,
650653
4D16839E2098C901008819E3 /* NSStringBranchTests.m */,
654+
5F6D86D82BB5E9650068B536 /* BNCClassSerializationTests.m */,
651655
);
652656
path = "Branch-SDK-Tests";
653657
sourceTree = "<group>";
@@ -1371,6 +1375,7 @@
13711375
C15CC9DE2ABCB549003CC339 /* BNCCurrencyTests.m in Sources */,
13721376
5F205D0823186AF700C776D1 /* BNCUserAgentCollectorTests.m in Sources */,
13731377
5FCF7EAD29DC96A7008D629E /* BNCURLFilterSkiplistUpgradeTests.m in Sources */,
1378+
5F6D86D92BB5E9650068B536 /* BNCClassSerializationTests.m in Sources */,
13741379
E7A728BD2AA9A112009343B7 /* BNCAPIServerTest.m in Sources */,
13751380
4D1683C12098C902008819E3 /* BNCApplicationTests.m in Sources */,
13761381
4D1683B92098C902008819E3 /* BNCSystemObserverTests.m in Sources */,

Sources/BranchSDK/BNCServerRequestQueue.m

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,19 @@ - (void)retrieve {
284284
}
285285
}
286286

287+
// It's been reported that unarchive can fail in some situations. In that case, remove the queued requests file.
288+
- (void)removeSaveFile {
289+
NSURL *fileURL = [BNCServerRequestQueue URLForQueueFile];
290+
if (fileURL) {
291+
NSError *error;
292+
[NSFileManager.defaultManager removeItemAtURL:fileURL error:&error];
293+
294+
if (error) {
295+
[[BranchLogger shared] logError:@"Failed to remove archived queue" error:error];
296+
}
297+
}
298+
}
299+
287300
- (NSMutableArray<BNCServerRequest *> *)unarchiveQueueFromData:(NSData *)data {
288301
NSMutableArray<BNCServerRequest *> *queue = [NSMutableArray new];
289302

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

319332
if (error) {
320-
[[BranchLogger shared] logWarning:@"Failed to unarchive" error:error];
333+
[[BranchLogger shared] logError:@"Failed to unarchive" error:error];
334+
[self removeSaveFile];
321335
}
322336

323337
return object;
@@ -331,7 +345,7 @@ - (id)unarchiveObjectFromData:(NSData *)data {
331345
NSArray *tmp = @[
332346
[BranchOpenRequest class],
333347
[BranchInstallRequest class],
334-
[BranchEventRequest class],
348+
[BranchEventRequest class]
335349
];
336350
requestClasses = [NSSet setWithArray:tmp];
337351
});

Sources/BranchSDK/BranchEvent.m

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,11 @@ - (instancetype)initWithCoder:(NSCoder *)decoder {
134134
self = [super initWithCoder:decoder];
135135
if (!self) return self;
136136

137-
self.serverURL = [decoder decodeObjectOfClass:NSString.class forKey:@"serverURL"];
138-
self.eventDictionary = [decoder decodeObjectOfClass:NSDictionary.class forKey:@"eventDictionary"];
137+
self.serverURL = [decoder decodeObjectOfClass:NSURL.class forKey:@"serverURL"];
138+
139+
NSSet *classes = [NSSet setWithArray:@[NSDictionary.class, NSArray.class, NSString.class, NSNumber.class]];
140+
self.eventDictionary = [decoder decodeObjectOfClasses:classes forKey:@"eventDictionary"];
141+
139142
return self;
140143
}
141144

Sources/BranchSDK/BranchOpenRequest.m

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,21 @@ - (NSString *)getActionName {
253253
return @"open";
254254
}
255255

256+
- (instancetype)initWithCoder:(NSCoder *)decoder {
257+
self = [super initWithCoder:decoder];
258+
if (!self) return self;
259+
self.urlString = [decoder decodeObjectOfClass:NSString.class forKey:@"urlString"];
260+
return self;
261+
}
262+
263+
- (void)encodeWithCoder:(NSCoder *)coder {
264+
[super encodeWithCoder:coder];
265+
[coder encodeObject:self.urlString forKey:@"urlString"];
266+
}
267+
268+
+ (BOOL)supportsSecureCoding {
269+
return YES;
270+
}
256271

257272
#pragma - Open Response Lock Handling
258273

0 commit comments

Comments
 (0)