// // Copyright (c) 2017 Open Whisper Systems. All rights reserved. // #import "NSDate+millisecondTimeStamp.h" #import "OWSDisappearingMessagesFinder.h" #import "TSContactThread.h" #import "TSMessage.h" #import "TSStorageManager.h" #import NS_ASSUME_NONNULL_BEGIN @interface OWSDisappearingMessagesFinder (Testing) - (NSArray *)fetchExpiredMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction; - (NSArray *)fetchUnstartedExpiringMessagesInThread:(TSThread *)thread transaction:(YapDatabaseReadTransaction *)transaction; @end @interface OWSDisappearingMessageFinderTest : XCTestCase @property YapDatabaseConnection *dbConnection; @property OWSDisappearingMessagesFinder *finder; @property TSStorageManager *storageManager; @property TSThread *thread; @property uint64_t now; @end @implementation OWSDisappearingMessageFinderTest - (void)setUp { [super setUp]; [TSMessage removeAllObjectsInCollection]; self.storageManager = [TSStorageManager sharedManager]; self.dbConnection = self.storageManager.newDatabaseConnection; self.thread = [TSContactThread getOrCreateThreadWithContactId:@"fake-thread-id"]; self.now = [NSDate ows_millisecondTimeStamp]; // Test subject self.finder = [OWSDisappearingMessagesFinder new]; [OWSDisappearingMessagesFinder blockingRegisterDatabaseExtensions:self.storageManager]; } - (void)testExpiredMessages { TSMessage *expiredMessage1 = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"expiredMessage1" attachmentIds:@[] expiresInSeconds:1 expireStartedAt:self.now - 20000]; [expiredMessage1 save]; TSMessage *expiredMessage2 = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"expiredMessage2" attachmentIds:@[] expiresInSeconds:2 expireStartedAt:self.now - 2001]; [expiredMessage2 save]; TSMessage *notYetExpiredMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"notYetExpiredMessage" attachmentIds:@[] expiresInSeconds:20 expireStartedAt:self.now - 10000]; [notYetExpiredMessage save]; TSMessage *unreadExpiringMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unereadExpiringMessage" attachmentIds:@[] expiresInSeconds:10 expireStartedAt:0]; [unreadExpiringMessage save]; TSMessage *unExpiringMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage" attachmentIds:@[] expiresInSeconds:0 expireStartedAt:0]; [unExpiringMessage save]; TSMessage *unExpiringMessage2 = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage2"]; [unExpiringMessage2 save]; __block NSArray *actualMessages; [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { actualMessages = [self.finder fetchExpiredMessagesWithTransaction:transaction]; }]; NSArray *expectedMessages = @[ expiredMessage1, expiredMessage2 ]; XCTAssertEqualObjects(expectedMessages, actualMessages); } - (void)testUnstartedExpiredMessagesForThread { TSMessage *expiredMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"expiredMessage2" attachmentIds:@[] expiresInSeconds:2 expireStartedAt:self.now - 2001]; [expiredMessage save]; TSMessage *notYetExpiredMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"notYetExpiredMessage" attachmentIds:@[] expiresInSeconds:20 expireStartedAt:self.now - 10000]; [notYetExpiredMessage save]; TSMessage *unreadExpiringMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unereadExpiringMessage" attachmentIds:@[] expiresInSeconds:10 expireStartedAt:0]; [unreadExpiringMessage save]; TSMessage *unExpiringMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage" attachmentIds:@[] expiresInSeconds:0 expireStartedAt:0]; [unExpiringMessage save]; TSMessage *unExpiringMessage2 = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage2"]; [unExpiringMessage2 save]; __block NSArray *actualMessages; [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { actualMessages = [self.finder fetchUnstartedExpiringMessagesInThread:self.thread transaction:transaction]; }]; NSArray *expectedMessages = @[ unreadExpiringMessage ]; XCTAssertEqualObjects(expectedMessages, actualMessages); } - (NSNumber *)nextExpirationTimestamp { __block NSNumber *nextExpirationTimestamp; [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { XCTAssertNotNil(self.finder); nextExpirationTimestamp = [self.finder nextExpirationTimestampWithTransaction:transaction]; }]; return nextExpirationTimestamp; } - (void)testNextExpirationTimestampNilWhenNoExpiringMessages { // Sanity check. XCTAssertNil(self.nextExpirationTimestamp); TSMessage *unExpiringMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"unexpiringMessage" attachmentIds:@[] expiresInSeconds:0 expireStartedAt:0]; [unExpiringMessage save]; XCTAssertNil(self.nextExpirationTimestamp); } - (void)testNextExpirationTimestampNotNilWithUpcomingExpiringMessages { TSMessage *soonToExpireMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"soonToExpireMessage" attachmentIds:@[] expiresInSeconds:10 expireStartedAt:self.now - 9000]; [soonToExpireMessage save]; XCTAssertNotNil(self.nextExpirationTimestamp); XCTAssertEqual(self.now + 1000, [self.nextExpirationTimestamp unsignedLongLongValue]); // expired message should take precedence TSMessage *expiredMessage = [[TSMessage alloc] initWithTimestamp:1 inThread:self.thread messageBody:@"expiredMessage" attachmentIds:@[] expiresInSeconds:10 expireStartedAt:self.now - 11000]; [expiredMessage save]; //FIXME remove sleep hack in favor of expiringMessage completion handler // sleep(2); XCTAssertNotNil(self.nextExpirationTimestamp); XCTAssertEqual(self.now - 1000, [self.nextExpirationTimestamp unsignedLongLongValue]); } @end NS_ASSUME_NONNULL_END