} TEST_ENDDEF

	
TEST_DEF(wrong_api_usage) {

    static pubnub_t *pbp;
    pbp = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp);
    pubnub_init(pbp, g_pubkey, g_keysub);
    
    expect_pnr(pubnub_subscribe(pbp, "ch", NULL), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    expect_pnr(pubnub_publish(pbp, "ch", "\"Test \""), PNR_STARTED);
    expect_pnr(pubnub_publish(pbp, "ch", "\"Test - 2\""), PNR_IN_PROGRESS);
    expect_pnr(pubnub_subscribe(pbp, "ch", NULL), PNR_IN_PROGRESS);
    await_timed(5*SECONDS, PNR_OK, pbp);

    pubnub_set_non_blocking_io(pbp);
    expect_pnr(pubnub_subscribe(pbp, "ch", NULL), PNR_STARTED);
    expect_pnr(pubnub_subscribe(pbp, "ch", NULL), PNR_IN_PROGRESS);
    expect_pnr(pubnub_publish(pbp, "ch", "\"Test - 2\""), PNR_IN_PROGRESS);

    pubnub_cancel(pbp);
    await_timed(5*SECONDS, PNR_CANCELLED, pbp);

    expect_pnr(pubnub_subscribe(pbp, NULL, NULL), PNR_INVALID_CHANNEL);

    TEST_POP_DEFERRED;
    } TEST_ENDDEF
    } TEST_ENDDEF


TEST_DEF(connect_disconnect_and_connect_again) {

    static pubnub_t *pbp;
    pbp = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp);
    pubnub_init(pbp, g_pubkey, g_keysub);
    
    expect_pnr(pubnub_subscribe(pbp, "ch", NULL), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    expect_pnr(pubnub_publish(pbp, "ch", "\"Test M4\""), PNR_STARTED);
    pubnub_cancel(pbp);
    await_timed(5*SECONDS, PNR_CANCELLED, pbp);

    expect_pnr(pubnub_publish(pbp, "ch", "\"Test M4 - 2\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect_pnr(pubnub_subscribe(pbp, "ch", NULL), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect(pnfntst_got_messages(pbp, "\"Test M4 - 2\"", NULL));

    pubnub_set_non_blocking_io(pbp);
    expect_pnr(pubnub_subscribe(pbp, "ch", NULL), PNR_STARTED);
    pubnub_cancel(pbp);
    await_timed(5*SECONDS, PNR_CANCELLED, pbp);
    expect_pnr(pubnub_publish(pbp, "ch", "\"Test M4 - 3\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect_pnr(pubnub_subscribe(pbp, "ch", NULL), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect(pnfntst_got_messages(pbp, "\"Test M4 - 3\"", NULL));

    TEST_POP_DEFERRED;
    } TEST_ENDDEF
    } TEST_ENDDEF


TEST_DEF(simple_connect_and_receiver_over_single_channel) {

    static pubnub_t *pbp;
    static pubnub_t *pbp_2;
    pbp = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp);
    pubnub_init(pbp, "demo", "demo");
    pbp_2 = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp_2);
    pubnub_init(pbp_2, "demo", "demo");

    expect_pnr(pubnub_subscribe(pbp_2, "ch", NULL), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);

    pubnub_set_non_blocking_io(pbp_2);
    expect_pnr(pubnub_subscribe(pbp_2, "ch", NULL), PNR_STARTED);
    expect_pnr(pubnub_publish(pbp, "ch", "\"Test 2\""), PNR_STARTED);
    await_timed_2(5*SECONDS, PNR_OK, pbp, PNR_OK, pbp_2);

    expect(pnfntst_got_messages(pbp_2, "\"Test 2\"", NULL));

    expect_pnr(pubnub_publish(pbp, "ch", "\"Test 2 - 2\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    expect_pnr(pubnub_subscribe(pbp_2, "ch", NULL), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);

    expect(pnfntst_got_messages(pbp_2, "\"Test 2 - 2\"", NULL));

    TEST_POP_DEFERRED;
    TEST_POP_DEFERRED;
    } TEST_ENDDEF
    } TEST_ENDDEF


