Bug 33146: Unit tests
[koha-ffzg.git] / t / db_dependent / api / v1 / suggestions.t
1 #!/usr/bin/env perl
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 use Test::More tests => 5;
21 use Test::Mojo;
22
23 use t::lib::TestBuilder;
24 use t::lib::Mocks;
25
26 use Koha::Suggestions;
27 use Koha::Database;
28
29 my $schema  = Koha::Database->new->schema;
30 my $builder = t::lib::TestBuilder->new;
31
32 my $t = Test::Mojo->new('Koha::REST::V1');
33 t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
34
35 subtest 'list() tests' => sub {
36
37     plan tests => 11;
38
39     $schema->storage->txn_begin;
40
41     my $librarian = $builder->build_object(
42         {
43             class => 'Koha::Patrons',
44             value => { flags => 2 ** 12 } # suggestions flag = 12
45         }
46     );
47     my $password = 'thePassword123';
48     $librarian->set_password( { password => $password, skip_validation => 1 } );
49     my $userid = $librarian->userid;
50
51     my $patron = $builder->build_object(
52         {
53             class => 'Koha::Patrons',
54             value => { flags => 0 }
55         }
56     );
57
58     $patron->set_password( { password => $password, skip_validation => 1 } );
59
60     my $unauth_userid = $patron->userid;
61     my $patron_id     = $patron->id;
62
63     ## Authorized user tests
64     # No suggestions by patron, so empty array should be returned
65     $t->get_ok("//$userid:$password@/api/v1/suggestions?q={\"suggested_by\":\"$patron_id\"}")
66       ->status_is(200)->json_is( [] );
67
68     my $suggestion_1 = $builder->build_object(
69         {
70             class => 'Koha::Suggestions',
71             value => { suggestedby => $patron_id, STATUS => 'ASKED' }
72         }
73     );
74
75     # One city created, should get returned
76     $t->get_ok("//$userid:$password@/api/v1/suggestions?q={\"suggested_by\":\"$patron_id\"}")
77       ->status_is(200)->json_is( [ $suggestion_1->to_api ] );
78
79     my $suggestion_2 = $builder->build_object(
80         {
81             class => 'Koha::Suggestions',
82             value => { suggestedby => $patron_id, STATUS => 'ASKED' }
83         }
84     );
85
86     # Two SMTP servers created, they should both be returned
87     $t->get_ok("//$userid:$password@/api/v1/suggestions?q={\"suggested_by\":\"$patron_id\"}")
88       ->status_is(200)
89       ->json_is( [ $suggestion_1->to_api, $suggestion_2->to_api, ] );
90
91     # Unauthorized access
92     $t->get_ok("//$unauth_userid:$password@/api/v1/suggestions")
93       ->status_is(403);
94
95     $schema->storage->txn_rollback;
96 };
97
98 subtest 'get() tests' => sub {
99
100     plan tests => 8;
101
102     $schema->storage->txn_begin;
103
104     my $librarian  = $builder->build_object(
105         {
106             class => 'Koha::Patrons',
107             value => { flags => 2 ** 12 } # suggestions flag = 12
108         }
109     );
110     my $password = 'thePassword123';
111     $librarian->set_password( { password => $password, skip_validation => 1 } );
112     my $userid = $librarian->userid;
113
114     my $patron = $builder->build_object(
115         {
116             class => 'Koha::Patrons',
117             value => { flags => 0 }
118         }
119     );
120
121     $patron->set_password( { password => $password, skip_validation => 1 } );
122     my $unauth_userid = $patron->userid;
123     my $patron_id = $patron->id;
124
125     my $suggestion = $builder->build_object(
126         {
127             class => 'Koha::Suggestions',
128             value => { suggestedby => $patron_id, STATUS => 'ASKED' }
129         }
130     );
131
132     $t->get_ok(
133         "//$userid:$password@/api/v1/suggestions/" . $suggestion->id )
134       ->status_is(200)->json_is( $suggestion->to_api );
135
136     $t->get_ok( "//$unauth_userid:$password@/api/v1/suggestions/"
137           . $suggestion->id )->status_is(403);
138
139     my $suggestion_to_delete = $builder->build_object( { class => 'Koha::Suggestions' } );
140     my $non_existent_id = $suggestion_to_delete->id;
141     $suggestion_to_delete->delete;
142
143     $t->get_ok(
144         "//$userid:$password@/api/v1/suggestions/$non_existent_id")
145       ->status_is(404)->json_is( '/error' => 'Suggestion not found.' );
146
147     $schema->storage->txn_rollback;
148 };
149
150 subtest 'add() tests' => sub {
151
152     plan tests => 16;
153
154     $schema->storage->txn_begin;
155
156     my $librarian = $builder->build_object(
157         {
158             class => 'Koha::Patrons',
159             value => { flags => 2 ** 12 } # suggestions flag = 12
160         }
161     );
162     my $password = 'thePassword123';
163     $librarian->set_password( { password => $password, skip_validation => 1 } );
164     my $userid = $librarian->userid;
165
166     my $patron = $builder->build_object(
167         {
168             class => 'Koha::Patrons',
169             value => { flags => 0 }
170         }
171     );
172
173     $patron->set_password( { password => $password, skip_validation => 1 } );
174
175     my $unauth_userid = $patron->userid;
176     my $patron_id     = $patron->id;
177
178     my $suggestion = $builder->build_object(
179         {
180             class => 'Koha::Suggestions',
181             value => { suggestedby => $patron_id, STATUS => 'ASKED' }
182         }
183     );
184     my $suggestion_data = $suggestion->to_api;
185     delete $suggestion_data->{suggestion_id};
186     $suggestion->delete;
187
188     # Unauthorized attempt to write
189     $t->post_ok(
190         "//$unauth_userid:$password@/api/v1/suggestions" => json =>
191           $suggestion_data )->status_is(403);
192
193     # Authorized attempt to write invalid data
194     my $suggestion_with_invalid_field = {
195         blah => 'blah'
196     };
197
198     $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json =>
199           $suggestion_with_invalid_field )->status_is(400)->json_is(
200         "/errors" => [
201             {
202                 message => "Properties not allowed: blah.",
203                 path    => "/body"
204             }
205         ]
206           );
207
208     # Authorized attempt to write
209     my $generated_suggestion =
210       $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json =>
211           $suggestion_data )->status_is( 201, 'SWAGGER3.2.1' )->header_like(
212         Location => qr|^\/api\/v1\/suggestions\/\d*|,
213         'SWAGGER3.4.1'
214     )->tx->res->json;
215
216     my $suggestion_id = $generated_suggestion->{suggestion_id};
217     is_deeply(
218         $generated_suggestion,
219         Koha::Suggestions->find($suggestion_id)->to_api,
220         'The object is returned'
221     );
222
223     # Authorized attempt to create with null id
224     $suggestion_data->{suggestion_id} = undef;
225     $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json =>
226           $suggestion_data )->status_is(400)->json_has('/errors');
227
228     # Authorized attempt to create with existing id
229     $suggestion_data->{suggestion_id} = $suggestion_id;
230     $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json =>
231           $suggestion_data )->status_is(400)->json_is(
232         "/errors" => [
233             {
234                 message => "Read-only.",
235                 path    => "/body/suggestion_id"
236             }
237         ]
238           );
239
240     subtest 'x-koha-override tests' => sub {
241
242         plan tests => 14;
243
244         my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
245
246         t::lib::Mocks::mock_preference( 'MaxTotalSuggestions',    4 );
247         t::lib::Mocks::mock_preference( 'MaxOpenSuggestions',     2 );
248         t::lib::Mocks::mock_preference( 'NumberOfSuggestionDays', 2 );
249
250         my $suggestion = $builder->build_object(
251             {   class => 'Koha::Suggestions',
252                 value => { suggestedby => $patron->id, STATUS => 'ACCEPTED' }
253             }
254         );
255
256         my $suggestion_data = $suggestion->to_api;
257         delete $suggestion_data->{suggestion_id};
258         delete $suggestion_data->{status};
259
260         $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json => $suggestion_data )
261           ->status_is( 201, 'First pending suggestion' );
262
263         $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json => $suggestion_data )
264           ->status_is( 201, 'Second pending suggestion' );
265
266         $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json => $suggestion_data )
267           ->status_is(400)
268           ->json_is( '/error_code' => 'max_pending_reached' );
269
270         $t->post_ok( "//$userid:$password@/api/v1/suggestions"
271              => { 'x-koha-override' => 'max_pending' }
272              => json => $suggestion_data )
273           ->status_is( 201, 'max_pending override does the job' );
274
275         $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json => $suggestion_data )
276           ->status_is(400)
277           ->json_is( '/error_code' => 'max_total_reached' );
278
279         $t->post_ok(
280             "//$userid:$password@/api/v1/suggestions" => { 'x-koha-override' => 'any' } => json => $suggestion_data )
281           ->status_is( 201, 'any overrides anything' );
282     };
283
284     $schema->storage->txn_rollback;
285 };
286
287 subtest 'update() tests' => sub {
288
289     plan tests => 12;
290
291     $schema->storage->txn_begin;
292
293     my $librarian = $builder->build_object(
294         {
295             class => 'Koha::Patrons',
296             value => { flags => 2 ** 12 } # suggestions flag = 12
297         }
298     );
299     my $password = 'thePassword123';
300     $librarian->set_password( { password => $password, skip_validation => 1 } );
301     my $userid = $librarian->userid;
302
303     my $patron = $builder->build_object(
304         {
305             class => 'Koha::Patrons',
306             value => { flags => 0 }
307         }
308     );
309
310     $patron->set_password( { password => $password, skip_validation => 1 } );
311     my $unauth_userid = $patron->userid;
312
313     my $suggestion_id = $builder->build_object(
314         {
315             class => 'Koha::Suggestions',
316             value => { STATUS => 'ASKED' }
317         }
318     )->id;
319
320     # Unauthorized attempt to update
321     $t->put_ok(
322         "//$unauth_userid:$password@/api/v1/suggestions/$suggestion_id"
323           => json => { name => 'New unauthorized name change' } )
324       ->status_is(403);
325
326     # Full object update on PUT
327     my $suggestion_with_updated_field = { reason => "Some reason", };
328
329     $t->put_ok(
330         "//$userid:$password@/api/v1/suggestions/$suggestion_id" =>
331           json => $suggestion_with_updated_field )->status_is(200)
332       ->json_is( '/reason' => 'Some reason' );
333
334     # Authorized attempt to write invalid data
335     my $suggestion_with_invalid_field = {
336         blah   => "Blah",
337         reason => 'Some reason'
338     };
339
340     $t->put_ok(
341         "//$userid:$password@/api/v1/suggestions/$suggestion_id" =>
342           json => $suggestion_with_invalid_field )->status_is(400)->json_is(
343         "/errors" => [
344             {
345                 message => "Properties not allowed: blah.",
346                 path    => "/body"
347             }
348         ]
349           );
350
351     my $suggestion_to_delete = $builder->build_object({ class => 'Koha::Suggestions' });
352     my $non_existent_id = $suggestion_to_delete->id;
353     $suggestion_to_delete->delete;
354
355     $t->put_ok(
356         "//$userid:$password@/api/v1/suggestions/$non_existent_id" =>
357           json => $suggestion_with_updated_field )->status_is(404);
358
359     # Wrong method (POST)
360     $suggestion_with_updated_field->{smtp_server_id} = 2;
361
362     $t->post_ok(
363         "//$userid:$password@/api/v1/suggestions/$suggestion_id" =>
364           json => $suggestion_with_updated_field )->status_is(404);
365
366     $schema->storage->txn_rollback;
367 };
368
369 subtest 'delete() tests' => sub {
370
371     plan tests => 7;
372
373     $schema->storage->txn_begin;
374
375     my $librarian = $builder->build_object(
376         {
377             class => 'Koha::Patrons',
378             value => { flags => 2 ** 12 } # suggestions flag = 12
379         }
380     );
381     my $password = 'thePassword123';
382     $librarian->set_password( { password => $password, skip_validation => 1 } );
383     my $userid = $librarian->userid;
384
385     my $patron = $builder->build_object(
386         {
387             class => 'Koha::Patrons',
388             value => { flags => 0 }
389         }
390     );
391
392     $patron->set_password( { password => $password, skip_validation => 1 } );
393     my $unauth_userid = $patron->userid;
394
395     my $suggestion_id = $builder->build_object({ class => 'Koha::Suggestions' } )->id;
396
397     # Unauthorized attempt to delete
398     $t->delete_ok(
399         "//$unauth_userid:$password@/api/v1/suggestions/$suggestion_id"
400     )->status_is(403);
401
402     $t->delete_ok(
403         "//$userid:$password@/api/v1/suggestions/$suggestion_id")
404       ->status_is( 204, 'SWAGGER3.2.4' )->content_is( q{}, 'SWAGGER3.3.4' );
405
406     $t->delete_ok(
407         "//$userid:$password@/api/v1/suggestions/$suggestion_id")
408       ->status_is(404);
409
410     $schema->storage->txn_rollback;
411 };