From 165f33c2d94219a048afca9c213b8536c1418ca9 Mon Sep 17 00:00:00 2001 From: datbth Date: Wed, 16 Dec 2020 15:09:03 +0700 Subject: [PATCH 01/15] record schema coverage when testing responses --- lib/committee.rb | 1 + lib/committee/test/methods.rb | 18 ++++++ lib/committee/test/schema_coverage.rb | 69 ++++++++++++++++++++ test/data/openapi3/coverage.yaml | 52 +++++++++++++++ test/test/methods_test.rb | 91 +++++++++++++++++++++++++++ test/test_helper.rb | 8 +++ 6 files changed, 239 insertions(+) create mode 100644 lib/committee/test/schema_coverage.rb create mode 100644 test/data/openapi3/coverage.yaml diff --git a/lib/committee.rb b/lib/committee.rb index bd2a4332..4d8d2680 100644 --- a/lib/committee.rb +++ b/lib/committee.rb @@ -29,3 +29,4 @@ def self.warn_deprecated(message) require_relative "committee/bin/committee_stub" require_relative "committee/test/methods" +require_relative "committee/test/schema_coverage" diff --git a/lib/committee/test/methods.rb b/lib/committee/test/methods.rb index c5aad5fe..59bf1252 100644 --- a/lib/committee/test/methods.rb +++ b/lib/committee/test/methods.rb @@ -24,6 +24,10 @@ def assert_response_schema_confirm end status, headers, body = response_data + + current_schema_coverage&.update_coverage!(request_object.path_info, request_object.request_method, status) + schema_coverage&.update_coverage!(request_object.path_info, request_object.request_method, status) + schema_validator.response_validate(status, headers, [body], true) if validate_response?(status) end @@ -55,6 +59,20 @@ def schema_validator @schema_validator ||= router.build_schema_validator(request_object) end + def current_schema_coverage + return nil unless schema.is_a?(Committee::Drivers::OpenAPI3::Schema) + + @current_schema_coverage ||= SchemaCoverage.new(schema) + end + + def schema_coverage + return nil unless schema.is_a?(Committee::Drivers::OpenAPI3::Schema) + + coverage = committee_options.fetch(:schema_coverage, nil) + + coverage.is_a?(SchemaCoverage) ? coverage : nil + end + def old_behavior old_assert_behavior = committee_options.fetch(:old_assert_behavior, nil) if old_assert_behavior.nil? diff --git a/lib/committee/test/schema_coverage.rb b/lib/committee/test/schema_coverage.rb new file mode 100644 index 00000000..90b9b902 --- /dev/null +++ b/lib/committee/test/schema_coverage.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module Committee + module Test + class SchemaCoverage + attr_reader :schema + + def initialize(schema) + raise 'Unsupported schema' unless schema.is_a?(Committee::Drivers::OpenAPI3::Schema) + + @schema = schema + @covered = {} + end + + def update_coverage!(path, method, response_status) + method = method.to_s.downcase + response_status = response_status.to_s + + @covered[path] ||= {} + @covered[path][method] ||= {} + @covered[path][method]['responses'] ||= {} + @covered[path][method]['responses'][response_status] = true + end + + # def method_missing(method, *args, &block) + # @covered.send(method, *args, &block) + # end + + def report + full = {} + covered_full_paths = [] + uncovered_full_paths = [] + + schema.open_api.paths.path.each do |path_name, path_item| + full[path_name] = {} + path_item._openapi_all_child_objects.each do |object_name, object| + next unless object.is_a?(OpenAPIParser::Schemas::Operation) + + method = object_name.split('/').last&.downcase + next unless method + + full[path_name][method] = { + # TODO: check coverage on request params/body as well? + 'responses' => object.responses.response.map do |response_status, _| + response_status = response_status.to_s + has_covered = @covered.dig(path_name, method, 'responses', response_status) || false + array_to_update = has_covered ? covered_full_paths : uncovered_full_paths + array_to_update << [path_name, method, 'responses', response_status].join(' ') + [response_status, has_covered] + end.to_h + } + end + end + + { + full: full, + covered: covered_full_paths, + uncovered: uncovered_full_paths, + } + end + + def test! + report = self.report + raise "Uncovered paths:\n#{report[:uncovered].join("\n")}" unless report[:uncovered].empty? + end + end + end +end + diff --git a/test/data/openapi3/coverage.yaml b/test/data/openapi3/coverage.yaml new file mode 100644 index 00000000..7a957505 --- /dev/null +++ b/test/data/openapi3/coverage.yaml @@ -0,0 +1,52 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: OpenAPI3 Coverage Test + description: A Sample file for coverage test +servers: +- url: https://github.com/interagent/committee/ +paths: + /posts: + get: + description: get post + responses: + '200': + description: success + content: + application/json: + schema: + type: object + '404': + description: post not found + content: + application/json: + schema: + type: object + post: + description: create a new post + responses: + '200': + description: success + content: + application/json: + schema: + type: object + /likes: + post: + description: like a post + responses: + '200': + description: success + content: + application/json: + schema: + type: object + delete: + description: unlike a post + responses: + '200': + description: success + content: + application/json: + schema: + type: object diff --git a/test/test/methods_test.rb b/test/test/methods_test.rb index abb2c298..5f8ea36d 100644 --- a/test/test/methods_test.rb +++ b/test/test/methods_test.rb @@ -227,6 +227,97 @@ def response_data end assert_match(/`GET \/undefined` undefined in schema/i, e.message) end + + describe 'coverage' do + it 'records openapi coverage' do + @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) + @committee_options.merge!(schema: open_api_3_coverage_schema, schema_coverage: @schema_coverage) + + @app = new_rack_app(JSON.generate({ success: true })) + get "/posts" + assert_response_schema_confirm + assert_equal(@schema_coverage.report[:covered], [ + '/posts get responses 200', + ]) + assert_equal(@schema_coverage.report[:uncovered], [ + '/posts get responses 404', + '/posts post responses 200', + '/likes post responses 200', + '/likes delete responses 200', + ]) + + post "/likes" + assert_response_schema_confirm + assert_equal([ + '/posts get responses 200', + '/likes post responses 200', + ], @schema_coverage.report[:covered]) + assert_equal([ + '/posts get responses 404', + '/posts post responses 200', + '/likes delete responses 200', + ], @schema_coverage.report[:uncovered]) + + delete "/likes" + assert_response_schema_confirm + assert_equal([ + '/posts get responses 200', + '/likes post responses 200', + '/likes delete responses 200', + ], @schema_coverage.report[:covered]) + assert_equal([ + '/posts get responses 404', + '/posts post responses 200', + ], @schema_coverage.report[:uncovered]) + assert_equal({ + '/posts' => { + 'get' => { + 'responses' => { + '200' => true, + '404' => false, + }, + }, + 'post' => { + 'responses' => { + '200' => false, + }, + }, + }, + '/likes' => { + 'post' => { + 'responses' => { + '200' => true, + }, + }, + 'delete' => { + 'responses' => { + '200' => true, + }, + }, + }, + }, @schema_coverage.report[:full]) + + e = assert_raises(RuntimeError) do + @schema_coverage.test! + end + assert_match(/Uncovered paths/i, e.message) + + post "/posts" + assert_response_schema_confirm + get "/posts" + last_response.status = 404 + assert_response_schema_confirm + assert_equal([ + '/posts get responses 200', + '/posts get responses 404', + '/posts post responses 200', + '/likes post responses 200', + '/likes delete responses 200', + ], @schema_coverage.report[:covered]) + assert_equal([], @schema_coverage.report[:uncovered]) + @schema_coverage.test! + end + end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index c60996e2..52d71d68 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -59,6 +59,10 @@ def open_api_3_schema @open_api_3_schema ||= Committee::Drivers.load_from_file(open_api_3_schema_path) end +def open_api_3_coverage_schema + @open_api_3_coverage_schema ||= Committee::Drivers.load_from_file(open_api_3_coverage_schema_path) +end + # Don't cache this because we'll often manipulate the created hash in tests. def hyper_schema_data JSON.parse(File.read(hyper_schema_schema_path)) @@ -85,6 +89,10 @@ def open_api_3_schema_path "./test/data/openapi3/normal.yaml" end +def open_api_3_coverage_schema_path + "./test/data/openapi3/coverage.yaml" +end + def open_api_3_0_1_schema_path "./test/data/openapi3/3_0_1.yaml" end From f8b71c94ccb2d2ffb394e3b658cc52cca6de1631 Mon Sep 17 00:00:00 2001 From: datbth Date: Wed, 16 Dec 2020 16:57:47 +0700 Subject: [PATCH 02/15] refactor and return report that is more processible --- lib/committee/test/methods.rb | 4 +- lib/committee/test/schema_coverage.rb | 43 +++++++-------- test/test/methods_test.rb | 78 ++++++++++++++------------- 3 files changed, 63 insertions(+), 62 deletions(-) diff --git a/lib/committee/test/methods.rb b/lib/committee/test/methods.rb index 59bf1252..e9501843 100644 --- a/lib/committee/test/methods.rb +++ b/lib/committee/test/methods.rb @@ -25,8 +25,8 @@ def assert_response_schema_confirm status, headers, body = response_data - current_schema_coverage&.update_coverage!(request_object.path_info, request_object.request_method, status) - schema_coverage&.update_coverage!(request_object.path_info, request_object.request_method, status) + current_schema_coverage&.update_response_coverage!(request_object.path_info, request_object.request_method, status) + schema_coverage&.update_response_coverage!(request_object.path_info, request_object.request_method, status) schema_validator.response_validate(status, headers, [body], true) if validate_response?(status) end diff --git a/lib/committee/test/schema_coverage.rb b/lib/committee/test/schema_coverage.rb index 90b9b902..3a871ae6 100644 --- a/lib/committee/test/schema_coverage.rb +++ b/lib/committee/test/schema_coverage.rb @@ -12,7 +12,7 @@ def initialize(schema) @covered = {} end - def update_coverage!(path, method, response_status) + def update_response_coverage!(path, method, response_status) method = method.to_s.downcase response_status = response_status.to_s @@ -22,14 +22,9 @@ def update_coverage!(path, method, response_status) @covered[path][method]['responses'][response_status] = true end - # def method_missing(method, *args, &block) - # @covered.send(method, *args, &block) - # end - def report full = {} - covered_full_paths = [] - uncovered_full_paths = [] + responses = [] schema.open_api.paths.path.each do |path_name, path_item| full[path_name] = {} @@ -39,30 +34,30 @@ def report method = object_name.split('/').last&.downcase next unless method - full[path_name][method] = { - # TODO: check coverage on request params/body as well? - 'responses' => object.responses.response.map do |response_status, _| - response_status = response_status.to_s - has_covered = @covered.dig(path_name, method, 'responses', response_status) || false - array_to_update = has_covered ? covered_full_paths : uncovered_full_paths - array_to_update << [path_name, method, 'responses', response_status].join(' ') - [response_status, has_covered] - end.to_h - } + full[path_name][method] ||= {} + + # TODO: check coverage on request params/body as well? + + full[path_name][method]['responses'] ||= {} + object.responses.response.each do |response_status, _| + response_status = response_status.to_s + is_covered = @covered.dig(path_name, method, 'responses', response_status) || false + full[path_name][method]['responses'][response_status] = is_covered + responses << { + path: path_name, + method: method, + status: response_status, + is_covered: is_covered, + } + end end end { full: full, - covered: covered_full_paths, - uncovered: uncovered_full_paths, + responses: responses, } end - - def test! - report = self.report - raise "Uncovered paths:\n#{report[:uncovered].join("\n")}" unless report[:uncovered].empty? - end end end end diff --git a/test/test/methods_test.rb b/test/test/methods_test.rb index 5f8ea36d..99024fe4 100644 --- a/test/test/methods_test.rb +++ b/test/test/methods_test.rb @@ -229,6 +229,18 @@ def response_data end describe 'coverage' do + def response_as_str(response) + [:path, :method, :status].map { |key| response[key] }.join(' ') + end + + def uncovered_responses + @schema_coverage.report[:responses].select { |r| !r[:is_covered] }.map { |r| response_as_str(r) } + end + + def covered_responses + @schema_coverage.report[:responses].select { |r| r[:is_covered] }.map { |r| response_as_str(r) } + end + it 'records openapi coverage' do @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) @committee_options.merge!(schema: open_api_3_coverage_schema, schema_coverage: @schema_coverage) @@ -236,39 +248,39 @@ def response_data @app = new_rack_app(JSON.generate({ success: true })) get "/posts" assert_response_schema_confirm - assert_equal(@schema_coverage.report[:covered], [ - '/posts get responses 200', - ]) - assert_equal(@schema_coverage.report[:uncovered], [ - '/posts get responses 404', - '/posts post responses 200', - '/likes post responses 200', - '/likes delete responses 200', - ]) + assert_equal([ + '/posts get 200', + ], covered_responses) + assert_equal([ + '/posts get 404', + '/posts post 200', + '/likes post 200', + '/likes delete 200', + ], uncovered_responses) post "/likes" assert_response_schema_confirm assert_equal([ - '/posts get responses 200', - '/likes post responses 200', - ], @schema_coverage.report[:covered]) + '/posts get 200', + '/likes post 200', + ], covered_responses) assert_equal([ - '/posts get responses 404', - '/posts post responses 200', - '/likes delete responses 200', - ], @schema_coverage.report[:uncovered]) + '/posts get 404', + '/posts post 200', + '/likes delete 200', + ], uncovered_responses) delete "/likes" assert_response_schema_confirm assert_equal([ - '/posts get responses 200', - '/likes post responses 200', - '/likes delete responses 200', - ], @schema_coverage.report[:covered]) + '/posts get 200', + '/likes post 200', + '/likes delete 200', + ], covered_responses) assert_equal([ - '/posts get responses 404', - '/posts post responses 200', - ], @schema_coverage.report[:uncovered]) + '/posts get 404', + '/posts post 200', + ], uncovered_responses) assert_equal({ '/posts' => { 'get' => { @@ -297,25 +309,19 @@ def response_data }, }, @schema_coverage.report[:full]) - e = assert_raises(RuntimeError) do - @schema_coverage.test! - end - assert_match(/Uncovered paths/i, e.message) - post "/posts" assert_response_schema_confirm get "/posts" last_response.status = 404 assert_response_schema_confirm assert_equal([ - '/posts get responses 200', - '/posts get responses 404', - '/posts post responses 200', - '/likes post responses 200', - '/likes delete responses 200', - ], @schema_coverage.report[:covered]) - assert_equal([], @schema_coverage.report[:uncovered]) - @schema_coverage.test! + '/posts get 200', + '/posts get 404', + '/posts post 200', + '/likes post 200', + '/likes delete 200', + ], covered_responses) + assert_equal([], uncovered_responses) end end end From 508c7bede8bd56885c4507f1610c37ca586a0f2d Mon Sep 17 00:00:00 2001 From: datbth Date: Wed, 16 Dec 2020 17:11:03 +0700 Subject: [PATCH 03/15] refactor --- lib/committee/test/schema_coverage.rb | 26 ++++++++++++++++++-------- test/test/methods_test.rb | 6 +++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/committee/test/schema_coverage.rb b/lib/committee/test/schema_coverage.rb index 3a871ae6..34aacea4 100644 --- a/lib/committee/test/schema_coverage.rb +++ b/lib/committee/test/schema_coverage.rb @@ -23,26 +23,38 @@ def update_response_coverage!(path, method, response_status) end def report - full = {} - responses = [] + report = {} schema.open_api.paths.path.each do |path_name, path_item| - full[path_name] = {} + report[path_name] = {} path_item._openapi_all_child_objects.each do |object_name, object| next unless object.is_a?(OpenAPIParser::Schemas::Operation) method = object_name.split('/').last&.downcase next unless method - full[path_name][method] ||= {} + report[path_name][method] ||= {} # TODO: check coverage on request params/body as well? - full[path_name][method]['responses'] ||= {} + report[path_name][method]['responses'] ||= {} object.responses.response.each do |response_status, _| response_status = response_status.to_s is_covered = @covered.dig(path_name, method, 'responses', response_status) || false - full[path_name][method]['responses'][response_status] = is_covered + report[path_name][method]['responses'][response_status] = is_covered + end + end + end + + report + end + + def report_flatten + responses = [] + report.each do |path_name, path_coverage| + path_coverage.each do |method, method_coverage| + responses_coverage = method_coverage['responses'] + responses_coverage.each do |response_status, is_covered| responses << { path: path_name, method: method, @@ -52,9 +64,7 @@ def report end end end - { - full: full, responses: responses, } end diff --git a/test/test/methods_test.rb b/test/test/methods_test.rb index 99024fe4..ecfccada 100644 --- a/test/test/methods_test.rb +++ b/test/test/methods_test.rb @@ -234,11 +234,11 @@ def response_as_str(response) end def uncovered_responses - @schema_coverage.report[:responses].select { |r| !r[:is_covered] }.map { |r| response_as_str(r) } + @schema_coverage.report_flatten[:responses].select { |r| !r[:is_covered] }.map { |r| response_as_str(r) } end def covered_responses - @schema_coverage.report[:responses].select { |r| r[:is_covered] }.map { |r| response_as_str(r) } + @schema_coverage.report_flatten[:responses].select { |r| r[:is_covered] }.map { |r| response_as_str(r) } end it 'records openapi coverage' do @@ -307,7 +307,7 @@ def covered_responses }, }, }, - }, @schema_coverage.report[:full]) + }, @schema_coverage.report) post "/posts" assert_response_schema_confirm From 4d9374469e064224d6cbb18e728626d4f978e5cb Mon Sep 17 00:00:00 2001 From: datbth Date: Wed, 16 Dec 2020 17:43:01 +0700 Subject: [PATCH 04/15] add helper method to merge reports --- lib/committee/test/schema_coverage.rb | 18 +++++ test/test/schema_coverage_test.rb | 99 +++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 test/test/schema_coverage_test.rb diff --git a/lib/committee/test/schema_coverage.rb b/lib/committee/test/schema_coverage.rb index 34aacea4..93385c4c 100644 --- a/lib/committee/test/schema_coverage.rb +++ b/lib/committee/test/schema_coverage.rb @@ -5,6 +5,24 @@ module Test class SchemaCoverage attr_reader :schema + class << self + def merge_report(first, second) + report = first.dup + second.each do |k, v| + if v.is_a?(Hash) + if report[k].nil? + report[k] = v + else + report[k] = merge_report(report[k], v) + end + else + report[k] ||= v + end + end + report + end + end + def initialize(schema) raise 'Unsupported schema' unless schema.is_a?(Committee::Drivers::OpenAPI3::Schema) diff --git a/test/test/schema_coverage_test.rb b/test/test/schema_coverage_test.rb new file mode 100644 index 00000000..8848e250 --- /dev/null +++ b/test/test/schema_coverage_test.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require "test_helper" + +describe Committee::Test::SchemaCoverage do + before do + @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) + end + + describe '.merge_report' do + it 'can merge 2 coverage reports together' do + report = Committee::Test::SchemaCoverage.merge_report( + { + '/posts' => { + 'get' => { + 'responses' => { + '200' => true, + '404' => false, + }, + }, + 'post' => { + 'responses' => { + '200' => false, + }, + }, + }, + '/likes' => { + 'post' => { + 'responses' => { + '200' => true, + }, + }, + }, + }, + { + '/posts' => { + 'get' => { + 'responses' => { + '200' => true, + '404' => true, + }, + }, + 'post' => { + 'responses' => { + '200' => false, + }, + }, + }, + '/likes' => { + 'post' => { + 'responses' => { + '200' => false, + '400' => false, + }, + }, + }, + '/users' => { + 'get' => { + 'responses' => { + '200' => true, + }, + }, + }, + }, + ) + + assert_equal({ + '/posts' => { + 'get' => { + 'responses' => { + '200' => true, + '404' => true, + }, + }, + 'post' => { + 'responses' => { + '200' => false, + }, + }, + }, + '/likes' => { + 'post' => { + 'responses' => { + '200' => true, + '400' => false, + }, + }, + }, + '/users' => { + 'get' => { + 'responses' => { + '200' => true, + }, + }, + }, + }, report) + end + end +end From e6d0647280022b3d76e27e4627a7a68e1789a52a Mon Sep 17 00:00:00 2001 From: datbth Date: Wed, 16 Dec 2020 17:47:31 +0700 Subject: [PATCH 05/15] refactor tests --- test/test/methods_test.rb | 63 +--------------------- test/test/schema_coverage_test.rb | 87 +++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 61 deletions(-) diff --git a/test/test/methods_test.rb b/test/test/methods_test.rb index ecfccada..bb69727c 100644 --- a/test/test/methods_test.rb +++ b/test/test/methods_test.rb @@ -229,18 +229,6 @@ def response_data end describe 'coverage' do - def response_as_str(response) - [:path, :method, :status].map { |key| response[key] }.join(' ') - end - - def uncovered_responses - @schema_coverage.report_flatten[:responses].select { |r| !r[:is_covered] }.map { |r| response_as_str(r) } - end - - def covered_responses - @schema_coverage.report_flatten[:responses].select { |r| r[:is_covered] }.map { |r| response_as_str(r) } - end - it 'records openapi coverage' do @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) @committee_options.merge!(schema: open_api_3_coverage_schema, schema_coverage: @schema_coverage) @@ -248,39 +236,6 @@ def covered_responses @app = new_rack_app(JSON.generate({ success: true })) get "/posts" assert_response_schema_confirm - assert_equal([ - '/posts get 200', - ], covered_responses) - assert_equal([ - '/posts get 404', - '/posts post 200', - '/likes post 200', - '/likes delete 200', - ], uncovered_responses) - - post "/likes" - assert_response_schema_confirm - assert_equal([ - '/posts get 200', - '/likes post 200', - ], covered_responses) - assert_equal([ - '/posts get 404', - '/posts post 200', - '/likes delete 200', - ], uncovered_responses) - - delete "/likes" - assert_response_schema_confirm - assert_equal([ - '/posts get 200', - '/likes post 200', - '/likes delete 200', - ], covered_responses) - assert_equal([ - '/posts get 404', - '/posts post 200', - ], uncovered_responses) assert_equal({ '/posts' => { 'get' => { @@ -298,30 +253,16 @@ def covered_responses '/likes' => { 'post' => { 'responses' => { - '200' => true, + '200' => false, }, }, 'delete' => { 'responses' => { - '200' => true, + '200' => false, }, }, }, }, @schema_coverage.report) - - post "/posts" - assert_response_schema_confirm - get "/posts" - last_response.status = 404 - assert_response_schema_confirm - assert_equal([ - '/posts get 200', - '/posts get 404', - '/posts post 200', - '/likes post 200', - '/likes delete 200', - ], covered_responses) - assert_equal([], uncovered_responses) end end end diff --git a/test/test/schema_coverage_test.rb b/test/test/schema_coverage_test.rb index 8848e250..f3768b27 100644 --- a/test/test/schema_coverage_test.rb +++ b/test/test/schema_coverage_test.rb @@ -7,6 +7,93 @@ @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) end + describe 'recording coverage' do + def response_as_str(response) + [:path, :method, :status].map { |key| response[key] }.join(' ') + end + + def uncovered_responses + @schema_coverage.report_flatten[:responses].select { |r| !r[:is_covered] }.map { |r| response_as_str(r) } + end + + def covered_responses + @schema_coverage.report_flatten[:responses].select { |r| r[:is_covered] }.map { |r| response_as_str(r) } + end + it 'can record and report coverage properly' do + @schema_coverage.update_response_coverage!('/posts', 'get', '200') + assert_equal([ + '/posts get 200', + ], covered_responses) + assert_equal([ + '/posts get 404', + '/posts post 200', + '/likes post 200', + '/likes delete 200', + ], uncovered_responses) + + @schema_coverage.update_response_coverage!('/likes', 'post', '200') + assert_equal([ + '/posts get 200', + '/likes post 200', + ], covered_responses) + assert_equal([ + '/posts get 404', + '/posts post 200', + '/likes delete 200', + ], uncovered_responses) + + @schema_coverage.update_response_coverage!('/likes', 'delete', '200') + assert_equal([ + '/posts get 200', + '/likes post 200', + '/likes delete 200', + ], covered_responses) + assert_equal([ + '/posts get 404', + '/posts post 200', + ], uncovered_responses) + + assert_equal({ + '/posts' => { + 'get' => { + 'responses' => { + '200' => true, + '404' => false, + }, + }, + 'post' => { + 'responses' => { + '200' => false, + }, + }, + }, + '/likes' => { + 'post' => { + 'responses' => { + '200' => true, + }, + }, + 'delete' => { + 'responses' => { + '200' => true, + }, + }, + }, + }, @schema_coverage.report) + + @schema_coverage.update_response_coverage!('/posts', 'post', '200') + @schema_coverage.update_response_coverage!('/posts', 'get', '404') + assert_equal([ + '/posts get 200', + '/posts get 404', + '/posts post 200', + '/likes post 200', + '/likes delete 200', + ], covered_responses) + assert_equal([], uncovered_responses) + end + end + describe '.merge_report' do it 'can merge 2 coverage reports together' do report = Committee::Test::SchemaCoverage.merge_report( From 9e60f00c55004d08a71e260e83bf9a046b33d2ad Mon Sep 17 00:00:00 2001 From: datbth Date: Wed, 16 Dec 2020 17:48:37 +0700 Subject: [PATCH 06/15] refactor helper method --- lib/committee/test/schema_coverage.rb | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/committee/test/schema_coverage.rb b/lib/committee/test/schema_coverage.rb index 93385c4c..cd17d19b 100644 --- a/lib/committee/test/schema_coverage.rb +++ b/lib/committee/test/schema_coverage.rb @@ -21,6 +21,26 @@ def merge_report(first, second) end report end + + def flatten_report(report) + responses = [] + report.each do |path_name, path_coverage| + path_coverage.each do |method, method_coverage| + responses_coverage = method_coverage['responses'] + responses_coverage.each do |response_status, is_covered| + responses << { + path: path_name, + method: method, + status: response_status, + is_covered: is_covered, + } + end + end + end + { + responses: responses, + } + end end def initialize(schema) @@ -68,23 +88,7 @@ def report end def report_flatten - responses = [] - report.each do |path_name, path_coverage| - path_coverage.each do |method, method_coverage| - responses_coverage = method_coverage['responses'] - responses_coverage.each do |response_status, is_covered| - responses << { - path: path_name, - method: method, - status: response_status, - is_covered: is_covered, - } - end - end - end - { - responses: responses, - } + self.class.flatten_report(report) end end end From 718222ce63515c3d22d9387beb86d71cc9ba0b5a Mon Sep 17 00:00:00 2001 From: datbth Date: Wed, 16 Dec 2020 18:04:21 +0700 Subject: [PATCH 07/15] update README for test schema coverage --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/README.md b/README.md index a871d45e..b3c20b7f 100644 --- a/README.md +++ b/README.md @@ -403,6 +403,38 @@ end The default assertion option in 2.* was `validate_success_only=true`, but this becomes `validate_success_only=false` in 3.*. For the smoothest possible upgrade, you should set it to `false` in your test suite before upgrading to 3.*. +**Test schema coverage** +NOTE: Currently committee only supports schema coverage for openapi schemas, and only checks coverage on responses. +Steps: +1. Either: + 1. Set schema_coverage option of `committee_options` (e.g. `@committee_options[:schema_coverage] = Committee::Test::SchemaCoverage.new(schema)`) to combine coverage of multiple tests + 2. Or get schema coverage after individual tests using helper method `current_schema_coverage` +2. Then use `SchemaCoverage#report` or `SchemaCoverage#report_flatten` to get coverage report + +Coverage report structure: +``` +/* using #report */ +{ + => { + => { + 'responses' => { + => + } + } + } +} +/* using #report_flatten */ +{ + responses: [ + { path: , method: , status: , is_covered: }, + ] +} +``` + +Other helper methods: +* `Committee::Test::SchemaCoverage.merge_report(, )`: merge 2 coverage reports together +* `Committee::Test::SchemaCoverage.flatten_report()`: flatten a coverage report Hash into flatten structure + ### Other changes * `GET` request bodies are ignored in OpenAPI 3 by default. If you want to use them, set the `allow_get_body` option to `true`. From 63c036d1834fee1fb884fd5527b5d96fd9be46bb Mon Sep 17 00:00:00 2001 From: datbth Date: Mon, 21 Dec 2020 10:39:26 +0700 Subject: [PATCH 08/15] clarify docs --- README.md | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b3c20b7f..03f5b545 100644 --- a/README.md +++ b/README.md @@ -404,13 +404,35 @@ end The default assertion option in 2.* was `validate_success_only=true`, but this becomes `validate_success_only=false` in 3.*. For the smoothest possible upgrade, you should set it to `false` in your test suite before upgrading to 3.*. **Test schema coverage** -NOTE: Currently committee only supports schema coverage for openapi schemas, and only checks coverage on responses. -Steps: +NOTICE: Currently committee only supports schema coverage for **openapi** schemas, and only checks coverage on responses, via `assert_response_schema_confirm` or `assert_schema_conform` methods. +Usage: 1. Either: - 1. Set schema_coverage option of `committee_options` (e.g. `@committee_options[:schema_coverage] = Committee::Test::SchemaCoverage.new(schema)`) to combine coverage of multiple tests - 2. Or get schema coverage after individual tests using helper method `current_schema_coverage` + 1. Set schema_coverage option of `committee_options` to combine coverage of multiple tests + 2. Or get schema coverage after individual tests using helper method `current_schema_coverage` 2. Then use `SchemaCoverage#report` or `SchemaCoverage#report_flatten` to get coverage report +Example: +```ruby +before do + schema_coverage_to_be_used_among_multiple_tests = Committee::Test::SchemaCoverage.new(openapi_schema) + @committee_options[:schema_coverage] = schema_coverage_to_be_used_among_multiple_tests +end +it 'covers the openapi schema' do + get '/some_api' + assert_response_schema_confirm # or assert_schema_confirm + current_schema_coverage.report +end +it 'covers the openapi schema' do + get '/other_api' + assert_response_schema_confirm # or assert_schema_confirm + current_schema_coverage.report +end +after do + coverage_report = schema_coverage_to_be_used_among_multiple_tests.report + # check coverage expectations on coverage_report here +end +``` + Coverage report structure: ``` /* using #report */ From 0712eedd3eb1e433dd2434b46912d6199cd7b1bb Mon Sep 17 00:00:00 2001 From: datbth Date: Mon, 21 Dec 2020 11:00:08 +0700 Subject: [PATCH 09/15] schema coverage: support 'default' response --- lib/committee/test/schema_coverage.rb | 7 ++++++- test/data/openapi3/coverage.yaml | 8 +++++++- test/test/schema_coverage_test.rb | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/committee/test/schema_coverage.rb b/lib/committee/test/schema_coverage.rb index cd17d19b..a2dce88c 100644 --- a/lib/committee/test/schema_coverage.rb +++ b/lib/committee/test/schema_coverage.rb @@ -77,10 +77,15 @@ def report report[path_name][method]['responses'] ||= {} object.responses.response.each do |response_status, _| - response_status = response_status.to_s is_covered = @covered.dig(path_name, method, 'responses', response_status) || false report[path_name][method]['responses'][response_status] = is_covered end + if object.responses.default + is_default_covered = (@covered.dig(path_name, method, 'responses') || {}).any? do |status, is_covered| + is_covered && !object.responses.response.key?(status) + end + report[path_name][method]['responses']['default'] = is_default_covered + end end end diff --git a/test/data/openapi3/coverage.yaml b/test/data/openapi3/coverage.yaml index 7a957505..5094e376 100644 --- a/test/data/openapi3/coverage.yaml +++ b/test/data/openapi3/coverage.yaml @@ -8,7 +8,7 @@ servers: paths: /posts: get: - description: get post + description: get a post responses: '200': description: success @@ -22,6 +22,12 @@ paths: application/json: schema: type: object + default: + description: unknown request + content: + application/json: + schema: + type: object post: description: create a new post responses: diff --git a/test/test/schema_coverage_test.rb b/test/test/schema_coverage_test.rb index f3768b27..6a67f93d 100644 --- a/test/test/schema_coverage_test.rb +++ b/test/test/schema_coverage_test.rb @@ -26,6 +26,7 @@ def covered_responses ], covered_responses) assert_equal([ '/posts get 404', + '/posts get default', '/posts post 200', '/likes post 200', '/likes delete 200', @@ -38,6 +39,7 @@ def covered_responses ], covered_responses) assert_equal([ '/posts get 404', + '/posts get default', '/posts post 200', '/likes delete 200', ], uncovered_responses) @@ -48,6 +50,19 @@ def covered_responses '/likes post 200', '/likes delete 200', ], covered_responses) + assert_equal([ + '/posts get 404', + '/posts get default', + '/posts post 200', + ], uncovered_responses) + + @schema_coverage.update_response_coverage!('/posts', 'get', '422') + assert_equal([ + '/posts get 200', + '/posts get default', + '/likes post 200', + '/likes delete 200', + ], covered_responses) assert_equal([ '/posts get 404', '/posts post 200', @@ -59,6 +74,7 @@ def covered_responses 'responses' => { '200' => true, '404' => false, + 'default' => true, }, }, 'post' => { @@ -86,6 +102,7 @@ def covered_responses assert_equal([ '/posts get 200', '/posts get 404', + '/posts get default', '/posts post 200', '/likes post 200', '/likes delete 200', From 1681c8708531d275c813da807602266fe35a35f8 Mon Sep 17 00:00:00 2001 From: datbth Date: Mon, 21 Dec 2020 11:06:37 +0700 Subject: [PATCH 10/15] remove current_schema_coverage to avoid confusion It was hard to tell which tests took part in current_schema_coverage --- README.md | 26 ++++++++++++++------------ lib/committee/test/methods.rb | 7 ------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 03f5b545..d6af215e 100644 --- a/README.md +++ b/README.md @@ -404,32 +404,34 @@ end The default assertion option in 2.* was `validate_success_only=true`, but this becomes `validate_success_only=false` in 3.*. For the smoothest possible upgrade, you should set it to `false` in your test suite before upgrading to 3.*. **Test schema coverage** +You can check how much of your API schema your tests have covered. NOTICE: Currently committee only supports schema coverage for **openapi** schemas, and only checks coverage on responses, via `assert_response_schema_confirm` or `assert_schema_conform` methods. Usage: -1. Either: - 1. Set schema_coverage option of `committee_options` to combine coverage of multiple tests - 2. Or get schema coverage after individual tests using helper method `current_schema_coverage` -2. Then use `SchemaCoverage#report` or `SchemaCoverage#report_flatten` to get coverage report +1. Set schema_coverage option of `committee_options` +2. Use `assert_response_schema_confirm` or `assert_schema_conform` +3. Then use `SchemaCoverage#report` or `SchemaCoverage#report_flatten` to get coverage report Example: ```ruby before do - schema_coverage_to_be_used_among_multiple_tests = Committee::Test::SchemaCoverage.new(openapi_schema) - @committee_options[:schema_coverage] = schema_coverage_to_be_used_among_multiple_tests + schema_coverage = Committee::Test::SchemaCoverage.new(openapi_schema) + @committee_options[:schema_coverage] = schema_coverage end -it 'covers the openapi schema' do +it 'covers /some_api' do get '/some_api' assert_response_schema_confirm # or assert_schema_confirm - current_schema_coverage.report + coverage_report = schema_coverage.report + # check coverage expectations of /some_api here end -it 'covers the openapi schema' do +it 'covers /other_api schema' do get '/other_api' assert_response_schema_confirm # or assert_schema_confirm - current_schema_coverage.report + coverage_report = schema_coverage.report + # check coverage expectations of /other_api here end after do - coverage_report = schema_coverage_to_be_used_among_multiple_tests.report - # check coverage expectations on coverage_report here + coverage_report = schema_coverage.report + # check coverage expectations of all apis here end ``` diff --git a/lib/committee/test/methods.rb b/lib/committee/test/methods.rb index e9501843..6fbacd77 100644 --- a/lib/committee/test/methods.rb +++ b/lib/committee/test/methods.rb @@ -25,7 +25,6 @@ def assert_response_schema_confirm status, headers, body = response_data - current_schema_coverage&.update_response_coverage!(request_object.path_info, request_object.request_method, status) schema_coverage&.update_response_coverage!(request_object.path_info, request_object.request_method, status) schema_validator.response_validate(status, headers, [body], true) if validate_response?(status) @@ -59,12 +58,6 @@ def schema_validator @schema_validator ||= router.build_schema_validator(request_object) end - def current_schema_coverage - return nil unless schema.is_a?(Committee::Drivers::OpenAPI3::Schema) - - @current_schema_coverage ||= SchemaCoverage.new(schema) - end - def schema_coverage return nil unless schema.is_a?(Committee::Drivers::OpenAPI3::Schema) From 5778b2c577baf74b9e84848bc9df757a52673bf1 Mon Sep 17 00:00:00 2001 From: datbth Date: Mon, 21 Dec 2020 11:10:50 +0700 Subject: [PATCH 11/15] update test --- test/test/methods_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test/methods_test.rb b/test/test/methods_test.rb index bb69727c..5d18b266 100644 --- a/test/test/methods_test.rb +++ b/test/test/methods_test.rb @@ -242,6 +242,7 @@ def response_data 'responses' => { '200' => true, '404' => false, + 'default' => false, }, }, 'post' => { From c0ccbb10606c38c45185c1e376649b4b530ae901 Mon Sep 17 00:00:00 2001 From: datbth Date: Mon, 21 Dec 2020 14:23:40 +0700 Subject: [PATCH 12/15] fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d6af215e..3f92164e 100644 --- a/README.md +++ b/README.md @@ -419,13 +419,13 @@ before do end it 'covers /some_api' do get '/some_api' - assert_response_schema_confirm # or assert_schema_confirm + assert_response_schema_confirm # or assert_schema_conform coverage_report = schema_coverage.report # check coverage expectations of /some_api here end it 'covers /other_api schema' do get '/other_api' - assert_response_schema_confirm # or assert_schema_confirm + assert_response_schema_confirm # or assert_schema_conform coverage_report = schema_coverage.report # check coverage expectations of /other_api here end From 32600b24c4835e138a72b376f62885b8fbcf0bf5 Mon Sep 17 00:00:00 2001 From: datbth Date: Tue, 22 Dec 2020 15:37:59 +0700 Subject: [PATCH 13/15] raise error when request does not match prefix --- lib/committee/schema_validator/open_api_3/router.rb | 4 +++- lib/committee/test/methods.rb | 4 ++-- test/test/methods_test.rb | 10 ++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/committee/schema_validator/open_api_3/router.rb b/lib/committee/schema_validator/open_api_3/router.rb index 2e62a22a..e8310212 100644 --- a/lib/committee/schema_validator/open_api_3/router.rb +++ b/lib/committee/schema_validator/open_api_3/router.rb @@ -23,7 +23,9 @@ def build_schema_validator(request) def operation_object(request) path = request.path - path = path.gsub(@prefix_regexp, '') if prefix_request?(request) + return nil unless includes_request?(request) + + path = path.gsub(@prefix_regexp, '') if @prefix_regexp request_method = request.request_method.downcase diff --git a/lib/committee/test/methods.rb b/lib/committee/test/methods.rb index 6fbacd77..7ea0e166 100644 --- a/lib/committee/test/methods.rb +++ b/lib/committee/test/methods.rb @@ -10,7 +10,7 @@ def assert_schema_conform def assert_request_schema_confirm unless schema_validator.link_exist? - request = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema." + request = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema (prefix: #{committee_options[:prefix].inspect})." raise Committee::InvalidRequest.new(request) end @@ -19,7 +19,7 @@ def assert_request_schema_confirm def assert_response_schema_confirm unless schema_validator.link_exist? - response = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema." + response = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema (prefix: #{committee_options[:prefix].inspect})." raise Committee::InvalidResponse.new(response) end diff --git a/test/test/methods_test.rb b/test/test/methods_test.rb index 5d18b266..ed90d38f 100644 --- a/test/test/methods_test.rb +++ b/test/test/methods_test.rb @@ -228,6 +228,16 @@ def response_data assert_match(/`GET \/undefined` undefined in schema/i, e.message) end + it "raises error when path does not match prefix" do + @committee_options.merge!({prefix: '/api'}) + @app = new_rack_app(JSON.generate(@correct_response)) + get "/characters" + e = assert_raises(Committee::InvalidResponse) do + assert_response_schema_confirm + end + assert_match(/`GET \/characters` undefined in schema \(prefix: "\/api"\)/i, e.message) + end + describe 'coverage' do it 'records openapi coverage' do @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) From 9c9f330de110a64a6e4a38f3401f48815bbf281d Mon Sep 17 00:00:00 2001 From: datbth Date: Tue, 22 Dec 2020 16:02:17 +0700 Subject: [PATCH 14/15] fix coverage report when prefix is set --- .../schema_validator/open_api_3/router.rb | 10 ++++- lib/committee/test/methods.rb | 2 +- test/test/methods_test.rb | 37 +++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/lib/committee/schema_validator/open_api_3/router.rb b/lib/committee/schema_validator/open_api_3/router.rb index e8310212..f5d5c880 100644 --- a/lib/committee/schema_validator/open_api_3/router.rb +++ b/lib/committee/schema_validator/open_api_3/router.rb @@ -21,11 +21,17 @@ def build_schema_validator(request) Committee::SchemaValidator::OpenAPI3.new(self, request, @validator_option) end - def operation_object(request) - path = request.path + def operation_path(request) return nil unless includes_request?(request) + path = request.path path = path.gsub(@prefix_regexp, '') if @prefix_regexp + path + end + + def operation_object(request) + path = operation_path(request) + return nil unless path request_method = request.request_method.downcase diff --git a/lib/committee/test/methods.rb b/lib/committee/test/methods.rb index 7ea0e166..f3117641 100644 --- a/lib/committee/test/methods.rb +++ b/lib/committee/test/methods.rb @@ -25,7 +25,7 @@ def assert_response_schema_confirm status, headers, body = response_data - schema_coverage&.update_response_coverage!(request_object.path_info, request_object.request_method, status) + schema_coverage&.update_response_coverage!(router.operation_path(request_object), request_object.request_method, status) schema_validator.response_validate(status, headers, [body], true) if validate_response?(status) end diff --git a/test/test/methods_test.rb b/test/test/methods_test.rb index ed90d38f..cdd33292 100644 --- a/test/test/methods_test.rb +++ b/test/test/methods_test.rb @@ -275,6 +275,43 @@ def response_data }, }, @schema_coverage.report) end + + it 'can records openapi coverage correctly when prefix is set' do + @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) + @committee_options.merge!(schema: open_api_3_coverage_schema, schema_coverage: @schema_coverage, prefix: '/api') + + @app = new_rack_app(JSON.generate({ success: true })) + post "/api/likes" + assert_response_schema_confirm + assert_equal({ + '/posts' => { + 'get' => { + 'responses' => { + '200' => false, + '404' => false, + 'default' => false, + }, + }, + 'post' => { + 'responses' => { + '200' => false, + }, + }, + }, + '/likes' => { + 'post' => { + 'responses' => { + '200' => true, + }, + }, + 'delete' => { + 'responses' => { + '200' => false, + }, + }, + }, + }, @schema_coverage.report) + end end end end From 8043cc758254505902dd5bd2ba36f3b1198de285 Mon Sep 17 00:00:00 2001 From: datbth Date: Tue, 22 Dec 2020 16:29:55 +0700 Subject: [PATCH 15/15] schema coverage: handle path params --- .../open_api_3/operation_wrapper.rb | 4 ++ .../schema_validator/open_api_3/router.rb | 8 +-- lib/committee/test/methods.rb | 5 +- test/data/openapi3/coverage.yaml | 16 +++++ test/test/methods_test.rb | 65 +++++++++++++++++-- test/test/schema_coverage_test.rb | 13 ++++ 6 files changed, 97 insertions(+), 14 deletions(-) diff --git a/lib/committee/schema_validator/open_api_3/operation_wrapper.rb b/lib/committee/schema_validator/open_api_3/operation_wrapper.rb index f4b62da5..f5ba9422 100644 --- a/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +++ b/lib/committee/schema_validator/open_api_3/operation_wrapper.rb @@ -17,6 +17,10 @@ def original_path request_operation.original_path end + def http_method + request_operation.http_method + end + def coerce_path_parameter(validator_option) options = build_openapi_parser_path_option(validator_option) return {} unless options.coerce_value diff --git a/lib/committee/schema_validator/open_api_3/router.rb b/lib/committee/schema_validator/open_api_3/router.rb index f5d5c880..d0d49ab1 100644 --- a/lib/committee/schema_validator/open_api_3/router.rb +++ b/lib/committee/schema_validator/open_api_3/router.rb @@ -21,17 +21,11 @@ def build_schema_validator(request) Committee::SchemaValidator::OpenAPI3.new(self, request, @validator_option) end - def operation_path(request) + def operation_object(request) return nil unless includes_request?(request) path = request.path path = path.gsub(@prefix_regexp, '') if @prefix_regexp - path - end - - def operation_object(request) - path = operation_path(request) - return nil unless path request_method = request.request_method.downcase diff --git a/lib/committee/test/methods.rb b/lib/committee/test/methods.rb index f3117641..3c0489ca 100644 --- a/lib/committee/test/methods.rb +++ b/lib/committee/test/methods.rb @@ -25,7 +25,10 @@ def assert_response_schema_confirm status, headers, body = response_data - schema_coverage&.update_response_coverage!(router.operation_path(request_object), request_object.request_method, status) + if schema_coverage + operation_object = router.operation_object(request_object) + schema_coverage&.update_response_coverage!(operation_object.original_path, operation_object.http_method, status) + end schema_validator.response_validate(status, headers, [body], true) if validate_response?(status) end diff --git a/test/data/openapi3/coverage.yaml b/test/data/openapi3/coverage.yaml index 5094e376..b36c9b0d 100644 --- a/test/data/openapi3/coverage.yaml +++ b/test/data/openapi3/coverage.yaml @@ -6,6 +6,22 @@ info: servers: - url: https://github.com/interagent/committee/ paths: + /threads/{id}: + parameters: + - name: id + in: path + required: true + schema: + type: string + get: + description: get a thread + responses: + '200': + description: success + content: + application/json: + schema: + type: object /posts: get: description: get a post diff --git a/test/test/methods_test.rb b/test/test/methods_test.rb index cdd33292..47b445ab 100644 --- a/test/test/methods_test.rb +++ b/test/test/methods_test.rb @@ -239,14 +239,23 @@ def response_data end describe 'coverage' do - it 'records openapi coverage' do + before do @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) @committee_options.merge!(schema: open_api_3_coverage_schema, schema_coverage: @schema_coverage) @app = new_rack_app(JSON.generate({ success: true })) + end + it 'records openapi coverage' do get "/posts" assert_response_schema_confirm assert_equal({ + '/threads/{id}' => { + 'get' => { + 'responses' => { + '200' => false, + }, + }, + }, '/posts' => { 'get' => { 'responses' => { @@ -276,14 +285,18 @@ def response_data }, @schema_coverage.report) end - it 'can records openapi coverage correctly when prefix is set' do - @schema_coverage = Committee::Test::SchemaCoverage.new(open_api_3_coverage_schema) - @committee_options.merge!(schema: open_api_3_coverage_schema, schema_coverage: @schema_coverage, prefix: '/api') - - @app = new_rack_app(JSON.generate({ success: true })) + it 'can record openapi coverage correctly when prefix is set' do + @committee_options.merge!(prefix: '/api') post "/api/likes" assert_response_schema_confirm assert_equal({ + '/threads/{id}' => { + 'get' => { + 'responses' => { + '200' => false, + }, + }, + }, '/posts' => { 'get' => { 'responses' => { @@ -312,6 +325,46 @@ def response_data }, }, @schema_coverage.report) end + + it 'records openapi coverage correctly with path param' do + get "/threads/asd" + assert_response_schema_confirm + assert_equal({ + '/threads/{id}' => { + 'get' => { + 'responses' => { + '200' => true, + }, + }, + }, + '/posts' => { + 'get' => { + 'responses' => { + '200' => false, + '404' => false, + 'default' => false, + }, + }, + 'post' => { + 'responses' => { + '200' => false, + }, + }, + }, + '/likes' => { + 'post' => { + 'responses' => { + '200' => false, + }, + }, + 'delete' => { + 'responses' => { + '200' => false, + }, + }, + }, + }, @schema_coverage.report) + end end end end diff --git a/test/test/schema_coverage_test.rb b/test/test/schema_coverage_test.rb index 6a67f93d..db72ce32 100644 --- a/test/test/schema_coverage_test.rb +++ b/test/test/schema_coverage_test.rb @@ -25,6 +25,7 @@ def covered_responses '/posts get 200', ], covered_responses) assert_equal([ + '/threads/{id} get 200', '/posts get 404', '/posts get default', '/posts post 200', @@ -38,6 +39,7 @@ def covered_responses '/likes post 200', ], covered_responses) assert_equal([ + '/threads/{id} get 200', '/posts get 404', '/posts get default', '/posts post 200', @@ -51,6 +53,7 @@ def covered_responses '/likes delete 200', ], covered_responses) assert_equal([ + '/threads/{id} get 200', '/posts get 404', '/posts get default', '/posts post 200', @@ -64,11 +67,19 @@ def covered_responses '/likes delete 200', ], covered_responses) assert_equal([ + '/threads/{id} get 200', '/posts get 404', '/posts post 200', ], uncovered_responses) assert_equal({ + '/threads/{id}' => { + 'get' => { + 'responses' => { + '200' => false, + }, + }, + }, '/posts' => { 'get' => { 'responses' => { @@ -99,7 +110,9 @@ def covered_responses @schema_coverage.update_response_coverage!('/posts', 'post', '200') @schema_coverage.update_response_coverage!('/posts', 'get', '404') + @schema_coverage.update_response_coverage!('/threads/{id}', 'get', '200') assert_equal([ + '/threads/{id} get 200', '/posts get 200', '/posts get 404', '/posts get default',