Async-Redis

 view release on metacpan or  search on metacpan

t/03-pubsub.t  view on Meta::CPAN

#!/usr/bin/env perl

use strict;
use warnings;
use Test::Lib;
use Test::Async::Redis ':redis';
use Future::AsyncAwait;
use Test2::V0;
use Time::HiRes qw(time);
use Future::IO;

use lib 'lib';
use Async::Redis;

# Each subtest body runs inside a single async sub and ->get is called
# exactly once at the end. This avoids the Future::AsyncAwait
# "lost its returning future" pitfall that arose when the body mixed
# fire-and-forget `(async sub { ... })->()` with synchronous `->get`
# on a separate signal Future (the caller would unwind through the
# subtest's closing brace before F::AA finished bookkeeping on the
# background sub, destroying its returning Future mid-suspension).

# ============================================================================
# Test: Pub/Sub basic flow
# ============================================================================

subtest 'publish and subscribe' => sub {
    (async sub {
        my $pub = Async::Redis->new(host => redis_host(), port => redis_port());
        my $sub = Async::Redis->new(host => redis_host(), port => redis_port());
        await Future->needs_all($pub->connect, $sub->connect);

        my $subscription = await $sub->subscribe('test:channel');

        # Publish in the background while we read.
        my $pub_f = (async sub {
            await Future::IO->sleep(0.05);
            my $listeners = await $pub->publish('test:channel', 'message 1');
            ok $listeners >= 1, "publish returned $listeners listeners";
            await $pub->publish('test:channel', 'message 2');
            await $pub->publish('test:channel', 'message 3');
        })->();

        my @received;
        for my $i (1..3) {
            push @received, await $subscription->next_message;
        }
        await $pub_f;

        is scalar(@received), 3, 'received 3 messages';
        is $received[0]{channel}, 'test:channel', 'correct channel';
        is $received[0]{message}, 'message 1', 'correct message 1';
        is $received[1]{message}, 'message 2', 'correct message 2';
        is $received[2]{message}, 'message 3', 'correct message 3';

        $pub->disconnect;
        $sub->disconnect;
    })->()->get;
};

# ============================================================================
# Test: Multiple channels
# ============================================================================

subtest 'multiple channel subscription' => sub {
    (async sub {
        my $pub = Async::Redis->new(host => redis_host(), port => redis_port());
        my $sub = Async::Redis->new(host => redis_host(), port => redis_port());
        await Future->needs_all($pub->connect, $sub->connect);

        my $subscription = await $sub->subscribe('chan:a', 'chan:b', 'chan:c');

        my $pub_f = (async sub {
            await Future::IO->sleep(0.05);
            await $pub->publish('chan:a', 'msg-a');
            await $pub->publish('chan:b', 'msg-b');
            await $pub->publish('chan:c', 'msg-c');
        })->();



( run in 0.715 second using v1.01-cache-2.11-cpan-9581c071862 )