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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e04b182de6052b1d8c395f48016e8b9f37d6b769
4
- data.tar.gz: 392e75a0af97023f53585472e27a94cb83843406
3
+ metadata.gz: bf841d9b8d6f50655b5d8f0a265980660be83232
4
+ data.tar.gz: 0413072e04a9eab17e619c0821d4bc05f0cd2592
5
5
  SHA512:
6
- metadata.gz: 639a9c1b2d78babd961fabc52464b962017e97904dc1b1c3b10cab94e14434880ec315eb8509ee6aa081a5af83b4ad494b1b16b8cf4f841634996d03c6cdfa4f
7
- data.tar.gz: 4200b2c82e8ef7f8b4b1b893818859c8ac7f5ec2fb6bce148b93b782b644b0945c9a0393343930afd6905283b8901754ee766ce6a8c5ad54721a1c7207677d9c
6
+ metadata.gz: 2f08e076fcfd2c8fae3ffa8a3173a35b727b47e240fb3cd7ad2fa65b9fd77da4cdb481cd07aabc60ec05b9bd56fa50fa6144f8071b2ea78026e51a362661b634
7
+ data.tar.gz: 610bcca9e1152c96af7fbfff997ff3146ffe7cfcdca20777b97e775c1384b7a0b0b34d2711795d717afd9ad1151560642a3d51095f617c8bb704235aeca5ce6f
@@ -1,5 +1,16 @@
1
1
  # Change log
2
2
 
3
+ ### 2.3.0 - 2017-09-13
4
+
5
+ * features
6
+ * configuration via yaml file
7
+ * setting for multiple prefixes
8
+
9
+ ### 2.2.0 - 2017-08-23
10
+
11
+ * features
12
+ * ignore requests which match with ignore list
13
+
3
14
  ### 2.1.3 - 2017-08-07
4
15
 
5
16
  * bug fixes
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Fitting
2
2
 
