/* * Copyright 2017 Google * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import #import #import "FirebaseInAppMessaging/Sources/Private/Data/FIRIAMMessageDefinition.h" #import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMMsgFetcherUsingRestful.h" #import "FirebaseInAppMessaging/Sources/Private/Runtime/FIRIAMFetchFlow.h" static NSString *serverHost = @"myhost"; static NSString *projectNumber = @"My-project-number"; static NSString *appId = @"My-app-id"; static NSString *apiKey = @"Api-key"; @interface FIRIAMMsgFetcherUsingRestfulTests : XCTestCase @property NSURLSession *mockedNSURLSession; @property FIRIAMClientInfoFetcher *mockclientInfoFetcher; @property FIRIAMMsgFetcherUsingRestful *fetcher; @end @implementation FIRIAMMsgFetcherUsingRestfulTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the // class. self.mockedNSURLSession = OCMClassMock([NSURLSession class]); self.mockclientInfoFetcher = OCMClassMock([FIRIAMClientInfoFetcher class]); FIRIAMFetchResponseParser *parser = [[FIRIAMFetchResponseParser alloc] initWithTimeFetcher:[[FIRIAMTimerWithNSDate alloc] init]]; self.fetcher = [[FIRIAMMsgFetcherUsingRestful alloc] initWithHost:serverHost HTTPProtocol:@"https" project:projectNumber firebaseApp:appId APIKey:apiKey fetchStorage:[[FIRIAMServerMsgFetchStorage alloc] init] instanceIDFetcher:_mockclientInfoFetcher usingURLSession:_mockedNSURLSession responseParser:parser]; } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the // class. [super tearDown]; } - (void)testRequestConstructionWithoutImpressionData { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. __block NSURLRequest *capturedNSURLRequest; OCMStub([self.mockedNSURLSession dataTaskWithRequest:[OCMArg checkWithBlock:^BOOL(NSURLRequest *request) { capturedNSURLRequest = request; return YES; }] completionHandler:[OCMArg any] // second parameter is the callback which we don't care in // this unit testing ]); NSString *FIDValue = @"my FID"; NSString *FISToken = @"my FIS token"; OCMStub([self.mockclientInfoFetcher fetchFirebaseInstallationDataWithProjectNumber:[OCMArg any] withCompletion:([OCMArg invokeBlockWithArgs:FIDValue, FISToken, [NSNull null], nil])]); NSString *osVersion = @"OS Version"; OCMStub([self.mockclientInfoFetcher getOSVersion]).andReturn(osVersion); NSString *appVersion = @"App Version"; OCMStub([self.mockclientInfoFetcher getAppVersion]).andReturn(appVersion); NSString *deviceLanguage = @"Language"; OCMStub([self.mockclientInfoFetcher getDeviceLanguageCode]).andReturn(deviceLanguage); NSString *timezone = @"time zone"; OCMStub([self.mockclientInfoFetcher getTimezone]).andReturn(timezone); [self.fetcher fetchMessagesWithImpressionList:@[] withCompletion:^(NSArray *_Nullable messages, NSNumber *nextFetchWaitTime, NSInteger discardCount, NSError *_Nullable error){ // blank on purpose: it won't get triggered }]; // verify that the dataTaskWithRequest:completionHandler: is triggered for NSURLSession object OCMVerify([self.mockedNSURLSession dataTaskWithRequest:[OCMArg any] completionHandler:[OCMArg any]]); XCTAssertEqualObjects(@"POST", capturedNSURLRequest.HTTPMethod); NSDictionary *requestHeaders = capturedNSURLRequest.allHTTPHeaderFields; // verifying some request header fields XCTAssertEqualObjects([NSBundle mainBundle].bundleIdentifier, requestHeaders[@"X-Ios-Bundle-Identifier"]); XCTAssertEqualObjects(@"application/json", requestHeaders[@"Content-Type"]); XCTAssertEqualObjects(@"application/json", requestHeaders[@"Accept"]); // verify that the request contains the desired api key NSString *s = [NSString stringWithFormat:@"key=%@", apiKey]; XCTAssertTrue([capturedNSURLRequest.URL.absoluteString containsString:s]); XCTAssertTrue([capturedNSURLRequest.URL.absoluteString containsString:projectNumber]); // verify that we the request body contains desired iid data NSError *errorJson = nil; NSDictionary *requestBodyDict = [NSJSONSerialization JSONObjectWithData:capturedNSURLRequest.HTTPBody options:kNilOptions error:&errorJson]; XCTAssertEqualObjects(appId, requestBodyDict[@"requesting_client_app"][@"gmp_app_id"]); XCTAssertEqualObjects(FIDValue, requestBodyDict[@"requesting_client_app"][@"app_instance_id"]); XCTAssertEqualObjects(FISToken, requestBodyDict[@"requesting_client_app"][@"app_instance_id_token"]); XCTAssertEqualObjects(osVersion, requestBodyDict[@"client_signals"][@"platform_version"]); XCTAssertEqualObjects(appVersion, requestBodyDict[@"client_signals"][@"app_version"]); XCTAssertEqualObjects(deviceLanguage, requestBodyDict[@"client_signals"][@"language_code"]); XCTAssertEqualObjects(timezone, requestBodyDict[@"client_signals"][@"time_zone"]); } - (void)testRequestConstructionWithImpressionData { __block NSURLRequest *capturedNSURLRequest; OCMStub([self.mockedNSURLSession dataTaskWithRequest:[OCMArg checkWithBlock:^BOOL(NSURLRequest *request) { capturedNSURLRequest = request; return YES; }] completionHandler:[OCMArg any] // second parameter is the callback which we don't care in // this unit testing ]); NSString *FIDValue = @"my FID"; NSString *FISToken = @"my FIS token"; OCMStub([self.mockclientInfoFetcher fetchFirebaseInstallationDataWithProjectNumber:[OCMArg any] withCompletion:([OCMArg invokeBlockWithArgs:FIDValue, FISToken, [NSNull null], nil])]); // this is to test the case that only partial client signal fields are available NSString *osVersion = @"OS Version"; OCMStub([self.mockclientInfoFetcher getOSVersion]).andReturn(osVersion); NSString *appVersion = @"App Version"; OCMStub([self.mockclientInfoFetcher getAppVersion]).andReturn(appVersion); long impression1Timestamp = 12345; FIRIAMImpressionRecord *impression1 = [[FIRIAMImpressionRecord alloc] initWithMessageID:@"impression 1" impressionTimeInSeconds:impression1Timestamp]; long impression2Timestamp = 45678; FIRIAMImpressionRecord *impression2 = [[FIRIAMImpressionRecord alloc] initWithMessageID:@"impression 2" impressionTimeInSeconds:impression2Timestamp]; [self.fetcher fetchMessagesWithImpressionList:@[ impression1, impression2 ] withCompletion:^(NSArray *_Nullable messages, NSNumber *_Nullable nextFetchWaitTime, NSInteger discardCount, NSError *_Nullable error){ // blank on purpose: it won't get triggered }]; // verify that the captured nsurl request has expected body NSError *errorJson = nil; NSDictionary *requestBodyDict = [NSJSONSerialization JSONObjectWithData:capturedNSURLRequest.HTTPBody options:kNilOptions error:&errorJson]; XCTAssertEqualObjects(impression1.messageID, requestBodyDict[@"already_seen_campaigns"][0][@"campaign_id"]); XCTAssertEqualWithAccuracy( impression1Timestamp * 1000, ((NSNumber *)requestBodyDict[@"already_seen_campaigns"][0][@"impression_timestamp_millis"]) .longValue, 0.1); XCTAssertEqualObjects(impression2.messageID, requestBodyDict[@"already_seen_campaigns"][1][@"campaign_id"]); XCTAssertEqualWithAccuracy( impression2Timestamp * 1000, ((NSNumber *)requestBodyDict[@"already_seen_campaigns"][1][@"impression_timestamp_millis"]) .longValue, 0.1); XCTAssertEqualObjects(osVersion, requestBodyDict[@"client_signals"][@"platform_version"]); XCTAssertEqualObjects(appVersion, requestBodyDict[@"client_signals"][@"app_version"]); // not expexting language siganl since it's not mocked on mockclientInfoFetcher XCTAssertNil(requestBodyDict[@"client_signals"][@"language_code"]); } - (void)testBailoutOnFIDError { // in this test, the attempt to fetch iid data failed and as a result, we expect the whole // fetch operation attempt to fail with that error NSError *FIDError = [[NSError alloc] initWithDomain:@"Error Domain" code:100 userInfo:nil]; OCMStub([self.mockclientInfoFetcher fetchFirebaseInstallationDataWithProjectNumber:[OCMArg any] withCompletion:([OCMArg invokeBlockWithArgs:[NSNull null], [NSNull null], FIDError, nil])]); XCTestExpectation *expectation = [self expectationWithDescription:@"fetch callback block triggered."]; [self.fetcher fetchMessagesWithImpressionList:@[] withCompletion:^(NSArray *_Nullable messages, NSNumber *_Nullable nextFetchWaitTime, NSInteger discardCount, NSError *_Nullable error) { // expecting triggering the completion callback with error XCTAssertNil(messages); XCTAssertEqualObjects(FIDError, error); [expectation fulfill]; }]; [self waitForExpectationsWithTimeout:5.0 handler:nil]; } @end