Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pause execution until Websocket connects

I'm using the SocketRocket library to handle connecting to a Websocket. It connects just fine, but I'm trying to run some unit tests that have to first wait on the WS connecting. Since the only way to know that the WS has connected is through its delegate method, I'm having trouble making this process synchronous. I want my unit tests' setup method to simply create a WS connection and then tearDown close it.

I've implemented two types of connection methods for my Websocket class. The first two are pretty basic and I've verified that they work as expected. The last one is my attempt at making it blocking primarily for testing purposes. I have not been able to get it working and it just ends up waiting forever, so I believe that's a conceptual misunderstanding on my part.

I guess my big question is how can I stop execution in a test case to wait on a return call to a delegate? The problem arising in test cases is that I can't just do all my tests in the completion block -- the test method sees this just as a success and ends the program.

- (void)connect
{
    DLog(@"Websocket is connecting now");
    [_socket open];
}


- (void)connectWithCompletion:(WebsocketConnection)completion
{
    DLog(@"Connecting now...");
    [_onConnectBlocksToRun addObject:^{
        completion(self.isConnected, self.socket);
    }];
    [_socket open];
}

- (bool)connectBlocking // XXX Doesn't work!
{
    sem = dispatch_semaphore_create(0);
    [_socket open];

    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    return _isConnected;
}

#pragma mark - Socket rocket delegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket
{
    DLog(@"Websocket has opened");
    _isConnected = YES;
    _socket = webSocket;

    for (void(^block)() in _onConnectBlocksToRun) {
        block();
    }
    [_onConnectBlocksToRun removeAllObjects];

    if (sem) {
        dispatch_semaphore_signal(sem);
        dispatch_release(sem);
    }
}
like image 698
joslinm Avatar asked Oct 06 '22 00:10

joslinm


1 Answers

While you are waiting for your semaphore to get signaled the main thread is blocked so no code can run at all. If your library integrates with the runloop system you can run the runloop using CFRunLoopRun() instead of waiting on your semaphore. From your ready callback you can then stop the runloop using CFRunLoopStop( CFRunLoopGetMain() ).

like image 141
Sven Avatar answered Oct 13 '22 09:10

Sven