Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For asynch parse operations when testing - waitUntilFinished hangs indefinitely #19

Closed
bitfinity opened this issue Feb 21, 2014 · 4 comments

Comments

@bitfinity
Copy link

bitfinity commented Feb 21, 2014

When you use "waitUntilFinished" at the end of a task, the parse completion block for a somethingInBackground is never called. It works with a dispatch semaphore.

The reason why may be that parse block callbacks always occur on the main thread.

Example:

-(BFTask *)createCorporation {
    NSLog(@"Creating corporation.");
    BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];

    PFObject *corporation = [PFObject objectWithClassName:@"AcctCorporation"];
    [corporation setObject:[_locationInfo objectForKey:@"locationName"] forKey:@"name"];
    [corporation setObject:[_locationInfo objectForKey:@"postalCode"] forKey:@"postal"];
    [corporation setObject:[_locationInfo objectForKey:@"country"] forKey:@"country"];
    [corporation setObject:[_locationInfo objectForKey:@"state"] forKey:@"state"];
    [corporation setObject:[_locationInfo objectForKey:@"address"] forKey:@"address"];

    [corporation saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
        NSLog(@"HERE!");  // Never gets called
        if(!error) {
            [task setResult: corporation];
        } else {
            [task setError: error];
        }
    }];
    return task.task;
}

Test:

- (void) testCreateCorporation {
    NSDictionary *userProfile = [NSDictionary dictionaryWithObjectsAndKeys:@"[email protected]", @"email", @"jimbo2s223s4", @"username", @"Jim", @"firstName", @"O'Brien", @"lastName", @"1234", @"pin", @"888xxxx8", @"password", @"619-xxxxxxx", @"cell", nil];
    NSDictionary *locationInfo = @{
                                   @"locationName": @"Joe's Garage",
                                   @"address": @"111 Frank Zappa Street",
                                   @"mainPhone": @"619-xxx-xxxx",
                                   @"postalCode": @"91910",
                                   @"city": @"Palmdale",
                                   @"state": @"California",
                                   @"country": @"USA",
                                   @"position": @"Head Chief and Cook"
                                   };

    __block PFObject *corporation = nil;

    TAPParseSignup *signup = [[TAPParseSignup alloc] initWithLocationInfo:locationInfo andUserProfile:userProfile];
    [[[signup createCorporation] continueWithBlock:^id(BFTask *task) {
        STAssertNil(task.error, @"Error should be nil");
        corporation = [task result];
        return nil;
    }] waitUntilFinished];
    STAssertNotNil(corporation, @"Corp should not be nil.");
    STAssertNotNil([corporation objectId], @"Object id should not be nil");
}

With semaphore working:

- (void) testCreateCorporation {
    NSDictionary *userProfile = [NSDictionary dictionaryWithObjectsAndKeys:@"[email protected]", @"email", @"jimbo2s223s4", @"username", @"Jim", @"firstName", @"O'Brien", @"lastName", @"1234", @"pin", @"8888", @"password", @"619-xxxxxxxx", @"cell", nil];
    NSDictionary *locationInfo = @{
                                   @"locationName": @"Joe's Garage",
                                   @"address": @"111 Frank Zappa Street",
                                   @"mainPhone": @"619-xxx-xxxx",
                                   @"postalCode": @"91910",
                                   @"city": @"Palmdale",
                                   @"state": @"California",
                                   @"country": @"USA",
                                   @"position": @"Head Chief and Cook"
                                   };

    __block PFObject *corporation = nil;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    TAPParseSignup *signup = [[TAPParseSignup alloc] initWithLocationInfo:locationInfo andUserProfile:userProfile];
    [[signup createCorporation] continueWithBlock:^id(BFTask *task) {
        STAssertNil(task.error, @"Error should be nil");
        dispatch_semaphore_signal(semaphore);
        corporation = [task result];
        return nil;
    }];
    while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:20]];
    }
    STAssertNotNil(corporation, @"Corp should not be nil.");
    STAssertNotNil([corporation objectId], @"Object id should not be nil");
}
@bklimt
Copy link
Contributor

bklimt commented Feb 21, 2014

Right, this is working as intended, in the sense that the callbacks for Parse always happen on the main thread, and ST does not have an easy way to make async tests like this. Your solution of having a manual run loop is actually a good way to handle it for tests. That's the way the GHUnit test framework works, for example.

But a future update from Parse may make this easier, if callbacks don't have to be on the main thread.

@bitfinity
Copy link
Author

bitfinity commented Feb 23, 2014

Thanks - wasn't sure if this was a bug or not. They said they probably
won't put callbacks on other than the main thread because too many apps
rely on it being that way.
-jim

On Fri, Feb 21, 2014 at 11:58 AM, Bryan Klimt [email protected]:

Right, this is working as intended, in the sense that the callbacks for
Parse always happen on the main thread, and ST does not have an easy way to
make async tests like this. Your solution of having a manual run loop is
actually a good way to handle it for tests. That's the way the GHUnit test
framework works, for example.

But a future update from Parse may make this easier, if callbacks don't
have to be on the main thread.

Reply to this email directly or view it on GitHubhttps://github.com//issues/19#issuecomment-35767268
.

@bitfinity
Copy link
Author

bitfinity commented Feb 23, 2014

Of course not sure why an updated SDK couldn't do that.
-jim

On Sat, Feb 22, 2014 at 5:23 PM, Jim O'Brien [email protected] wrote:

Thanks - wasn't sure if this was a bug or not. They said they probably
won't put callbacks on other than the main thread because too many apps
rely on it being that way.
-jim

On Fri, Feb 21, 2014 at 11:58 AM, Bryan Klimt [email protected]:

Right, this is working as intended, in the sense that the callbacks for
Parse always happen on the main thread, and ST does not have an easy way to
make async tests like this. Your solution of having a manual run loop is
actually a good way to handle it for tests. That's the way the GHUnit test
framework works, for example.

But a future update from Parse may make this easier, if callbacks don't
have to be on the main thread.

Reply to this email directly or view it on GitHubhttps://github.com//issues/19#issuecomment-35767268
.

ghost referenced this issue in agener917/Bolts-iOS Jul 31, 2014
@grantland
Copy link
Member

Closing this since it seems to be resolved. Feel free to re-open if you think this was a mistake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants