Skip to content

Commit

Permalink
setup test to use custom queue for RCTBlobManager operations instead …
Browse files Browse the repository at this point in the history
…of module queue (#41182)

Summary:
Pull Request resolved: #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
  • Loading branch information
philIip authored and facebook-github-bot committed Oct 25, 2023
1 parent 7e26e02 commit 7093a45
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 5 deletions.
2 changes: 1 addition & 1 deletion packages/react-native/Libraries/Blob/RCTBlobCollector.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
{
RCTBlobManager *blobManager = blobManager_;
NSString *blobId = [NSString stringWithUTF8String:blobId_.c_str()];
dispatch_async([blobManager_ methodQueue], ^{
dispatch_async([blobManager_ executionQueue], ^{
[blobManager remove:blobId];
});
}
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native/Libraries/Blob/RCTBlobManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,4 +28,6 @@

- (void)createFromParts:(NSArray<NSDictionary<NSString *, id> *> *)parts withId:(NSString *)blobId;

- (dispatch_queue_t)executionQueue;

@end
30 changes: 28 additions & 2 deletions packages/react-native/Libraries/Blob/RCTBlobManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,24 @@

#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTConvert.h>
#import <React/RCTMockDef.h>
#import <React/RCTNetworking.h>
#import <React/RCTUtils.h>
#import <React/RCTWebSocketModule.h>

#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 () <
Expand All @@ -35,6 +46,7 @@ @implementation RCTBlobManager {
std::mutex _blobsMutex;

NSOperationQueue *_queue;
dispatch_queue_t _processingQueue;
}

RCT_EXPORT_MODULE(BlobModule)
Expand All @@ -48,6 +60,10 @@ - (void)initialize
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);
}

Expand Down Expand Up @@ -194,12 +210,22 @@ - (void)remove:(NSString *)blobId
[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
Expand Down
4 changes: 2 additions & 2 deletions packages/react-native/Libraries/Blob/RCTFileReaderModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ @implementation RCTFileReaderModule
: (RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"];
dispatch_async(blobManager.methodQueue, ^{
dispatch_async([blobManager executionQueue], ^{
NSData *data = [blobManager resolve:blob];

if (data == nil) {
Expand Down Expand Up @@ -62,7 +62,7 @@ @implementation RCTFileReaderModule
: (RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"];
dispatch_async(blobManager.methodQueue, ^{
dispatch_async([blobManager executionQueue], ^{
NSData *data = [blobManager resolve:blob];

if (data == nil) {
Expand Down
53 changes: 53 additions & 0 deletions packages/rn-tester/RNTesterUnitTests/RCTBlobManagerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -23,8 +32,12 @@ - (void)setUp
{
[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];
Expand All @@ -36,6 +49,13 @@ - (void)setUp
[_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]]);
Expand Down Expand Up @@ -98,4 +118,37 @@ - (void)testCreateFromParts
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

0 comments on commit 7093a45

Please sign in to comment.