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
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