session-ios/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m

2644 lines
123 KiB
Mathematica
Raw Normal View History

//
2018-01-26 23:31:45 +01:00
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "DebugUIMessages.h"
#import "DebugUIContacts.h"
#import "OWSTableViewController.h"
#import "Signal-Swift.h"
#import "ThreadUtil.h"
#import <AxolotlKit/PreKeyBundle.h>
#import <Curve25519Kit/Randomness.h>
2017-12-19 03:50:51 +01:00
#import <SignalMessaging/Environment.h>
#import <SignalServiceKit/NSDate+OWS.h>
#import <SignalServiceKit/OWSBatchMessageProcessor.h>
#import <SignalServiceKit/OWSDisappearingConfigurationUpdateInfoMessage.h>
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
#import <SignalServiceKit/OWSPrimaryStorage+SessionStore.h>
#import <SignalServiceKit/OWSSyncGroupsRequestMessage.h>
#import <SignalServiceKit/OWSVerificationStateChangeMessage.h>
2017-07-31 20:48:43 +02:00
#import <SignalServiceKit/SecurityUtils.h>
#import <SignalServiceKit/TSCall.h>
2017-11-15 18:10:29 +01:00
#import <SignalServiceKit/TSDatabaseView.h>
#import <SignalServiceKit/TSIncomingMessage.h>
#import <SignalServiceKit/TSInvalidIdentityKeyReceivingErrorMessage.h>
#import <SignalServiceKit/TSThread.h>
NS_ASSUME_NONNULL_BEGIN
2018-03-23 15:19:04 +01:00
typedef void (^ActionSuccessBlock)(void);
2018-03-23 14:57:22 +01:00
typedef void (^ActionFailureBlock)(void);
2018-03-23 16:14:07 +01:00
typedef void (^ActionPrepareBlock)(ActionSuccessBlock success, ActionFailureBlock failure);
2018-03-23 22:49:46 +01:00
typedef void (^StaggeredActionBlock)(NSUInteger index,
YapDatabaseReadWriteTransaction *transaction,
ActionSuccessBlock success,
ActionFailureBlock failure);
typedef void (^UnstaggeredActionBlock)(NSUInteger index, YapDatabaseReadWriteTransaction *transaction);
2018-03-23 14:57:22 +01:00
2018-03-23 22:49:46 +01:00
typedef NS_ENUM(NSUInteger, SubactionMode) {
SubactionMode_Random = 0,
SubactionMode_Ordered,
};
2018-03-23 16:14:07 +01:00
2018-03-23 22:49:46 +01:00
@interface FakeAssetLoader : NSObject
@property (nonatomic) NSString *fileUrl;
@property (nonatomic) NSString *filename;
@property (nonatomic) NSString *mimeType;
@property (nonatomic, nullable) NSString *filePath;
2018-03-23 16:14:07 +01:00
@end
#pragma mark -
2018-03-23 22:49:46 +01:00
@implementation FakeAssetLoader
2018-03-23 16:14:07 +01:00
2018-03-23 22:49:46 +01:00
- (void)ensureAssetLoaded:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
2018-03-23 16:14:07 +01:00
{
2018-03-23 22:49:46 +01:00
OWSAssert(success);
OWSAssert(failure);
OWSAssert(self.fileUrl.length > 0);
OWSAssert(self.filename.length > 0);
OWSAssert(self.mimeType.length > 0);
2018-03-23 16:14:07 +01:00
2018-03-23 22:49:46 +01:00
if (self.filePath) {
success();
return;
}
NSString *filePath = [OWSFileSystem temporaryFilePathWithFileExtension:self.filename.pathExtension];
// NSFileManager *fileManager = [NSFileManager defaultManager];
// [fileManager]
// NSURL *documentDirectoryURL =
// [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
// NSString *randomFilesDirectoryPath =
// [[documentDirectoryURL path] stringByAppendingPathComponent:@"cached_random_files"];
// [OWSFileSystem ensureDirectoryExists:randomFilesDirectoryPath];
// NSString *filePath = [randomFilesDirectoryPath stringByAppendingPathComponent:self.filename];
// if ([fileManager fileExistsAtPath:filePath]) {
// success(filePath);
// } else {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
OWSAssert(sessionManager.responseSerializer);
[sessionManager GET:self.fileUrl
parameters:nil
progress:nil
success:^(NSURLSessionDataTask *task, NSData *_Nullable responseObject) {
if ([responseObject writeToFile:filePath atomically:YES]) {
self.filePath = filePath;
OWSAssert([NSFileManager.defaultManager fileExistsAtPath:filePath]);
success();
} else {
OWSFail(@"Error write url response [%@]: %@", self.fileUrl, filePath);
failure();
}
}
failure:^(NSURLSessionDataTask *_Nullable task, NSError *requestError) {
OWSFail(@"Error downloading url[%@]: %@", self.fileUrl, requestError);
failure();
}];
}
+ (instancetype)jpegInstance
{
static FakeAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [self new];
instance.fileUrl = @"https://s3.amazonaws.com/ows-data/example_attachment_media/random-jpg.JPG";
instance.filename = @"random-jpg.jpg";
instance.mimeType = @"image/jpeg";
});
2018-03-23 16:14:07 +01:00
return instance;
}
2018-03-23 22:49:46 +01:00
+ (instancetype)gifInstance
2018-03-23 16:14:07 +01:00
{
2018-03-23 22:49:46 +01:00
static FakeAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [self new];
instance.fileUrl = @"https://s3.amazonaws.com/ows-data/example_attachment_media/random-gif.gif";
instance.filename = @"random-gif.gif";
instance.mimeType = @"image/gif";
});
return instance;
}
2018-03-23 16:14:07 +01:00
2018-03-23 22:49:46 +01:00
+ (instancetype)mp3Instance
{
static FakeAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [self new];
instance.fileUrl = @"https://s3.amazonaws.com/ows-data/example_attachment_media/random-mp3.mp3";
instance.filename = @"random-mp3.mp3";
instance.mimeType = @"audio/mpeg";
});
2018-03-23 16:14:07 +01:00
return instance;
}
2018-03-23 22:49:46 +01:00
+ (instancetype)mp4Instance
2018-03-23 16:14:07 +01:00
{
2018-03-23 22:49:46 +01:00
static FakeAssetLoader *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [self new];
instance.fileUrl = @"https://s3.amazonaws.com/ows-data/example_attachment_media/random-mp4.mp4";
instance.filename = @"random-mp4.mp4";
instance.mimeType = @"video/mp4";
});
return instance;
}
2018-03-23 16:14:07 +01:00
2018-03-23 22:49:46 +01:00
- (ActionPrepareBlock)prepareBlock
{
__weak FakeAssetLoader *weakSelf = self;
return ^(ActionSuccessBlock success, ActionFailureBlock failure) {
[weakSelf ensureAssetLoaded:success failure:failure];
2018-03-23 16:14:07 +01:00
};
2018-03-23 22:49:46 +01:00
}
@end
#pragma mark -
@class DebugUIMessagesSingleAction;
@interface DebugUIMessagesAction : NSObject
@property (nonatomic) NSString *label;
@end
#pragma mark -
@interface DebugUIMessagesSingleAction : DebugUIMessagesAction
@property (nonatomic, nullable) ActionPrepareBlock prepareBlock;
// "Single" actions should have exactly one "staggered" or "unstaggered" action block.
@property (nonatomic, nullable) StaggeredActionBlock staggeredActionBlock;
@property (nonatomic, nullable) UnstaggeredActionBlock unstaggeredActionBlock;
@end
#pragma mark -
@implementation DebugUIMessagesAction
- (DebugUIMessagesSingleAction *)nextActionToPerform
{
return (DebugUIMessagesSingleAction *)self;
}
- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
OWS_ABSTRACT_METHOD();
success();
2018-03-23 16:14:07 +01:00
}
- (void)prepareAndPerformNTimes:(NSUInteger)count
{
2018-03-23 22:49:46 +01:00
// __weak DebugUIMessagesAction *weakSelf = self;
2018-03-23 16:14:07 +01:00
[self prepare:^{
2018-03-23 22:49:46 +01:00
[self performNTimes:count
success:^{
}
failure:^{
}];
2018-03-23 16:14:07 +01:00
}
failure:^{
}];
}
2018-03-23 22:49:46 +01:00
- (void)performNTimes:(NSUInteger)countParam success:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
2018-03-23 16:14:07 +01:00
{
2018-03-23 16:37:29 +01:00
OWSAssert(success);
OWSAssert(failure);
2018-03-23 22:49:46 +01:00
DDLogInfo(@"%@ %@ performNTimes: %zd", self.logTag, self.label, countParam);
2018-03-23 16:37:29 +01:00
[DDLog flushLog];
2018-03-23 22:49:46 +01:00
if (countParam < 1) {
2018-03-23 16:37:29 +01:00
success();
2018-03-23 16:14:07 +01:00
return;
}
2018-03-23 22:49:46 +01:00
__block NSUInteger count = countParam;
[OWSPrimaryStorage.sharedManager.newDatabaseConnection readWriteWithBlock:^(
YapDatabaseReadWriteTransaction *transaction) {
NSUInteger batchSize = 0;
while (count > 0) {
NSUInteger index = count;
DebugUIMessagesSingleAction *action = [self nextActionToPerform];
OWSAssert([action isKindOfClass:[DebugUIMessagesSingleAction class]]);
if (action.staggeredActionBlock) {
OWSAssert(!action.unstaggeredActionBlock);
action.staggeredActionBlock(index,
transaction,
^{
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
DDLogInfo(@"%@ %@ performNTimes success: %zd", self.logTag, self.label, count);
[self performNTimes:count - 1 success:success failure:failure];
});
},
failure);
break;
} else {
OWSAssert(action.unstaggeredActionBlock);
// TODO: We could check result for failure.
action.unstaggeredActionBlock(index, transaction);
const NSUInteger kMaxBatchSize = 2500;
batchSize++;
if (batchSize >= kMaxBatchSize) {
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
DDLogInfo(@"%@ %@ performNTimes success: %zd", self.logTag, self.label, count);
[self performNTimes:count - 1 success:success failure:failure];
});
break;
}
count--;
}
}
}];
}
@end
#pragma mark -
@implementation DebugUIMessagesSingleAction
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock
{
OWSAssert(label.length > 0);
OWSAssert(staggeredActionBlock);
DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new];
instance.label = label;
instance.staggeredActionBlock = staggeredActionBlock;
return instance;
2018-03-23 16:37:29 +01:00
}
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock
2018-03-23 16:37:29 +01:00
{
2018-03-23 22:49:46 +01:00
OWSAssert(label.length > 0);
OWSAssert(unstaggeredActionBlock);
2018-03-23 16:37:29 +01:00
2018-03-23 22:49:46 +01:00
DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new];
instance.label = label;
instance.unstaggeredActionBlock = unstaggeredActionBlock;
return instance;
}
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
staggeredActionBlock:(StaggeredActionBlock)staggeredActionBlock
prepareBlock:(ActionPrepareBlock)prepareBlock
{
OWSAssert(label.length > 0);
OWSAssert(staggeredActionBlock);
OWSAssert(prepareBlock);
DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new];
instance.label = label;
instance.staggeredActionBlock = staggeredActionBlock;
instance.prepareBlock = prepareBlock;
return instance;
}
+ (DebugUIMessagesAction *)actionWithLabel:(NSString *)label
unstaggeredActionBlock:(UnstaggeredActionBlock)unstaggeredActionBlock
prepareBlock:(ActionPrepareBlock)prepareBlock
{
OWSAssert(label.length > 0);
OWSAssert(unstaggeredActionBlock);
OWSAssert(prepareBlock);
DebugUIMessagesSingleAction *instance = [DebugUIMessagesSingleAction new];
instance.label = label;
instance.unstaggeredActionBlock = unstaggeredActionBlock;
instance.prepareBlock = prepareBlock;
return instance;
2018-03-23 16:14:07 +01:00
}
- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
if (self.prepareBlock) {
self.prepareBlock(success, failure);
} else {
success();
}
}
2018-03-23 22:49:46 +01:00
@end
#pragma mark -
@interface DebugUIMessagesGroupAction : DebugUIMessagesAction
// "Group" actions should have these properties.
@property (nonatomic) SubactionMode subactionMode;
@property (nonatomic, nullable) NSArray<DebugUIMessagesAction *> *subactions;
@property (nonatomic) NSUInteger subactionIndex;
//@property (nonatomic, nullable) MessageActionBlock actionBlock;
//@property (nonatomic, nullable) StaggeredActionBlock staggeredActionBlock;
//@property (nonatomic, nullable) BulkActionBlock staggeredActionBlock;
//@property (nonatomic, nullable) BulkActionBlock bulkActionBlock;
//@property (nonatomic) BOOL isStaggered;
@end
#pragma mark -
@implementation DebugUIMessagesGroupAction
- (DebugUIMessagesSingleAction *)nextActionToPerform
{
OWSAssert(self.subactions.count > 0);
switch (self.subactionMode) {
case SubactionMode_Random: {
DebugUIMessagesAction *subaction = self.subactions[arc4random_uniform((uint32_t)self.subactions.count)];
OWSAssert(subaction);
return subaction.nextActionToPerform;
}
case SubactionMode_Ordered: {
DebugUIMessagesAction *subaction = self.subactions[self.subactionIndex];
OWSAssert(subaction);
self.subactionIndex = (self.subactionIndex + 1) % self.subactions.count;
return subaction.nextActionToPerform;
}
}
}
- (void)prepare:(ActionSuccessBlock)success failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
[DebugUIMessagesGroupAction prepareSubactions:[self.subactions mutableCopy] success:success failure:failure];
}
2018-03-23 16:14:07 +01:00
+ (void)prepareSubactions:(NSMutableArray<DebugUIMessagesAction *> *)unpreparedSubactions
success:(ActionSuccessBlock)success
failure:(ActionFailureBlock)failure
{
OWSAssert(success);
OWSAssert(failure);
if (unpreparedSubactions.count < 1) {
return success();
}
DebugUIMessagesAction *nextAction = unpreparedSubactions.lastObject;
[unpreparedSubactions removeLastObject];
[nextAction prepare:^{
[self prepareSubactions:unpreparedSubactions success:success failure:failure];
}
failure:^{
}];
}
2018-03-23 22:49:46 +01:00
// Given a group of subactions, perform a single random subaction each time.
+ (DebugUIMessagesAction *)randomGroupActionWithLabel:(NSString *)label
subactions:(NSArray<DebugUIMessagesAction *> *)subactions
{
OWSAssert(label.length > 0);
OWSAssert(subactions.count > 0);
DebugUIMessagesGroupAction *instance = [DebugUIMessagesGroupAction new];
instance.label = label;
instance.subactions = subactions;
instance.subactionMode = SubactionMode_Random;
// instance.staggeredActionBlock = ^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction,
// ActionSuccessBlock success, ActionFailureBlock failure) {
// [self performRandomStaggeredSubaction:subactions index:index transaction:transaction success:success
// failure:failure];
// };
// instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) {
// [DebugUIMessagesAction prepareSubactions:[subactions mutableCopy] success:success failure:failure];
// };
return instance;
}
// Given a group of subactions, perform all of the subactions each time.
+ (DebugUIMessagesAction *)allGroupActionWithLabel:(NSString *)label
subactions:(NSArray<DebugUIMessagesAction *> *)subactions
{
OWSAssert(label.length > 0);
OWSAssert(subactions.count > 0);
DebugUIMessagesGroupAction *instance = [DebugUIMessagesGroupAction new];
instance.label = label;
instance.subactions = subactions;
instance.subactionMode = SubactionMode_Ordered;
// instance.bulkActionBlock = ^(NSUInteger count, YapDatabaseReadWriteTransaction *transaction,
// ActionSuccessBlock success, ActionFailureBlock failure) {
// for (NSUInteger index = 0; index < count; index++) {
// [self performAllUnstaggeredSubactions:[subactions mutableCopy] index:index transaction:transaction
// success:success failure:failure];
// }
// };
// instance.prepareBlock = ^(ActionSuccessBlock success, ActionFailureBlock failure) {
// [DebugUIMessagesAction prepareSubactions:[subactions mutableCopy] success:success failure:failure];
// };
return instance;
}
2018-03-23 16:14:07 +01:00
@end
#pragma mark -
2018-03-16 15:31:26 +01:00
@interface TSOutgoingMessage (PostDatingDebug)
- (void)setReceivedAtTimestamp:(uint64_t)value;
@end
2018-03-23 16:14:07 +01:00
#pragma mark -
@implementation DebugUIMessages
#pragma mark - Factory Methods
- (NSString *)name
{
return @"Messages";
}
- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread
{
OWSAssert(thread);
2018-03-23 22:49:46 +01:00
NSMutableArray<OWSTableItem *> *items = [NSMutableArray new];
for (DebugUIMessagesAction *action in @[
[DebugUIMessages sendMessageVariationsAction:thread],
// Send Media
[DebugUIMessages sendJpegAction:thread],
[DebugUIMessages sendGifAction:thread],
[DebugUIMessages sendMp3Action:thread],
[DebugUIMessages sendMp4Action:thread],
[DebugUIMessages sendAllMediaAction:thread],
[DebugUIMessages sendRandomMediaAction:thread],
// Fake Media
[DebugUIMessages fakeAllMediaAction:thread],
[DebugUIMessages fakeRandomMediaAction:thread],
// Fake Text
[DebugUIMessages fakeAllTextAction:thread],
[DebugUIMessages fakeRandomTextAction:thread],
// Exemplary
[DebugUIMessages allExemplaryAction:thread],
]) {
[items addObject:[OWSTableItem itemWithTitle:action.label
actionBlock:^{
// For "all in group" actions, do each subaction in the group
// exactly once, in a predictable order.
if ([action isKindOfClass:[DebugUIMessagesGroupAction class]]) {
DebugUIMessagesGroupAction *groupAction
= (DebugUIMessagesGroupAction *)action;
if (groupAction.subactionMode == SubactionMode_Ordered) {
[action prepareAndPerformNTimes:groupAction.subactions.count];
return;
}
}
[DebugUIMessages performActionNTimes:action];
}]];
}
[items addObjectsFromArray:@[
2018-03-23 15:19:04 +01:00
#pragma mark - Actions
[OWSTableItem itemWithTitle:@"Send N text messages (1/sec.)"
actionBlock:^{
2018-03-23 15:19:04 +01:00
[DebugUIMessages sendNTextMessagesInThread:thread];
}],
2018-03-23 22:49:46 +01:00
// [OWSTableItem itemWithTitle:@"Send N Random Media (1/sec.)"
// actionBlock:^{
// [DebugUIMessages sendSelectedMediaTypeInThread:thread];
// }],
2018-03-23 15:19:04 +01:00
#pragma mark - Misc.
[OWSTableItem itemWithTitle:@"Perform 100 random actions"
actionBlock:^{
2018-03-23 15:19:04 +01:00
[DebugUIMessages performRandomActions:100 thread:thread];
}],
2018-03-23 15:19:04 +01:00
[OWSTableItem itemWithTitle:@"Perform 1,000 random actions"
actionBlock:^{
2018-03-23 15:19:04 +01:00
[DebugUIMessages performRandomActions:1000 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 10 tiny text messages (1/sec.)"
actionBlock:^{
[DebugUIMessages sendTinyTextMessages:10 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 100 tiny text messages (1/sec.)"
actionBlock:^{
[DebugUIMessages sendTinyTextMessages:100 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 10 tiny attachments"
actionBlock:^{
[DebugUIMessages sendTinyAttachments:10 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 100 tiny attachments"
actionBlock:^{
[DebugUIMessages sendTinyAttachments:100 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 1,000 tiny attachments"
actionBlock:^{
[DebugUIMessages sendTinyAttachments:1000 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 3,000 tiny attachments"
actionBlock:^{
[DebugUIMessages sendTinyAttachments:3000 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Create 10 fake messages"
actionBlock:^{
[DebugUIMessages sendFakeMessages:10 thread:thread];
}],
2017-09-01 20:30:39 +02:00
[OWSTableItem itemWithTitle:@"Create 1 fake thread with 1 message"
actionBlock:^{
[DebugUIMessages createFakeThreads:1 withFakeMessages:1];
}],
[OWSTableItem itemWithTitle:@"Create 100 fake threads with 10 messages"
actionBlock:^{
[DebugUIMessages createFakeThreads:100 withFakeMessages:10];
}],
[OWSTableItem itemWithTitle:@"Create 10 fake threads with 100 messages"
actionBlock:^{
[DebugUIMessages createFakeThreads:10 withFakeMessages:100];
}],
[OWSTableItem itemWithTitle:@"Create 10 fake threads with 10 messages"
actionBlock:^{
[DebugUIMessages createFakeThreads:10 withFakeMessages:10];
}],
[OWSTableItem itemWithTitle:@"Create 100 fake threads with 100 messages"
actionBlock:^{
[DebugUIMessages createFakeThreads:100 withFakeMessages:100];
}],
[OWSTableItem itemWithTitle:@"Create 1k fake threads with 1 message"
actionBlock:^{
[DebugUIMessages createFakeThreads:1000 withFakeMessages:1];
}],
[OWSTableItem itemWithTitle:@"Create 1k fake messages"
actionBlock:^{
[DebugUIMessages sendFakeMessages:1000 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Create 10k fake messages"
actionBlock:^{
[DebugUIMessages sendFakeMessages:10 * 1000 thread:thread];
}],
2018-01-26 23:31:45 +01:00
[OWSTableItem itemWithTitle:@"Create 100k fake messages"
actionBlock:^{
[DebugUIMessages sendFakeMessages:100 * 1000 thread:thread];
}],
2018-01-29 16:11:19 +01:00
[OWSTableItem itemWithTitle:@"Create 100k fake text messages"
actionBlock:^{
[DebugUIMessages sendFakeMessages:100 * 1000 thread:thread isTextOnly:YES];
}],
[OWSTableItem itemWithTitle:@"Create 1 fake unread messages"
actionBlock:^{
[DebugUIMessages createFakeUnreadMessages:1 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Create 10 fake unread messages"
actionBlock:^{
[DebugUIMessages createFakeUnreadMessages:10 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Create 10 fake large attachments"
actionBlock:^{
[DebugUIMessages createFakeLargeOutgoingAttachments:10 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Create 100 fake large attachments"
actionBlock:^{
[DebugUIMessages createFakeLargeOutgoingAttachments:100 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Create 1k fake large attachments"
actionBlock:^{
[DebugUIMessages createFakeLargeOutgoingAttachments:1000 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Create 10k fake large attachments"
actionBlock:^{
[DebugUIMessages createFakeLargeOutgoingAttachments:10000 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send text/x-signal-plain"
actionBlock:^{
[DebugUIMessages sendOversizeTextMessage:thread];
}],
[OWSTableItem itemWithTitle:@"Send unknown mimetype"
actionBlock:^{
[DebugUIMessages sendRandomAttachment:thread uti:kUnknownTestAttachmentUTI];
}],
[OWSTableItem itemWithTitle:@"Send pdf"
actionBlock:^{
[DebugUIMessages sendRandomAttachment:thread uti:(NSString *)kUTTypePDF];
}],
[OWSTableItem itemWithTitle:@"Create all system messages"
actionBlock:^{
[DebugUIMessages createSystemMessagesInThread:thread];
}],
2018-02-13 19:06:08 +01:00
[OWSTableItem itemWithTitle:@"Create messages with variety of timestamps"
actionBlock:^{
[DebugUIMessages createTimestampMessagesInThread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 10 text and system messages"
actionBlock:^{
[DebugUIMessages sendTextAndSystemMessages:10 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 100 text and system messages"
actionBlock:^{
[DebugUIMessages sendTextAndSystemMessages:100 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 1,000 text and system messages"
actionBlock:^{
[DebugUIMessages sendTextAndSystemMessages:1000 thread:thread];
}],
[OWSTableItem
itemWithTitle:@"Request Bogus group info"
actionBlock:^{
2017-11-08 20:04:51 +01:00
DDLogInfo(@"%@ Requesting bogus group info for thread: %@", self.logTag, thread);
OWSSyncGroupsRequestMessage *syncGroupsRequestMessage =
[[OWSSyncGroupsRequestMessage alloc] initWithThread:thread
groupId:[Randomness generateRandomBytes:16]];
[[Environment current].messageSender enqueueMessage:syncGroupsRequestMessage
success:^{
2017-11-08 20:04:51 +01:00
DDLogWarn(@"%@ Successfully sent Request Group Info message.", self.logTag);
}
failure:^(NSError *error) {
2017-11-08 20:04:51 +01:00
DDLogError(
@"%@ Failed to send Request Group Info message with error: %@", self.logTag, error);
}];
}],
[OWSTableItem itemWithTitle:@"Inject 10 fake incoming messages"
actionBlock:^{
[DebugUIMessages injectFakeIncomingMessages:10 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Inject 100 fake incoming messages"
actionBlock:^{
[DebugUIMessages injectFakeIncomingMessages:100 thread:thread];
}],
[OWSTableItem itemWithTitle:@"Inject 1,000 fake incoming messages"
actionBlock:^{
[DebugUIMessages injectFakeIncomingMessages:1000 thread:thread];
}],
2018-02-16 02:45:28 +01:00
[OWSTableItem itemWithTitle:@"Test Indic Scripts"
actionBlock:^{
[DebugUIMessages testIndicScriptsInThread:thread];
}],
[OWSTableItem itemWithTitle:@"Test Zalgo"
actionBlock:^{
[DebugUIMessages testZalgoTextInThread:thread];
}],
[OWSTableItem itemWithTitle:@"Test Directional Filenames"
actionBlock:^{
[DebugUIMessages testDirectionalFilenamesInThread:thread];
}],
2018-03-23 22:49:46 +01:00
]];
if ([thread isKindOfClass:[TSContactThread class]]) {
TSContactThread *contactThread = (TSContactThread *)thread;
NSString *recipientId = contactThread.contactIdentifier;
[items addObject:[OWSTableItem itemWithTitle:@"Create 10 new groups"
actionBlock:^{
[DebugUIMessages createNewGroups:10 recipientId:recipientId];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Create 100 new groups"
actionBlock:^{
[DebugUIMessages createNewGroups:100 recipientId:recipientId];
}]];
[items addObject:[OWSTableItem itemWithTitle:@"Create 1,000 new groups"
actionBlock:^{
[DebugUIMessages createNewGroups:1000 recipientId:recipientId];
}]];
}
2018-01-26 23:31:45 +01:00
if ([thread isKindOfClass:[TSGroupThread class]]) {
TSGroupThread *groupThread = (TSGroupThread *)thread;
[items addObject:[OWSTableItem itemWithTitle:@"Send message to all members"
actionBlock:^{
[DebugUIMessages sendMessages:1 toAllMembersOfGroup:groupThread];
}]];
}
return [OWSTableSection sectionWithTitle:self.name items:items];
}
2018-03-23 15:19:04 +01:00
+ (void)sendMessages:(NSUInteger)count toAllMembersOfGroup:(TSGroupThread *)groupThread
2018-01-26 23:31:45 +01:00
{
for (NSString *recipientId in groupThread.groupModel.groupMemberIds) {
TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:recipientId];
2018-03-23 16:14:07 +01:00
[[self sendTextMessagesActionInThread:contactThread] prepareAndPerformNTimes:count];
2018-01-26 23:31:45 +01:00
}
}
2018-03-23 15:19:04 +01:00
+ (void)sendTextMessageInThread:(TSThread *)thread counter:(NSUInteger)counter
{
2018-03-23 15:19:04 +01:00
DDLogInfo(@"%@ sendTextMessageInThread: %zd", self.logTag, counter);
[DDLog flushLog];
NSString *randomText = [self randomText];
NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText];
OWSMessageSender *messageSender = [Environment current].messageSender;
TSOutgoingMessage *message = [ThreadUtil sendMessageWithText:text inThread:thread messageSender:messageSender];
DDLogError(@"%@ sendTextMessageInThread timestamp: %llu.", self.logTag, message.timestamp);
}
2018-03-23 15:19:04 +01:00
+ (void)sendNTextMessagesInThread:(TSThread *)thread
{
2018-03-23 15:19:04 +01:00
[self performActionNTimes:[self sendTextMessagesActionInThread:thread]];
}
2018-03-23 16:14:07 +01:00
+ (DebugUIMessagesAction *)sendTextMessagesActionInThread:(TSThread *)thread
2018-03-23 15:19:04 +01:00
{
OWSAssert(thread);
2018-03-23 22:49:46 +01:00
return [DebugUIMessagesSingleAction actionWithLabel:@"Send Text Message"
staggeredActionBlock:^(NSUInteger index,
YapDatabaseReadWriteTransaction *transaction,
ActionSuccessBlock success,
ActionFailureBlock failure) {
dispatch_async(dispatch_get_main_queue(), ^{
[self sendTextMessageInThread:thread counter:index];
// TODO:
success();
});
}];
2018-03-23 15:19:04 +01:00
}
+ (void)sendTinyTextMessageInThread:(TSThread *)thread counter:(NSUInteger)counter
{
NSString *randomText = [[self randomText] substringToIndex:arc4random_uniform(4)];
NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText];
OWSMessageSender *messageSender = [Environment current].messageSender;
[ThreadUtil sendMessageWithText:text inThread:thread messageSender:messageSender];
}
2018-03-23 15:19:04 +01:00
+ (void)sendTinyTextMessages:(NSUInteger)counter thread:(TSThread *)thread
{
if (counter < 1) {
return;
}
[self sendTinyTextMessageInThread:thread counter:counter];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self sendTinyTextMessages:counter - 1 thread:thread];
});
}
2018-03-23 22:49:46 +01:00
//+ (void)ensureRandomFileWithURL:(NSString *)url
// filename:(NSString *)filename
// success:(nullable void (^)(NSString *filePath))success
// failure:(nullable void (^)(void))failure
//{
// NSFileManager *fileManager = [NSFileManager defaultManager];
// NSURL *documentDirectoryURL =
// [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
// NSString *randomFilesDirectoryPath =
// [[documentDirectoryURL path] stringByAppendingPathComponent:@"cached_random_files"];
// [OWSFileSystem ensureDirectoryExists:randomFilesDirectoryPath];
// NSString *filePath = [randomFilesDirectoryPath stringByAppendingPathComponent:filename];
// if ([fileManager fileExistsAtPath:filePath]) {
// success(filePath);
// } else {
// NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
// AFHTTPSessionManager *sessionManager =
// [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
// sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
// OWSAssert(sessionManager.responseSerializer);
// [sessionManager GET:url
// parameters:nil
// progress:nil
// success:^(NSURLSessionDataTask *task, NSData *_Nullable responseObject) {
// if ([responseObject writeToFile:filePath atomically:YES]) {
// success(filePath);
// } else {
// OWSFail(@"Error write url response [%@]: %@", url, filePath);
// failure();
// }
// }
// failure:^(NSURLSessionDataTask *_Nullable task, NSError *requestError) {
// OWSFail(@"Error downloading url[%@]: %@", url, requestError);
// failure();
// }];
// }
//}
+ (void)sendAttachment:(NSString *)filePath
thread:(TSThread *)thread
2017-11-08 20:04:51 +01:00
success:(nullable void (^)(void))success
failure:(nullable void (^)(void))failure
{
OWSAssert(filePath);
OWSAssert(thread);
OWSMessageSender *messageSender = [Environment current].messageSender;
NSString *filename = [filePath lastPathComponent];
NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:filename.pathExtension];
2017-09-18 21:02:34 +02:00
DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath];
[dataSource setSourceFilename:filename];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType imageQuality:TSImageQualityOriginal];
if (arc4random_uniform(100) > 50) {
attachment.captionText = [self randomCaptionText];
}
OWSAssert(attachment);
if ([attachment hasError]) {
DDLogError(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]);
[DDLog flushLog];
}
OWSAssert(![attachment hasError]);
[ThreadUtil sendMessageWithAttachment:attachment inThread:thread messageSender:messageSender completion:nil];
success();
}
2018-03-23 16:14:07 +01:00
#pragma mark - Infrastructure
2018-03-23 14:40:49 +01:00
2018-03-23 16:14:07 +01:00
+ (void)performActionNTimes:(DebugUIMessagesAction *)action
{
2018-03-23 16:14:07 +01:00
OWSAssertIsOnMainThread();
OWSAssert(action);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"How many?"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
for (NSNumber *countValue in @[
@(1),
@(10),
@(100),
@(1 * 1000),
@(10 * 1000),
]) {
[alert addAction:[UIAlertAction actionWithTitle:countValue.stringValue
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *ignore) {
[action prepareAndPerformNTimes:countValue.unsignedIntegerValue];
}]];
}
[alert addAction:[OWSAlerts cancelAction]];
UIViewController *fromViewController = [[UIApplication sharedApplication] frontmostViewController];
[fromViewController presentViewController:alert animated:YES completion:nil];
2018-03-23 14:40:49 +01:00
}
2018-03-23 22:49:46 +01:00
#pragma mark - Send Media
2018-03-23 16:14:07 +01:00
2018-03-23 22:49:46 +01:00
//+ (void)sendSelectedMediaTypeInThread:(TSThread *)thread
2018-03-23 16:14:07 +01:00
//{
2018-03-23 22:49:46 +01:00
// OWSAssertIsOnMainThread() OWSAssert(thread);
//
// NSArray<DebugUIMessagesAction *> *actions = @[
// [self sendJpegAction:thread],
// [self sendGifAction:thread],
// [self sendMp3Action:thread],
// [self sendMp4Action:thread],
// [self sendRandomMediaAction:thread],
2018-03-23 16:14:07 +01:00
// ];
2018-03-23 22:49:46 +01:00
//
// UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Select Media Type"
// message:nil
// preferredStyle:UIAlertControllerStyleActionSheet];
// for (DebugUIMessagesAction *action in actions) {
// [alert addAction:[UIAlertAction actionWithTitle:action.label
// style:UIAlertActionStyleDefault
// handler:^(UIAlertAction *ignore) {
// [self performActionNTimes:action];
// }]];
// }
//
// [alert addAction:[OWSAlerts cancelAction]];
//
// UIViewController *fromViewController = [[UIApplication sharedApplication] frontmostViewController];
// [fromViewController presentViewController:alert animated:YES completion:nil];
2018-03-23 16:14:07 +01:00
//}
2018-03-23 22:49:46 +01:00
+ (NSArray<DebugUIMessagesAction *> *)allSendMediaActions:(TSThread *)thread
2018-03-23 14:40:49 +01:00
{
2018-03-23 22:49:46 +01:00
OWSAssert(thread);
2018-03-23 14:40:49 +01:00
2018-03-23 16:14:07 +01:00
NSArray<DebugUIMessagesAction *> *actions = @[
[self sendJpegAction:thread],
[self sendGifAction:thread],
[self sendMp3Action:thread],
[self sendMp4Action:thread],
];
2018-03-23 22:49:46 +01:00
return actions;
}
2018-03-23 16:14:07 +01:00
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)sendJpegAction:(TSThread *)thread
{
OWSAssert(thread);
2018-03-23 14:40:49 +01:00
2018-03-23 22:49:46 +01:00
return [self sendMediaAction:@"Send Jpeg" fakeAssetLoader:[FakeAssetLoader jpegInstance] thread:thread];
}
2018-03-23 14:40:49 +01:00
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)sendGifAction:(TSThread *)thread
{
OWSAssert(thread);
return [self sendMediaAction:@"Send Gif" fakeAssetLoader:[FakeAssetLoader gifInstance] thread:thread];
}
+ (DebugUIMessagesAction *)sendMp3Action:(TSThread *)thread
{
OWSAssert(thread);
return [self sendMediaAction:@"Send Mp3" fakeAssetLoader:[FakeAssetLoader mp3Instance] thread:thread];
}
+ (DebugUIMessagesAction *)sendMp4Action:(TSThread *)thread
{
OWSAssert(thread);
return [self sendMediaAction:@"Send Mp4" fakeAssetLoader:[FakeAssetLoader mp4Instance] thread:thread];
}
+ (DebugUIMessagesAction *)sendMediaAction:(NSString *)label
fakeAssetLoader:(FakeAssetLoader *)fakeAssetLoader
thread:(TSThread *)thread
{
OWSAssert(label.length > 0);
OWSAssert(fakeAssetLoader);
OWSAssert(thread);
return [DebugUIMessagesSingleAction
actionWithLabel:label
staggeredActionBlock:^(NSUInteger index,
YapDatabaseReadWriteTransaction *transaction,
ActionSuccessBlock success,
ActionFailureBlock failure) {
dispatch_async(dispatch_get_main_queue(), ^{
OWSAssert(fakeAssetLoader.filePath.length > 0);
[self sendAttachment:fakeAssetLoader.filePath thread:thread success:success failure:failure];
});
}
prepareBlock:fakeAssetLoader.prepareBlock];
}
+ (DebugUIMessagesAction *)sendAllMediaAction:(TSThread *)thread
{
OWSAssert(thread);
return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Send All Media"
subactions:[self allSendMediaActions:thread]];
}
2018-03-23 16:14:07 +01:00
+ (DebugUIMessagesAction *)sendRandomMediaAction:(TSThread *)thread
2018-03-23 14:57:22 +01:00
{
OWSAssert(thread);
2018-03-23 22:49:46 +01:00
return [DebugUIMessagesGroupAction randomGroupActionWithLabel:@"Send Random Media"
subactions:[self allSendMediaActions:thread]];
}
#pragma mark - Fake Outgoing Media
+ (DebugUIMessagesAction *)fakeOutgoingJpegAction:(TSThread *)thread
messageState:(TSOutgoingMessageState)messageState
hasCaption:(BOOL)hasCaption
{
OWSAssert(thread);
return [self fakeOutgoingMediaAction:@"Fake Outgoing Jpeg"
messageState:messageState
hasCaption:hasCaption
fakeAssetLoader:[FakeAssetLoader jpegInstance]
thread:thread];
}
+ (DebugUIMessagesAction *)fakeOutgoingGifAction:(TSThread *)thread
messageState:(TSOutgoingMessageState)messageState
hasCaption:(BOOL)hasCaption
{
OWSAssert(thread);
return [self fakeOutgoingMediaAction:@"Fake Outgoing Gif"
messageState:messageState
hasCaption:hasCaption
fakeAssetLoader:[FakeAssetLoader gifInstance]
thread:thread];
}
+ (DebugUIMessagesAction *)fakeOutgoingMp3Action:(TSThread *)thread
messageState:(TSOutgoingMessageState)messageState
hasCaption:(BOOL)hasCaption
{
OWSAssert(thread);
return [self fakeOutgoingMediaAction:@"Fake Outgoing Mp3"
messageState:messageState
hasCaption:hasCaption
fakeAssetLoader:[FakeAssetLoader mp3Instance]
thread:thread];
}
+ (DebugUIMessagesAction *)fakeOutgoingMp4Action:(TSThread *)thread
messageState:(TSOutgoingMessageState)messageState
hasCaption:(BOOL)hasCaption
{
OWSAssert(thread);
return [self fakeOutgoingMediaAction:@"Fake Outgoing Mp4"
messageState:messageState
hasCaption:hasCaption
fakeAssetLoader:[FakeAssetLoader mp4Instance]
thread:thread];
}
+ (DebugUIMessagesAction *)fakeOutgoingMediaAction:(NSString *)labelParam
messageState:(TSOutgoingMessageState)messageState
hasCaption:(BOOL)hasCaption
fakeAssetLoader:(FakeAssetLoader *)fakeAssetLoader
thread:(TSThread *)thread
{
OWSAssert(labelParam.length > 0);
OWSAssert(fakeAssetLoader);
OWSAssert(thread);
NSString *label = labelParam;
if (hasCaption) {
label = [label stringByAppendingString:@" 🔤"];
}
if (messageState == TSOutgoingMessageStateUnsent) {
label = [label stringByAppendingString:@" (Unsent)"];
} else if (messageState == TSOutgoingMessageStateAttemptingOut) {
label = [label stringByAppendingString:@" (Sending)"];
} else if (messageState == TSOutgoingMessageStateSentToService) {
label = [label stringByAppendingString:@" (Sent)"];
} else {
OWSFail(@"%@ unknown message state.", self.logTag)
}
return
[DebugUIMessagesSingleAction actionWithLabel:label
unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) {
OWSAssert(fakeAssetLoader.filePath.length > 0);
[self createFakeOutgoingMedia:index
messageState:messageState
hasCaption:hasCaption
fakeAssetLoader:fakeAssetLoader
thread:thread
transaction:transaction];
}
prepareBlock:fakeAssetLoader.prepareBlock];
}
+ (void)createFakeOutgoingMedia:(NSUInteger)index
messageState:(TSOutgoingMessageState)messageState
hasCaption:(BOOL)hasCaption
fakeAssetLoader:(FakeAssetLoader *)fakeAssetLoader
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(thread);
OWSAssert(fakeAssetLoader.filePath);
OWSAssert(transaction);
// Random time within last n years. Helpful for filling out a media gallery over time.
// double yearsMillis = 4.0 * kYearsInMs;
// uint64_t millisAgo = (uint64_t)(((double)arc4random() / ((double)0xffffffff)) * yearsMillis);
// uint64_t timestamp = [NSDate ows_millisecondTimeStamp] - millisAgo;
uint64_t timestamp = [NSDate ows_millisecondTimeStamp];
NSString *messageBody = nil;
if (hasCaption) {
messageBody = [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:[self randomText]];
if (hasCaption) {
messageBody = [messageBody stringByAppendingString:@" 🔤"];
}
if (messageState == TSOutgoingMessageStateUnsent) {
messageBody = [messageBody stringByAppendingString:@" (Unsent)"];
} else if (messageState == TSOutgoingMessageStateAttemptingOut) {
messageBody = [messageBody stringByAppendingString:@" (Sending)"];
} else if (messageState == TSOutgoingMessageStateSentToService) {
messageBody = [messageBody stringByAppendingString:@" (Sent)"];
} else {
OWSFail(@"%@ unknown message state.", self.logTag)
}
}
NSString *_Nullable randomCaption;
if (arc4random() % 2 == 2) {
randomCaption = [self randomText];
}
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:timestamp
inThread:thread
messageBody:randomCaption
isVoiceMessage:NO
expiresInSeconds:0];
[message setReceivedAtTimestamp:timestamp];
DataSource *dataSource = [DataSourcePath dataSourceWithFilePath:fakeAssetLoader.filePath];
NSString *filename = dataSource.sourceFilename;
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:fakeAssetLoader.mimeType
byteCount:(UInt32)dataSource.dataLength
sourceFilename:filename];
NSError *error;
BOOL success = [attachmentStream writeData:dataSource.data error:&error];
OWSAssert(success && !error);
[attachmentStream saveWithTransaction:transaction];
[message.attachmentIds addObject:attachmentStream.uniqueId];
if (filename) {
message.attachmentFilenameMap[attachmentStream.uniqueId] = filename;
}
[message saveWithTransaction:transaction];
[message updateWithMessageState:messageState transaction:transaction];
}
#pragma mark - Fake Incoming Media
+ (DebugUIMessagesAction *)fakeIncomingJpegAction:(TSThread *)thread
isAttachmentDownloaded:(BOOL)isAttachmentDownloaded
hasCaption:(BOOL)hasCaption
{
OWSAssert(thread);
return [self fakeIncomingMediaAction:@"Fake Incoming Jpeg"
isAttachmentDownloaded:isAttachmentDownloaded
hasCaption:hasCaption
fakeAssetLoader:[FakeAssetLoader jpegInstance]
thread:thread];
}
+ (DebugUIMessagesAction *)fakeIncomingGifAction:(TSThread *)thread
isAttachmentDownloaded:(BOOL)isAttachmentDownloaded
hasCaption:(BOOL)hasCaption
{
OWSAssert(thread);
return [self fakeIncomingMediaAction:@"Fake Incoming Gif"
isAttachmentDownloaded:isAttachmentDownloaded
hasCaption:hasCaption
fakeAssetLoader:[FakeAssetLoader gifInstance]
thread:thread];
}
+ (DebugUIMessagesAction *)fakeIncomingMp3Action:(TSThread *)thread
isAttachmentDownloaded:(BOOL)isAttachmentDownloaded
hasCaption:(BOOL)hasCaption
{
OWSAssert(thread);
return [self fakeIncomingMediaAction:@"Fake Incoming Mp3"
isAttachmentDownloaded:isAttachmentDownloaded
hasCaption:hasCaption
fakeAssetLoader:[FakeAssetLoader mp3Instance]
thread:thread];
}
+ (DebugUIMessagesAction *)fakeIncomingMp4Action:(TSThread *)thread
isAttachmentDownloaded:(BOOL)isAttachmentDownloaded
hasCaption:(BOOL)hasCaption
{
OWSAssert(thread);
return [self fakeIncomingMediaAction:@"Fake Incoming Mp4"
isAttachmentDownloaded:isAttachmentDownloaded
hasCaption:hasCaption
fakeAssetLoader:[FakeAssetLoader mp4Instance]
thread:thread];
}
+ (DebugUIMessagesAction *)fakeIncomingMediaAction:(NSString *)labelParam
isAttachmentDownloaded:(BOOL)isAttachmentDownloaded
hasCaption:(BOOL)hasCaption
fakeAssetLoader:(FakeAssetLoader *)fakeAssetLoader
thread:(TSThread *)thread
{
OWSAssert(labelParam.length > 0);
OWSAssert(fakeAssetLoader);
OWSAssert(thread);
NSString *label = labelParam;
if (hasCaption) {
label = [label stringByAppendingString:@" 🔤"];
}
if (isAttachmentDownloaded) {
label = [label stringByAppendingString:@" 👍"];
}
return
[DebugUIMessagesSingleAction actionWithLabel:label
unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) {
OWSAssert(fakeAssetLoader.filePath.length > 0);
[self createFakeIncomingMedia:index
isAttachmentDownloaded:isAttachmentDownloaded
hasCaption:hasCaption
fakeAssetLoader:fakeAssetLoader
thread:thread
transaction:transaction];
}
prepareBlock:fakeAssetLoader.prepareBlock];
}
+ (void)createFakeIncomingMedia:(NSUInteger)index
isAttachmentDownloaded:(BOOL)isAttachmentDownloaded
hasCaption:(BOOL)hasCaption
fakeAssetLoader:(FakeAssetLoader *)fakeAssetLoader
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(thread);
OWSAssert(fakeAssetLoader.filePath);
OWSAssert(transaction);
// // Random time within last n years. Helpful for filling out a media gallery over time.
// double yearsMillis = 4.0 * kYearsInMs;
// uint64_t millisAgo = (uint64_t)(((double)arc4random() / ((double)0xffffffff)) * yearsMillis);
// uint64_t timestamp = [NSDate ows_millisecondTimeStamp] - millisAgo;
NSString *messageBody = nil;
if (hasCaption) {
messageBody = [[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:[self randomText]];
if (hasCaption) {
messageBody = [messageBody stringByAppendingString:@" 🔤"];
}
if (isAttachmentDownloaded) {
messageBody = [messageBody stringByAppendingString:@" 👍"];
}
}
NSString *attachmentId;
if (isAttachmentDownloaded) {
DataSource *dataSource = [DataSourcePath dataSourceWithFilePath:fakeAssetLoader.filePath];
NSString *filename = dataSource.sourceFilename;
TSAttachmentStream *attachmentStream =
[[TSAttachmentStream alloc] initWithContentType:fakeAssetLoader.mimeType
byteCount:(UInt32)dataSource.dataLength
sourceFilename:filename];
NSError *error;
BOOL success = [attachmentStream writeData:dataSource.data error:&error];
OWSAssert(success && !error);
[attachmentStream saveWithTransaction:transaction];
attachmentId = attachmentStream.uniqueId;
} else {
UInt32 filesize = 64;
TSAttachmentPointer *pointer =
[[TSAttachmentPointer alloc] initWithServerId:237391539706350548
key:[self createRandomNSDataOfSize:filesize]
digest:nil
byteCount:filesize
contentType:fakeAssetLoader.mimeType
relay:@""
sourceFilename:fakeAssetLoader.filename
attachmentType:TSAttachmentTypeDefault];
pointer.state = TSAttachmentPointerStateFailed;
[pointer saveWithTransaction:transaction];
attachmentId = pointer.uniqueId;
}
TSIncomingMessage *message = [[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
authorId:@"+19174054215"
sourceDeviceId:0
messageBody:messageBody
attachmentIds:@[
attachmentId,
]
expiresInSeconds:0];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
}
#pragma mark - Fake Media
+ (NSArray<DebugUIMessagesAction *> *)allFakeMediaActions:(TSThread *)thread
{
OWSAssert(thread);
2018-03-23 16:14:07 +01:00
NSArray<DebugUIMessagesAction *> *actions = @[
2018-03-23 22:49:46 +01:00
// Outgoing
[self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateUnsent hasCaption:NO],
[self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateUnsent hasCaption:YES],
[self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateAttemptingOut hasCaption:NO],
[self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateAttemptingOut hasCaption:YES],
[self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateSentToService hasCaption:NO],
[self fakeOutgoingJpegAction:thread messageState:TSOutgoingMessageStateSentToService hasCaption:YES],
// Don't bother with multiple GIF states.
[self fakeOutgoingGifAction:thread messageState:TSOutgoingMessageStateSentToService hasCaption:NO],
//
[self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateAttemptingOut hasCaption:YES],
[self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateAttemptingOut hasCaption:NO],
[self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateUnsent hasCaption:NO],
[self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateUnsent hasCaption:YES],
[self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateSentToService hasCaption:NO],
[self fakeOutgoingMp3Action:thread messageState:TSOutgoingMessageStateSentToService hasCaption:YES],
//
[self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateAttemptingOut hasCaption:NO],
[self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateAttemptingOut hasCaption:YES],
[self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateUnsent hasCaption:NO],
[self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateUnsent hasCaption:YES],
[self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateSentToService hasCaption:NO],
[self fakeOutgoingMp4Action:thread messageState:TSOutgoingMessageStateSentToService hasCaption:YES],
// Incoming
[self fakeIncomingJpegAction:thread isAttachmentDownloaded:NO hasCaption:NO],
[self fakeIncomingJpegAction:thread isAttachmentDownloaded:YES hasCaption:NO],
[self fakeIncomingJpegAction:thread isAttachmentDownloaded:NO hasCaption:YES],
[self fakeIncomingJpegAction:thread isAttachmentDownloaded:YES hasCaption:YES],
// Don't bother with multiple GIF states.
[self fakeIncomingGifAction:thread isAttachmentDownloaded:YES hasCaption:NO],
//
[self fakeIncomingMp3Action:thread isAttachmentDownloaded:NO hasCaption:NO],
[self fakeIncomingMp3Action:thread isAttachmentDownloaded:YES hasCaption:NO],
[self fakeIncomingMp3Action:thread isAttachmentDownloaded:NO hasCaption:YES],
[self fakeIncomingMp3Action:thread isAttachmentDownloaded:YES hasCaption:YES],
//
[self fakeIncomingMp4Action:thread isAttachmentDownloaded:NO hasCaption:NO],
[self fakeIncomingMp4Action:thread isAttachmentDownloaded:YES hasCaption:NO],
[self fakeIncomingMp4Action:thread isAttachmentDownloaded:NO hasCaption:YES],
[self fakeIncomingMp4Action:thread isAttachmentDownloaded:YES hasCaption:YES],
2018-03-23 16:14:07 +01:00
];
2018-03-23 22:49:46 +01:00
return actions;
}
2018-03-23 16:14:07 +01:00
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)fakeAllMediaAction:(TSThread *)thread
{
OWSAssert(thread);
return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Fake All Media"
subactions:[self allFakeMediaActions:thread]];
2018-03-23 16:14:07 +01:00
}
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)fakeRandomMediaAction:(TSThread *)thread
2018-03-23 16:14:07 +01:00
{
OWSAssert(thread);
2018-03-23 22:49:46 +01:00
return [DebugUIMessagesGroupAction randomGroupActionWithLabel:@"Fake Random Media"
subactions:[self allFakeMediaActions:thread]];
}
#pragma mark - Send Text Messages
+ (DebugUIMessagesAction *)sendShortTextMessageAction:(TSThread *)thread
{
OWSAssert(thread);
return [DebugUIMessagesSingleAction actionWithLabel:@"Send Short Text Message"
staggeredActionBlock:^(NSUInteger index,
YapDatabaseReadWriteTransaction *transaction,
ActionSuccessBlock success,
ActionFailureBlock failure) {
dispatch_async(dispatch_get_main_queue(), ^{
[self sendTextMessageInThread:thread counter:index];
});
}];
}
+ (DebugUIMessagesAction *)sendOversizeTextMessageAction:(TSThread *)thread
{
OWSAssert(thread);
return [DebugUIMessagesSingleAction actionWithLabel:@"Send Oversize Text Message"
staggeredActionBlock:^(NSUInteger index,
YapDatabaseReadWriteTransaction *transaction,
ActionSuccessBlock success,
ActionFailureBlock failure) {
dispatch_async(dispatch_get_main_queue(), ^{
[self sendOversizeTextMessage:thread];
});
}];
}
+ (DebugUIMessagesAction *)sendMessageVariationsAction:(TSThread *)thread
{
OWSAssert(thread);
NSArray<DebugUIMessagesAction *> *actions = @[
[self sendShortTextMessageAction:thread],
[self sendOversizeTextMessageAction:thread],
];
return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Send Conversation Cell Variations" subactions:actions];
}
#pragma mark - Fake Text Messages
+ (DebugUIMessagesAction *)fakeShortIncomingTextMessageAction:(TSThread *)thread
{
OWSAssert(thread);
return [DebugUIMessagesSingleAction
actionWithLabel:@"Fake Short Incoming Text Message"
unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) {
NSString *messageBody =
[[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:[self randomText]];
TSIncomingMessage *message = [[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
authorId:@"+19174054215"
sourceDeviceId:0
messageBody:messageBody];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
2018-03-23 16:14:07 +01:00
}];
}
2018-03-23 14:57:22 +01:00
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)fakeIncomingTextMessageAction:(TSThread *)thread text:(NSString *)text
2018-03-23 16:14:07 +01:00
{
OWSAssert(thread);
2018-03-23 22:49:46 +01:00
return [DebugUIMessagesSingleAction
actionWithLabel:[NSString stringWithFormat:@"Fake Incoming Text Message (%@)", text]
unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) {
TSIncomingMessage *message = [[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
authorId:@"+19174054215"
sourceDeviceId:0
messageBody:text];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
2018-03-23 16:14:07 +01:00
}];
2018-03-23 14:57:22 +01:00
}
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)fakeOutgoingTextMessageAction:(TSThread *)thread
messageState:(TSOutgoingMessageState)messageState
text:(NSString *)text
{
2018-03-23 16:14:07 +01:00
OWSAssert(thread);
2018-03-23 14:40:49 +01:00
2018-03-23 22:49:46 +01:00
return [DebugUIMessagesSingleAction
actionWithLabel:[NSString stringWithFormat:@"Fake Incoming Text Message (%@)", text]
unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) {
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:text];
[message saveWithTransaction:transaction];
[message updateWithMessageState:messageState transaction:transaction];
2018-03-23 16:14:07 +01:00
}];
}
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)fakeShortOutgoingTextMessageAction:(TSThread *)thread
messageState:(TSOutgoingMessageState)messageState
{
2018-03-23 16:14:07 +01:00
OWSAssert(thread);
2018-03-23 14:40:49 +01:00
2018-03-23 22:49:46 +01:00
return [DebugUIMessagesSingleAction
actionWithLabel:@"Fake Short Incoming Text Message"
unstaggeredActionBlock:^(NSUInteger index, YapDatabaseReadWriteTransaction *transaction) {
NSString *messageBody =
[[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:[self randomText]];
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:messageBody];
[message saveWithTransaction:transaction];
[message updateWithMessageState:messageState transaction:transaction];
2018-03-23 16:14:07 +01:00
}];
}
2018-03-23 22:49:46 +01:00
+ (NSArray<DebugUIMessagesAction *> *)allFakeTextActions:(TSThread *)thread
{
2018-03-23 22:49:46 +01:00
OWSAssert(thread);
NSArray<DebugUIMessagesAction *> *actions = @[
[self fakeShortIncomingTextMessageAction:thread],
[self fakeIncomingTextMessageAction:thread text:@"Hi"],
[self fakeIncomingTextMessageAction:thread text:@"1⃣"],
[self fakeIncomingTextMessageAction:thread text:@"1⃣2⃣"],
[self fakeIncomingTextMessageAction:thread text:@"1⃣2⃣3⃣"],
[self fakeIncomingTextMessageAction:thread text:@"落"],
[self fakeIncomingTextMessageAction:thread text:@"﷽"],
[self fakeShortOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateUnsent],
[self fakeShortOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateAttemptingOut],
[self fakeShortOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSentToService],
[self fakeOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSentToService text:@"Hi"],
[self fakeOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSentToService text:@"1⃣"],
[self fakeOutgoingTextMessageAction:thread
messageState:TSOutgoingMessageStateSentToService
text:@"1⃣2⃣"],
[self fakeOutgoingTextMessageAction:thread
messageState:TSOutgoingMessageStateSentToService
text:@"1⃣2⃣3⃣"],
[self fakeOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSentToService text:@"1⃣"],
[self fakeOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSentToService text:@"落"],
[self fakeOutgoingTextMessageAction:thread messageState:TSOutgoingMessageStateSentToService text:@"﷽"],
];
return actions;
}
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)fakeAllTextAction:(TSThread *)thread
{
2018-03-23 22:49:46 +01:00
OWSAssert(thread);
return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Fake All Text"
subactions:[self allFakeTextActions:thread]];
}
2018-03-23 22:49:46 +01:00
+ (DebugUIMessagesAction *)fakeRandomTextAction:(TSThread *)thread
{
2018-03-23 22:49:46 +01:00
OWSAssert(thread);
return [DebugUIMessagesGroupAction randomGroupActionWithLabel:@"Fake Random Text"
subactions:[self allFakeTextActions:thread]];
}
2018-03-23 22:49:46 +01:00
#pragma mark - Exemplary
+ (DebugUIMessagesAction *)allExemplaryAction:(TSThread *)thread
{
2018-03-23 22:49:46 +01:00
OWSAssert(thread);
NSMutableArray<DebugUIMessagesAction *> *actions = [NSMutableArray new];
[actions addObjectsFromArray:[self allFakeMediaActions:thread]];
[actions addObjectsFromArray:[self allFakeTextActions:thread]];
return [DebugUIMessagesGroupAction allGroupActionWithLabel:@"Exemplary Permutations" subactions:actions];
}
2018-03-23 22:49:46 +01:00
#pragma mark -
+ (void)sendOversizeTextMessage:(TSThread *)thread
{
OWSMessageSender *messageSender = [Environment current].messageSender;
NSMutableString *message = [NSMutableString new];
2018-03-23 15:19:04 +01:00
for (NSUInteger i = 0; i < 32; i++) {
[message appendString:@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse rutrum, nulla "
@"vitae pretium hendrerit, tellus turpis pharetra libero, vitae sodales tortor ante vel "
@"sem. Fusce sed nisl a lorem gravida tincidunt. Suspendisse efficitur non quam ac "
@"sodales. Aenean ut velit maximus, posuere sem a, accumsan nunc. Donec ullamcorper "
@"turpis lorem. Quisque dignissim purus eu placerat ultricies. Proin at urna eget mi "
@"semper congue. Aenean non elementum ex. Praesent pharetra quam at sem vestibulum, "
@"vestibulum ornare dolor elementum. Vestibulum massa tortor, scelerisque sit amet "
@"pulvinar a, rhoncus vitae nisl. Sed mi nunc, tempus at varius in, malesuada vitae "
@"dui. Vivamus efficitur pulvinar erat vitae congue. Proin vehicula turpis non felis "
@"congue facilisis. Nullam aliquet dapibus ligula ac mollis. Etiam sit amet posuere "
@"lorem, in rhoncus nisi.\n\n"];
}
2017-09-18 21:02:34 +02:00
DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:message];
2017-09-08 16:28:21 +02:00
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:kOversizeTextAttachmentUTI];
[ThreadUtil sendMessageWithAttachment:attachment inThread:thread messageSender:messageSender completion:nil];
}
+ (NSData *)createRandomNSDataOfSize:(size_t)size
{
OWSAssert(size % 4 == 0);
2018-03-23 14:40:49 +01:00
return [Randomness generateRandomBytes:(int)size];
}
+ (void)sendRandomAttachment:(TSThread *)thread uti:(NSString *)uti
{
[self sendRandomAttachment:thread uti:uti length:256];
}
+ (NSString *)randomCaptionText
{
return [NSString stringWithFormat:@"%@ (caption)", [self randomText]];
}
+ (void)sendRandomAttachment:(TSThread *)thread uti:(NSString *)uti length:(NSUInteger)length
{
OWSMessageSender *messageSender = [Environment current].messageSender;
2017-09-18 21:02:34 +02:00
DataSource *_Nullable dataSource =
[DataSourceValue dataSourceWithData:[self createRandomNSDataOfSize:length] utiType:uti];
2017-12-18 23:48:07 +01:00
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:uti imageQuality:TSImageQualityOriginal];
if (arc4random_uniform(100) > 50) {
// give 1/2 our attachments captions, and add a hint that it's a caption since we
// style them indistinguishably from a separate text message.
attachment.captionText = [self randomCaptionText];
}
[ThreadUtil sendMessageWithAttachment:attachment
inThread:thread
messageSender:messageSender
ignoreErrors:YES
completion:nil];
}
2018-03-23 22:49:46 +01:00
+ (OWSSignalServiceProtosEnvelope *)createEnvelopeForThread:(TSThread *)thread
{
OWSAssert(thread);
OWSSignalServiceProtosEnvelopeBuilder *builder = [OWSSignalServiceProtosEnvelopeBuilder new];
if ([thread isKindOfClass:[TSGroupThread class]]) {
TSGroupThread *gThread = (TSGroupThread *)thread;
[builder setSource:gThread.groupModel.groupMemberIds[0]];
} else if ([thread isKindOfClass:[TSContactThread class]]) {
TSContactThread *contactThread = (TSContactThread *)thread;
[builder setSource:contactThread.contactIdentifier];
}
return [builder build];
}
+ (NSArray<TSInteraction *> *)unsavedSystemMessagesInThread:(TSThread *)thread
{
OWSAssert(thread);
NSMutableArray<TSInteraction *> *result = [NSMutableArray new];
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
if ([thread isKindOfClass:[TSContactThread class]]) {
TSContactThread *contactThread = (TSContactThread *)thread;
[result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
withCallNumber:@"+19174054215"
callType:RPRecentCallTypeIncoming
inThread:contactThread]];
[result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
withCallNumber:@"+19174054215"
callType:RPRecentCallTypeOutgoing
inThread:contactThread]];
[result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
withCallNumber:@"+19174054215"
callType:RPRecentCallTypeMissed
inThread:contactThread]];
[result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
withCallNumber:@"+19174054215"
callType:RPRecentCallTypeMissedBecauseOfChangedIdentity
inThread:contactThread]];
[result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
withCallNumber:@"+19174054215"
callType:RPRecentCallTypeOutgoingIncomplete
inThread:contactThread]];
[result addObject:[[TSCall alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
withCallNumber:@"+19174054215"
callType:RPRecentCallTypeIncomingIncomplete
inThread:contactThread]];
}
{
NSNumber *durationSeconds = [OWSDisappearingMessagesConfiguration validDurationsSeconds][0];
OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration =
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
enabled:YES
durationSeconds:(uint32_t)[durationSeconds intValue]];
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
configuration:disappearingMessagesConfiguration
createdByRemoteName:@"Alice"]];
}
{
NSNumber *durationSeconds = [[OWSDisappearingMessagesConfiguration validDurationsSeconds] lastObject];
OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration =
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
enabled:YES
durationSeconds:(uint32_t)[durationSeconds intValue]];
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
configuration:disappearingMessagesConfiguration
createdByRemoteName:@"Alice"]];
}
{
OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration =
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
enabled:NO
durationSeconds:0];
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
configuration:disappearingMessagesConfiguration
createdByRemoteName:@"Alice"]];
}
[result addObject:[TSInfoMessage userNotRegisteredMessageInThread:thread]];
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageType:TSInfoMessageTypeSessionDidEnd]];
// TODO: customMessage?
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageType:TSInfoMessageTypeGroupUpdate]];
// TODO: customMessage?
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageType:TSInfoMessageTypeGroupQuit]];
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
recipientId:@"+19174054215"
verificationState:OWSVerificationStateDefault
isLocalChange:YES]];
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
recipientId:@"+19174054215"
verificationState:OWSVerificationStateVerified
isLocalChange:YES]];
[result
addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
recipientId:@"+19174054215"
verificationState:OWSVerificationStateNoLongerVerified
isLocalChange:YES]];
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
recipientId:@"+19174054215"
verificationState:OWSVerificationStateDefault
isLocalChange:NO]];
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
recipientId:@"+19174054215"
verificationState:OWSVerificationStateVerified
isLocalChange:NO]];
[result
addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
recipientId:@"+19174054215"
verificationState:OWSVerificationStateNoLongerVerified
isLocalChange:NO]];
[result addObject:[TSErrorMessage missingSessionWithEnvelope:[self createEnvelopeForThread:thread]
withTransaction:transaction]];
[result addObject:[TSErrorMessage invalidKeyExceptionWithEnvelope:[self createEnvelopeForThread:thread]
withTransaction:transaction]];
[result addObject:[TSErrorMessage invalidVersionWithEnvelope:[self createEnvelopeForThread:thread]
withTransaction:transaction]];
[result addObject:[TSInvalidIdentityKeyReceivingErrorMessage
untrustedKeyWithEnvelope:[self createEnvelopeForThread:thread]
withTransaction:transaction]];
[result addObject:[TSErrorMessage corruptedMessageWithEnvelope:[self createEnvelopeForThread:thread]
withTransaction:transaction]];
[result addObject:[[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
failedMessageType:TSErrorMessageNonBlockingIdentityChange
recipientId:@"+19174054215"]];
}];
return result;
}
+ (void)createSystemMessagesInThread:(TSThread *)thread
{
OWSAssert(thread);
NSArray<TSInteraction *> *messages = [self unsavedSystemMessagesInThread:thread];
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2017-12-19 03:34:22 +01:00
for (TSInteraction *message in messages) {
[message saveWithTransaction:transaction];
}
}];
}
+ (void)createSystemMessageInThread:(TSThread *)thread
{
OWSAssert(thread);
NSArray<TSInteraction *> *messages = [self unsavedSystemMessagesInThread:thread];
TSInteraction *message = messages[(NSUInteger)arc4random_uniform((uint32_t)messages.count)];
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2017-12-19 03:34:22 +01:00
[message saveWithTransaction:transaction];
}];
}
2018-03-23 15:19:04 +01:00
+ (void)sendTextAndSystemMessages:(NSUInteger)counter thread:(TSThread *)thread
{
if (counter < 1) {
return;
}
if (arc4random_uniform(2) == 0) {
[self sendTextMessageInThread:thread counter:counter];
} else {
[self createSystemMessageInThread:thread];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self sendTextAndSystemMessages:counter - 1 thread:thread];
});
}
+ (NSString *)randomText
{
NSArray<NSString *> *randomTexts = @[
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. ",
(@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
@"Suspendisse rutrum, nulla vitae pretium hendrerit, tellus "
@"turpis pharetra libero, vitae sodales tortor ante vel sem."),
@"In a time of universal deceit - telling the truth is a revolutionary act.",
@"If you want a vision of the future, imagine a boot stamping on a human face - forever.",
@"Who controls the past controls the future. Who controls the present controls the past.",
@"All animals are equal, but some animals are more equal than others.",
@"War is peace. Freedom is slavery. Ignorance is strength.",
(@"All the war-propaganda, all the screaming and lies and hatred, comes invariably from people who are not "
@"fighting."),
(@"Political language. . . is designed to make lies sound truthful and murder respectable, and to give an "
@"appearance of solidity to pure wind."),
(@"The nationalist not only does not disapprove of atrocities committed by his own side, but he has a "
@"remarkable capacity for not even hearing about them."),
(@"Every generation imagines itself to be more intelligent than the one that went before it, and wiser than "
@"the "
@"one that comes after it."),
@"War against a foreign country only happens when the moneyed classes think they are going to profit from it.",
@"People have only as much liberty as they have the intelligence to want and the courage to take.",
2017-07-07 10:36:16 +02:00
(@"You cannot buy the revolution. You cannot make the revolution. You can only be the revolution. It is in your "
@"spirit, or it is nowhere."),
(@"That is what I have always understood to be the essence of anarchism: the conviction that the burden of "
@"proof has to be placed on authority, and that it should be dismantled if that burden cannot be met."),
(@"Ask for work. If they don't give you work, ask for bread. If they do not give you work or bread, then take "
@"bread."),
@"Every society has the criminals it deserves.",
2017-07-07 10:36:16 +02:00
(@"Anarchism is founded on the observation that since few men are wise enough to rule themselves, even fewer "
@"are wise enough to rule others."),
@"If you would know who controls you see who you may not criticise.",
@"At one time in the world there were woods that no one owned."
];
NSString *randomText = randomTexts[(NSUInteger)arc4random_uniform((uint32_t)randomTexts.count)];
return randomText;
}
2018-03-23 15:19:04 +01:00
+ (void)createFakeUnreadMessages:(NSUInteger)counter thread:(TSThread *)thread
{
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2018-03-23 15:19:04 +01:00
for (NSUInteger i = 0; i < counter; i++) {
NSString *randomText = [self randomText];
TSIncomingMessage *message = [[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
authorId:@"+19174054215"
sourceDeviceId:0
messageBody:randomText];
[message saveWithTransaction:transaction];
}
}];
}
+ (void)createFakeThreads:(NSUInteger)threadCount withFakeMessages:(NSUInteger)messageCount
{
[DebugUIContacts
createRandomContacts:threadCount
contactHandler:^(CNContact *_Nonnull contact, NSUInteger idx, BOOL *_Nonnull stop) {
NSString *phoneNumberText = contact.phoneNumbers.firstObject.value.stringValue;
OWSAssert(phoneNumberText);
PhoneNumber *phoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:phoneNumberText];
OWSAssert(phoneNumber);
OWSAssert(phoneNumber.toE164);
TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:phoneNumber.toE164];
[self sendFakeMessages:messageCount thread:contactThread];
2017-09-01 20:30:39 +02:00
DDLogError(@"Create fake thread: %@, interactions: %zd",
phoneNumber.toE164,
contactThread.numberOfInteractions);
}];
}
+ (void)sendFakeMessages:(NSUInteger)counter thread:(TSThread *)thread
{
2018-01-29 16:11:19 +01:00
[self sendFakeMessages:counter thread:thread isTextOnly:NO];
}
+ (void)sendFakeMessages:(NSUInteger)counter thread:(TSThread *)thread isTextOnly:(BOOL)isTextOnly
{
const NSUInteger kMaxBatchSize = 2500;
if (counter < kMaxBatchSize) {
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2018-01-29 16:11:19 +01:00
[self sendFakeMessages:counter thread:thread isTextOnly:isTextOnly transaction:transaction];
}];
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSUInteger remainder = counter;
while (remainder > 0) {
NSUInteger batchSize = MIN(kMaxBatchSize, remainder);
[OWSPrimaryStorage.dbReadWriteConnection
2018-01-29 16:11:19 +01:00
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self sendFakeMessages:batchSize thread:thread isTextOnly:isTextOnly transaction:transaction];
}];
remainder -= batchSize;
DDLogInfo(@"%@ sendFakeMessages %zd / %zd", self.logTag, counter - remainder, counter);
}
});
2018-01-26 23:31:45 +01:00
}
}
+ (void)sendFakeMessages:(NSUInteger)counter
thread:(TSThread *)thread
2018-01-29 16:11:19 +01:00
isTextOnly:(BOOL)isTextOnly
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
DDLogInfo(@"%@ sendFakeMessages: %zd", self.logTag, counter);
for (NSUInteger i = 0; i < counter; i++) {
NSString *randomText = [self randomText];
2018-01-29 16:11:19 +01:00
switch (arc4random_uniform(isTextOnly ? 2 : 4)) {
case 0: {
TSIncomingMessage *message =
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
authorId:@"+19174054215"
sourceDeviceId:0
messageBody:randomText];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
break;
}
case 1: {
TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:randomText];
[message saveWithTransaction:transaction];
2018-01-26 23:46:49 +01:00
[message updateWithMessageState:TSOutgoingMessageStateUnsent transaction:transaction];
break;
}
case 2: {
UInt32 filesize = 64;
TSAttachmentPointer *pointer =
[[TSAttachmentPointer alloc] initWithServerId:237391539706350548
key:[self createRandomNSDataOfSize:filesize]
digest:nil
byteCount:filesize
contentType:@"audio/mp3"
relay:@""
sourceFilename:@"test.mp3"
attachmentType:TSAttachmentTypeDefault];
2018-01-29 16:11:19 +01:00
pointer.state = TSAttachmentPointerStateFailed;
[pointer saveWithTransaction:transaction];
TSIncomingMessage *message =
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
authorId:@"+19174054215"
sourceDeviceId:0
messageBody:nil
attachmentIds:@[
pointer.uniqueId,
]
expiresInSeconds:0];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
break;
}
case 3: {
TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:nil
isVoiceMessage:NO
expiresInSeconds:0];
NSString *filename = @"test.mp3";
UInt32 filesize = 16;
TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3"
byteCount:filesize
sourceFilename:filename];
NSError *error;
BOOL success = [attachmentStream writeData:[self createRandomNSDataOfSize:filesize] error:&error];
OWSAssert(success && !error);
[attachmentStream saveWithTransaction:transaction];
[message.attachmentIds addObject:attachmentStream.uniqueId];
if (filename) {
message.attachmentFilenameMap[attachmentStream.uniqueId] = filename;
}
[message saveWithTransaction:transaction];
2018-01-26 23:46:49 +01:00
[message updateWithMessageState:TSOutgoingMessageStateUnsent transaction:transaction];
break;
}
}
}
}
2018-03-23 22:49:46 +01:00
#pragma mark -
2018-03-16 15:31:26 +01:00
2018-03-23 15:19:04 +01:00
+ (void)createFakeLargeOutgoingAttachments:(NSUInteger)counter thread:(TSThread *)thread
{
if (counter < 1) {
return;
}
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:nil
isVoiceMessage:NO
expiresInSeconds:0];
DDLogError(@"%@ sendFakeMessages outgoing attachment timestamp: %llu.", self.logTag, message.timestamp);
NSString *filename = @"test.mp3";
UInt32 filesize = 8 * 1024 * 1024;
TSAttachmentStream *attachmentStream =
[[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" byteCount:filesize sourceFilename:filename];
NSError *error;
BOOL success = [attachmentStream writeData:[self createRandomNSDataOfSize:filesize] error:&error];
OWSAssert(success && !error);
[attachmentStream saveWithTransaction:transaction];
[message.attachmentIds addObject:attachmentStream.uniqueId];
if (filename) {
message.attachmentFilenameMap[attachmentStream.uniqueId] = filename;
}
[message updateWithMessageState:TSOutgoingMessageStateUnsent transaction:transaction];
[message saveWithTransaction:transaction];
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self createFakeLargeOutgoingAttachments:counter - 1 thread:thread];
});
}
2018-03-23 15:19:04 +01:00
+ (void)sendTinyAttachments:(NSUInteger)counter thread:(TSThread *)thread
{
if (counter < 1) {
return;
}
NSArray<NSString *> *utis = @[
(NSString *)kUTTypePDF,
(NSString *)kUTTypeMP3,
(NSString *)kUTTypeGIF,
(NSString *)kUTTypeMPEG4,
(NSString *)kUTTypeJPEG,
];
NSString *uti = utis[(NSUInteger)arc4random_uniform((uint32_t)utis.count)];
[self sendRandomAttachment:thread uti:uti length:16];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self sendTinyAttachments:counter - 1 thread:thread];
});
}
2018-03-23 15:19:04 +01:00
+ (void)createNewGroups:(NSUInteger)counter recipientId:(NSString *)recipientId
{
if (counter < 1) {
return;
}
NSString *groupName = [NSUUID UUID].UUIDString;
NSMutableArray<NSString *> *recipientIds = [@[
recipientId,
[TSAccountManager localNumber],
] mutableCopy];
NSData *groupId = [SecurityUtils generateRandomBytes:16];
TSGroupModel *groupModel =
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];
__block TSGroupThread *thread;
[OWSPrimaryStorage.dbReadWriteConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
}];
OWSAssert(thread);
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
groupMetaMessage:TSGroupMessageNew];
[message updateWithCustomMessage:NSLocalizedString(@"GROUP_CREATED", nil)];
OWSMessageSender *messageSender = [Environment current].messageSender;
2017-11-08 20:04:51 +01:00
void (^completion)(void) = ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[ThreadUtil sendMessageWithText:[@(counter) description] inThread:thread messageSender:messageSender];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)1.f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self createNewGroups:counter - 1 recipientId:recipientId];
});
});
};
2017-11-15 19:21:31 +01:00
[messageSender enqueueMessage:message
success:completion
failure:^(NSError *error) {
completion();
}];
}
2018-03-23 15:19:04 +01:00
+ (void)injectFakeIncomingMessages:(NSUInteger)counter thread:(TSThread *)thread
{
// Wait 5 seconds so debug user has time to navigate to another
// view before message processing occurs.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.f * NSEC_PER_SEC)),
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
2018-03-23 15:19:04 +01:00
for (NSUInteger i = 0; i < counter; i++) {
2017-10-19 07:46:19 +02:00
[self injectIncomingMessageInThread:thread counter:counter - i];
}
});
}
2018-03-23 15:19:04 +01:00
+ (void)injectIncomingMessageInThread:(TSThread *)thread counter:(NSUInteger)counter
{
OWSAssert(thread);
2018-03-23 15:19:04 +01:00
DDLogInfo(@"%@ injectIncomingMessageInThread: %zd", self.logTag, counter);
NSString *randomText = [self randomText];
NSString *text = [[[@(counter) description] stringByAppendingString:@" "] stringByAppendingString:randomText];
OWSSignalServiceProtosDataMessageBuilder *dataMessageBuilder = [OWSSignalServiceProtosDataMessageBuilder new];
[dataMessageBuilder setBody:text];
if ([thread isKindOfClass:[TSGroupThread class]]) {
TSGroupThread *groupThread = (TSGroupThread *)thread;
OWSSignalServiceProtosGroupContextBuilder *groupBuilder = [OWSSignalServiceProtosGroupContextBuilder new];
[groupBuilder setType:OWSSignalServiceProtosGroupContextTypeDeliver];
[groupBuilder setId:groupThread.groupModel.groupId];
[dataMessageBuilder setGroup:groupBuilder.build];
}
OWSSignalServiceProtosContentBuilder *payloadBuilder = [OWSSignalServiceProtosContentBuilder new];
[payloadBuilder setDataMessage:dataMessageBuilder.build];
NSData *plaintextData = [payloadBuilder build].data;
2017-10-18 17:50:47 +02:00
// Try to use an arbitrary member of the current thread that isn't
// ourselves as the sender.
NSString *_Nullable recipientId = [[thread recipientIdentifiers] firstObject];
// This might be an "empty" group with no other members. If so, use a fake
// sender id.
2017-10-19 07:46:19 +02:00
if (!recipientId) {
recipientId = @"+12345678901";
}
2017-10-18 17:50:47 +02:00
OWSSignalServiceProtosEnvelopeBuilder *envelopeBuilder = [OWSSignalServiceProtosEnvelopeBuilder new];
[envelopeBuilder setType:OWSSignalServiceProtosEnvelopeTypeCiphertext];
2017-10-18 17:50:47 +02:00
[envelopeBuilder setSource:recipientId];
[envelopeBuilder setSourceDevice:1];
[envelopeBuilder setTimestamp:[NSDate ows_millisecondTimeStamp]];
[envelopeBuilder setContent:plaintextData];
NSData *envelopeData = [envelopeBuilder build].data;
OWSAssert(envelopeData);
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2018-01-30 21:49:36 +01:00
[[OWSBatchMessageProcessor sharedInstance] enqueueEnvelopeData:envelopeData
plaintextData:plaintextData
transaction:transaction];
}];
}
2018-03-23 15:19:04 +01:00
+ (void)performRandomActions:(NSUInteger)counter thread:(TSThread *)thread
2017-11-15 18:10:29 +01:00
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[self performRandomActionInThread:thread counter:counter];
if (counter > 0) {
[self performRandomActions:counter - 1 thread:thread];
}
});
}
2018-03-23 16:14:07 +01:00
//+ (ActionBlock)sendTextMessagesActionInThread:(TSThread *)thread
//{
// OWSAssert(thread);
//
// return ^(NSUInteger index, ActionSuccessBlock success, ActionFailureBlock failure) {
// [self sendTextMessageInThread:thread counter:index];
// // TODO:
// success();
// };
//}
//
//+ (void)performRandomActionInThread:(TSThread *)thread counter:(NSUInteger)counter
//{
//}
2018-03-23 15:19:04 +01:00
+ (void)performRandomActionInThread:(TSThread *)thread counter:(NSUInteger)counter
2017-11-15 18:10:29 +01:00
{
2018-03-23 16:14:07 +01:00
typedef void (^TransactionBlock)(YapDatabaseReadWriteTransaction *transaction);
NSArray<TransactionBlock> *actionBlocks = @[
^(YapDatabaseReadWriteTransaction *transaction) {
// injectIncomingMessageInThread doesn't take a transaction.
dispatch_async(dispatch_get_main_queue(), ^{
[self injectIncomingMessageInThread:thread counter:counter];
});
2017-11-15 18:31:57 +01:00
},
^(YapDatabaseReadWriteTransaction *transaction) {
// sendTextMessageInThread doesn't take a transaction.
dispatch_async(dispatch_get_main_queue(), ^{
[self sendTextMessageInThread:thread counter:counter];
});
2017-11-15 18:31:57 +01:00
},
^(YapDatabaseReadWriteTransaction *transaction) {
2017-11-15 18:31:57 +01:00
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
2018-01-29 16:11:19 +01:00
[self sendFakeMessages:messageCount thread:thread isTextOnly:NO transaction:transaction];
2017-11-15 18:31:57 +01:00
},
^(YapDatabaseReadWriteTransaction *transaction) {
2017-11-15 18:31:57 +01:00
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
[self deleteRandomMessages:messageCount thread:thread transaction:transaction];
2017-11-15 18:31:57 +01:00
},
^(YapDatabaseReadWriteTransaction *transaction) {
2017-11-15 18:31:57 +01:00
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
[self deleteLastMessages:messageCount thread:thread transaction:transaction];
2017-11-15 18:31:57 +01:00
},
^(YapDatabaseReadWriteTransaction *transaction) {
2017-11-15 18:31:57 +01:00
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
[self deleteRandomRecentMessages:messageCount thread:thread transaction:transaction];
2017-11-15 18:31:57 +01:00
},
^(YapDatabaseReadWriteTransaction *transaction) {
2017-11-15 18:31:57 +01:00
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
[self insertAndDeleteNewOutgoingMessages:messageCount thread:thread transaction:transaction];
2017-11-15 18:31:57 +01:00
},
^(YapDatabaseReadWriteTransaction *transaction) {
2017-11-15 18:31:57 +01:00
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
[self resurrectNewOutgoingMessages1:messageCount thread:thread transaction:transaction];
2017-11-15 18:31:57 +01:00
},
^(YapDatabaseReadWriteTransaction *transaction) {
2017-11-15 18:31:57 +01:00
NSUInteger messageCount = (NSUInteger)(1 + arc4random_uniform(4));
[self resurrectNewOutgoingMessages2:messageCount thread:thread transaction:transaction];
2017-11-15 18:31:57 +01:00
},
];
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2018-03-23 15:19:04 +01:00
NSUInteger actionCount = 1 + (NSUInteger)arc4random_uniform(3);
for (NSUInteger actionIdx = 0; actionIdx < actionCount; actionIdx++) {
2018-03-23 16:14:07 +01:00
TransactionBlock actionBlock = actionBlocks[(NSUInteger)arc4random_uniform((uint32_t)actionBlocks.count)];
2017-12-19 03:34:22 +01:00
actionBlock(transaction);
}
}];
2017-11-15 18:10:29 +01:00
}
+ (void)deleteRandomMessages:(NSUInteger)count
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)transaction
2017-11-15 18:10:29 +01:00
{
2017-11-15 18:31:57 +01:00
DDLogInfo(@"%@ deleteRandomMessages: %zd", self.logTag, count);
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
NSUInteger messageCount = [interactionsByThread numberOfItemsInGroup:thread.uniqueId];
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
for (NSUInteger messageIdx = 0; messageIdx < messageCount; messageIdx++) {
[messageIndices addObject:@(messageIdx)];
}
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
for (NSUInteger i = 0; i < count && messageIndices.count > 0; i++) {
NSUInteger idx = (NSUInteger)arc4random_uniform((uint32_t)messageIndices.count);
NSNumber *messageIdx = messageIndices[idx];
[messageIndices removeObjectAtIndex:idx];
TSInteraction *_Nullable interaction =
2017-11-15 18:10:29 +01:00
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
OWSAssert(interaction);
[interactions addObject:interaction];
}
for (TSInteraction *interaction in interactions) {
[interaction removeWithTransaction:transaction];
}
2017-11-15 18:10:29 +01:00
}
+ (void)deleteLastMessages:(NSUInteger)count
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)transaction
2017-11-15 18:10:29 +01:00
{
2017-11-15 18:31:57 +01:00
DDLogInfo(@"%@ deleteLastMessages", self.logTag);
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
NSUInteger messageCount = (NSUInteger)[interactionsByThread numberOfItemsInGroup:thread.uniqueId];
2017-11-15 18:31:57 +01:00
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
for (NSUInteger i = 0; i < count && i < messageCount; i++) {
NSUInteger messageIdx = messageCount - (1 + i);
[messageIndices addObject:@(messageIdx)];
}
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
for (NSNumber *messageIdx in messageIndices) {
TSInteraction *_Nullable interaction =
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
OWSAssert(interaction);
[interactions addObject:interaction];
}
for (TSInteraction *interaction in interactions) {
[interaction removeWithTransaction:transaction];
}
2017-11-15 18:10:29 +01:00
}
+ (void)deleteRandomRecentMessages:(NSUInteger)count
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)transaction
2017-11-15 18:10:29 +01:00
{
2017-11-15 18:31:57 +01:00
DDLogInfo(@"%@ deleteRandomRecentMessages: %zd", self.logTag, count);
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
NSInteger messageCount = (NSInteger)[interactionsByThread numberOfItemsInGroup:thread.uniqueId];
NSMutableArray<NSNumber *> *messageIndices = [NSMutableArray new];
const NSInteger kRecentMessageCount = 10;
for (NSInteger i = 0; i < kRecentMessageCount; i++) {
NSInteger messageIdx = messageCount - (1 + i);
if (messageIdx >= 0) {
[messageIndices addObject:@(messageIdx)];
2017-11-15 18:10:29 +01:00
}
}
NSMutableArray<TSInteraction *> *interactions = [NSMutableArray new];
for (NSUInteger i = 0; i < count && messageIndices.count > 0; i++) {
NSUInteger idx = (NSUInteger)arc4random_uniform((uint32_t)messageIndices.count);
NSNumber *messageIdx = messageIndices[idx];
[messageIndices removeObjectAtIndex:idx];
TSInteraction *_Nullable interaction =
2017-11-15 18:10:29 +01:00
[interactionsByThread objectAtIndex:messageIdx.unsignedIntegerValue inGroup:thread.uniqueId];
OWSAssert(interaction);
[interactions addObject:interaction];
}
for (TSInteraction *interaction in interactions) {
[interaction removeWithTransaction:transaction];
}
2017-11-15 18:10:29 +01:00
}
+ (void)insertAndDeleteNewOutgoingMessages:(NSUInteger)count
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)transaction
2017-11-15 18:10:29 +01:00
{
2017-11-15 18:31:57 +01:00
DDLogInfo(@"%@ insertAndDeleteNewOutgoingMessages: %zd", self.logTag, count);
2017-11-15 18:10:29 +01:00
NSMutableArray<TSOutgoingMessage *> *messages = [NSMutableArray new];
for (NSUInteger i =0; i < count; i++) {
NSString *text = [self randomText];
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId transaction:transaction];
2017-11-15 18:10:29 +01:00
TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:text
attachmentIds:[NSMutableArray new]
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
DDLogError(@"%@ insertAndDeleteNewOutgoingMessages timestamp: %llu.", self.logTag, message.timestamp);
2017-11-15 18:10:29 +01:00
[messages addObject:message];
}
for (TSOutgoingMessage *message in messages) {
[message saveWithTransaction:transaction];
}
for (TSOutgoingMessage *message in messages) {
[message removeWithTransaction:transaction];
}
2017-11-15 18:10:29 +01:00
}
+ (void)resurrectNewOutgoingMessages1:(NSUInteger)count
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)initialTransaction
2017-11-15 18:10:29 +01:00
{
2017-11-15 18:31:57 +01:00
DDLogInfo(@"%@ resurrectNewOutgoingMessages1.1: %zd", self.logTag, count);
2017-11-15 18:10:29 +01:00
NSMutableArray<TSOutgoingMessage *> *messages = [NSMutableArray new];
for (NSUInteger i =0; i < count; i++) {
NSString *text = [self randomText];
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId
transaction:initialTransaction];
2017-11-15 18:10:29 +01:00
TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:text
attachmentIds:[NSMutableArray new]
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
DDLogError(@"%@ resurrectNewOutgoingMessages1 timestamp: %llu.", self.logTag, message.timestamp);
2017-11-15 18:10:29 +01:00
[messages addObject:message];
}
for (TSOutgoingMessage *message in messages) {
[message saveWithTransaction:initialTransaction];
}
2017-11-15 18:31:57 +01:00
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
DDLogInfo(@"%@ resurrectNewOutgoingMessages1.2: %zd", self.logTag, count);
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2017-12-19 03:34:22 +01:00
for (TSOutgoingMessage *message in messages) {
[message removeWithTransaction:transaction];
}
for (TSOutgoingMessage *message in messages) {
[message saveWithTransaction:transaction];
}
}];
2017-11-15 18:31:57 +01:00
});
2017-11-15 18:10:29 +01:00
}
+ (void)resurrectNewOutgoingMessages2:(NSUInteger)count
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)initialTransaction
2017-11-15 18:10:29 +01:00
{
2017-11-15 18:31:57 +01:00
DDLogInfo(@"%@ resurrectNewOutgoingMessages2.1: %zd", self.logTag, count);
2017-11-15 18:10:29 +01:00
NSMutableArray<TSOutgoingMessage *> *messages = [NSMutableArray new];
for (NSUInteger i =0; i < count; i++) {
NSString *text = [self randomText];
OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId
transaction:initialTransaction];
2017-11-15 18:10:29 +01:00
TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
messageBody:text
attachmentIds:[NSMutableArray new]
expiresInSeconds:(configuration.isEnabled ? configuration.durationSeconds : 0)];
DDLogError(@"%@ resurrectNewOutgoingMessages2 timestamp: %llu.", self.logTag, message.timestamp);
2017-11-15 18:10:29 +01:00
[messages addObject:message];
}
for (TSOutgoingMessage *message in messages) {
[message updateWithMessageState:TSOutgoingMessageStateAttemptingOut transaction:initialTransaction];
[message saveWithTransaction:initialTransaction];
}
2017-11-15 18:31:57 +01:00
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
DDLogInfo(@"%@ resurrectNewOutgoingMessages2.2: %zd", self.logTag, count);
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2017-12-19 03:34:22 +01:00
for (TSOutgoingMessage *message in messages) {
[message removeWithTransaction:transaction];
}
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
DDLogInfo(@"%@ resurrectNewOutgoingMessages2.3: %zd", self.logTag, count);
[OWSPrimaryStorage.dbReadWriteConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (TSOutgoingMessage *message in messages) {
[message saveWithTransaction:transaction];
}
}];
2017-11-15 18:31:57 +01:00
});
});
2017-11-15 18:10:29 +01:00
}
2018-02-13 19:06:08 +01:00
+ (void)createTimestampMessagesInThread:(TSThread *)thread
{
OWSAssert(thread);
2018-03-23 15:19:04 +01:00
long long now = (long long)[NSDate ows_millisecondTimeStamp];
2018-02-13 19:06:08 +01:00
NSArray<NSNumber *> *timestamps = @[
2018-03-23 15:19:04 +01:00
@(now + 1 * (long long)kHourInMs),
2018-02-13 19:06:08 +01:00
@(now),
2018-03-23 15:19:04 +01:00
@(now - 1 * (long long)kHourInMs),
@(now - 12 * (long long)kHourInMs),
@(now - 1 * (long long)kDayInMs),
@(now - 2 * (long long)kDayInMs),
@(now - 3 * (long long)kDayInMs),
@(now - 6 * (long long)kDayInMs),
@(now - 7 * (long long)kDayInMs),
@(now - 8 * (long long)kDayInMs),
@(now - 2 * (long long)kWeekInMs),
@(now - 1 * (long long)kMonthInMs),
@(now - 2 * (long long)kMonthInMs),
2018-02-13 19:06:08 +01:00
];
NSMutableArray<NSString *> *recipientIds = [thread.recipientIdentifiers mutableCopy];
[recipientIds removeObject:[TSAccountManager localNumber]];
NSString *recipientId = (recipientIds.count > 0 ? recipientIds.firstObject : @"+19174054215");
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
2018-02-13 19:06:08 +01:00
for (NSNumber *timestamp in timestamps) {
NSString *randomText = [self randomText];
{
TSIncomingMessage *message =
[[TSIncomingMessage alloc] initWithTimestamp:timestamp.unsignedLongLongValue
inThread:thread
authorId:recipientId
sourceDeviceId:0
messageBody:randomText];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
}
{
TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initWithTimestamp:timestamp.unsignedLongLongValue
inThread:thread
messageBody:randomText];
[message saveWithTransaction:transaction];
[message updateWithMessageState:TSOutgoingMessageStateSentToService transaction:transaction];
[message updateWithSentRecipient:recipientId transaction:transaction];
[message updateWithDeliveredToRecipientId:recipientId
deliveryTimestamp:timestamp
transaction:transaction];
[message updateWithReadRecipientId:recipientId
readTimestamp:timestamp.unsignedLongLongValue
transaction:transaction];
}
}
}];
}
2018-02-16 02:45:28 +01:00
+ (void)testIndicScriptsInThread:(TSThread *)thread
{
NSArray<NSString *> *strings = @[
@"\u0C1C\u0C4D\u0C1E\u200C\u0C3E",
@"\u09B8\u09CD\u09B0\u200C\u09C1",
@"non-crashing string",
];
[OWSPrimaryStorage.sharedManager.dbReadWriteConnection
2018-02-16 02:45:28 +01:00
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSString *string in strings) {
// DO NOT log these strings with the debugger attached.
// DDLogInfo(@"%@ %@", self.logTag, string);
{
TSIncomingMessage *message =
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
authorId:@"+19174054215"
sourceDeviceId:0
messageBody:string];
[message saveWithTransaction:transaction];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
}
{
NSString *recipientId = @"+19174054215";
NSString *groupName = string;
NSMutableArray<NSString *> *recipientIds = [@[
recipientId,
[TSAccountManager localNumber],
] mutableCopy];
NSData *groupId = [SecurityUtils generateRandomBytes:16];
TSGroupModel *groupModel =
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];
TSGroupThread *groupThread =
[TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
OWSAssert(groupThread);
}
}
}];
}
+ (void)testZalgoTextInThread:(TSThread *)thread
{
NSArray<NSString *> *strings = @[
2018-02-16 16:49:52 +01:00
@"Ṱ̴̤̺̣͚͚̭̰̤̮̑̓̀͂͘͡h̵̢̤͔̼̗̦̖̬͌̀͒̀͘i̴̮̤͎͎̝̖̻͓̅̆͆̓̎͘͡ͅŝ̡̡̳͔̓͗̾̀̇͒͘͢͢͡͡ ỉ̛̲̩̫̝͉̀̒͐͋̾͘͢͡͞s̶̨̫̞̜̹͛́̇͑̅̒̊̈ s̵͍̲̗̠̗͈̦̬̉̿͂̏̐͆̾͐͊̾ǫ̶͍̼̝̉͊̉͢͜͞͝ͅͅṁ̵̡̨̬̤̝͔̣̄̍̋͊̿̄͋̈ͅe̪̪̻̱͖͚͈̲̍̃͘͠͝ z̷̢̢̛̩̦̱̺̼͑́̉̾ą͕͎̠̮̹̱̓̔̓̈̈́̅̐͢l̵̨͚̜͉̟̜͉͎̃͆͆͒͑̍̈̚͜͞ğ͔̖̫̞͎͍̒̂́̒̿̽̆͟o̶̢̬͚̘̤̪͇̻̒̋̇̊̏͢͡͡͠ͅ t̡̛̥̦̪̮̅̓̑̈́̉̓̽͛͢͡ȩ̡̩͓͈̩͎͗̔͑̌̓͊͆͝x̫̦͓̤͓̘̝̪͊̆͌͊̽̃̏͒͘͘͢ẗ̶̢̨̛̰̯͕͔́̐͗͌͟͠.̷̩̼̼̩̞̘̪́͗̅͊̎̾̅̏̀̕͟ͅ",
@"This is some normal text",
];
[OWSPrimaryStorage.sharedManager.dbReadWriteConnection
2018-02-16 16:49:52 +01:00
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSString *string in strings) {
DDLogInfo(@"%@ sending zalgo", self.logTag);
{
TSIncomingMessage *message =
[[TSIncomingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread
authorId:@"+19174054215"
sourceDeviceId:0
messageBody:string];
[message saveWithTransaction:transaction];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
}
{
NSString *recipientId = @"+19174054215";
NSString *groupName = string;
NSMutableArray<NSString *> *recipientIds = [@[
recipientId,
[TSAccountManager localNumber],
] mutableCopy];
NSData *groupId = [SecurityUtils generateRandomBytes:16];
TSGroupModel *groupModel =
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];
TSGroupThread *groupThread =
[TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
OWSAssert(groupThread);
}
}
}];
2018-02-16 02:45:28 +01:00
}
+ (void)testDirectionalFilenamesInThread:(TSThread *)thread
{
NSMutableArray<NSString *> *filenames = [@[
@"a_test\u202Dabc.exe",
@"b_test\u202Eabc.exe",
@"c_testabc.exe",
] mutableCopy];
__block void (^sendUnsafeFile)(void);
sendUnsafeFile = ^{
if (filenames.count < 1) {
return;
}
NSString *filename = filenames.lastObject;
[filenames removeLastObject];
OWSMessageSender *messageSender = [Environment current].messageSender;
NSString *utiType = (NSString *)kUTTypeData;
const NSUInteger kDataLength = 32;
DataSource *_Nullable dataSource =
[DataSourceValue dataSourceWithData:[self createRandomNSDataOfSize:kDataLength] utiType:utiType];
[dataSource setSourceFilename:filename];
SignalAttachment *attachment =
[SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType imageQuality:TSImageQualityOriginal];
OWSAssert(attachment);
if ([attachment hasError]) {
DDLogError(@"attachment[%@]: %@", [attachment sourceFilename], [attachment errorName]);
[DDLog flushLog];
}
OWSAssert(![attachment hasError]);
[ThreadUtil sendMessageWithAttachment:attachment inThread:thread messageSender:messageSender completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
sendUnsafeFile();
});
};
}
@end
NS_ASSUME_NONNULL_END