Bug 32942: (QA follow-up) Fix regression test
[koha.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 suggestion 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 => 11;
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     my $authorised_value = Koha::AuthorisedValue->new(
137         {
138             category         => 'SUGGEST_STATUS',
139             authorised_value => 'FREDERIC'
140         }
141     )->store;
142     $suggestion->STATUS('FREDERIC')->store->discard_changes;
143
144     $t->get_ok( "//$userid:$password@/api/v1/suggestions/" . $suggestion->id )->status_is(200)
145         ->json_is( $suggestion->to_api );
146
147     $t->get_ok( "//$unauth_userid:$password@/api/v1/suggestions/"
148           . $suggestion->id )->status_is(403);
149
150     my $suggestion_to_delete = $builder->build_object( { class => 'Koha::Suggestions' } );
151     my $non_existent_id = $suggestion_to_delete->id;
152     $suggestion_to_delete->delete;
153
154     $t->get_ok(
155         "//$userid:$password@/api/v1/suggestions/$non_existent_id")
156       ->status_is(404)->json_is( '/error' => 'Suggestion not found.' );
157
158     $schema->storage->txn_rollback;
159 };
160
161 subtest 'add() tests' => sub {
162
163     plan tests => 16;
164
165     $schema->storage->txn_begin;
166
167     my $librarian = $builder->build_object(
168         {
169             class => 'Koha::Patrons',
170             value => { flags => 2 ** 12 } # suggestions flag = 12
171         }
172     );
173     my $password = 'thePassword123';
174     $librarian->set_password( { password => $password, skip_validation => 1 } );
175     my $userid = $librarian->userid;
176
177     my $patron = $builder->build_object(
178         {
179             class => 'Koha::Patrons',
180             value => { flags => 0 }
181         }
182     );
183
184     $patron->set_password( { password => $password, skip_validation => 1 } );
185
186     my $unauth_userid = $patron->userid;
187     my $patron_id     = $patron->id;
188
189     my $suggestion = $builder->build_object(
190         {
191             class => 'Koha::Suggestions',
192             value => { suggestedby => $patron_id, STATUS => 'ASKED' }
193         }
194     );
195     my $suggestion_data = $suggestion->to_api;
196     delete $suggestion_data->{suggestion_id};
197     $suggestion->delete;
198
199     # Unauthorized attempt to write
200     $t->post_ok(
201         "//$unauth_userid:$password@/api/v1/suggestions" => json =>
202           $suggestion_data )->status_is(403);
203
204     # Authorized attempt to write invalid data
205     my $suggestion_with_invalid_field = {
206         blah => 'blah'
207     };
208
209     $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json =>
210           $suggestion_with_invalid_field )->status_is(400)->json_is(
211         "/errors" => [
212             {
213                 message => "Properties not allowed: blah.",
214                 path    => "/body"
215             }
216         ]
217           );
218
219     # Authorized attempt to write
220     my $generated_suggestion =
221       $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json =>
222           $suggestion_data )->status_is( 201, 'SWAGGER3.2.1' )->header_like(
223         Location => qr|^\/api\/v1\/suggestions\/\d*|,
224         'SWAGGER3.4.1'
225     )->tx->res->json;
226
227     my $suggestion_id = $generated_suggestion->{suggestion_id};
228     is_deeply(
229         $generated_suggestion,
230         Koha::Suggestions->find($suggestion_id)->to_api,
231         'The object is returned'
232     );
233
234     # Authorized attempt to create with null id
235     $suggestion_data->{suggestion_id} = undef;
236     $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json =>
237           $suggestion_data )->status_is(400)->json_has('/errors');
238
239     # Authorized attempt to create with existing id
240     $suggestion_data->{suggestion_id} = $suggestion_id;
241     $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json =>
242           $suggestion_data )->status_is(400)->json_is(
243         "/errors" => [
244             {
245                 message => "Read-only.",
246                 path    => "/body/suggestion_id"
247             }
248         ]
249           );
250
251     subtest 'x-koha-override tests' => sub {
252
253         plan tests => 14;
254
255         my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
256
257         t::lib::Mocks::mock_preference( 'MaxTotalSuggestions',    4 );
258         t::lib::Mocks::mock_preference( 'MaxOpenSuggestions',     2 );
259         t::lib::Mocks::mock_preference( 'NumberOfSuggestionDays', 2 );
260
261         my $suggestion = $builder->build_object(
262             {   class => 'Koha::Suggestions',
263                 value => { suggestedby => $patron->id, STATUS => 'ACCEPTED' }
264             }
265         );
266
267         my $suggestion_data = $suggestion->to_api;
268         delete $suggestion_data->{suggestion_id};
269         delete $suggestion_data->{status};
270
271         $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json => $suggestion_data )
272           ->status_is( 201, 'First pending suggestion' );
273
274         $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json => $suggestion_data )
275           ->status_is( 201, 'Second pending suggestion' );
276
277         $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json => $suggestion_data )
278           ->status_is(400)
279           ->json_is( '/error_code' => 'max_pending_reached' );
280
281         $t->post_ok( "//$userid:$password@/api/v1/suggestions"
282              => { 'x-koha-override' => 'max_pending' }
283              => json => $suggestion_data )
284           ->status_is( 201, 'max_pending override does the job' );
285
286         $t->post_ok( "//$userid:$password@/api/v1/suggestions" => json => $suggestion_data )
287           ->status_is(400)
288           ->json_is( '/error_code' => 'max_total_reached' );
289
290         $t->post_ok(
291             "//$userid:$password@/api/v1/suggestions" => { 'x-koha-override' => 'any' } => json => $suggestion_data )
292           ->status_is( 201, 'any overrides anything' );
293     };
294
295     $schema->storage->txn_rollback;
296 };
297
298 subtest 'update() tests' => sub {
299
300     plan tests => 12;
301
302     $schema->storage->txn_begin;
303
304     my $librarian = $builder->build_object(
305         {
306             class => 'Koha::Patrons',
307             value => { flags => 2 ** 12 } # suggestions flag = 12
308         }
309     );
310     my $password = 'thePassword123';
311     $librarian->set_password( { password => $password, skip_validation => 1 } );
312     my $userid = $librarian->userid;
313
314     my $patron = $builder->build_object(
315         {
316             class => 'Koha::Patrons',
317             value => { flags => 0 }
318         }
319     );
320
321     $patron->set_password( { password => $password, skip_validation => 1 } );
322     my $unauth_userid = $patron->userid;
323
324     my $suggestion_id = $builder->build_object(
325         {
326             class => 'Koha::Suggestions',
327             value => { STATUS => 'ASKED' }
328         }
329     )->id;
330
331     # Unauthorized attempt to update
332     $t->put_ok(
333         "//$unauth_userid:$password@/api/v1/suggestions/$suggestion_id"
334           => json => { name => 'New unauthorized name change' } )
335       ->status_is(403);
336
337     # Full object update on PUT
338     my $suggestion_with_updated_field = { reason => "Some reason", };
339
340     $t->put_ok(
341         "//$userid:$password@/api/v1/suggestions/$suggestion_id" =>
342           json => $suggestion_with_updated_field )->status_is(200)
343       ->json_is( '/reason' => 'Some reason' );
344
345     # Authorized attempt to write invalid data
346     my $suggestion_with_invalid_field = {
347         blah   => "Blah",
348         reason => 'Some reason'
349     };
350
351     $t->put_ok(
352         "//$userid:$password@/api/v1/suggestions/$suggestion_id" =>
353           json => $suggestion_with_invalid_field )->status_is(400)->json_is(
354         "/errors" => [
355             {
356                 message => "Properties not allowed: blah.",
357                 path    => "/body"
358             }
359         ]
360           );
361
362     my $suggestion_to_delete = $builder->build_object({ class => 'Koha::Suggestions' });
363     my $non_existent_id = $suggestion_to_delete->id;
364     $suggestion_to_delete->delete;
365
366     $t->put_ok(
367         "//$userid:$password@/api/v1/suggestions/$non_existent_id" =>
368           json => $suggestion_with_updated_field )->status_is(404);
369
370     # Wrong method (POST)
371     $suggestion_with_updated_field->{smtp_server_id} = 2;
372
373     $t->post_ok(
374         "//$userid:$password@/api/v1/suggestions/$suggestion_id" =>
375           json => $suggestion_with_updated_field )->status_is(404);
376
377     $schema->storage->txn_rollback;
378 };
379
380 subtest 'delete() tests' => sub {
381
382     plan tests => 7;
383
384     $schema->storage->txn_begin;
385
386     my $librarian = $builder->build_object(
387         {
388             class => 'Koha::Patrons',
389             value => { flags => 2 ** 12 } # suggestions flag = 12
390         }
391     );
392     my $password = 'thePassword123';
393     $librarian->set_password( { password => $password, skip_validation => 1 } );
394     my $userid = $librarian->userid;
395
396     my $patron = $builder->build_object(
397         {
398             class => 'Koha::Patrons',
399             value => { flags => 0 }
400         }
401     );
402
403     $patron->set_password( { password => $password, skip_validation => 1 } );
404     my $unauth_userid = $patron->userid;
405
406     my $suggestion_id = $builder->build_object({ class => 'Koha::Suggestions' } )->id;
407
408     # Unauthorized attempt to delete
409     $t->delete_ok(
410         "//$unauth_userid:$password@/api/v1/suggestions/$suggestion_id"
411     )->status_is(403);
412
413     $t->delete_ok(
414         "//$userid:$password@/api/v1/suggestions/$suggestion_id")
415       ->status_is( 204, 'SWAGGER3.2.4' )->content_is( q{}, 'SWAGGER3.3.4' );
416
417     $t->delete_ok(
418         "//$userid:$password@/api/v1/suggestions/$suggestion_id")
419       ->status_is(404);
420
421     $schema->storage->txn_rollback;
422 };