File Coverage

blib/lib/Test/Varnish.pm
Criterion Covered Total %
statement 42 108 38.8
branch 4 32 12.5
condition 5 32 15.6
subroutine 12 19 63.1
pod 8 8 100.0
total 71 199 35.6


line stmt bran cond sub pod time code
1             package Test::Varnish;
2              
3             our $VERSION = '0.03';
4              
5 2     2   56694 use warnings;
  2         4  
  2         64  
6 2     2   9 use strict;
  2         3  
  2         60  
7              
8 2     2   10 use Carp;
  2         6  
  2         148  
9 2     2   2469 use Getopt::Long;
  2         27714  
  2         13  
10 2     2   2321 use HTTP::Cookies;
  2         28133  
  2         71  
11 2     2   1739 use HTTP::Request;
  2         69942  
  2         73  
12 2     2   2720 use LWP::UserAgent;
  2         47592  
  2         72  
13 2     2   111 use Test::More;
  2         5  
  2         34  
14 2     2   776 use URI;
  2         4  
  2         2832  
15              
16             sub analyze_response {
17 5     5 1 2863 my ($self, $res) = @_;
18 5         7 my $cached = 0;
19              
20 5 50       11 if ($self->verbose) {
21              
22 0         0 my $hdr_obj = $res->headers;
23 0         0 my @hdr_names = $hdr_obj->header_field_names;
24              
25             # Only "X-Varnish" is the standard, but some people use
26             # custom and/or debugging headers
27 0         0 for my $name (@hdr_names) {
28 0 0       0 next unless $name =~ m{^X\-Varnish};
29 0   0     0 my $value = $res->header($name) || q{};
30 0         0 diag("$name: $value");
31             }
32              
33             }
34              
35 5         25 my $main_header = $res->header("X-Varnish");
36             #my $status = $res->header("X-Varnish-Status");
37             #my $cacheable = $res->header("X-Varnish-Cacheable");
38              
39             # "X-Varnish: 2131920313 1299858343" means cached
40             # "X-Varnish: 2039442137" means not cached
41 5 100 100     258 if (defined $main_header && $main_header =~ m{^ \s* \d+ \s+ \d+ \s* $}mx) {
42 1         3 $cached = 1;
43             }
44              
45 5         12 return $cached;
46             }
47              
48             sub new {
49 1     1 1 893 my ($class, $opt) = @_;
50              
51 1   33     10 $class = ref $class || $class;
52 1   50     12 $opt ||= {};
53              
54 1         3 my $self = {
55             _verbose => $opt->{verbose},
56             };
57              
58 1         7 bless $self, $class;
59             }
60              
61             sub is_cached {
62 0     0 1 0 my ($self, $args, $message) = @_;
63              
64 0         0 my $is_cached = $self->_is_cached($args);
65 0         0 my $url = $args->{url};
66              
67 0 0       0 if (! defined $is_cached) {
68 0   0     0 $message ||= qq{Request to url '$url' failed};
69 0         0 return ok(0 => $message);
70             }
71              
72 0   0     0 $message ||= qq{Request to url '$url' should be cached by Varnish};
73              
74 0         0 return ok($is_cached, $message);
75             }
76              
77             sub isnt_cached {
78 0     0 1 0 my ($self, $args, $message) = @_;
79              
80 0         0 my $is_cached = $self->_is_cached($args);
81 0         0 my $url = $args->{url};
82              
83 0 0       0 if (! defined $is_cached) {
84 0   0     0 $message ||= qq{Request to url '$url' failed};
85 0         0 return ok(0 => $message);
86             }
87              
88 0   0     0 $message ||= qq{Request to $url should not be cached by Varnish};
89              
90 0         0 return ok(! $is_cached, $message);
91             }
92              
93             sub _is_cached {
94 0     0   0 my ($self, $args) = @_;
95              
96 0 0 0     0 if (! $args || ref $args ne 'HASH') {
97 0         0 croak q{is_cached() requires a hashref};
98             }
99              
100             # 'headers' is optional, 'url' is mandatory
101 0 0       0 if (! $args->{url}) {
102 0         0 croak q{is_cached() requires a 'url'};
103             }
104              
105 0         0 my $res = $self->request($args);
106              
107             # Request failed, assert a test failure
108 0 0       0 if (! $res) {
109 0         0 return;
110             }
111              
112             # Request successful, check if varnish has cached it
113 0         0 return $self->analyze_response($res);
114              
115             }
116              
117             sub request {
118 0     0 1 0 my ($self, $args) = @_;
119              
120 0   0     0 my $method = $args->{method} || q(GET);
121 0   0     0 my $headers = $args->{headers} || {};
122 0         0 my $url = $args->{url};
123              
124 0 0       0 if (! $url) {
125 0         0 croak(q(No 'url' argument?));
126             }
127              
128             #if (! exists $headers->{Host} || ! $headers->{Host}) {
129             # croak(q(No 'host' header?));
130             #}
131              
132             # Init user agent object
133 0         0 my $ua = $self->user_agent();
134              
135             # Avoid the '//' or varnish rules don't fire properly
136 0         0 my $host = $headers->{Host};
137 0 0       0 if (! $host) {
138 0         0 my $url_obj = URI->new($url);
139 0 0       0 if (! $url_obj) {
140 0         0 croak(qq(URI failed parsing url '$url'. Can't continue without a "Host" header.));
141             }
142 0         0 $host = $url_obj->host();
143             }
144              
145 0         0 my $req = HTTP::Request->new($method => $url);
146              
147             # We need to set HTTP/1.1 Host: header or the varnish
148             # rules based on hostname won't kick in (my.cn. vs my.)
149 0         0 $req->header(Host => $host);
150              
151 0 0       0 if ($headers) {
152 0         0 while (my ($name, $value) = each %{ $headers }) {
  0         0  
153 0 0       0 if ($name eq 'Cookie') {
154 0         0 ($name, $value) = split '=', $value, 2;
155             #diag ("Setting cookie [$name] => [$value]");
156 0         0 $ua->cookie_jar->set_cookie(undef, $name, $value, '/', $host);
157             #$req->header(Cookie => "$name=$value");
158             }
159             else {
160 0         0 $req->header($name => $value);
161             }
162             }
163             }
164              
165 0         0 my $res = $ua->request($req);
166              
167             #if ($headers && exists $headers->{Cookie}) {
168             # $ua->cookie_jar->clear_temporary_cookies();
169             #}
170              
171 0         0 return $res;
172             }
173              
174             sub _response_sets_cookies {
175 0     0   0 my ($res) = @_;
176              
177 0         0 my $cookie_header = $res->header("Set-Cookie");
178             #diag("cookie_header: " . ($cookie_header || ""));
179              
180 0 0 0     0 return defined $cookie_header && $cookie_header ne q{}
181             ? 1
182             : 0;
183             }
184              
185             sub user_agent {
186 0     0 1 0 my ($self) = @_;
187              
188 0         0 my $ua = LWP::UserAgent->new( max_redirect => 0 );
189 0         0 my $jar = HTTP::Cookies->new();
190              
191 0         0 $ua->agent($self->user_agent_string());
192 0         0 $ua->cookie_jar($jar);
193              
194 0         0 return $ua;
195             }
196              
197             sub user_agent_string {
198              
199 0     0 1 0 return qq{Test-Varnish/$VERSION};
200              
201             }
202              
203             sub verbose {
204 5     5 1 8 my $self = shift;
205            
206 5 50       17 if (@_) {
207 0 0       0 $self->{_verbose} = shift(@_) ? 1 : 0;
208             }
209              
210 5         15 return $self->{_verbose};
211             }
212              
213             1; # End of Test::Varnish
214              
215             __END__