File Coverage

blib/lib/SimpleMock/Model/LWP_UA.pm
Criterion Covered Total %
statement 58 58 100.0
branch 12 12 100.0
condition 11 12 91.6
subroutine 9 9 100.0
pod 0 2 0.0
total 90 93 96.7


line stmt bran cond sub pod time code
1             package SimpleMock::Model::LWP_UA;
2 5     5   34 use strict;
  5         7  
  5         153  
3 5     5   14 use warnings;
  5         5  
  5         231  
4 5     5   16 use HTTP::Status qw(status_message);
  5         40  
  5         715  
5 5     5   17 use URI::QueryParam;
  5         7  
  5         180  
6 5     5   15 use URI;
  5         24  
  5         115  
7 5     5   14 use Data::Dumper;
  5         7  
  5         284  
8              
9 5         2510 use SimpleMock::Util qw(
10             generate_args_sha
11 5     5   16 );
  5         5  
12              
13             our $VERSION = '0.01';
14              
15             sub mock_send_request {
16 14     14 0 9217 my ($request, $ua, $h) = @_;
17 14         29 my $method = $request->method;
18 14         117 my $url = $request->uri;
19              
20             # initially, only supporting 'application/x-www-form-urlencoded'
21 14         69 my %request_args;
22 14 100       62 if ($method eq 'POST') {
    100          
23 2         5 my $content = $request->content;
24 2         19 my $uri = URI->new("http:dummy/"); # dummy base to reuse parser
25 2         81 $uri->query($content);
26 2         27 %request_args = $uri->query_form;
27             }
28             elsif ($method eq 'GET') {
29 11         19 my $uri = URI->new($request->uri);
30 11         708 %request_args = $uri->query_form;
31             }
32              
33             # if the request has no args, make it undef so that generate_args_sha
34             # returns _default
35 14 100       262 my $sha_arg = %request_args ? \%request_args : undef;
36 14         39 my $args_sha = generate_args_sha($sha_arg);
37              
38             # remove QS from URL before lookup
39 14         294 $url =~ s/\?.*//;
40              
41 14         99 for my $layer (reverse @SimpleMock::MOCK_STACK) {
42 15 100       36 my $lwp = $layer->{LWP_UA} or next;
43             my $response = $lwp->{$url}->{$method}->{$args_sha}
44 14   100     41 || $lwp->{$url}->{$method}->{_default};
45 14 100       101 return $response if $response;
46             }
47              
48 2         5 die "No mock is defined (nor default with no args) for url ($url), method ($method), args: " . Dumper(\%request_args);
49             }
50              
51             sub validate_mocks {
52 5     5 0 22 my $mocks_data = shift;
53              
54 5         10 my $new_mocks = {};
55              
56 5         12 URL: foreach my $url (keys %$mocks_data) {
57 6         8 METHOD: foreach my $method (keys %{$mocks_data->{$url}}) {
  6         16  
58 7         8 MOCK: foreach my $mock (@{ $mocks_data->{$url}->{$method}}) {
  7         23  
59 9         16 my $response_arg_or_content = $mock->{response};
60 9 100       27 my $response_arg = ref $response_arg_or_content eq 'HASH'
61             ? $response_arg_or_content
62             : { content => $response_arg_or_content };
63              
64 9   100     35 $response_arg->{code} //= 200;
65 9   66     46 $response_arg->{message} //= status_message($response_arg->{code});
66 9   100     47 $response_arg->{content} //= '';
67 9   100     29 $response_arg->{headers} //= {};
68              
69             my $response = HTTP::Response->new(
70             $response_arg->{code},
71             $response_arg->{message},
72 9         46 HTTP::Headers->new( %{ $response_arg->{headers} } ),
73             $response_arg->{content},
74 9         13 );
75              
76 9         539 my $sha = generate_args_sha($mock->{args});
77 9         192 $new_mocks->{LWP_UA}->{$url}->{$method}->{$sha} = $response;
78             }
79             }
80             }
81 5         11 return $new_mocks;
82             }
83              
84             1;
85              
86             =head1 NAME
87              
88             SimpleMock::Model::LWP_UA
89              
90             =head1 DESCRIPTION
91              
92             This module allows you to register HTTP mocks for LWP requests, enabling you to simulate various responses for testing purposes without making actual HTTP calls.
93              
94             =head1 USAGE
95              
96             You probably won't use this module directly. Instead, you will use the `SimpleMock` module to register your mocks. Here's an example of how to do that:
97              
98             use SimpleMock qw(register_mocks);
99             register_mocks(
100             LWP_UA => {
101             # URL
102             'http://example.com/api' => {
103             # HTTP method
104             GET => [
105              
106             # Each mock is a hashref with args and response
107             # args can be undef for default mock
108             # response can be a content string, or a hashref with code, message, content, and headers
109              
110             { args => { foo => 'bar' },
111             response => { code => 200, content => 'Success' }
112             },
113              
114             { args => { foo => 'bar2' },
115             response => 'Success'
116             },
117              
118             # Default mock for GET method (no args) or for any other args not explicitly defined
119             { response => { code => 404, content => 'Not Found' } },
120             ],
121             POST => [
122             { args => { data => 'test' },
123             response => { code => 201, content => 'Created' }
124             },
125             ],
126             },
127             },
128             );
129              
130             If args are not specified, the mock will be registered as a default mock for that URL and method.
131             If args are specified, they will be used to differentiate between different mocks for the same
132             URL and method that have different arguments.
133              
134             The response can be a simple content string, or a hashref with the following keys:
135              
136             =over
137              
138             =item * code - HTTP status code (default: 200)
139             =item * message - HTTP status message (default: derived from code)
140             =item * content - The body of the response (default: empty string)
141             =item * headers - A hashref of HTTP headers to include in the response (default: empty)
142              
143             =back
144              
145             See the tests for more examples.
146              
147             =cut