TEST_DEF(connect_disconnect_and_connect_again_combo) {

    static pubnub_t *pbp;
    static pubnub_t *pbp_2;
    pbp = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp);
    pubnub_init(pbp, g_pubkey, g_keysub);
    pbp_2 = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp_2);
    pubnub_init(pbp_2, g_pubkey, g_keysub);
    
    expect_pnr(pubnub_remove_channel_group(pbp, "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect_pnr(pubnub_add_channel_to_group(pbp, "ch", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    TEST_SLEEP_FOR(CHANNEL_REGISTRY_PROPAGATION_DELAY);

    expect_pnr(pubnub_subscribe(pbp, NULL, "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    expect_pnr(pubnub_publish(pbp, "ch", "\"Test M4\""), PNR_STARTED);
    pubnub_cancel(pbp);
    expect_pnr(pubnub_publish(pbp_2, "two", "\"Test M5\""), PNR_STARTED);
    pubnub_cancel(pbp_2);
    await_timed_2(5*SECONDS, PNR_CANCELLED, pbp, PNR_CANCELLED, pbp_2);

    expect_pnr(pubnub_publish(pbp, "ch", "\"Test M4 - 2\""), PNR_STARTED);
    expect_pnr(pubnub_publish(pbp_2, "two", "\"Test M5 - 2\""), PNR_STARTED);
    await_timed_2(5*SECONDS, PNR_OK, pbp, PNR_OK, pbp_2);
    expect_pnr(pubnub_subscribe(pbp, "two", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect(pnfntst_got_messages(pbp, "\"Test M4 - 2\"", "\"Test M5 - 2\"", NULL));

    pubnub_set_non_blocking_io(pbp);
    expect_pnr(pubnub_subscribe(pbp, "two", "gr"), PNR_STARTED);
    pubnub_cancel(pbp);
    await_timed(5*SECONDS, PNR_CANCELLED, pbp);
    expect_pnr(pubnub_publish(pbp, "ch", "\"Test M4 - 3\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect_pnr(pubnub_publish(pbp, "two", "\"Test M5 - 3\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect_pnr(pubnub_subscribe(pbp, "two", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect(pnfntst_got_messages(pbp, "\"Test M4 - 3\"", "\"Test M5 - 3\"", NULL));

    expect_pnr(pubnub_remove_channel_from_group(pbp, "ch", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    TEST_POP_DEFERRED;
    TEST_POP_DEFERRED;
    } TEST_ENDDEF
    } TEST_ENDDEF


TEST_DEF(simple_connect_and_receiver_over_single_channel_in_group) {

    static pubnub_t *pbp;
    static pubnub_t *pbp_2;
    pbp = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp);
    pubnub_init(pbp, "demo", "demo");
    pbp_2 = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp_2);
    pubnub_init(pbp_2, "demo", "demo");

    expect_pnr(pubnub_remove_channel_group(pbp_2, "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);
    expect_pnr(pubnub_add_channel_to_group(pbp_2, "ch", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);

    TEST_SLEEP_FOR(CHANNEL_REGISTRY_PROPAGATION_DELAY);

    expect_pnr(pubnub_subscribe(pbp_2, NULL, "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);

    pubnub_set_non_blocking_io(pbp_2);
    expect_pnr(pubnub_subscribe(pbp_2, NULL, "gr"), PNR_STARTED);
    expect_pnr(pubnub_publish(pbp, "ch", "\"Test 2\""), PNR_STARTED);
    await_timed_2(5*SECONDS, PNR_OK, pbp, PNR_OK, pbp_2);

    expect(pnfntst_got_messages(pbp_2, "\"Test 2\"", NULL));

    expect_pnr(pubnub_publish(pbp, "ch", "\"Test 2 - 2\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    expect_pnr(pubnub_subscribe(pbp_2, NULL, "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);

    expect(pnfntst_got_messages(pbp_2, "\"Test 2 - 2\"", NULL));

    expect_pnr(pubnub_remove_channel_from_group(pbp, "ch", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    TEST_POP_DEFERRED;
    TEST_POP_DEFERRED;
    } TEST_ENDDEF
    } TEST_ENDDEF


TEST_DEF(connect_and_receive_over_channel_in_group_and_multi_channel_simultaneously) {

    static pubnub_t *pbp;
    static pubnub_t *pbp_2;
    pbp = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp);
    pubnub_init(pbp, "demo", "demo");
    pbp_2 = pubnub_alloc();
    TEST_DEFER(pubnub_free, pbp_2);
    pubnub_init(pbp_2, "demo", "demo");

    expect_pnr(pubnub_remove_channel_group(pbp_2, "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);
    expect_pnr(pubnub_add_channel_to_group(pbp_2, "three", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);

    TEST_SLEEP_FOR(CHANNEL_REGISTRY_PROPAGATION_DELAY);

    expect_pnr(pubnub_subscribe(pbp_2, "ch,two", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp_2);

    pubnub_set_non_blocking_io(pbp_2);
    expect_pnr(pubnub_publish(pbp, "ch", "\"Test M2\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect_pnr(pubnub_publish(pbp, "two", "\"Test M2-2\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);
    expect_pnr(pubnub_publish(pbp, "three", "\"Test M2-3\""), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    expect(pnfntst_subscribe_and_check(pbp_2, "ch,two", "gr", 5*SECONDS, "\"Test M2\"", "ch", "\"Test M2-2\"", "two", "\"Test M2-3\"", "three", NULL));

    expect_pnr(pubnub_remove_channel_from_group(pbp_2, "three", "gr"), PNR_STARTED);
    await_timed(5*SECONDS, PNR_OK, pbp);

    TEST_POP_DEFERRED;
    TEST_POP_DEFERRED;
    } TEST_ENDDEF
int main()
{
    /* This is a widely use channel, something should happen there
       from time to time
    */
    char const *chan = "hello_world";
    pubnub_t *pbp = pubnub_alloc();
    if (NULL == pbp) {
        printf("Failed to allocate Pubnub context!\n");
        return -1;
    }

    pubnub_init(pbp, "demo", "demo");
    srand(time(NULL));

    /* This is essential, as otherwise waiting for incoming data will
       block! Since we're doing this, be sure to not enable verbose
       debugging, as you won't see a thing except endless lines of
       some tracing.
    */
    pubnub_set_non_blocking_io(pbp);

    puts("--------------------------");
    puts("Subscribe loop starting...");
    puts("--------------------------");
	
    for (;;) {
        time_t t = time(NULL);
        bool stop = false;
        enum pubnub_res res = pubnub_subscribe(pbp, chan, NULL);
        if (res != PNR_STARTED) {
            printf("pubnub_subscribe() returned unexpected: %d\n", res);
            break;;
        }

        /* Don't await here, 'cause it will loop until done */
        while (!stop) {
            res = pubnub_last_result(pbp);
            if (res == PNR_STARTED) {
                /* Here we simulate the "get out of subscribe loop"
                   external signal with a random number. Basically,
                   this has a 4% chance of stopping the wait every
                   second.
                */
                if (time(NULL) != t) {
                    stop = (rand() % 25) == 3;
                    t = time(NULL);
                }
            }
            else {
                if (PNR_OK == res) {
                    puts("Subscribed! Got messages:");
                    for (;;) {
                        char const *msg = pubnub_get(pbp);
                        if (NULL == msg) {
                            break;
                        }
                        puts(msg);
                    }
                }
                else {
                    printf("Subscribing failed with code: %d\n", res);
                }
                break;
            }
        }
        if (stop) {
            puts("---------------------------");
            puts("Cancelling the Subscribe...");
            puts("---------------------------");
            pubnub_cancel(pbp);
            /* Now it's OK to await, since we don't have anything else
               to do
            */
            pubnub_await(pbp);
            break;
        }
    }

	
    /* We're done */
    if (pubnub_free(pbp) != 0) {
        printf("Failed to free the Pubnub context `pbp`\n");
    }

    puts("Pubnub callback demo over.");

    return 0;
}