Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ For each release, **Core** (main SDK) changes are listed first, followed by **Ki

## [Unreleased]

### Core

#### Fixed

- `MPRokt.selectPlacements` and `MPRokt.selectShoppableAds` now deliver a `RoktPlacementFailure` event to the caller's `onEvent` handler when the Rokt kit configuration is unavailable. Previously the call was dropped with only a log message, leaving callers waiting on a callback that never arrived. ([#814](https://github.com/mParticle/mparticle-apple-sdk/pull/814))

### Kits

#### Rokt
Expand Down
62 changes: 62 additions & 0 deletions UnitTests/ObjCTests/MPRoktTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,43 @@ - (void)testSelectPlacementsSimpleWithNilMapping {
OCMVerifyAll((id)self.mockContainer);
}

- (void)testSelectPlacementsWithNilMappingInvokesOnEventWithPlacementFailure {
[[[self.mockRokt stub] andReturn:nil] getRoktPlacementAttributesMapping];
MParticle *instance = [MParticle sharedInstance];
self.mockInstance = OCMPartialMock(instance);
self.mockContainer = OCMClassMock([MPKitContainer_PRIVATE class]);
[[[self.mockInstance stub] andReturn:self.mockContainer] kitContainer_PRIVATE];
[[[self.mockInstance stub] andReturn:self.mockInstance] sharedInstance];

NSString *identifier = @"testView";
XCTestExpectation *expectation = [self expectationWithDescription:@"onEvent called"];
__block RoktEvent *receivedEvent = nil;

[self.rokt selectPlacements:identifier
attributes:@{@"f.name": @"Brandon"}
embeddedViews:nil
config:nil
onEvent:^(RoktEvent * _Nonnull event) {
receivedEvent = event;
[expectation fulfill];
}];

[self waitForExpectationsWithTimeout:0.2 handler:nil];
XCTAssertTrue([receivedEvent isKindOfClass:[RoktPlacementFailure class]]);
XCTAssertEqualObjects(((RoktPlacementFailure *)receivedEvent).identifier, identifier);
}

- (void)testSelectPlacementsWithNilMappingAndNilOnEventDoesNotCrash {
[[[self.mockRokt stub] andReturn:nil] getRoktPlacementAttributesMapping];
MParticle *instance = [MParticle sharedInstance];
self.mockInstance = OCMPartialMock(instance);
self.mockContainer = OCMClassMock([MPKitContainer_PRIVATE class]);
[[[self.mockInstance stub] andReturn:self.mockContainer] kitContainer_PRIVATE];
[[[self.mockInstance stub] andReturn:self.mockInstance] sharedInstance];

XCTAssertNoThrow([self.rokt selectPlacements:@"testView" attributes:@{@"f.name": @"Brandon"}]);
}

- (void)testGetRoktPlacementAttributesMapping {
MParticle *instance = [MParticle sharedInstance];
self.mockInstance = OCMPartialMock(instance);
Expand Down Expand Up @@ -1027,6 +1064,31 @@ - (void)testSelectShoppableAdsWithNilMappingDoesNotForward {
OCMVerifyAll((id)self.mockContainer);
}

- (void)testSelectShoppableAdsWithNilMappingInvokesOnEventWithPlacementFailure {
[[[self.mockRokt stub] andReturn:nil] getRoktPlacementAttributesMapping];
MParticle *instance = [MParticle sharedInstance];
self.mockInstance = OCMPartialMock(instance);
self.mockContainer = OCMClassMock([MPKitContainer_PRIVATE class]);
[[[self.mockInstance stub] andReturn:self.mockContainer] kitContainer_PRIVATE];
[[[self.mockInstance stub] andReturn:self.mockInstance] sharedInstance];

NSString *identifier = @"shoppableView";
XCTestExpectation *expectation = [self expectationWithDescription:@"onEvent called"];
__block RoktEvent *receivedEvent = nil;

[self.rokt selectShoppableAds:identifier
attributes:@{@"f.name": @"Brandon"}
config:nil
onEvent:^(RoktEvent * _Nonnull event) {
receivedEvent = event;
[expectation fulfill];
}];

[self waitForExpectationsWithTimeout:0.2 handler:nil];
XCTAssertTrue([receivedEvent isKindOfClass:[RoktPlacementFailure class]]);
XCTAssertEqualObjects(((RoktPlacementFailure *)receivedEvent).identifier, identifier);
}

- (void)testSelectShoppableAdsInvokesConfirmUser {
[[[self.mockRokt stub] andReturn:@[]] getRoktPlacementAttributesMapping];
MParticle *instance = [MParticle sharedInstance];
Expand Down
18 changes: 18 additions & 0 deletions mParticle-Apple-SDK/MPRokt.m
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ - (void)selectPlacements:(NSString *)identifier
});
} else {
MPILogWarning(@"MPRokt selectPlacements not performed - Rokt Kit not configured. Check with your Rokt representative to ensure the kit is enabled.");
[self notifyPlacementFailure:identifier onEvent:onEvent];
Comment thread
jamesnrokt marked this conversation as resolved.
}
}];
}
Expand Down Expand Up @@ -383,6 +384,7 @@ - (void)selectShoppableAds:(NSString * _Nonnull)identifier
});
} else {
MPILogWarning(@"MPRokt selectShoppableAds not performed - Rokt Kit not configured. Check with your Rokt representative to ensure the kit is enabled.");
[self notifyPlacementFailure:identifier onEvent:onEvent];
}
}];
}
Expand Down Expand Up @@ -431,6 +433,22 @@ - (BOOL)handleURLCallback:(NSURL * _Nonnull)url {

#pragma mark - Private Helper Methods

/// Delivers a \c RoktPlacementFailure to the caller so a placement request that cannot be served never
/// completes silently. Dispatched to the main queue because callers drive UI from this handler.
/// - Parameters:
/// - identifier: The placement identifier the caller requested
/// - onEvent: The caller's event handler; nothing is delivered when it is nil
- (void)notifyPlacementFailure:(NSString * _Nullable)identifier
onEvent:(void (^ _Nullable)(RoktEvent * _Nonnull))onEvent {
if (!onEvent) {
return;
}

dispatch_async(dispatch_get_main_queue(), ^{
onEvent([[RoktPlacementFailure alloc] initWithIdentifier:identifier]);
});
}

/// Applies dashboard placement attribute key mapping, then sets each non-sandbox key on the user.
/// @return Mutable dictionary after remapping (empty when \p attributes is nil).
- (NSMutableDictionary<NSString *, NSString *> *)mapPlacementAttributes:(NSDictionary<NSString *, NSString *> * _Nullable)attributes
Expand Down
Loading