The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

JMAP::Tester - a JMAP client made for testing JMAP servers

VERSION

version 0.101

OVERVIEW

Achtung! This library is in its really early days, so use it with that in mind.

JMAP::Tester is for testing JMAP servers. Okay? Okay!

JMAP::Tester calls the whole thing you get back from a JMAP server a "response" if it's an HTTP 200. Every JSON Array (of three entries -- go read the spec if you need to!) is called a Sentence. Runs of Sentences with the same client id are called Paragraphs.

You use the test client like this:

  my $jtest = JMAP::Tester->new({
    api_uri => 'https://jmap.local/account/123',
  });

  my $response = $jtest->request([
    [ getMailboxes => {} ],
    [ getMessageUpdates => { sinceState => "123" } ],
  ]);

  # This returns two Paragraph objects if there are exactly two paragraphs.
  # Otherwise, it throws an exception.
  my ($mbx_p, $msg_p) = $response->assert_n_paragraphs(2);

  # These get the single Sentence of each paragraph, asserting that there is
  # exactly one Sentence in each Paragraph, and that it's of the given type.
  my $mbx = $mbx_p->single('mailboxes');
  my $msg = $msg_p->single('messageUpdates');

  is( @{ $mbx->arguments->{list} }, 10, "we expect 10 mailboxes");
  ok( ! $msg->arguments->{hasMoreUpdates}, "we got all the msg updates needed");

By default, all the structures returned have been passed through JSON::Typist, so you may want to strip their type data before using normal Perl code on them. You can do that with:

  my $struct = $response->as_triples;  # gets the complete JSON data
  $jtest->strip_json_types( $struct ); # strips all the JSON::Typist types

Or more simply:

  my $struct = $response->as_stripped_triples;

There is also "as_stripped_pairs" in JMAP::Tester::Response.

ATTRIBUTES

should_return_futures

If true, this indicates that the various network-accessing methods should return Future objects rather than immediate results.

default_using

This is an arrayref of strings that specify which capabilities the client wishes to use. (See https://jmap.io/spec-core.html#the-request-object for more info). By default, JMAP::Tester will not send a 'using' parameter.

default_arguments

This is a hashref of arguments to be put into each method call. It's especially useful for setting a default accountId. Values given in methods passed to request will override defaults. If the value is a reference to undef, then no value will be passed for that key.

In other words, in this situation:

  my $tester = JMAP::Tester->new({
    ...,
    default_arguments => { a => 1, b => 2, c => 3 },
  });

  $tester->request([
    [ eatPies => { a => 100, b => \undef } ],
  ]);

The request will effectively be:

  [ [ "eatPies", { "a": 100, "c": 3 }, "a" ] ]

accounts

This method will return a list of pairs mapping accountIds to accounts as provided by the client session object if any have been configured.

METHODS

primary_account_for

  my $account_id = $tester->primary_account_for($using);

This returns the primary accountId to be used for the given capability, or undef if none is available. This is only useful if the tester has been configured from a client session.

request

  my $result = $jtest->request([
    [ methodOne => { ... } ],
    [ methodTwo => { ... } ],
  ]);

This method accepts either an arrayref of method calls or a hashref with a methodCalls key. It sends the calls to the JMAP server and returns a result.

For each method call, if there's a third element (a client id) then it's left as-is. If no client id is given, one is generated. You can mix explicit and autogenerated client ids. They will never conflict.

The arguments to methods are JSON-encoded with a JSON::Typist-aware encoder, so JSON::Typist types can be used to ensure string or number types in the generated JSON. If an argument is a reference to undef, it will be removed before the method call is made. This lets you override a default by omission.

The return value is an object that does the JMAP::Tester::Result role, meaning it's got an is_success method that returns true or false. For now, at least, failures are JMAP::Tester::Result::Failure objects. More refined failure objects may exist in the future. Successful requests return JMAP::Tester::Response objects.

Before the JMAP request is made, each triple is passed to a method called munge_method_triple, which can tweak the method however it likes.

This method respects the should_return_futures attributes of the JMAP::Tester object, and in futures mode will return a future that will resolve to the Result.

upload

  my $result = $tester->upload(\%arg);

Required arguments are:

  accountId - the account for which we're uploading (no default)
  type      - the content-type we want to provide to the server
  blob      - the data to upload. Must be a reference to a string

This uploads the given blob.

The return value will either be a failure object or an upload result.

This method respects the should_return_futures attributes of the JMAP::Tester object, and in futures mode will return a future that will resolve to the Result.

download

  my $result = $tester->download(\%arg);

Valid arguments are:

  blobId    - the blob to download (no default)
  accountId - the account for which we're downloading (no default)
  type      - the content-type we want the server to provide back (no default)
  name      - the name we want the server to provide back (default: "download")

If the download URI template has a blobId, accountId, or type placeholder but no argument for that is given to download, an exception will be thrown.

The return value will either be a failure object or an upload result.

This method respects the should_return_futures attributes of the JMAP::Tester object, and in futures mode will return a future that will resolve to the Result.

simple_auth

  my $auth_struct = $tester->simple_auth($username, $password);

This method respects the should_return_futures attributes of the JMAP::Tester object, and in futures mode will return a future that will resolve to the Result.

update_client_session

  $tester->update_client_session;
  $tester->update_client_session($auth_uri);

This method fetches the content at the authentication endpoint and uses it to configure the tester's target URIs and signing keys.

This method respects the should_return_futures attributes of the JMAP::Tester object, and in futures mode will return a future that will resolve to the Result.

configure_from_client_session

  $tester->configure_from_client_session($client_session);

Given a client session object (like those stored in an Auth result), this reconfigures the testers access token, signing keys, URIs, and so forth. This method is used internally when logging in.

logout

  $tester->logout;

This method attempts to log out from the server by sending a DELETE request to the authentication URI.

This method respects the should_return_futures attributes of the JMAP::Tester object, and in futures mode will return a future that will resolve to the Result.

http_request

  my $response = $jtest->http_request($http_request);

Sometimes, you may need to make an HTTP request with your existing web connection. This might be to interact with a custom authentication mechanism, to access custom endpoints, or just to make very, very specifically crafted requests. For this reasons, http_request exists.

Pass this method an HTTP::Request and it will use the tester's UA object to make the request.

This method respects the should_return_futures attributes of the JMAP::Tester object, and in futures mode will return a future that will resolve to the HTTP::Response.

http_get

  my $response = $jtest->http_get($url, $headers);

This method is just sugar for calling http_request to make a GET request for the given URL. $headers is an optional arrayref of headers.

http_post

  my $response = $jtest->http_post($url, $body, $headers);

This method is just sugar for calling http_request to make a POST request for the given URL. $headers is an arrayref of headers and $body is the byte string to be passed as the body.

AUTHOR

Ricardo SIGNES <rjbs@cpan.org>

CONTRIBUTORS

  • Alfie John <alfiej@fastmail.fm>

  • Matthew Horsfall <alh@fastmailteam.com>

  • Matthew Horsfall <wolfsage@gmail.com>

  • Michael McClimon <michael@mcclimon.org>

  • Ricardo Signes <rjbs@semiotic.systems>

  • Ricardo Signes <rjbs@users.noreply.github.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2016 by FastMail, Ltd.

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