fitting 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +7 -0
- data/lib/fitting.rb +1 -3
- data/lib/fitting/configuration.rb +41 -11
- data/lib/fitting/configuration/legacy.rb +41 -0
- data/lib/fitting/configuration/yaml.rb +60 -0
- data/lib/fitting/matchers/response_matcher.rb +33 -14
- data/lib/fitting/records/documented/request.rb +53 -0
- data/lib/fitting/records/tested/request.rb +30 -0
- data/lib/fitting/records/tested/response.rb +19 -0
- data/lib/fitting/records/unit/json_schema.rb +25 -0
- data/lib/fitting/records/unit/request.rb +36 -0
- data/lib/fitting/records/unit/response.rb +31 -0
- data/lib/fitting/statistics.rb +14 -19
- data/lib/fitting/statistics/analysis.rb +24 -0
- data/lib/fitting/statistics/great.rb +13 -0
- data/lib/fitting/statistics/list.rb +45 -0
- data/lib/fitting/statistics/lists.rb +52 -0
- data/lib/fitting/statistics/measurement.rb +94 -0
- data/lib/fitting/statistics/not_covered_responses.rb +13 -0
- data/lib/fitting/statistics/percent.rb +19 -0
- data/lib/fitting/statistics/requests_stats.rb +40 -0
- data/lib/fitting/statistics/responses_stats.rb +32 -0
- data/lib/fitting/statistics/template.rb +90 -0
- data/lib/fitting/storage/responses.rb +6 -28
- data/lib/fitting/version.rb +1 -1
- metadata +20 -11
- data/lib/fitting/route.rb +0 -28
- data/lib/fitting/route/coverage.rb +0 -45
- data/lib/fitting/route/requests.rb +0 -25
- data/lib/fitting/route/requests/combine.rb +0 -113
- data/lib/fitting/route/requests/coverage.rb +0 -58
- data/lib/fitting/route/requests/lists.rb +0 -92
- data/lib/fitting/route/requests/statistics.rb +0 -40
- data/lib/fitting/route/responses.rb +0 -24
- data/lib/fitting/storage/documentation.rb +0 -22
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'fitting/records/unit/json_schema'
|
2
|
+
|
3
|
+
module Fitting
|
4
|
+
class Records
|
5
|
+
class Unit
|
6
|
+
class Response
|
7
|
+
def initialize(documented_response, tested_responses)
|
8
|
+
@documented_response = documented_response
|
9
|
+
@tested_responses = tested_responses
|
10
|
+
end
|
11
|
+
|
12
|
+
def status
|
13
|
+
@status ||= @documented_response['status']
|
14
|
+
end
|
15
|
+
|
16
|
+
def json_schemas
|
17
|
+
@json_schemas ||= @documented_response['json_schemas'].inject([]) do |res, documented_json_schema|
|
18
|
+
res.push(Fitting::Records::Unit::JsonSchema.new(documented_json_schema, tested_bodies))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def tested_bodies
|
23
|
+
@tested_bodies ||= @tested_responses.inject([]) do |res, tested_response|
|
24
|
+
next res unless status == tested_response.status.to_s
|
25
|
+
res.push(tested_response.body)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/fitting/statistics.rb
CHANGED
@@ -1,30 +1,25 @@
|
|
1
|
-
require 'fitting/
|
2
|
-
require 'fileutils'
|
1
|
+
require 'fitting/statistics/template'
|
3
2
|
|
4
3
|
module Fitting
|
5
4
|
class Statistics
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@black_route = Fitting::Route.new(all_responses, @documentation.black, strict)
|
9
|
-
@white_route = Fitting::Route.new(all_responses, @documentation.white, strict)
|
5
|
+
def initialize(tested_requests)
|
6
|
+
@tested_requests = tested_requests
|
10
7
|
end
|
11
8
|
|
12
9
|
def save
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
if @documentation.black.any?
|
20
|
-
[
|
21
|
-
['[Black list]', @black_route.statistics_with_conformity_lists].join("\n"),
|
22
|
-
['[White list]', @white_route.statistics_with_conformity_lists].join("\n"),
|
23
|
-
''
|
24
|
-
].join("\n\n")
|
10
|
+
make_dir('fitting')
|
11
|
+
if Fitting.configuration.is_a?(Array)
|
12
|
+
Fitting.configuration.each do |config|
|
13
|
+
make_dir("fitting/#{config.title}")
|
14
|
+
Fitting::Statistics::Template.new(@tested_requests, config).save
|
15
|
+
end
|
25
16
|
else
|
26
|
-
|
17
|
+
Fitting::Statistics::Template.new(@tested_requests, Fitting.configuration).save
|
27
18
|
end
|
28
19
|
end
|
20
|
+
|
21
|
+
def make_dir(dir_name)
|
22
|
+
FileUtils.mkdir_p(dir_name)
|
23
|
+
end
|
29
24
|
end
|
30
25
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'fitting/statistics/lists'
|
2
|
+
require 'fitting/statistics/requests_stats'
|
3
|
+
require 'fitting/statistics/responses_stats'
|
4
|
+
require 'fitting/statistics/great'
|
5
|
+
require 'fitting/statistics/not_covered_responses'
|
6
|
+
|
7
|
+
module Fitting
|
8
|
+
class Statistics
|
9
|
+
class Analysis
|
10
|
+
def initialize(measurement)
|
11
|
+
@measurement = measurement
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
[
|
16
|
+
Fitting::Statistics::Lists.new(@measurement).to_s,
|
17
|
+
Fitting::Statistics::RequestsStats.new(@measurement).to_s,
|
18
|
+
Fitting::Statistics::ResponsesStats.new(@measurement).to_s,
|
19
|
+
Fitting::Statistics::Great.new(@measurement).to_s
|
20
|
+
].compact.join("\n\n")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Fitting
|
2
|
+
class Statistics
|
3
|
+
class Great
|
4
|
+
def initialize(measurement)
|
5
|
+
@measurement = measurement
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
return 'All responses are 100% valid! Great job!' if @measurement.cover_responses == @measurement.all_responses
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Fitting
|
2
|
+
class Statistics
|
3
|
+
class List
|
4
|
+
def initialize(coverage, max_response_path)
|
5
|
+
@coverage = coverage
|
6
|
+
@max_response_path = max_response_path
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
list_sort.inject([]) do |res, request|
|
11
|
+
res.push("#{request.method}\t#{request.path}#{responses_stat(request)}")
|
12
|
+
end.join("\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
def list_sort
|
16
|
+
@coverage.sort do |first, second|
|
17
|
+
first.path.to_s <=> second.path.to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def responses_stat(request)
|
22
|
+
tab = "\t" * ((@max_response_path - request.path.to_s.size / 8) + 3)
|
23
|
+
tab + request.responses.to_a.each_with_object([]) do |response, res|
|
24
|
+
response_stat(response, res)
|
25
|
+
end.join(' ')
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def response_stat(response, res)
|
31
|
+
response.json_schemas.map do |json_schema|
|
32
|
+
json_schema_stat(res, json_schema, response)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def json_schema_stat(res, json_schema, response)
|
37
|
+
if json_schema.bodies == []
|
38
|
+
res.push("✖ #{response.status}")
|
39
|
+
else
|
40
|
+
res.push("✔ #{response.status}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'fitting/statistics/list'
|
2
|
+
|
3
|
+
module Fitting
|
4
|
+
class Statistics
|
5
|
+
class Lists
|
6
|
+
def initialize(measurement)
|
7
|
+
@measurement = measurement
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
[
|
12
|
+
coverage_fully_stat,
|
13
|
+
coverage_partially_stat,
|
14
|
+
coverage_non_stat
|
15
|
+
].compact.join("\n\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
def coverage_fully_stat
|
19
|
+
if @measurement.coverage_fully == []
|
20
|
+
nil
|
21
|
+
else
|
22
|
+
[
|
23
|
+
'Fully conforming requests:',
|
24
|
+
Fitting::Statistics::List.new(@measurement.coverage_fully, @measurement.max_response_path).to_s
|
25
|
+
].join("\n")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def coverage_partially_stat
|
30
|
+
if @measurement.coverage_partially == []
|
31
|
+
nil
|
32
|
+
else
|
33
|
+
[
|
34
|
+
'Partially conforming requests:',
|
35
|
+
Fitting::Statistics::List.new(@measurement.coverage_partially, @measurement.max_response_path).to_s
|
36
|
+
].join("\n")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def coverage_non_stat
|
41
|
+
if @measurement.coverage_non == []
|
42
|
+
nil
|
43
|
+
else
|
44
|
+
[
|
45
|
+
'Non-conforming requests:',
|
46
|
+
Fitting::Statistics::List.new(@measurement.coverage_non, @measurement.max_response_path).to_s
|
47
|
+
].join("\n")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Fitting
|
2
|
+
class Statistics
|
3
|
+
class Measurement
|
4
|
+
attr_reader :requests, :all_responses, :cover_responses, :not_cover_responses, :max_response_path,
|
5
|
+
:coverage_fully, :coverage_non, :coverage_partially, :not_covered_responses
|
6
|
+
|
7
|
+
def initialize(requests)
|
8
|
+
@requests = requests
|
9
|
+
@all_responses = 0
|
10
|
+
@cover_responses = 0
|
11
|
+
@not_cover_responses = 0
|
12
|
+
@max_response_path = 0
|
13
|
+
@coverage_fully = []
|
14
|
+
@coverage_non = []
|
15
|
+
@coverage_partially = []
|
16
|
+
@not_covered_responses = []
|
17
|
+
check_responses
|
18
|
+
end
|
19
|
+
|
20
|
+
def check_responses
|
21
|
+
return if @ready
|
22
|
+
|
23
|
+
@requests.map do |request|
|
24
|
+
chech_request(request)
|
25
|
+
end
|
26
|
+
|
27
|
+
@ready = true
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def chech_request(request)
|
33
|
+
check_cover(request)
|
34
|
+
coverage_push(request)
|
35
|
+
|
36
|
+
if request.path.to_s.size / 8 > @max_response_path
|
37
|
+
@max_response_path = request.path.to_s.size / 8
|
38
|
+
end
|
39
|
+
request.responses.map do |response|
|
40
|
+
check_response(response, request)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_response(response, request)
|
45
|
+
json_schema_index = 0
|
46
|
+
response.json_schemas.map do |json_schema|
|
47
|
+
json_schema_index = check_json_schema(json_schema, request, response, json_schema_index)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_json_schema(json_schema, request, response, json_schema_index)
|
52
|
+
if json_schema.bodies == []
|
53
|
+
@not_cover_responses += 1
|
54
|
+
@not_covered_responses.push("#{request.method}\t#{request.path} #{response.status} #{json_schema_index}")
|
55
|
+
else
|
56
|
+
@cover_responses += 1
|
57
|
+
end
|
58
|
+
@all_responses += 1
|
59
|
+
json_schema_index + 1
|
60
|
+
end
|
61
|
+
|
62
|
+
def coverage_push(request)
|
63
|
+
if @all == @cover
|
64
|
+
@coverage_fully.push(request)
|
65
|
+
elsif @all == @not_cover
|
66
|
+
@coverage_non.push(request)
|
67
|
+
else
|
68
|
+
@coverage_partially.push(request)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_cover(request)
|
73
|
+
@all = 0
|
74
|
+
@cover = 0
|
75
|
+
@not_cover = 0
|
76
|
+
|
77
|
+
request.responses.map do |response|
|
78
|
+
response.json_schemas.map do |json_schema|
|
79
|
+
count_cover(json_schema)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def count_cover(json_schema)
|
85
|
+
@all += 1
|
86
|
+
if json_schema.bodies == []
|
87
|
+
@not_cover += 1
|
88
|
+
else
|
89
|
+
@cover += 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Fitting
|
2
|
+
class Statistics
|
3
|
+
class Percent
|
4
|
+
def initialize(divider, dividend)
|
5
|
+
@divider = divider
|
6
|
+
@dividend = dividend
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_f
|
10
|
+
return 0.to_f if @divider.zero?
|
11
|
+
(@dividend.to_f / @divider.to_f * 100.0).round(2)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"#{@dividend} (#{to_f}% of #{@divider})"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'fitting/statistics/percent'
|
2
|
+
|
3
|
+
module Fitting
|
4
|
+
class Statistics
|
5
|
+
class RequestsStats
|
6
|
+
def initialize(measurement)
|
7
|
+
@measurement = measurement
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
@to_s ||= [
|
12
|
+
"API requests with fully implemented responses: #{fully}.",
|
13
|
+
"API requests with partially implemented responses: #{partially}.",
|
14
|
+
"API requests with no implemented responses: #{non}."
|
15
|
+
].join("\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
def fully
|
19
|
+
@fully ||= Fitting::Statistics::Percent.new(
|
20
|
+
@measurement.requests.size,
|
21
|
+
@measurement.coverage_fully.size
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def partially
|
26
|
+
@partially ||= Fitting::Statistics::Percent.new(
|
27
|
+
@measurement.requests.size,
|
28
|
+
@measurement.coverage_partially.size
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def non
|
33
|
+
@non ||= Fitting::Statistics::Percent.new(
|
34
|
+
@measurement.requests.size,
|
35
|
+
@measurement.coverage_non.size
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'fitting/statistics/percent'
|
2
|
+
|
3
|
+
module Fitting
|
4
|
+
class Statistics
|
5
|
+
class ResponsesStats
|
6
|
+
def initialize(measurement)
|
7
|
+
@measurement = measurement
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
@to_s ||= [
|
12
|
+
"API responses conforming to the blueprint: #{cover}.",
|
13
|
+
"API responses with validation errors or untested: #{not_cover}."
|
14
|
+
].join("\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
def cover
|
18
|
+
@cover ||= Fitting::Statistics::Percent.new(
|
19
|
+
@measurement.all_responses,
|
20
|
+
@measurement.cover_responses
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def not_cover
|
25
|
+
@not_cover ||= Fitting::Statistics::Percent.new(
|
26
|
+
@measurement.all_responses,
|
27
|
+
@measurement.not_cover_responses
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'fitting/statistics/not_covered_responses'
|
2
|
+
require 'fitting/statistics/analysis'
|
3
|
+
require 'fitting/statistics/measurement'
|
4
|
+
require 'fitting/records/unit/request'
|
5
|
+
require 'fitting/storage/white_list'
|
6
|
+
require 'fitting/records/documented/request'
|
7
|
+
|
8
|
+
module Fitting
|
9
|
+
class Statistics
|
10
|
+
class Template
|
11
|
+
def initialize(tested_requests, config)
|
12
|
+
@tested_requests = tested_requests
|
13
|
+
@config = config
|
14
|
+
end
|
15
|
+
|
16
|
+
def save
|
17
|
+
File.open(@config.stats_path, 'w') { |file| file.write(stats) }
|
18
|
+
File.open(@config.not_covered_path, 'w') { |file| file.write(not_covered) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def stats
|
22
|
+
if documented.to_a.size > documented_requests_white.size
|
23
|
+
[
|
24
|
+
['[Black list]', black_statistics].join("\n"),
|
25
|
+
['[White list]', white_statistics].join("\n"),
|
26
|
+
''
|
27
|
+
].join("\n\n")
|
28
|
+
else
|
29
|
+
[white_statistics, "\n\n"].join
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def not_covered
|
34
|
+
Fitting::Statistics::NotCoveredResponses.new(white_measurement).to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def white_statistics
|
38
|
+
@white_statistics ||= Fitting::Statistics::Analysis.new(white_measurement)
|
39
|
+
end
|
40
|
+
|
41
|
+
def black_statistics
|
42
|
+
@black_statistics ||= Fitting::Statistics::Analysis.new(black_measurement)
|
43
|
+
end
|
44
|
+
|
45
|
+
def white_measurement
|
46
|
+
@white_measurement ||= Fitting::Statistics::Measurement.new(white_unit)
|
47
|
+
end
|
48
|
+
|
49
|
+
def black_measurement
|
50
|
+
@black_measurement ||= Fitting::Statistics::Measurement.new(black_unit)
|
51
|
+
end
|
52
|
+
|
53
|
+
def white_unit
|
54
|
+
@white_unit_requests ||= documented_requests_white.inject([]) do |res, documented_request|
|
55
|
+
res.push(Fitting::Records::Unit::Request.new(documented_request, @tested_requests))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def black_unit
|
60
|
+
@black_unit_requests ||= documented_requests_black.inject([]) do |res, documented_request|
|
61
|
+
res.push(Fitting::Records::Unit::Request.new(documented_request, @tested_requests))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def documented_requests_white
|
66
|
+
@documented_requests_white ||= documented.find_all(&:white)
|
67
|
+
end
|
68
|
+
|
69
|
+
def documented_requests_black
|
70
|
+
@documented_requests_black ||= documented.find_all do |request|
|
71
|
+
!request.white
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def documented
|
76
|
+
@documented_requests ||= @config.tomogram.to_hash.inject([]) do |res, tomogram_request|
|
77
|
+
res.push(Fitting::Records::Documented::Request.new(tomogram_request, white_list.to_a))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def white_list
|
82
|
+
@white_list ||= Fitting::Storage::WhiteList.new(
|
83
|
+
@config.white_list,
|
84
|
+
@config.resource_white_list,
|
85
|
+
@config.tomogram.to_resources
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|