3
+ <a href="https://funbox.ru">
4
+ <img src="https://funbox.ru/badges/sponsored_by_funbox.svg" alt="Sponsored by FunBox" width=250 />
5
+ </a>
6
+
3
7
  [![Build Status](https://travis-ci.org/funbox/fitting.svg?branch=master)](https://travis-ci.org/funbox/fitting)
4
8
 
5
9
  This gem will help you implement your API in strict accordance to the documentation in [API Blueprint](https://apiblueprint.org/) format.
@@ -113,6 +117,9 @@ expect(response).to strictly_match_schema
113
117
 
114
118
  ## Config
115
119
 
120
+ You can specify the settings either in a yaml file `.fitting.yml` or in config.
121
+ If your project uses several prefixes, for each one you need to create a separate yaml file in the folder `fitting` (`fitting/*.yml`).
122
+
116
123
  ### apib_path
117
124
 
118
125
  Path to API Blueprint documentation. There must be an installed [drafter](https://github.com/apiaryio/drafter) to parse it.
@@ -1,8 +1,6 @@
1
1
  require 'fitting/version'
2
2
  require 'fitting/configuration'
3
- require 'fitting/storage/documentation'
4
3
  require 'fitting/matchers/response_matcher'
5
- require 'fitting/statistics'
6
4
  require 'fitting/documentation'
7
5
  require 'fitting/storage/responses'
8
6
 
@@ -13,7 +11,7 @@ module Fitting
13
11
  end
14
12
 
15
13
  def configuration
16
- @configuration ||= Configuration.new
14
+ @configuration ||= Configuration.craft
17
15
  end
18
16
 
19
17
  def statistics
@@ -1,17 +1,47 @@
1
+ require 'fitting/configuration/yaml'
2
+ require 'fitting/configuration/legacy'
3
+ require 'yaml'
4
+
1
5
  module Fitting
2
6
  class Configuration
3
- attr_accessor :apib_path,
4
- :drafter_yaml_path,
5
- :strict,
6
- :prefix,
7
- :white_list,
8
- :resource_white_list,
9
- :ignore_list
7
+ class << self
8
+ def craft
9
+ if one_yaml?
10
+ one_yaml
11
+ elsif more_than_one_yaml?
12
+ more_than_one_yaml
13
+ else
14
+ legacy
15
+ end
16
+ end
17
+
18
+ def one_yaml?
19
+ File.file?('.fitting.yml')
20
+ end
21
+
22
+ def more_than_one_yaml?
23
+ !Dir['fitting/*.yml'].empty?
24
+ end
25
+
26
+ def one_yaml
27
+ yaml = YAML.safe_load(File.read('.fitting.yml'))
28
+ Fitting::Configuration::Yaml.new(yaml)
29
+ end
30
+
31
+ def more_than_one_yaml
32
+ files.map do |file|
33
+ yaml = YAML.safe_load(File.read(file))
34
+ Fitting::Configuration::Yaml.new(yaml, file[8..-5])
35
+ end
36
+ end
37
+
38
+ def legacy
39
+ Fitting::Configuration::Legacy.new
40
+ end
10
41
 
11
- def initialize
12
- @strict = false
13
- @prefix = ''
14
- @ignore_list = []
42
+ def files
43
+ Dir['fitting/*.yml']
44
+ end
15
45
  end
16
46
  end
17
47
  end
@@ -0,0 +1,41 @@
1
+ require 'tomograph'
2
+
3
+ module Fitting
4
+ class Configuration
5
+ class Legacy
6
+ attr_accessor :apib_path,
7
+ :drafter_yaml_path,
8
+ :strict,
9
+ :prefix,
10
+ :white_list,
11
+ :resource_white_list,
12
+ :ignore_list
13
+
14
+ def initialize
15
+ @strict = false
16
+ @prefix = ''
17
+ @ignore_list = []
18
+ end
19
+
20
+ def tomogram
21
+ @tomogram ||= Tomograph::Tomogram.new(
22
+ prefix: @prefix,
23
+ apib_path: @apib_path,
24
+ drafter_yaml_path: @drafter_yaml_path
25
+ )
26
+ end
27
+
28
+ def title
29
+ 'fitting'
30
+ end
31
+
32
+ def stats_path
33
+ 'fitting/stats'
34
+ end
35
+
36
+ def not_covered_path
37
+ 'fitting/not_covered'
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,60 @@
1
+ require 'tomograph'
2
+
3
+ module Fitting
4
+ class Configuration
5
+ class Yaml
6
+ attr_reader :title
7
+ attr_accessor :apib_path,
8
+ :drafter_yaml_path,
9
+ :strict,
10
+ :prefix,
11
+ :white_list,
12
+ :resource_white_list,
13
+ :ignore_list
14
+
15
+ def initialize(yaml, title = 'fitting')
16
+ @apib_path = yaml['apib_path']
17
+ @drafter_yaml_path = yaml['drafter_yaml_path']
18
+ @strict = yaml['strict']
19
+ @prefix = yaml['prefix']
20
+ @white_list = yaml['white_list']
21
+ @resource_white_list = yaml['resource_white_list']
22
+ @ignore_list = yaml['ignore_list']
23
+ @title = title
24
+ default
25
+ end
26
+
27
+ def tomogram
28
+ @tomogram ||= Tomograph::Tomogram.new(
29
+ prefix: @prefix,
30
+ apib_path: @apib_path,
31
+ drafter_yaml_path: @drafter_yaml_path
32
+ )
33
+ end
34
+
35
+ def stats_path
36
+ if @title == 'fitting'
37
+ 'fitting/stats'
38
+ else
39
+ "fitting/#{@title}/stats"
40
+ end
41
+ end
42
+
43
+ def not_covered_path
44
+ if @title == 'fitting'
45
+ 'fitting/not_covered'
46
+ else
47
+ "fitting/#{@title}/not_covered"
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def default
54
+ @strict ||= false if @strict.nil?
55
+ @prefix ||= ''
56
+ @ignore_list ||= []
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,20 +1,16 @@
1
1
  require 'fitting/response'
2
- require 'fitting/storage/documentation'
3
2
  require 'fitting/configuration'
4
3
 
5
4
  module Fitting
6
5
  module Matchers
7
6
  class Response
8
7
  def matches?(response)
9
- @response = Fitting::Response.new(
10
- response,
11
- Fitting::Storage::Documentation.tomogram
12
- )
13
- return true if @response.ignored?(Fitting.configuration.ignore_list)
14
- if @response.within_prefix?(Fitting.configuration.prefix)
15
- @response.fully_validates.valid?
8
+ if Fitting.configuration.is_a?(Array)
9
+ Fitting.configuration.all? do |config|
10
+ one_match(response, config)
11
+ end
16
12
  else
17
- true
13
+ one_match(response, Fitting.configuration)
18
14
  end
19
15
  end
20
16
 
@@ -35,15 +31,28 @@ module Fitting
35
31
  "got: #{@response.got}\n\n"\
36
32
  "errors: \n#{@response.fully_validates}\n"
37
33
  end
34
+
35
+ private
36
+
37
+ def one_match(response, config)
38
+ response = Fitting::Response.new(response, config.tomogram)
39
+ if response.within_prefix?(config.prefix)
40
+ @response = response
41
+ return true if @response.ignored?(config.ignore_list)
42
+ return @response.fully_validates.valid?
43
+ else
44
+ true
45
+ end
46
+ end
38
47
  end
39
48
 
40
49
  class StrictResponse
41
50
  def matches?(response)
42
- @response = Fitting::Response.new(
43
- response,
44
- Fitting::Storage::Documentation.tomogram
45
- )
46
- @response.strict_fully_validates.valid?
51
+ if Fitting.configuration.is_a?(Array)
52
+ one_match(response, Fitting.configuration[0])
53
+ else
54
+ one_match(response, Fitting.configuration)
55
+ end
47
56
  end
48
57
 
49
58
  def ===(other)
@@ -63,6 +72,16 @@ module Fitting
63
72
  "got: #{@response.got}\n\n"\
64
73
  "errors: \n#{@response.strict_fully_validates}\n"
65
74
  end
75
+
76
+ private
77
+
78
+ def one_match(response, config)
79
+ @response = Fitting::Response.new(
80
+ response,
81
+ config.tomogram
82
+ )
83
+ @response.strict_fully_validates.valid?
84
+ end
66
85
  end
67
86
 
68
87
  def match_schema
@@ -0,0 +1,53 @@
1
+ module Fitting
2
+ class Records
3
+ class Documented
4
+ class Request
5
+ def initialize(tomogram_request, white_list)
6
+ @tomogram_request = tomogram_request
7
+ @white_list = white_list
8
+ end
9
+
10
+ def method
11
+ @method ||= @tomogram_request['method']
12
+ end
13
+
14
+ def path
15
+ @path ||= @tomogram_request['path']
16
+ end
17
+
18
+ def json_schema
19
+ @json_schema ||= @tomogram_request['json_schema']
20
+ end
21
+
22
+ def responses
23
+ @responses ||= groups.map do |group|
24
+ {
25
+ 'status' => group[0],
26
+ 'json_schemas' => group[1].map { |subgroup| subgroup['body'] }
27
+ }
28
+ end
29
+ end
30
+
31
+ def white
32
+ @white ||= white?
33
+ end
34
+
35
+ private
36
+
37
+ def white?
38
+ return true if @white_list == nil
39
+ return false if @white_list[path.to_s] == nil
40
+ return true if @white_list[path.to_s] == []
41
+ return true if @white_list[path.to_s].include?(method)
42
+ false
43
+ end
44
+
45
+ def groups
46
+ @groups ||= @tomogram_request['responses'].group_by do |tomogram_response|
47
+ tomogram_response['status']
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ require 'tomograph/path'
2
+ require 'fitting/records/tested/response'
3
+
4
+ module Fitting
5
+ class Records
6
+ class Tested
7
+ class Request
8
+ def initialize(env_response)
9
+ @env_response = env_response
10
+ end
11
+
12
+ def method
13
+ @method ||= @env_response.request.request_method
14
+ end
15
+
16
+ def path
17
+ @path ||= Tomograph::Path.new(@env_response.request.env['PATH_INFO'] || @env_response.request.fullpath)
18
+ end
19
+
20
+ def body
21
+ @body ||= @env_response.request.env['action_dispatch.request.request_parameters']
22
+ end
23
+
24
+ def response
25
+ @response ||= Fitting::Records::Tested::Response.new(@env_response)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ module Fitting
2
+ class Records
3
+ class Tested
4
+ class Response
5
+ def initialize(env_response)
6
+ @env_response = env_response
7
+ end
8
+
9
+ def status
10
+ @status ||= @env_response.status
11
+ end
12
+
13
+ def body
14
+ @body ||= @env_response.body
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ require 'json-schema'
2
+
3
+ module Fitting
4
+ class Records
5
+ class Unit
6
+ class JsonSchema
7
+ def initialize(json_schema, tested_bodies)
8
+ @json_schema = json_schema
9
+ @tested_bodies = tested_bodies
10
+ end
11
+
12
+ def bodies
13
+ @bodies ||= @tested_bodies.inject([]) do |res, tested_body|
14
+ begin
15
+ next res unless JSON::Validator.validate(@json_schema, tested_body)
16
+ res.push(tested_body)
17
+ rescue JSON::Schema::UriError
18
+ res.push(tested_body)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ require 'fitting/records/unit/response'
2
+
3
+ module Fitting
4
+ class Records
5
+ class Unit
6
+ class Request
7
+ def initialize(documented_request, tested_requests)
8
+ @documented_request = documented_request
9
+ @tested_requests = tested_requests
10
+ end
11
+
12
+ def path
13
+ @path ||= @documented_request.path
14
+ end
15
+
16
+ def method
17
+ @method ||= @documented_request.method
18
+ end
19
+
20
+ def responses
21
+ @responses ||= @documented_request.responses.to_a.inject([]) do |res, documented_response|
22
+ res.push(Fitting::Records::Unit::Response.new(documented_response, tested_responses))
23
+ end
24
+ end
25
+
26
+ def tested_responses
27
+ @tested_responses ||= @tested_requests.inject([]) do |res, tested_request|
28
+ next res unless @documented_request.method == tested_request.method &&
29
+ @documented_request.path.match(tested_request.path.to_s)
30
+ res.push(tested_request.response)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end