| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 |
- // Copyright 2019 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 <Foundation/Foundation.h>
- #import <XCTest/XCTest.h>
- #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
- #if __has_include(<FBLPromises/FBLPromises.h>)
- #import <FBLPromises/FBLPromises.h>
- #else
- #import "FBLPromises.h"
- #endif
- #include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
- #include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h"
- #import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h"
- #import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
- #import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h"
- #include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
- #import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
- #import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
- #import "Crashlytics/UnitTests/Mocks/FIRCLSMockExistingReportManager.h"
- #import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h"
- #import "Crashlytics/UnitTests/Mocks/FABMockApplicationIdentifierModel.h"
- #import "Crashlytics/UnitTests/Mocks/FIRAppFake.h"
- #import "Crashlytics/UnitTests/Mocks/FIRCLSMockReportManager.h"
- #import "Crashlytics/UnitTests/Mocks/FIRCLSMockReportUploader.h"
- #import "Crashlytics/UnitTests/Mocks/FIRCLSMockSettings.h"
- #import "Crashlytics/UnitTests/Mocks/FIRCLSTempMockFileManager.h"
- #import "Crashlytics/UnitTests/Mocks/FIRMockGDTCoreTransport.h"
- #import "Crashlytics/UnitTests/Mocks/FIRMockInstallations.h"
- #define TEST_API_KEY (@"DB5C8FA65C0D43419120FB96CFDBDE0C")
- #define TEST_GOOGLE_APP_ID (@"1:632950151350:ios:d5b0d08d4f00f4b1")
- #define TEST_INSTALL_ID (@"DC352568-33A7-4830-A9D8-20EA708F1905")
- #define TEST_API_ENDPOINT (@"http://test.com")
- #define TEST_BUNDLE_ID (@"com.crashlytics.test")
- #define TEST_ANALYTICS_JSON \
- (@"{\"name\":\"some_name\",\"nested\":{\"object\":\"with_stuff\"},\"price\":100}")
- @interface FIRCLSReportManagerTests : XCTestCase
- @property(nonatomic, strong) FIRCLSMockReportManager *reportManager;
- @property(nonatomic, strong) FIRCLSMockExistingReportManager *existingReportManager;
- @property(nonatomic, strong) FIRCLSMockSettings *mockSettings;
- @property(nonatomic, strong) FIRCLSMockReportUploader *mockReportUploader;
- @property(nonatomic, strong) FIRCLSTempMockFileManager *fileManager;
- @property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter;
- @property(nonatomic, strong) FIRCLSApplicationIdentifierModel *appIDModel;
- @end
- @implementation FIRCLSReportManagerTests
- - (void)setUp {
- [super setUp];
- FIRSetLoggerLevel(FIRLoggerLevelMax);
- FIRCLSContextBaseInit();
- id fakeApp = [[FIRAppFake alloc] init];
- self.dataArbiter = [[FIRCLSDataCollectionArbiter alloc] initWithApp:fakeApp withAppInfo:@{}];
- self.fileManager = [[FIRCLSTempMockFileManager alloc] init];
- // Delete cached settings
- [self.fileManager removeItemAtPath:_fileManager.settingsFilePath];
- FIRMockInstallations *iid = [[FIRMockInstallations alloc] initWithFID:@"test_token"];
- FIRMockGDTCORTransport *mockGoogleTransport =
- [[FIRMockGDTCORTransport alloc] initWithMappingID:@"id" transformers:nil target:0];
- self.appIDModel = [[FIRCLSApplicationIdentifierModel alloc] init];
- self.mockSettings = [[FIRCLSMockSettings alloc] initWithFileManager:self.fileManager
- appIDModel:self.appIDModel];
- FIRCLSManagerData *managerData =
- [[FIRCLSManagerData alloc] initWithGoogleAppID:TEST_GOOGLE_APP_ID
- googleTransport:mockGoogleTransport
- installations:iid
- analytics:nil
- fileManager:self.fileManager
- dataArbiter:self.dataArbiter
- settings:self.mockSettings];
- self.mockReportUploader = [[FIRCLSMockReportUploader alloc] initWithManagerData:managerData];
- self.existingReportManager =
- [[FIRCLSMockExistingReportManager alloc] initWithManagerData:managerData
- reportUploader:self.mockReportUploader];
- FIRCLSAnalyticsManager *analyticsManager = [[FIRCLSAnalyticsManager alloc] initWithAnalytics:nil];
- self.reportManager =
- [[FIRCLSMockReportManager alloc] initWithManagerData:managerData
- existingReportManager:self.existingReportManager
- analyticsManager:analyticsManager];
- }
- - (void)tearDown {
- self.reportManager = nil;
- if ([[NSFileManager defaultManager] fileExistsAtPath:[self.fileManager rootPath]]) {
- assert([self.fileManager removeItemAtPath:[self.fileManager rootPath]]);
- }
- FIRCLSContextBaseDeinit();
- [super tearDown];
- }
- #pragma mark - Path Helpers
- - (NSString *)resourcePath {
- return [[NSBundle bundleForClass:[self class]] resourcePath];
- }
- - (NSArray *)contentsOfActivePath {
- return [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.fileManager.activePath
- error:nil];
- }
- - (NSArray *)contentsOfPreparedPath {
- return [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.fileManager.preparedPath
- error:nil];
- }
- - (NSArray *)contentsOfProcessingPath {
- return [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.fileManager.processingPath
- error:nil];
- }
- #pragma mark - Report Helpers
- - (FIRCLSInternalReport *)createActiveReport {
- NSString *reportPath =
- [self.fileManager.activePath stringByAppendingPathComponent:@"my_session_id"];
- FIRCLSInternalReport *report = [[FIRCLSInternalReport alloc] initWithPath:reportPath
- executionIdentifier:@"my_session_id"];
- if (![self.fileManager createDirectoryAtPath:report.path]) {
- return nil;
- }
- if (![self createMetadata:
- @"{\"identity\":{\"api_key\":\"my_key\",\"session_id\":\"my_session_id\"}}\n"
- forReport:report]) {
- return nil;
- }
- return report;
- }
- - (BOOL)createFileWithContents:(NSString *)contents atPath:(NSString *)path {
- return [self.fileManager.underlyingFileManager
- createFileAtPath:path
- contents:[contents dataUsingEncoding:NSUTF8StringEncoding]
- attributes:nil];
- }
- - (BOOL)createMetadata:(NSString *)value forReport:(FIRCLSInternalReport *)report {
- return [self createFileWithContents:value atPath:[report metadataPath]];
- }
- #pragma mark - Property Helpers
- - (NSArray *)prepareAndSubmitReportArray {
- return self.mockReportUploader.prepareAndSubmitReportArray;
- }
- - (NSArray *)uploadReportArray {
- return self.mockReportUploader.uploadReportArray;
- }
- #pragma mark - File/Directory Handling
- - (void)testCreatesNewReportOnStart {
- FBLPromise<NSNumber *> *promise = [self->_reportManager startWithProfilingMark:0];
- XCTestExpectation *expectation =
- [[XCTestExpectation alloc] initWithDescription:@"waiting on promise"];
- [promise then:^id _Nullable(NSNumber *_Nullable value) {
- XCTAssertTrue([value boolValue]);
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- [expectation fulfill];
- return value;
- }];
- [self waitForExpectations:@[ expectation ] timeout:1.0];
- }
- - (void)waitForPromise:(FBLPromise<NSNumber *> *)promise {
- [self waitForPromise:promise withTimeout:1.0];
- }
- - (void)waitForPromise:(FBLPromise<NSNumber *> *)promise withTimeout:(double)timeout {
- __block NSNumber *value = nil;
- __block NSError *error = nil;
- XCTestExpectation *expectation =
- [[XCTestExpectation alloc] initWithDescription:@"waiting on promise"];
- [[promise then:^id _Nullable(NSNumber *_Nullable innerValue) {
- value = innerValue;
- [expectation fulfill];
- return nil;
- }] catch:^(NSError *_Nonnull innerError) {
- error = innerError;
- [expectation fulfill];
- }];
- [self waitForExpectations:@[ expectation ] timeout:timeout];
- XCTAssertNil(error);
- XCTAssertTrue([value boolValue]);
- }
- - (void)startReportManager {
- [self waitForPromise:[self startReportManagerWithDataCollectionEnabled:YES]];
- }
- - (FBLPromise<NSNumber *> *)startReportManagerWithDataCollectionEnabled:(BOOL)enabled {
- [self.dataArbiter setCrashlyticsCollectionEnabled:enabled];
- return [self.reportManager startWithProfilingMark:0];
- }
- - (void)processReports:(BOOL)send andExpectReports:(BOOL)reportsExpected {
- XCTestExpectation *processReportsComplete =
- [[XCTestExpectation alloc] initWithDescription:@"processReports: complete"];
- __block BOOL reportsAvailable = NO;
- [[[self.reportManager checkForUnsentReports]
- then:^id _Nullable(FIRCrashlyticsReport *_Nullable report) {
- reportsAvailable = report ? true : false;
- if (send) {
- return [self->_reportManager sendUnsentReports];
- } else {
- return [self->_reportManager deleteUnsentReports];
- }
- }] then:^id _Nullable(id _Nullable ignored) {
- [processReportsComplete fulfill];
- return nil;
- }];
- [self waitForExpectations:@[ processReportsComplete ] timeout:1.0];
- if (reportsExpected) {
- XCTAssertTrue(reportsAvailable, "should have unsent reports");
- } else {
- XCTAssertFalse(reportsAvailable, "should not have unsent reports");
- }
- }
- - (void)processReports:(BOOL)send {
- [self processReports:send andExpectReports:YES];
- }
- - (void)testExistingUnimportantReportOnStart {
- // Create a report representing the last run and put it in place
- [self createActiveReport];
- // Report from the last run should get deleted, and a new
- // one should be created for this run.
- [self startReportManager];
- // If this is > 1 it means we're not cleaning up reports from previous runs.
- // If this == 0, it means we're not creating new reports.
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- XCTAssertEqual([self.uploadReportArray count], 0);
- }
- - (void)testMetricKitResolvesPromiseIfNoDiagnostics {
- // Create a report representing the last run and put it in place, then create a crashed file
- // marker and MetricKit diagnostic file so that MetricKit manager doesn't resolve the promise
- // immediately.
- [self createActiveReport];
- [self.existingReportManager setShouldHaveExistingReport];
- NSString *metricKitPath =
- [self.fileManager.cachesPath stringByAppendingString:@"/MetricKit/Diagnostics/"];
- [self.fileManager createFileAtPath:[[self.fileManager rootPath]
- stringByAppendingPathComponent:@"previously-crashed"]
- contents:nil
- attributes:nil];
- [self.fileManager createDirectoryAtPath:metricKitPath];
- [self.fileManager createFileAtPath:[metricKitPath stringByAppendingString:@"Diagnostics.txt"]
- contents:nil
- attributes:nil];
- // MetricKit manager should resolve its promise after 3 seconds.
- [self waitForPromise:[self startReportManagerWithDataCollectionEnabled:YES] withTimeout:4];
- }
- - (void)testExistingUnimportantReportOnStartWithDataCollectionDisabled {
- // create a report and put it in place
- [self createActiveReport];
- // Starting with data collection disabled should report in nothing changing
- [self startReportManagerWithDataCollectionEnabled:NO];
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- XCTAssertEqual([self.uploadReportArray count], 0);
- }
- - (void)testExistingReportOnStart {
- // create a report and put it in place
- FIRCLSInternalReport *report = [self createActiveReport];
- // create a signal file so it is considering worth reporting
- XCTAssertTrue([self createFileWithContents:@"signal"
- atPath:[report pathForContentFile:FIRCLSReportSignalFile]]);
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- [self startReportManager];
- // verify that processReports won't get called.
- [self processReports:YES andExpectReports:NO];
- XCTAssertEqual([[self contentsOfActivePath] count], 1, @"should contain only the current report");
- // should call report manager once for that report
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 1);
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"process"], @(YES));
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"urgent"], @(NO));
- }
- - (void)testExistingReportOnStartWithDataCollectionDisabledThenEnabled {
- // create a report and put it in place
- FIRCLSInternalReport *report = [self createActiveReport];
- // create a signal file so it is considering worth reporting
- XCTAssertTrue([self createFileWithContents:@"signal"
- atPath:[report pathForContentFile:FIRCLSReportSignalFile]]);
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- FBLPromise<NSNumber *> *promise = [self startReportManagerWithDataCollectionEnabled:NO];
- XCTAssertEqual([[self contentsOfActivePath] count], 2,
- @"should contain the current and old reports");
- // should call report manager once for that report
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- // We can turn data collection on instead of calling processReports.
- [self.dataArbiter setCrashlyticsCollectionEnabled:YES];
- [self waitForPromise:promise];
- XCTAssertEqual([[self contentsOfActivePath] count], 1, @"should contain only the current report");
- // should call report manager once for that report
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 1);
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"process"], @(YES));
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"urgent"], @(NO));
- }
- - (void)testExistingReportOnStartWithDataCollectionDisabledAndSend {
- // create a report and put it in place
- FIRCLSInternalReport *report = [self createActiveReport];
- // create a signal file so it is considering worth reporting
- XCTAssertTrue([self createFileWithContents:@"signal"
- atPath:[report pathForContentFile:FIRCLSReportSignalFile]]);
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- [self startReportManagerWithDataCollectionEnabled:NO];
- XCTAssertEqual([[self contentsOfActivePath] count], 2,
- @"should contain the current and old reports");
- // should call report manager once for that report
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- [self processReports:YES];
- XCTAssertEqual([[self contentsOfActivePath] count], 1, @"should contain only the current report");
- // should call report manager once for that report
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 1);
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"process"], @(YES));
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"urgent"], @(NO));
- // Calling processReports again should not call the callback.
- // Technically, the behavior is unspecified.
- [self processReports:YES andExpectReports:NO];
- }
- - (void)testExistingReportOnStartWithDataCollectionDisabledAndDelete {
- // create a report and put it in place
- FIRCLSInternalReport *report = [self createActiveReport];
- // create a signal file so it is considering worth reporting
- XCTAssertTrue([self createFileWithContents:@"signal"
- atPath:[report pathForContentFile:FIRCLSReportSignalFile]]);
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- [self startReportManagerWithDataCollectionEnabled:NO];
- XCTAssertEqual([[self contentsOfActivePath] count], 2,
- @"should contain the current and old reports");
- // should call report manager once for that report
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- [self processReports:NO];
- XCTAssertEqual([[self contentsOfActivePath] count], 1, @"should contain only the current report");
- // Should not call report manager for that report.
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- }
- - (void)testExistingUrgentReportOnStart {
- // create a report and put it in place
- FIRCLSInternalReport *report = [self createActiveReport];
- // create a signal file so it is considering worth reporting
- XCTAssertTrue([self createFileWithContents:@"signal"
- atPath:[report pathForContentFile:FIRCLSReportSignalFile]]);
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- // Put the launch marker in place
- [self.reportManager.launchMarker createLaunchFailureMarker];
- // should call back to the delegate on start
- [self startReportManager];
- XCTAssertEqual([[self contentsOfActivePath] count], 1, @"should contain only the current report");
- // should call report manager once for that report
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 1);
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"process"], @(YES));
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"urgent"], @(YES));
- }
- - (void)testExistingUrgentReportOnStartWithDataCollectionDisabled {
- // create a report and put it in place
- FIRCLSInternalReport *report = [self createActiveReport];
- // create a signal file so it is considering worth reporting
- XCTAssertTrue([self createFileWithContents:@"signal"
- atPath:[report pathForContentFile:FIRCLSReportSignalFile]]);
- XCTAssertEqual([[self contentsOfActivePath] count], 1);
- // Put the launch marker in place
- [self.reportManager.launchMarker createLaunchFailureMarker];
- // Should wait for processReports: to be called.
- [self startReportManagerWithDataCollectionEnabled:NO];
- XCTAssertEqual([[self contentsOfActivePath] count], 2, @"the report hasn't been sent");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- [self processReports:YES];
- XCTAssertEqual([[self contentsOfActivePath] count], 1, @"should contain only current report");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 1);
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"process"], @(YES));
- // If data collection is disabled, you can never send the report urgently / blocking
- // startup because you need to call a method after startup to send the report
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"urgent"], @(NO));
- }
- - (void)testFilesLeftInProcessing {
- // put report in processing
- FIRCLSInternalReport *report = [self createActiveReport];
- XCTAssert([_fileManager createDirectoryAtPath:_fileManager.processingPath]);
- XCTAssert([_fileManager moveItemAtPath:[report path] toDirectory:_fileManager.processingPath]);
- [self startReportManager];
- // we should not process reports left over in processing
- XCTAssertEqual([[self contentsOfProcessingPath] count], 0, @"Processing should be cleared");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 1);
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"process"], @(NO));
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"urgent"], @(NO));
- }
- /*
- * This tests an edge case where there is a report in processing. For the purposes of unsent
- * reports these are not shown to the developer, but they are uploaded / deleted upon
- * calling send / delete.
- */
- - (void)testFilesLeftInProcessingWithDataCollectionDisabled {
- // Put report in processing.
- FIRCLSInternalReport *report = [self createActiveReport];
- XCTAssert([_fileManager createDirectoryAtPath:_fileManager.processingPath]);
- XCTAssert([_fileManager moveItemAtPath:[report path] toDirectory:_fileManager.processingPath]);
- [self startReportManagerWithDataCollectionEnabled:NO];
- // Nothing should have happened yet.
- XCTAssertEqual([[self contentsOfProcessingPath] count], 1,
- @"Processing should still have the report");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- // We don't expect reports here because we don't consider processing or prepared
- // reports as unsent as they need to be marked for sending before being placed
- // in those directories.
- [self processReports:YES andExpectReports:NO];
- // We should not process reports left over in processing.
- XCTAssertEqual([[self contentsOfProcessingPath] count], 0, @"Processing should be cleared");
- XCTAssertEqual([[self contentsOfPreparedPath] count], 0, @"Prepared should be cleared");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 1);
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"process"], @(NO));
- XCTAssertEqualObjects(self.prepareAndSubmitReportArray[0][@"urgent"], @(NO));
- }
- - (void)testFilesLeftInPrepared {
- // Drop a phony multipart-mime file in here, with non-zero contents.
- XCTAssert([_fileManager createDirectoryAtPath:_fileManager.preparedPath]);
- NSString *path = [_fileManager.preparedPath stringByAppendingPathComponent:@"phony-report"];
- path = [path stringByAppendingPathExtension:@"multipart-mime"];
- XCTAssertTrue([[_fileManager underlyingFileManager]
- createFileAtPath:path
- contents:[@"contents" dataUsingEncoding:NSUTF8StringEncoding]
- attributes:nil]);
- [self startReportManager];
- // Reports should be moved out of prepared
- XCTAssertEqual([[self contentsOfPreparedPath] count], 0, @"Prepared should be cleared");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- XCTAssertEqual([self.uploadReportArray count], 1);
- XCTAssertEqualObjects(self.uploadReportArray[0][@"path"], path);
- }
- /*
- * This tests an edge case where there is a report in prepared. For the purposes of unsent
- * reports these are not shown to the developer, but they are uploaded / deleted upon
- * calling send / delete.
- */
- - (void)testFilesLeftInPreparedWithDataCollectionDisabled {
- // drop a phony multipart-mime file in here, with non-zero contents
- XCTAssert([_fileManager createDirectoryAtPath:_fileManager.preparedPath]);
- NSString *path = [_fileManager.preparedPath stringByAppendingPathComponent:@"phony-report"];
- path = [path stringByAppendingPathExtension:@"multipart-mime"];
- XCTAssertTrue([[_fileManager underlyingFileManager]
- createFileAtPath:path
- contents:[@"contents" dataUsingEncoding:NSUTF8StringEncoding]
- attributes:nil]);
- [self startReportManagerWithDataCollectionEnabled:NO];
- // Nothing should have happened yet.
- XCTAssertEqual([[self contentsOfPreparedPath] count], 1,
- @"Prepared should still have the report");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- // We don't expect reports here because we don't consider processing or prepared
- // reports as unsent as they need to be marked for sending before being placed
- // in those directories.
- [self processReports:YES andExpectReports:NO];
- // Reports should be moved out of prepared
- XCTAssertEqual([[self contentsOfPreparedPath] count], 0, @"Prepared should be cleared");
- XCTAssertEqual([[self contentsOfProcessingPath] count], 0, @"Processing should be cleared");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- XCTAssertEqual([self.uploadReportArray count], 1);
- XCTAssertEqualObjects(self.uploadReportArray[0][@"path"], path);
- }
- - (void)testSuccessfulSubmission {
- // drop a phony multipart-mime file in here, with non-zero contents
- XCTAssert([_fileManager createDirectoryAtPath:_fileManager.preparedPath]);
- NSString *path = [_fileManager.preparedPath stringByAppendingPathComponent:@"phony-report"];
- path = [path stringByAppendingPathExtension:@"multipart-mime"];
- XCTAssertTrue([[_fileManager underlyingFileManager]
- createFileAtPath:path
- contents:[@"contents" dataUsingEncoding:NSUTF8StringEncoding]
- attributes:nil]);
- [self startReportManager];
- // we should not process reports left over in processing
- XCTAssertEqual([[self contentsOfProcessingPath] count], 0, @"Processing should be cleared");
- XCTAssertEqual([self.prepareAndSubmitReportArray count], 0);
- XCTAssertEqual([self.uploadReportArray count], 1);
- XCTAssertEqualObjects(self.uploadReportArray[0][@"path"], path);
- [self.reportManager.operationQueue waitUntilAllOperationsAreFinished];
- // not 100% sure what to verify here
- // lol
- }
- - (void)testLogInvalidJSONAnalyticsEvents {
- NSDictionary *eventAsDict = @{
- @"price" : @(NAN),
- @"count" : @(INFINITY),
- };
- NSString *json = FIRCLSFIRAEventDictionaryToJSON(eventAsDict);
- XCTAssertEqualObjects(json, nil);
- }
- @end
|