File Coverage

blib/lib/Plack/App/DAIA/Test/Suite.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1 1     1   50969 use strict;
  1         2  
  1         24  
2 1     1   3 use warnings;
  1         2  
  1         47  
3             package Plack::App::DAIA::Test::Suite;
4             {
5             $Plack::App::DAIA::Test::Suite::VERSION = '0.45_1';
6             }
7             #ABSTRACT: Test DAIA Servers via a test scripting language
8              
9 1     1   3 use base 'Test::Builder::Module';
  1         1  
  1         98  
10             our @EXPORT = qw(provedaia);
11              
12 1     1   3 use Test::More;
  1         2  
  1         4  
13 1     1   472 use Plack::App::DAIA::Test;
  0            
  0            
14             use Scalar::Util qw(reftype blessed);
15             use Test::JSON::Entails;
16             use Carp;
17              
18             sub provedaia {
19             my ($suite, %args) = @_;
20              
21             my $test = __PACKAGE__->builder;
22             my @lines;
23              
24             if ( ref($suite) ) {
25             croak 'usage: provedaia( $file | $glob | $string )'
26             unless reftype($suite) eq 'GLOB' or blessed($suite) and $suite->isa('IO::File');
27             @lines = <$suite>;
28             } elsif ( $suite !~ qr{^https?://} and $suite !~ /[\r\n]/ ) {
29             open (my $fh, '<', $suite) or croak "failed to open daia test suite $suite";
30             @lines = <$fh>;
31             close $fh;
32             } else {
33             @lines = split /\n/, $suite;
34             }
35            
36             my $line = 0;
37             my $comment = '';
38             my $json = undef;
39             my %vars = ( server => $args{server} );
40             my @ids;
41             @ids = @{$args{ids}} if $args{ids};
42              
43             my $run = sub {
44             my $server = $vars{server} or return;
45             $json ||= '{ }';
46             my $server_name = $server;
47             if ( $server !~ qr{^https?://}) {
48             no warnings 'redefine'; # we may load the same twice
49             $_ = Plack::Util::load_psgi($server);
50             if ( ref($_) ) {
51             diag("loaded PSGI from $server");
52             $server = $_;
53             } else {
54             fail("failed to load PSGI from $server");
55             return;
56             }
57             }
58             foreach my $id (@ids) {
59             my $test_name = "$server_name?id=$id";
60             $comment =~ s/^\s+|\s+$//g;
61             $test_name .= " ($comment)" if $comment ne '';
62             local $Test::Builder::Level = $Test::Builder::Level + 2; # called 2 levels above
63             my $test_json = $json;
64             $vars{id} = $id;
65             $test_json =~ s/\$([a-z]+)/defined $vars{$1} ? $vars{$1} : "\$$1"/emg;
66             if (ref($server)) {
67             test_daia_psgi $server, $id => $test_json, $test_name;
68             } else {
69             test_daia $server, $id => $test_json, $test_name;
70             }
71             }
72             };
73              
74             foreach (@lines) {
75             if ($args{end}) {
76             $args{end} = 0 if /__END__/;
77             next;
78             }
79             chomp;
80             $comment = $1 if /^#(.*)/;
81             s/^(#.*|\s+)$//; # empty line or comment
82             $line++;
83              
84             if (defined $json) {
85             $json .= $_;
86             if ($_ eq '') {
87             $run->();
88             $json = undef;
89             $comment = '';
90             }
91             } elsif ( $_ eq '' ) {
92             next;
93             } elsif( $_ =~ qr{^([a-z]+)\s*=\s*(.*)}i ) {
94             $comment = '';
95             my ($key, $value) = ($1,$2);
96             if ($1 =~ /^id[s]?/) {
97             @ids = $value eq '' ? () : ($value);
98             } else {
99             $vars{$key} = $value;
100             }
101             diag( "$key = $value" ) if $args{verbose};
102             } elsif( $_ =~ qr/^\s*{/ ) {
103             $json = $_;
104             } else { # identifier
105             $comment = '';
106             push @ids, $_;
107             }
108             }
109             $run->();
110             }
111              
112             1;
113              
114              
115             __END__
116             =pod
117              
118             =head1 NAME
119              
120             Plack::App::DAIA::Test::Suite - Test DAIA Servers via a test scripting language
121              
122             =head1 VERSION
123              
124             version 0.45_1
125              
126             =head1 SYNOPSIS
127              
128             use Test::More;
129             use Plack::App::DAIA::Test::Suite;
130              
131             provedaia <<SUITE, server => "http://example.com/your-daia-server";
132             foo:bar
133              
134             # document expected
135             { "document" : [ { } ] }
136             SUITE
137              
138             done_testing;
139              
140             =head1 METHODS
141              
142             =head2 provedaia ( $suite [, %options ] )
143              
144             Run a DAIA test suite from a string or stream (GLOB or L<IO::File>). A DAIA
145             test suite lists servers, identifiers, and DAIA/JSON response fragments to test
146             DAIA servers. The command line client L<provedaia> is included in this
147             distribution for convenience.
148              
149             Additional option supported so far are C<server> and C<ids>. The former is
150             equivalent to an inital C<server=...> statement in you test suite and the
151             latter is equivalent to an initial list of identifiers in you test suite.
152              
153             If the option C<end> is set, all lines before C<__END__> are ignored in the
154             test suite script. The option C<verbose> adds more diagnostic messages.
155              
156             =head1 TEST SUITE FORMAT
157              
158             A test suite is defined in a text-based format that is parsed line by line.
159             Empty lines are ignored. There are four kinds of statements:
160              
161             =over 4
162              
163             =item comments
164              
165             All lines starting with C<#> are treated as comments.
166              
167             =item responses
168              
169             All lines starting with C<{>} begin a response (fragment) in JSON format.
170             Following lines are treated as part of the JSON structure until an empty line
171             or the end of the file. References to assigned variables, such as C<$server>,
172             are replaced, including the special variable C<$id> for the current identifier.
173              
174             =item assignements
175              
176             All lines of the form C<key=value>, where C<key> contains of lowercase letters
177             a-z only, are treated as variable assignements. In particular, the variable
178             C<server> is used to set a server (an URL or a PSGI script) and the variable
179             C<id> can be used to reset the list of identifiers.
180              
181             =item identifiers
182              
183             All other non-empty lines are treated as identifiers. Identifiers are not
184             expected to be URI-encoded.
185              
186             =back
187              
188             Every time a response has been read, all preceding identifiers are used to
189             query the current server and the response is compared with
190             L<Test::JSON::Entails>. Here is an example of a test suite:
191              
192             server=http://example.com/your-daia-server
193              
194             # some document ids
195             isbn:0486225437
196             urn:isbn:0486225437
197             http://example.org/this-is-also-an-id
198              
199             # the response must contain at least one document with the query id
200             { "document" : [
201             { "id" : "$id" }
202             ] }
203              
204             See the file C<app.psgi> and C<examples/daia-ubbielefeld.pl> for further
205             examples of test suites included in server implementations.
206              
207             =head1 AUTHOR
208              
209             Jakob Voss
210              
211             =head1 COPYRIGHT AND LICENSE
212              
213             This software is copyright (c) 2012 by Jakob Voss.
214              
215             This is free software; you can redistribute it and/or modify it under
216             the same terms as the Perl 5 programming language system itself.
217              
218             =cut
219