setup test to use custom queue for RCTBlobManager operations instead of module queue (#41182)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/41182

Changelog: [Internal]

in my quest to get rid of all synthesized methodQueues, we have RCTBlobManager which exposes its underlying execution queue. in this diff, i add a config that replaces that queue with one that is managed by the module itself instead of the one generated by the infra.

Reviewed By: cipolleschi

Differential Revision: D50587693

fbshipit-source-id: 993a13c617afe48c3989d8cd5ad5fbda050603f4
This commit is contained in:
Phillip Pan
2023-10-25 09:13:06 -07:00
committed by Facebook GitHub Bot
parent 7e26e0270b
commit 7093a45b1c
5 changed files with 88 additions and 5 deletions
@@ -21,7 +21,7 @@ RCTBlobCollector::~RCTBlobCollector()
{
RCTBlobManager *blobManager = blobManager_;
NSString *blobId = [NSString stringWithUTF8String:blobId_.c_str()];
dispatch_async([blobManager_ methodQueue], ^{
dispatch_async([blobManager_ executionQueue], ^{
[blobManager remove:blobId];
});
}
@@ -10,6 +10,8 @@
#import <React/RCTInitializing.h>
#import <React/RCTURLRequestHandler.h>
RCT_EXTERN void RCTEnableBlobManagerProcessingQueue(BOOL enabled);
@interface RCTBlobManager : NSObject <RCTBridgeModule, RCTURLRequestHandler, RCTInitializing>
- (NSString *)store:(NSData *)data;
@@ -26,4 +28,6 @@
- (void)createFromParts:(NSArray<NSDictionary<NSString *, id> *> *)parts withId:(NSString *)blobId;
- (dispatch_queue_t)executionQueue;
@end
@@ -11,6 +11,7 @@
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTConvert.h>
#import <React/RCTMockDef.h>
#import <React/RCTNetworking.h>
#import <React/RCTUtils.h>
#import <React/RCTWebSocketModule.h>
@@ -18,6 +19,16 @@
#import "RCTBlobCollector.h"
#import "RCTBlobPlugins.h"
RCT_MOCK_DEF(RCTBlobManager, dispatch_async);
#define dispatch_async RCT_MOCK_USE(RCTBlobManager, dispatch_async)
static BOOL gBlobManagerProcessingQueueEnabled = NO;
RCT_EXTERN void RCTEnableBlobManagerProcessingQueue(BOOL enabled)
{
gBlobManagerProcessingQueueEnabled = enabled;
}
static NSString *const kBlobURIScheme = @"blob";
@interface RCTBlobManager () <
@@ -35,6 +46,7 @@ static NSString *const kBlobURIScheme = @"blob";
std::mutex _blobsMutex;
NSOperationQueue *_queue;
dispatch_queue_t _processingQueue;
}
RCT_EXPORT_MODULE(BlobModule)
@@ -48,6 +60,10 @@ RCT_EXPORT_MODULE(BlobModule)
std::lock_guard<std::mutex> lock(_blobsMutex);
_blobs = [NSMutableDictionary new];
if (gBlobManagerProcessingQueueEnabled) {
_processingQueue = dispatch_queue_create("com.facebook.react.blobmanager.processing", DISPATCH_QUEUE_SERIAL);
}
facebook::react::RCTBlobCollector::install(self);
}
@@ -194,12 +210,22 @@ RCT_EXPORT_METHOD(createFromParts : (NSArray<NSDictionary<NSString *, id> *> *)p
[NSException raise:@"Invalid type for blob" format:@"%@ is invalid", type];
}
}
[self store:data withId:blobId];
dispatch_async([self executionQueue], ^{
[self store:data withId:blobId];
});
}
RCT_EXPORT_METHOD(release : (NSString *)blobId)
{
[self remove:blobId];
dispatch_async([self executionQueue], ^{
[self remove:blobId];
});
}
- (dispatch_queue_t)executionQueue
{
return gBlobManagerProcessingQueueEnabled ? _processingQueue : _methodQueue;
}
#pragma mark - RCTURLRequestHandler methods
@@ -31,7 +31,7 @@ RCT_EXPORT_METHOD(readAsText
: (RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"];
dispatch_async(blobManager.methodQueue, ^{
dispatch_async([blobManager executionQueue], ^{
NSData *data = [blobManager resolve:blob];
if (data == nil) {
@@ -62,7 +62,7 @@ RCT_EXPORT_METHOD(readAsDataURL
: (RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"];
dispatch_async(blobManager.methodQueue, ^{
dispatch_async([blobManager executionQueue], ^{
NSData *data = [blobManager resolve:blob];
if (data == nil) {
@@ -8,6 +8,15 @@
#import <XCTest/XCTest.h>
#import <React/RCTBlobManager.h>
#import <React/RCTMockDef.h>
RCT_MOCK_REF(RCTBlobManager, dispatch_async);
static void _mock_dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
{
XCTAssertNotNil(queue);
block();
}
@interface RCTBlobManagerTests : XCTestCase
@@ -23,8 +32,12 @@
{
[super setUp];
RCT_MOCK_SET(RCTBlobManager, dispatch_async, _mock_dispatch_async);
_module = [RCTBlobManager new];
dispatch_queue_t methodQueue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
[_module setValue:nil forKey:@"bridge"];
[_module setValue:methodQueue forKey:@"methodQueue"];
[_module initialize];
NSInteger size = 120;
_data = [NSMutableData dataWithCapacity:size];
@@ -36,6 +49,13 @@
[_module store:_data withId:_blobId];
}
- (void)tearDown
{
[super tearDown];
RCT_MOCK_RESET(RCTBlobManager, dispatch_async);
}
- (void)testResolve
{
XCTAssertTrue([_data isEqualToData:[_module resolve:_blobId offset:0 size:_data.length]]);
@@ -98,4 +118,37 @@
XCTAssertTrue([expectedData isEqualToData:result]);
}
- (void)testCreateFromPartsProcessingQueue
{
RCTEnableBlobManagerProcessingQueue(YES);
[self setUp];
NSDictionary<NSString *, id> *blobData = @{
@"blobId" : _blobId,
@"offset" : @0,
@"size" : @(_data.length),
};
NSDictionary<NSString *, id> *blob = @{
@"data" : blobData,
@"type" : @"blob",
};
NSString *stringData = @"i \u2665 dogs";
NSDictionary<NSString *, id> *string = @{
@"data" : stringData,
@"type" : @"string",
};
NSString *resultId = [NSUUID UUID].UUIDString;
NSArray<id> *parts = @[ blob, string ];
[_module createFromParts:parts withId:resultId];
NSMutableData *expectedData = [NSMutableData new];
[expectedData appendData:_data];
[expectedData appendData:[stringData dataUsingEncoding:NSUTF8StringEncoding]];
NSData *result = [_module resolve:resultId offset:0 size:expectedData.length];
XCTAssertTrue([expectedData isEqualToData:result]);
}
@end