fitting 2.2.0 → 2.3.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.
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