| # |
| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| use t::APISIX 'no_plan'; |
| |
| repeat_each(1); |
| no_long_string(); |
| no_shuffle(); |
| no_root_location(); |
| |
| add_block_preprocessor(sub { |
| my ($block) = @_; |
| |
| my $http_config = $block->http_config // <<_EOC_; |
| # fake server, only for test |
| server { |
| listen 1970; |
| location / { |
| content_by_lua_block { |
| ngx.say("ok") |
| } |
| } |
| } |
| _EOC_ |
| |
| $block->set_value("http_config", $http_config); |
| |
| if (!$block->request) { |
| $block->set_value("request", "GET /t"); |
| } |
| |
| if (!$block->error_log && !$block->no_error_log) { |
| $block->set_value("no_error_log", "[error]\n[alert]"); |
| } |
| }); |
| |
| run_tests; |
| |
| __DATA__ |
| |
| === TEST 1: OAS 3.1 -- create route with spec31.json |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s" |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1970": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 2: OAS 3.1 exclusiveMinimum/Maximum (numeric) -- value within range should pass |
| --- request |
| POST /api/v31/exclusive |
| {"score": 50} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 3: OAS 3.1 exclusiveMinimum -- value equal to lower bound (0) should fail |
| --- request |
| POST /api/v31/exclusive |
| {"score": 0} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 4: OAS 3.1 exclusiveMaximum -- value equal to upper bound (100) should fail |
| --- request |
| POST /api/v31/exclusive |
| {"score": 100} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 5: OAS 3.1 if/then/else -- circle with radius should pass (then branch) |
| --- request |
| POST /api/v31/shape |
| {"type": "circle", "radius": 5} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 6: OAS 3.1 if/then -- circle without radius should fail |
| --- request |
| POST /api/v31/shape |
| {"type": "circle"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 7: OAS 3.1 if/else -- rectangle with width and height should pass (else branch) |
| --- request |
| POST /api/v31/shape |
| {"type": "rectangle", "width": 10, "height": 5} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 8: OAS 3.1 if/else -- rectangle missing width should fail |
| --- request |
| POST /api/v31/shape |
| {"type": "rectangle", "height": 5} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 9: OAS 3.1 anyOf -- matching first subschema should pass |
| --- request |
| POST /api/v31/anyof |
| {"name": "doggie"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 10: OAS 3.1 anyOf -- matching second subschema should pass |
| --- request |
| POST /api/v31/anyof |
| {"id": 42} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 11: OAS 3.1 anyOf -- matching neither subschema should fail |
| --- request |
| POST /api/v31/anyof |
| {"other": "value"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 12: OAS 3.1 oneOf -- matching exactly one subschema should pass |
| --- request |
| POST /api/v31/oneof |
| {"cat": "whiskers"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 13: OAS 3.1 oneOf -- matching both subschemas should fail |
| --- request |
| POST /api/v31/oneof |
| {"cat": "whiskers", "dog": "rex"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 14: OAS 3.1 allOf -- all subschemas satisfied should pass |
| --- request |
| POST /api/v31/allof |
| {"a": "hello", "b": 42} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 15: OAS 3.1 allOf -- missing field required by one subschema should fail |
| --- request |
| POST /api/v31/allof |
| {"a": "hello"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 16: OAS 3.1 -- route with spec31.json and reject_if_not_match = false |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s", |
| "reject_if_not_match": false |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1980": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 17: OAS 3.1 reject_if_not_match = false -- invalid body passes through to upstream |
| --- upstream_server_config |
| location /api/v31/pet { |
| content_by_lua_block { |
| ngx.log(ngx.WARN, "upstream reached") |
| ngx.status = 200 |
| ngx.say("ok") |
| } |
| } |
| --- request |
| POST /api/v31/pet |
| {"lol": "watdis?"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- error_log |
| error occurred while validating request |
| --- grep_error_log eval |
| qr/upstream reached/ |
| --- grep_error_log_out |
| upstream reached |
| |
| |
| |
| === TEST 18: OAS 3.1 -- route with spec31.json and rejection_status_code = 422 |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s", |
| "reject_if_not_match": true, |
| "rejection_status_code": 422 |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1970": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 19: OAS 3.1 rejection_status_code = 422 -- invalid body returns 422 |
| --- request |
| POST /api/v31/pet |
| {"lol": "watdis?"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 422 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 20: OAS 3.1 -- route with spec31.json and verbose_errors = true |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s", |
| "verbose_errors": true |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1970": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 21: OAS 3.1 verbose_errors = true -- error response body contains schema detail |
| --- request |
| POST /api/v31/pet |
| {"lol": "watdis?"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request\..+ |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 22: OAS 3.1 -- route with spec31.json and skip_request_body_validation = true |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s", |
| "skip_request_body_validation": true |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1970": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 23: OAS 3.1 skip_request_body_validation = true -- invalid body is not rejected |
| --- request |
| POST /api/v31/pet |
| {"lol": "watdis?"} |
| --- more_headers |
| Content-Type: application/json |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 24: OAS 3.1 -- route with spec31.json and skip_query_param_validation = true |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s", |
| "skip_query_param_validation": true |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1970": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 25: OAS 3.1 skip_query_param_validation = true -- invalid enum query param is not rejected |
| --- request |
| GET /api/v31/pet/findByStatus?status=married |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| |
| |
| |
| === TEST 26: OAS 3.1 -- route with spec31.json and skip_path_params_validation = true |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s", |
| "skip_path_params_validation": true |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1970": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 27: OAS 3.1 skip_path_params_validation = true -- non-integer path param is not rejected |
| --- request |
| GET /api/v31/pet/not-an-id |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| |
| |
| |
| === TEST 28: OAS 3.1 -- restore route with spec31.json (no extra options) |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s" |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1970": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 29: OAS 3.1 body validation -- valid Pet passes plugin (upstream returns 404) |
| --- request |
| POST /api/v31/pet |
| {"name": "doggie", "photoUrls": ["http://example.com/img.jpg"]} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 30: OAS 3.1 body validation -- missing required field should fail |
| --- request |
| POST /api/v31/pet |
| {"name": "doggie"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 31: OAS 3.1 path param validation -- valid integer id passes plugin |
| --- request |
| GET /api/v31/pet/42 |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 32: OAS 3.1 path param validation -- non-integer id should fail |
| --- request |
| GET /api/v31/pet/not-an-id |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 33: OAS 3.1 query param validation -- valid enum value passes plugin |
| --- request |
| GET /api/v31/pet/findByStatus?status=available |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 34: OAS 3.1 query param validation -- invalid enum value should fail |
| --- request |
| GET /api/v31/pet/findByStatus?status=married |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 35: OAS 3.1 nullable type array -- null value should pass |
| --- request |
| POST /api/v31/nullable |
| {"value": null} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 36: OAS 3.1 nullable type array -- string value should pass |
| --- request |
| POST /api/v31/nullable |
| {"value": "hello"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 37: OAS 3.1 nullable type array -- integer value should fail |
| --- request |
| POST /api/v31/nullable |
| {"value": 123} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 38: OAS 3.1 const keyword -- correct value should pass |
| --- request |
| POST /api/v31/const |
| {"version": "v1"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 39: OAS 3.1 const keyword -- wrong value should fail |
| --- request |
| POST /api/v31/const |
| {"version": "v2"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 40: OAS 3.1 multipleOf validation -- valid value passes |
| --- request |
| POST /api/v31/multipleoftest |
| {"testnumber": 1.13} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 41: OAS 3.1 multipleOf validation -- invalid value should fail |
| --- request |
| POST /api/v31/multipleoftest |
| {"testnumber": 1.1312} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 42: OAS 3.1 -- create route with spec31-gaps.json (components/pathItems, not, patternProperties, $dynamicRef) |
| --- config |
| location /t { |
| content_by_lua_block { |
| local t = require("lib.test_admin") |
| local spec = t.read_file("t/spec/spec31-gaps.json") |
| spec = spec:gsub('\"', '\\"') |
| |
| local code, body = t.test('/apisix/admin/routes/1', |
| ngx.HTTP_PUT, |
| string.format([[{ |
| "uri": "/*", |
| "plugins": { |
| "oas-validator": { |
| "spec": "%s" |
| } |
| }, |
| "upstream": { |
| "type": "roundrobin", |
| "nodes": { |
| "127.0.0.1:1970": 1 |
| } |
| } |
| }]], spec) |
| ) |
| if code >= 300 then |
| ngx.status = code |
| end |
| ngx.say(body) |
| } |
| } |
| --- response_body |
| passed |
| |
| |
| |
| === TEST 43: components/pathItems -- valid body via $ref path should pass |
| --- request |
| POST /api/v31gap/widget |
| {"name": "foo"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 44: components/pathItems -- invalid body via $ref path should fail |
| --- request |
| POST /api/v31gap/widget |
| {"notaname": "foo"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 45: not keyword -- value satisfying not constraint should pass |
| --- request |
| POST /api/v31gap/item |
| {"value": "not-an-integer"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 46: not keyword -- value violating not constraint should fail |
| --- request |
| POST /api/v31gap/item |
| {"value": 42} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 47: patternProperties -- matching key with correct type should pass |
| --- request |
| POST /api/v31gap/pattern |
| {"S_name": "hello"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 48: patternProperties -- matching key with wrong type should fail |
| --- request |
| POST /api/v31gap/pattern |
| {"S_name": 123} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 49: patternProperties with additionalProperties:false -- non-matching key should be rejected |
| --- request |
| POST /api/v31gap/pattern |
| {"S_name": "hello", "extra": "not_allowed"} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 50: $dynamicRef -- array with correct element type should pass |
| --- request |
| POST /api/v31gap/dynref |
| {"items": ["hello", "world"]} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 51: $dynamicRef -- array with wrong element type should fail |
| --- request |
| POST /api/v31gap/dynref |
| {"items": [1, 2, 3]} |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 52: [LIMITATION] contentMediaType/contentEncoding are annotations only -- non-JSON string passes without content validation |
| --- request |
| POST /api/v31gap/content-annotation |
| {"data": "this is NOT valid base64 nor JSON"} |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 53: prefixItems -- correct positional types should pass |
| --- request |
| POST /api/v31gap/prefixitems |
| ["hello", 42, true] |
| --- more_headers |
| Content-Type: application/json |
| --- error_code: 200 |
| --- no_error_log |
| [error] |
| |
| |
| |
| === TEST 54: prefixItems -- wrong type at first position should fail |
| --- request |
| POST /api/v31gap/prefixitems |
| [123, 42, true] |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |
| |
| |
| |
| === TEST 55: [LIMITATION] prefixItems + items -- extra items beyond prefixItems are validated by items schema |
| --- request |
| POST /api/v31gap/prefixitems |
| ["hello", 42, "not_a_boolean"] |
| --- more_headers |
| Content-Type: application/json |
| --- response_body_like: failed to validate request. |
| --- error_code: 400 |
| --- error_log |
| error occurred while validating request |