fitting 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +7 -0
  4. data/lib/fitting.rb +1 -3
  5. data/lib/fitting/configuration.rb +41 -11
  6. data/lib/fitting/configuration/legacy.rb +41 -0
  7. data/lib/fitting/configuration/yaml.rb +60 -0
  8. data/lib/fitting/matchers/response_matcher.rb +33 -14
  9. data/lib/fitting/records/documented/request.rb +53 -0
  10. data/lib/fitting/records/tested/request.rb +30 -0
  11. data/lib/fitting/records/tested/response.rb +19 -0
  12. data/lib/fitting/records/unit/json_schema.rb +25 -0
  13. data/lib/fitting/records/unit/request.rb +36 -0
  14. data/lib/fitting/records/unit/response.rb +31 -0
  15. data/lib/fitting/statistics.rb +14 -19
  16. data/lib/fitting/statistics/analysis.rb +24 -0
  17. data/lib/fitting/statistics/great.rb +13 -0
  18. data/lib/fitting/statistics/list.rb +45 -0
  19. data/lib/fitting/statistics/lists.rb +52 -0
  20. data/lib/fitting/statistics/measurement.rb +94 -0
  21. data/lib/fitting/statistics/not_covered_responses.rb +13 -0
  22. data/lib/fitting/statistics/percent.rb +19 -0
  23. data/lib/fitting/statistics/requests_stats.rb +40 -0
  24. data/lib/fitting/statistics/responses_stats.rb +32 -0
  25. data/lib/fitting/statistics/template.rb +90 -0
  26. data/lib/fitting/storage/responses.rb +6 -28
  27. data/lib/fitting/version.rb +1 -1
  28. metadata +20 -11
  29. data/lib/fitting/route.rb +0 -28
  30. data/lib/fitting/route/coverage.rb +0 -45
  31. data/lib/fitting/route/requests.rb +0 -25
  32. data/lib/fitting/route/requests/combine.rb +0 -113
  33. data/lib/fitting/route/requests/coverage.rb +0 -58
  34. data/lib/fitting/route/requests/lists.rb +0 -92
  35. data/lib/fitting/route/requests/statistics.rb +0 -40
  36. data/lib/fitting/route/responses.rb +0 -24
  37. 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
@@ -1,30 +1,25 @@
1
- require 'fitting/route'
2
- require 'fileutils'
1
+ require 'fitting/statistics/template'
3
2
 
4
3
  module Fitting
5
4
  class Statistics
6
- def initialize(documentation, all_responses, strict)
7
- @documentation = documentation
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
- FileUtils.mkdir_p 'fitting'
14
- File.open('fitting/stats', 'w') { |file| file.write(to_s) }
15
- File.open('fitting/not_covered', 'w') { |file| file.write(@white_route.errors) }
16
- end
17
-
18
- def to_s
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
- [@white_route.statistics_with_conformity_lists, "\n\n"].join
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,13 @@
1
+ module Fitting
2
+ class Statistics
3
+ class NotCoveredResponses
4
+ def initialize(measurement)
5
+ @measurement = measurement
6
+ end
7
+
8
+ def to_s
9
+ @measurement.not_covered_responses.join("\n") + "\n"
10
+ end
11
+ end
12
+ end
13
+ 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