fitting 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +77 -31
- data/fitting.gemspec +1 -0
- data/lib/fitting/cover.rb +66 -0
- data/lib/fitting/cover/json_schema.rb +106 -0
- data/lib/fitting/cover/response.rb +41 -0
- data/lib/fitting/records/unit/combination.rb +28 -0
- data/lib/fitting/records/unit/json_schema.rb +30 -0
- data/lib/fitting/response.rb +6 -0
- data/lib/fitting/statistics/analysis.rb +3 -2
- data/lib/fitting/statistics/cover_error.rb +31 -0
- data/lib/fitting/statistics/list.rb +9 -4
- data/lib/fitting/statistics/lists.rb +5 -4
- data/lib/fitting/statistics/measurement_cover.rb +94 -0
- data/lib/fitting/statistics/template.rb +17 -5
- data/lib/fitting/statistics/template_cover_error.rb +54 -0
- data/lib/fitting/version.rb +1 -1
- data/lib/fitting/view/report.html.haml +16 -0
- data/lib/fitting/view/style.css +47 -0
- data/lib/tasks/fitting.rake +62 -0
- metadata +25 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 058ccfba8eb94e0929f24473e00684c70d39fe19
|
4
|
+
data.tar.gz: 1a3395ec6ea7e9dd577671a523f85042773a025f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6fcea3482af2fec8090fed3306af166d8c98699f18d1c629c13d2f8027fe95a42edf22ffb6ddbe0e15e883e446839450fea817273f18ddb5a0f986912ed9f33
|
7
|
+
data.tar.gz: a4ffbd091060c642052b2d4e5d9d5b33fcd3d3204622d86397b7407a6b8fdcb17527ee74ebe9d6ba759efb41fe3ecee0145b4cac27a80045a6b79fd0b6abed43
|
data/README.md
CHANGED
@@ -39,30 +39,52 @@ In your `spec_helper.rb`:
|
|
39
39
|
```ruby
|
40
40
|
require 'fitting'
|
41
41
|
|
42
|
-
Fitting.
|
42
|
+
Fitting.save_test_data
|
43
43
|
```
|
44
44
|
|
45
|
-
|
45
|
+
The tests.json file will be created
|
46
46
|
|
47
|
-
|
48
|
-
require 'fitting'
|
47
|
+
Example:
|
49
48
|
|
50
|
-
|
49
|
+
```
|
50
|
+
[
|
51
|
+
{
|
52
|
+
"method": "GET",
|
53
|
+
"path": "/api/v1/book",
|
54
|
+
"body": {},
|
55
|
+
"response": {
|
56
|
+
"status": 200,
|
57
|
+
"body": {
|
58
|
+
"title": "The Martian Chronicles"
|
59
|
+
}
|
60
|
+
},
|
61
|
+
"title": "/spec/controllers/api/v1/books_controller_spec.rb:11",
|
62
|
+
"group": "/spec/controllers/api/v1/books_controller_spec.rb"
|
63
|
+
},
|
64
|
+
{
|
65
|
+
"method": "POST",
|
66
|
+
"path": "/api/v1/book",
|
67
|
+
"body": {},
|
68
|
+
"response": {
|
69
|
+
"status": 200,
|
70
|
+
"body": {
|
71
|
+
"title": "The Old Man and the Sea"
|
72
|
+
}
|
73
|
+
},
|
74
|
+
"title": "/spec/controllers/api/v1/books_controller_spec.rb:22",
|
75
|
+
"group": "/spec/controllers/api/v1/books_controller_spec.rb"
|
76
|
+
},
|
77
|
+
...
|
78
|
+
```
|
51
79
|
|
52
|
-
RSpec.configure do |config|
|
53
|
-
config.after(:each, type: :controller) do
|
54
|
-
responses.add(response)
|
55
|
-
end
|
56
80
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
```
|
81
|
+
## Check documentation cover
|
82
|
+
|
83
|
+
### xs size
|
62
84
|
|
63
|
-
|
85
|
+
For match routes and valid json-schemas run `rake fitting:documentation_responses[xs]`
|
64
86
|
|
65
|
-
|
87
|
+
You will get statistics:
|
66
88
|
|
67
89
|
```
|
68
90
|
Fully conforming requests:
|
@@ -88,31 +110,50 @@ API responses conforming to the blueprint: 16 (64.00% of 25).
|
|
88
110
|
API responses with validation errors or untested: 9 (36.00% of 25).
|
89
111
|
```
|
90
112
|
|
91
|
-
|
92
|
-
|
93
|
-
## Matchers
|
113
|
+
### s size
|
94
114
|
|
95
|
-
|
115
|
+
In addition to the previous comand, you will learn the coverage json-schemas with task `rake fitting:documentation_responses[s]`
|
96
116
|
|
97
|
-
```ruby
|
98
|
-
config.include Fitting::Matchers, type: :controller
|
99
117
|
```
|
118
|
+
Fully conforming requests:
|
119
|
+
DELETE /api/v1/book 100% 200 100% 201 100% 404
|
120
|
+
DELETE /api/v1/book/{id} 100% 200 100% 201 100% 404
|
121
|
+
GET /api/v1/book/{id}/seller 100% 200 100% 201 100% 404
|
100
122
|
|
101
|
-
|
123
|
+
Partially conforming requests:
|
124
|
+
GET /api/v1/book 0% 200 66% 404
|
125
|
+
POST /api/v1/book 0% 200 90% 201 100% 404
|
126
|
+
GET /api/v1/book/{id} 0% 200 88% 404 10% 200
|
127
|
+
PATCH /api/v1/book/{id} 0% 200 100% 201 10% 404
|
102
128
|
|
103
|
-
|
129
|
+
Non-conforming requests:
|
130
|
+
GET /api/v1/seller 0% 200 0% 201 0 404
|
131
|
+
GET /api/v1/buyer 0% 200 0% 404
|
104
132
|
|
105
|
-
|
106
|
-
|
107
|
-
|
133
|
+
API requests with fully implemented responses: 3 (33.33% of 9).
|
134
|
+
API requests with partially implemented responses: 4 (44.44% of 9).
|
135
|
+
API requests with no implemented responses: 2 (22.22% of 9).
|
108
136
|
|
109
|
-
|
137
|
+
API responses conforming to the blueprint: 16 (64.00% of 25).
|
138
|
+
API responses with validation errors or untested: 9 (36.00% of 25).
|
139
|
+
```
|
110
140
|
|
111
|
-
|
141
|
+
For details `rake fitting:documentation_responses_error[s]`
|
112
142
|
|
113
|
-
```ruby
|
114
|
-
expect(response).to strictly_match_schema
|
115
143
|
```
|
144
|
+
request metohd: GET
|
145
|
+
request path: /api/v1/book
|
146
|
+
response staus: 200
|
147
|
+
source json-schema: {"$schema"=>"http://json-schema.org/draft-04/schema#", "type"=>"object", ...}
|
148
|
+
combination: ["required", "pages"]
|
149
|
+
new json-schema: {"$schema"=>"http://json-schema.org/draft-04/schema#", "type"=>"object", ...}
|
150
|
+
```
|
151
|
+
|
152
|
+
## Check tests cover
|
153
|
+
|
154
|
+
### xs size
|
155
|
+
|
156
|
+
`rake fitting:tests_responses[xs]`
|
116
157
|
|
117
158
|
## Config
|
118
159
|
|
@@ -176,6 +217,11 @@ resource_white_list:
|
|
176
217
|
|
177
218
|
Empty array `[]` means all methods.
|
178
219
|
|
220
|
+
### json_schema_cover
|
221
|
+
|
222
|
+
Default: false. Json-schema covering becomes mandatory.
|
223
|
+
Or you can call `responses.statistics.cover_save` if you don't use call `Fitting.statistics`.
|
224
|
+
|
179
225
|
### include_resources
|
180
226
|
|
181
227
|
Default: all resources if `include_resources` and `include_actions` is not used.
|
data/fitting.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_runtime_dependency 'json-schema', '~> 2.6', '>= 2.6.2'
|
24
24
|
spec.add_runtime_dependency 'multi_json'
|
25
25
|
spec.add_runtime_dependency 'tomograph', '~> 2.0', '>= 2.2.0'
|
26
|
+
spec.add_runtime_dependency 'haml'
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.12'
|
27
28
|
spec.add_development_dependency 'rake', '~> 10.0'
|
28
29
|
spec.add_development_dependency 'byebug', '~> 8.2', '>= 8.2.1'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'fitting/cover/response'
|
2
|
+
require 'haml'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Fitting
|
6
|
+
class Cover
|
7
|
+
def initialize(all_responses, coverage)
|
8
|
+
@all_responses = all_responses
|
9
|
+
@coverage = coverage
|
10
|
+
@list = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_hash
|
14
|
+
return @list unless @list == {}
|
15
|
+
@all_responses.each_with_object({}) do |response, res|
|
16
|
+
next res unless response.documented?
|
17
|
+
if res.key?(response.route)
|
18
|
+
res[response.route].update(response)
|
19
|
+
else
|
20
|
+
res[response.route] = Fitting::Cover::Response.new(response)
|
21
|
+
end
|
22
|
+
end.map do |key, value|
|
23
|
+
@list[key] = value.to_hash
|
24
|
+
end
|
25
|
+
@list
|
26
|
+
end
|
27
|
+
|
28
|
+
def template
|
29
|
+
return @template if @template
|
30
|
+
@template = {}
|
31
|
+
to_hash.each do |key, value|
|
32
|
+
@template[key] = value
|
33
|
+
@template[key]['cover'] = 100.0
|
34
|
+
if value['flags'] == []
|
35
|
+
@template[key]['type'] = 'passed'
|
36
|
+
else
|
37
|
+
flag_true = value['flags'].find_all{|flag| flag == true}
|
38
|
+
flag_false = value['flags'].find_all{|flag| flag == false}
|
39
|
+
if flag_false.size == 0
|
40
|
+
@template[key]['type'] = 'passed'
|
41
|
+
else
|
42
|
+
if flag_true.size == 0
|
43
|
+
@template[key]['cover'] = 0.0
|
44
|
+
else
|
45
|
+
@template[key]['cover'] = flag_false.size / flag_true.size
|
46
|
+
end
|
47
|
+
@template[key]['type'] = 'failed'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
@template[key]['json_schema'] = JSON.pretty_generate(value['json_schemas'].last)
|
51
|
+
end
|
52
|
+
@template
|
53
|
+
end
|
54
|
+
|
55
|
+
def save
|
56
|
+
to_hash
|
57
|
+
contents = File.read(File.expand_path('../view/report.html.haml', __FILE__))
|
58
|
+
html = "<style>\n#{File.read(File.expand_path('../view/style.css', __FILE__))}\n</style>\n"
|
59
|
+
html += Haml::Engine.new(contents).render(
|
60
|
+
Object.new,
|
61
|
+
:@to_hash => template
|
62
|
+
)
|
63
|
+
html
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Fitting
|
2
|
+
class Cover
|
3
|
+
class JSONSchema
|
4
|
+
def initialize(json_schema)
|
5
|
+
@json_schema = json_schema
|
6
|
+
end
|
7
|
+
|
8
|
+
def json_schemas
|
9
|
+
return @json_schemas if @json_schemas
|
10
|
+
@json_schemas, @combinations = required(@json_schema)
|
11
|
+
|
12
|
+
return @json_schemas unless @json_schema['properties']
|
13
|
+
super_each(@json_schema['properties'], 'properties' => nil)
|
14
|
+
|
15
|
+
@json_schemas
|
16
|
+
end
|
17
|
+
|
18
|
+
def super_each(json_schema, old_keys_hash)
|
19
|
+
json_schema.each do |key, value|
|
20
|
+
new_keys_hash = clone_hash(old_keys_hash)
|
21
|
+
add_super_key(new_keys_hash, key)
|
22
|
+
if value.is_a?(Hash)
|
23
|
+
modify_json_shema(value, new_keys_hash)
|
24
|
+
super_each(value, new_keys_hash)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_super_key(vbn, new_key)
|
30
|
+
vbn.each do |key, value|
|
31
|
+
if value
|
32
|
+
add_super_key(value, new_key)
|
33
|
+
else
|
34
|
+
vbn[key] = { new_key => nil }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def super_merge(vbn, asd, old_json_schema)
|
40
|
+
vbn.each do |key, value|
|
41
|
+
if value
|
42
|
+
super_merge(value, asd, old_json_schema[key])
|
43
|
+
else
|
44
|
+
old_json_schema[key].merge!(asd)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
old_json_schema
|
48
|
+
end
|
49
|
+
|
50
|
+
def modify_json_shema(value, vbn)
|
51
|
+
qwe = required(value)
|
52
|
+
qwe[0].map do |asd|
|
53
|
+
new_json_shema = clone_hash(@json_schema)
|
54
|
+
super_merge(vbn, asd, new_json_shema)
|
55
|
+
@json_schemas += [new_json_shema]
|
56
|
+
end
|
57
|
+
@combinations += qwe[1]
|
58
|
+
end
|
59
|
+
|
60
|
+
def clone_hash(old_json_schema)
|
61
|
+
new_json_schema = {}
|
62
|
+
old_json_schema.each do |key, value|
|
63
|
+
if value.is_a?(Hash)
|
64
|
+
new_json_schema.merge!(key => clone_hash(value))
|
65
|
+
elsif value
|
66
|
+
new_json_schema.merge!(key => value.clone)
|
67
|
+
else
|
68
|
+
new_json_schema.merge!(key => nil)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
new_json_schema
|
72
|
+
end
|
73
|
+
|
74
|
+
def combinations
|
75
|
+
json_schemas
|
76
|
+
@combinations
|
77
|
+
end
|
78
|
+
|
79
|
+
def required(json_schema)
|
80
|
+
combinations = []
|
81
|
+
json_schemas = new_keys(json_schema).inject([]) do |new_json_shemas, new_key|
|
82
|
+
new_json_shema = json_schema.dup
|
83
|
+
if new_json_shema['required']
|
84
|
+
new_json_shema['required'] += [new_key]
|
85
|
+
else
|
86
|
+
new_json_shema['required'] = [new_key]
|
87
|
+
end
|
88
|
+
combinations.push(['required', new_key])
|
89
|
+
new_json_shemas.push(new_json_shema)
|
90
|
+
end
|
91
|
+
[json_schemas, combinations]
|
92
|
+
end
|
93
|
+
|
94
|
+
def new_keys(json_schema)
|
95
|
+
return [] unless json_schema && json_schema['properties']
|
96
|
+
all = json_schema['properties'].keys.map(&:to_s)
|
97
|
+
old = json_schema['required']
|
98
|
+
if old
|
99
|
+
all - old
|
100
|
+
else
|
101
|
+
all
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'fitting/cover/json_schema'
|
2
|
+
require 'json-schema'
|
3
|
+
|
4
|
+
module Fitting
|
5
|
+
class Cover
|
6
|
+
class Response
|
7
|
+
def initialize(response)
|
8
|
+
@cover_json_schemas = Fitting::Cover::JSONSchema.new(response.json_schema)
|
9
|
+
@json_schemas = @cover_json_schemas.json_schemas + [response.json_schema]
|
10
|
+
@combinations = @cover_json_schemas.combinations
|
11
|
+
@flags = @cover_json_schemas.json_schemas.map do |json_schema|
|
12
|
+
JSON::Validator.validate(json_schema, response.body)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :json_schemas
|
17
|
+
|
18
|
+
attr_reader :combinations
|
19
|
+
|
20
|
+
attr_reader :flags
|
21
|
+
|
22
|
+
def update(response)
|
23
|
+
index = 0
|
24
|
+
@cover_json_schemas.json_schemas.map do |json_schema|
|
25
|
+
flag = JSON::Validator.validate(json_schema, response.body)
|
26
|
+
@flags[index] = @flags[index] || flag
|
27
|
+
index += 1
|
28
|
+
end
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_hash
|
33
|
+
{
|
34
|
+
'json_schemas' => json_schemas,
|
35
|
+
'combinations' => combinations,
|
36
|
+
'flags' => flags
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'json-schema'
|
2
|
+
|
3
|
+
module Fitting
|
4
|
+
class Records
|
5
|
+
class Unit
|
6
|
+
class Combination
|
7
|
+
attr_reader :description, :json_schema, :bodies
|
8
|
+
|
9
|
+
def initialize(description, json_schema, bodies)
|
10
|
+
@description = description
|
11
|
+
@json_schema = json_schema
|
12
|
+
@bodies = bodies
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid_bodies
|
16
|
+
@valid_bodies ||= @bodies.inject([]) do |res, tested_body|
|
17
|
+
begin
|
18
|
+
next res unless JSON::Validator.validate(@json_schema, tested_body)
|
19
|
+
res.push(tested_body)
|
20
|
+
rescue JSON::Schema::UriError
|
21
|
+
res.push(tested_body)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,9 +1,13 @@
|
|
1
1
|
require 'json-schema'
|
2
|
+
require 'fitting/cover/json_schema'
|
3
|
+
require 'fitting/records/unit/combination'
|
2
4
|
|
3
5
|
module Fitting
|
4
6
|
class Records
|
5
7
|
class Unit
|
6
8
|
class JsonSchema
|
9
|
+
attr_reader :json_schema
|
10
|
+
|
7
11
|
def initialize(json_schema, tested_bodies)
|
8
12
|
@json_schema = json_schema
|
9
13
|
@tested_bodies = tested_bodies
|
@@ -19,6 +23,32 @@ module Fitting
|
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
26
|
+
|
27
|
+
def combinations
|
28
|
+
return @combinations if @combinations
|
29
|
+
@combinations = []
|
30
|
+
cover_json_schema = Fitting::Cover::JSONSchema.new(@json_schema)
|
31
|
+
cover_json_schema.json_schemas.each_index do |index|
|
32
|
+
@combinations.push(Fitting::Records::Unit::Combination.new(
|
33
|
+
cover_json_schema.combinations[index],
|
34
|
+
cover_json_schema.json_schemas[index],
|
35
|
+
bodies
|
36
|
+
))
|
37
|
+
end
|
38
|
+
@combinations
|
39
|
+
end
|
40
|
+
|
41
|
+
def cover
|
42
|
+
@cover ||= if bodies == []
|
43
|
+
0
|
44
|
+
else
|
45
|
+
count = 0
|
46
|
+
combinations.map do |combination|
|
47
|
+
count += 1 unless combination.valid_bodies == []
|
48
|
+
end
|
49
|
+
(count + 1) * 100 / (combinations.size + 1)
|
50
|
+
end
|
51
|
+
end
|
22
52
|
end
|
23
53
|
end
|
24
54
|
end
|
data/lib/fitting/response.rb
CHANGED
@@ -5,6 +5,8 @@ require 'multi_json'
|
|
5
5
|
|
6
6
|
module Fitting
|
7
7
|
class Response
|
8
|
+
attr_reader :body
|
9
|
+
|
8
10
|
def initialize(env_response, tomogram)
|
9
11
|
@request = Fitting::Request.new(env_response.request, tomogram)
|
10
12
|
@status = env_response.status
|
@@ -54,6 +56,10 @@ module Fitting
|
|
54
56
|
end.join("\n\n")
|
55
57
|
end
|
56
58
|
|
59
|
+
def json_schema
|
60
|
+
@schemas[index.first]
|
61
|
+
end
|
62
|
+
|
57
63
|
def ignored?(ignore_list)
|
58
64
|
@request.ignored?(ignore_list)
|
59
65
|
end
|
@@ -7,13 +7,14 @@ require 'fitting/statistics/not_covered_responses'
|
|
7
7
|
module Fitting
|
8
8
|
class Statistics
|
9
9
|
class Analysis
|
10
|
-
def initialize(measurement)
|
10
|
+
def initialize(measurement, depth)
|
11
11
|
@measurement = measurement
|
12
|
+
@depth = depth
|
12
13
|
end
|
13
14
|
|
14
15
|
def to_s
|
15
16
|
[
|
16
|
-
Fitting::Statistics::Lists.new(@measurement).to_s,
|
17
|
+
Fitting::Statistics::Lists.new(@measurement, @depth).to_s,
|
17
18
|
Fitting::Statistics::RequestsStats.new(@measurement).to_s,
|
18
19
|
Fitting::Statistics::ResponsesStats.new(@measurement).to_s,
|
19
20
|
Fitting::Statistics::Great.new(@measurement).to_s
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Fitting
|
2
|
+
class Statistics
|
3
|
+
class CoverError
|
4
|
+
def initialize(request_unit)
|
5
|
+
@request_unit = request_unit
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
res = ''
|
10
|
+
@request_unit.map do |request|
|
11
|
+
request.responses.map do |response|
|
12
|
+
if response.tested_bodies == []
|
13
|
+
return 'Error, not all responses valid without cover!'
|
14
|
+
else
|
15
|
+
response.json_schemas.map do |json_schema|
|
16
|
+
json_schema.combinations.map do |combination|
|
17
|
+
if combination.valid_bodies == []
|
18
|
+
res += "request metohd: #{request.method}\nrequest path: #{request.path}\n"\
|
19
|
+
"response staus: #{response.status}\nsource json-schema: #{json_schema.json_schema}\n"\
|
20
|
+
"combination: #{combination.description}\nnew json-schema: #{combination.json_schema}\n\n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
res
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Fitting
|
2
2
|
class Statistics
|
3
3
|
class List
|
4
|
-
def initialize(coverage, max_response_path)
|
4
|
+
def initialize(coverage, max_response_path, depth)
|
5
5
|
@coverage = coverage
|
6
6
|
@max_response_path = max_response_path
|
7
|
+
@depth = depth
|
7
8
|
end
|
8
9
|
|
9
10
|
def to_s
|
@@ -34,10 +35,14 @@ module Fitting
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def json_schema_stat(res, json_schema, response)
|
37
|
-
if
|
38
|
-
|
38
|
+
if @depth == 'valid'
|
39
|
+
if json_schema.bodies == []
|
40
|
+
res.push("✖ #{response.status}")
|
41
|
+
else
|
42
|
+
res.push("✔ #{response.status}")
|
43
|
+
end
|
39
44
|
else
|
40
|
-
res.push("
|
45
|
+
res.push("#{json_schema.cover}% #{response.status}")
|
41
46
|
end
|
42
47
|
end
|
43
48
|
end
|
@@ -3,8 +3,9 @@ require 'fitting/statistics/list'
|
|
3
3
|
module Fitting
|
4
4
|
class Statistics
|
5
5
|
class Lists
|
6
|
-
def initialize(measurement)
|
6
|
+
def initialize(measurement, depth)
|
7
7
|
@measurement = measurement
|
8
|
+
@depth = depth
|
8
9
|
end
|
9
10
|
|
10
11
|
def to_s
|
@@ -21,7 +22,7 @@ module Fitting
|
|
21
22
|
else
|
22
23
|
[
|
23
24
|
'Fully conforming requests:',
|
24
|
-
Fitting::Statistics::List.new(@measurement.coverage_fully, @measurement.max_response_path).to_s
|
25
|
+
Fitting::Statistics::List.new(@measurement.coverage_fully, @measurement.max_response_path, @depth).to_s
|
25
26
|
].join("\n")
|
26
27
|
end
|
27
28
|
end
|
@@ -32,7 +33,7 @@ module Fitting
|
|
32
33
|
else
|
33
34
|
[
|
34
35
|
'Partially conforming requests:',
|
35
|
-
Fitting::Statistics::List.new(@measurement.coverage_partially, @measurement.max_response_path).to_s
|
36
|
+
Fitting::Statistics::List.new(@measurement.coverage_partially, @measurement.max_response_path, @depth).to_s
|
36
37
|
].join("\n")
|
37
38
|
end
|
38
39
|
end
|
@@ -43,7 +44,7 @@ module Fitting
|
|
43
44
|
else
|
44
45
|
[
|
45
46
|
'Non-conforming requests:',
|
46
|
-
Fitting::Statistics::List.new(@measurement.coverage_non, @measurement.max_response_path).to_s
|
47
|
+
Fitting::Statistics::List.new(@measurement.coverage_non, @measurement.max_response_path, @depth).to_s
|
47
48
|
].join("\n")
|
48
49
|
end
|
49
50
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Fitting
|
2
|
+
class Statistics
|
3
|
+
class MeasurementCover
|
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.cover != 100
|
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.cover != 100
|
87
|
+
@not_cover += 1
|
88
|
+
else
|
89
|
+
@cover += 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'fitting/statistics/not_covered_responses'
|
2
2
|
require 'fitting/statistics/analysis'
|
3
3
|
require 'fitting/statistics/measurement'
|
4
|
+
require 'fitting/statistics/measurement_cover'
|
4
5
|
require 'fitting/records/unit/request'
|
5
6
|
require 'fitting/storage/white_list'
|
6
7
|
require 'fitting/records/documented/request'
|
@@ -8,9 +9,10 @@ require 'fitting/records/documented/request'
|
|
8
9
|
module Fitting
|
9
10
|
class Statistics
|
10
11
|
class Template
|
11
|
-
def initialize(tested_requests, config)
|
12
|
+
def initialize(tested_requests, config, depth = 'valid')
|
12
13
|
@tested_requests = tested_requests
|
13
14
|
@config = config
|
15
|
+
@depth = depth
|
14
16
|
end
|
15
17
|
|
16
18
|
def save
|
@@ -35,19 +37,29 @@ module Fitting
|
|
35
37
|
end
|
36
38
|
|
37
39
|
def white_statistics
|
38
|
-
@white_statistics ||= Fitting::Statistics::Analysis.new(white_measurement)
|
40
|
+
@white_statistics ||= Fitting::Statistics::Analysis.new(white_measurement, @depth)
|
39
41
|
end
|
40
42
|
|
41
43
|
def black_statistics
|
42
|
-
@black_statistics ||= Fitting::Statistics::Analysis.new(black_measurement)
|
44
|
+
@black_statistics ||= Fitting::Statistics::Analysis.new(black_measurement, @depth)
|
43
45
|
end
|
44
46
|
|
45
47
|
def white_measurement
|
46
|
-
@white_measurement ||=
|
48
|
+
@white_measurement ||=
|
49
|
+
if @depth == 'valid'
|
50
|
+
Fitting::Statistics::Measurement.new(white_unit)
|
51
|
+
else
|
52
|
+
Fitting::Statistics::MeasurementCover.new(white_unit)
|
53
|
+
end
|
47
54
|
end
|
48
55
|
|
49
56
|
def black_measurement
|
50
|
-
@black_measurement ||=
|
57
|
+
@black_measurement ||=
|
58
|
+
if @depth == 'valid'
|
59
|
+
Fitting::Statistics::Measurement.new(black_unit)
|
60
|
+
else
|
61
|
+
Fitting::Statistics::MeasurementCover.new(black_unit)
|
62
|
+
end
|
51
63
|
end
|
52
64
|
|
53
65
|
def white_unit
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'fitting/statistics/cover_error'
|
2
|
+
require 'fitting/records/unit/request'
|
3
|
+
require 'fitting/storage/white_list'
|
4
|
+
require 'fitting/records/documented/request'
|
5
|
+
|
6
|
+
module Fitting
|
7
|
+
class Statistics
|
8
|
+
class TemplateCoverError
|
9
|
+
def initialize(tested_requests, config)
|
10
|
+
@tested_requests = tested_requests
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def stats
|
15
|
+
[
|
16
|
+
['[White list]', white_statistics].join("\n"),
|
17
|
+
''
|
18
|
+
].join("\n\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def white_statistics
|
23
|
+
@white_statistics ||= Fitting::Statistics::CoverError.new(white_unit)
|
24
|
+
end
|
25
|
+
|
26
|
+
def white_unit
|
27
|
+
@white_unit_requests ||= documented_requests_white.inject([]) do |res, documented_request|
|
28
|
+
res.push(Fitting::Records::Unit::Request.new(documented_request, @tested_requests))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def documented_requests_white
|
33
|
+
@documented_requests_white ||= documented.find_all(&:white)
|
34
|
+
end
|
35
|
+
|
36
|
+
def documented
|
37
|
+
@documented_requests ||= @config.tomogram.to_a.inject([]) do |res, tomogram_request|
|
38
|
+
res.push(Fitting::Records::Documented::Request.new(tomogram_request, white_list.to_a))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def white_list
|
43
|
+
@white_list ||= Fitting::Storage::WhiteList.new(
|
44
|
+
@config.prefix,
|
45
|
+
@config.white_list,
|
46
|
+
@config.resource_white_list,
|
47
|
+
@config.include_resources,
|
48
|
+
@config.include_actions,
|
49
|
+
@config.tomogram.to_resources
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/fitting/version.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
!!! 5
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title= Time.now
|
5
|
+
%meta{charset: "utf-8"}
|
6
|
+
%body
|
7
|
+
- @to_hash.each do |key, value|
|
8
|
+
%details
|
9
|
+
%summary{class: "collapse #{value['type']}"}
|
10
|
+
= "#{key} #{value['cover']}"
|
11
|
+
%div{class: 'group'}
|
12
|
+
%div{class: 'section'}
|
13
|
+
%div
|
14
|
+
%b main json-schema
|
15
|
+
%xmp
|
16
|
+
= value['json_schema']
|
@@ -0,0 +1,47 @@
|
|
1
|
+
summary {
|
2
|
+
margin: 10px;
|
3
|
+
}
|
4
|
+
|
5
|
+
summary:hover {
|
6
|
+
background: #e1e1e1;
|
7
|
+
}
|
8
|
+
|
9
|
+
.passed {
|
10
|
+
color: green;
|
11
|
+
}
|
12
|
+
|
13
|
+
.failed {
|
14
|
+
color: red;
|
15
|
+
}
|
16
|
+
|
17
|
+
.pending {
|
18
|
+
color: orange;
|
19
|
+
}
|
20
|
+
|
21
|
+
.collapse {
|
22
|
+
cursor: pointer;
|
23
|
+
display: block;
|
24
|
+
background: white;
|
25
|
+
}
|
26
|
+
|
27
|
+
.collapse + input {
|
28
|
+
display: none; /* hide the checkboxes */
|
29
|
+
}
|
30
|
+
|
31
|
+
.collapse + input + div {
|
32
|
+
display: none;
|
33
|
+
}
|
34
|
+
|
35
|
+
.collapse + input:checked + div {
|
36
|
+
display: block;
|
37
|
+
}
|
38
|
+
|
39
|
+
.section {
|
40
|
+
padding-top: 10px;
|
41
|
+
}
|
42
|
+
|
43
|
+
.group {
|
44
|
+
border: 1px solid black;
|
45
|
+
margin: 5px 0px;
|
46
|
+
padding: 0px 5px;
|
47
|
+
}
|
data/lib/tasks/fitting.rake
CHANGED
@@ -2,6 +2,7 @@ require 'fitting/records/spherical/requests'
|
|
2
2
|
require 'fitting/configuration'
|
3
3
|
require 'fitting/records/realized_unit'
|
4
4
|
require 'fitting/templates/realized_template'
|
5
|
+
require 'fitting/statistics/template_cover_error'
|
5
6
|
|
6
7
|
namespace :fitting do
|
7
8
|
desc 'Fitting documentation'
|
@@ -18,6 +19,49 @@ namespace :fitting do
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
22
|
+
desc 'Fitting documentation responses cover'
|
23
|
+
task :documentation_responses, [:size] => :environment do |_, args|
|
24
|
+
if args.size == 'xs'
|
25
|
+
documented_unit = Fitting::Statistics::Template.new(
|
26
|
+
Fitting::Records::Spherical::Requests.new,
|
27
|
+
Fitting.configuration
|
28
|
+
)
|
29
|
+
puts documented_unit.stats
|
30
|
+
|
31
|
+
unless documented_unit.not_covered == "\n"
|
32
|
+
puts 'Not all responses from the whitelist are covered!'
|
33
|
+
exit 1
|
34
|
+
end
|
35
|
+
elsif args.size == 's'
|
36
|
+
documented_unit = Fitting::Statistics::Template.new(
|
37
|
+
Fitting::Records::Spherical::Requests.new,
|
38
|
+
Fitting.configuration,
|
39
|
+
'cover'
|
40
|
+
)
|
41
|
+
puts documented_unit.stats
|
42
|
+
|
43
|
+
unless documented_unit.not_covered == "\n"
|
44
|
+
puts 'Not all responses from the whitelist are covered!'
|
45
|
+
exit 1
|
46
|
+
end
|
47
|
+
else
|
48
|
+
puts 'need key xs or s'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'Fitting documentation responses cover error'
|
53
|
+
task :documentation_responses_error, [:size] => :environment do |_, args|
|
54
|
+
if args.size == 's'
|
55
|
+
documented_unit = Fitting::Statistics::TemplateCoverError.new(
|
56
|
+
Fitting::Records::Spherical::Requests.new,
|
57
|
+
Fitting.configuration
|
58
|
+
)
|
59
|
+
puts documented_unit.stats
|
60
|
+
else
|
61
|
+
puts 'need key s'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
21
65
|
desc 'Fitting tests'
|
22
66
|
task :tests do
|
23
67
|
realized_unit = Fitting::Records::RealizedUnit.new(
|
@@ -31,4 +75,22 @@ namespace :fitting do
|
|
31
75
|
exit 1
|
32
76
|
end
|
33
77
|
end
|
78
|
+
|
79
|
+
desc 'Fitting tests'
|
80
|
+
task :tests_responses, [:size] => :environment do |_, args|
|
81
|
+
if args.size == 'xs'
|
82
|
+
realized_unit = Fitting::Records::RealizedUnit.new(
|
83
|
+
Fitting::Records::Spherical::Requests.new,
|
84
|
+
Fitting.configuration.tomogram
|
85
|
+
)
|
86
|
+
puts Fitting::Templates::RealizedTemplate.new(realized_unit).to_s
|
87
|
+
|
88
|
+
unless realized_unit.fully_covered?
|
89
|
+
puts 'Not all responses from the whitelist are covered!'
|
90
|
+
exit 1
|
91
|
+
end
|
92
|
+
else
|
93
|
+
puts 'need key xs'
|
94
|
+
end
|
95
|
+
end
|
34
96
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fitting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- d.efimov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json-schema
|
@@ -64,6 +64,20 @@ dependencies:
|
|
64
64
|
- - ">="
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: 2.2.0
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: haml
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
67
81
|
- !ruby/object:Gem::Dependency
|
68
82
|
name: bundler
|
69
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -195,6 +209,9 @@ files:
|
|
195
209
|
- lib/fitting/configuration.rb
|
196
210
|
- lib/fitting/configuration/legacy.rb
|
197
211
|
- lib/fitting/configuration/yaml.rb
|
212
|
+
- lib/fitting/cover.rb
|
213
|
+
- lib/fitting/cover/json_schema.rb
|
214
|
+
- lib/fitting/cover/response.rb
|
198
215
|
- lib/fitting/documentation.rb
|
199
216
|
- lib/fitting/matchers/response_matcher.rb
|
200
217
|
- lib/fitting/railtie.rb
|
@@ -206,6 +223,7 @@ files:
|
|
206
223
|
- lib/fitting/records/test_unit/request.rb
|
207
224
|
- lib/fitting/records/tested/request.rb
|
208
225
|
- lib/fitting/records/tested/response.rb
|
226
|
+
- lib/fitting/records/unit/combination.rb
|
209
227
|
- lib/fitting/records/unit/json_schema.rb
|
210
228
|
- lib/fitting/records/unit/request.rb
|
211
229
|
- lib/fitting/records/unit/response.rb
|
@@ -214,20 +232,25 @@ files:
|
|
214
232
|
- lib/fitting/response/fully_validates.rb
|
215
233
|
- lib/fitting/statistics.rb
|
216
234
|
- lib/fitting/statistics/analysis.rb
|
235
|
+
- lib/fitting/statistics/cover_error.rb
|
217
236
|
- lib/fitting/statistics/great.rb
|
218
237
|
- lib/fitting/statistics/list.rb
|
219
238
|
- lib/fitting/statistics/lists.rb
|
220
239
|
- lib/fitting/statistics/measurement.rb
|
240
|
+
- lib/fitting/statistics/measurement_cover.rb
|
221
241
|
- lib/fitting/statistics/not_covered_responses.rb
|
222
242
|
- lib/fitting/statistics/percent.rb
|
223
243
|
- lib/fitting/statistics/requests_stats.rb
|
224
244
|
- lib/fitting/statistics/responses_stats.rb
|
225
245
|
- lib/fitting/statistics/template.rb
|
246
|
+
- lib/fitting/statistics/template_cover_error.rb
|
226
247
|
- lib/fitting/storage/responses.rb
|
227
248
|
- lib/fitting/storage/white_list.rb
|
228
249
|
- lib/fitting/templates/realized_template.rb
|
229
250
|
- lib/fitting/tests.rb
|
230
251
|
- lib/fitting/version.rb
|
252
|
+
- lib/fitting/view/report.html.haml
|
253
|
+
- lib/fitting/view/style.css
|
231
254
|
- lib/tasks/fitting.rake
|
232
255
|
homepage: https://github.com/funbox/fitting
|
233
256
|
licenses:
|