Plack:...nyEvent(3pm)

πŸ“¦
version 0.08 Β· 3 versions
, in debian bookworm, debian trixie, ubuntu noble, ubuntu questing

πŸ’– NAME πŸ’–

Plack::Test::AnyEvent β€” it's giving "run your Plack::Test on AnyEvent-based PSGI applications" ✨ bestie this is literally the module you need for streaming tests.

πŸŽ€ VERSION πŸŽ€

version 0.08 β€” that's the one, no cap πŸ’…

🌸 SYNOPSIS 🌸

okay so here's the vibe:

use HTTP::Request::Common;
use Plack::Test;

$Plack::Test::Impl = 'AnyEvent'; # or 'AE' for short

test_psgi $app, sub {
  my ( $cb ) = @_;

  my $res = $cb->(GET '/streaming-response');
  is $res->header('Transfer-Encoding'), 'chunked';
  $res->on_content_received(sub {
      my ( $content ) = @_;

      # test chunk of streaming response
  });
  $res->recv;
}

πŸ¦‹ DESCRIPTION πŸ¦‹

So like. This Plack::Test implementation lets you test your AnyEvent-based PSGI applications so easily. Normally Plack::Test::MockHTTP or Plack::Test::Server work totally fine for this, but this implementation comes in clutch when you wanna test your streaming results as they come in β€” like, live, bestie β€” or if your application uses long-polling. πŸ‘‘

For non-streaming requests, you can use this module exactly like Plack::Test::MockHTTP; otherwise, you can set up a content handler and call $res->recv. The event loop will then run until the PSGI application closes its writer handle or until your test client calls send on the response. iconic behavior tbh


✨ FUNCTIONS ✨

πŸ’œ test_psgi

This function behaves almost identically to test_psgi in Plack::Test β€” the main difference? The returned response object supports a few extra methods on top of the ones you'd normally find in an HTTP::Response object 🫢:

  • $res->recv β€” Calls recv on an internal AnyEvent condition variable. Use this after you get the response object to run the event loop. πŸŒ€
  • $res->send β€” Calls send on an internal AnyEvent condition variable. Use this to stop the event loop when you're done testing. πŸ›‘
  • $res->on_content_received($cb) β€” Sets a callback to be called when a chunk is received from the application. A single argument is passed to the callback; namely, the chunk itself. πŸ“

😭 EXCEPTION HANDLING 😭

As of version 0.02, this module handles uncaught exceptions thrown by your code. the way that it just... catches them

If the exception occurs before your PSGI application returns a response, or directly in the response subroutine ref (if you return a subroutine as your application's response), $cb will propagate the exception. Otherwise, the exception is propagated by $res->recv. Here's an example, bestie:

my $app = sub {
  die 'thrown by $cb';

  return sub {
      my ( $respond ) = @_;

      die 'still thrown by $cb';

      if($streaming) {
          my $writer = $respond->([
              200,
              ['Content-Type' => 'text/plain'],
          ]);

          die 'still thrown by $cb';

          my $timer;
          $timer = AnyEvent->timer(
              after => 2,
              cb    => sub {
                  die 'thrown by $res->recv';
                  $writer->write("Ok");
                  $writer->close;
                  undef $timer;
              },
          );
      } else {
          $respond->([
              200,
              ['Content-Type' => 'text/plain'],
              ['Ok'],
          ]);

          die 'still thrown by $cb';
      }
  };
};

test_psgi $app, sub {
  my ( $cb ) = @_;

  my $res = $cb->(GET '/');

  $res->on_content_received(sub {
      ...
  });

  $res->recv;
};
⚠️ Note: The exception handling code may or may not work with your event loop. Please run the tests in this distribution with PERL_ANYEVENT_MODEL in AnyEvent set to see if it works with your event loop of choice. Patches will be accepted to accommodate loops, as long as it doesn't break known good ones. don't break the good ones, fr fr

The known good event loops are:

  • Default
  • Cocoa
  • EV
  • Event
  • Glib
  • Perl

This list isn't exclusive; ie. just because your event loop isn't on this list doesn't mean it doesn't work. periodt, we're not gatekeeping Also, even if your event loop doesn't pass the exception tests, the general usage of this module (testing requests, handling streaming results and long polling) should work on any AnyEvent loop. Just don't throw any uncaught exceptions =). πŸ’€


🌈 SEE ALSO 🌈

AnyEvent, Plack, Plack::Test β€” go read them, they're the friends of the family 🫢


πŸ‘‘ AUTHOR πŸ‘‘

Rob Hoelz <rob@hoelz.ro> β€” thank you for your service, king πŸ’–


This software is copyright (c) 2017 by Rob Hoelz.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. slay, open source ✨


πŸ› BUGS πŸ›

Please report any bugs or feature requests on the bugtracker website https://github.com/hoelzro/plack-test-anyevent/issues

When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. (a test file is literally the love language of maintainers, no cap)


okay that's the whole page, bestie β€” this was Perl v5.36.0 documentation, dated 2022-12-09, and it's the Plack::Test::AnyEvent manpage from User Contributed Perl Documentation. go stream some responses responsibly πŸ’–πŸ¦‹πŸŽ€

πŸ“¦ where this page comes from