fitting 3.0.2 → 4.0.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +9 -0
  5. data/README.md +272 -109
  6. data/fitting.gemspec +2 -2
  7. data/images/b1.png +0 -0
  8. data/images/b2.png +0 -0
  9. data/images/w1.png +0 -0
  10. data/images/w2.png +0 -0
  11. data/lib/fitting/action.rb +105 -0
  12. data/lib/fitting/cover/json_schema.rb +2 -2
  13. data/lib/fitting/cover/json_schema_one_of.rb +4 -2
  14. data/lib/fitting/debug.rb +47 -0
  15. data/lib/fitting/doc/action.rb +141 -0
  16. data/lib/fitting/doc/code.rb +53 -0
  17. data/lib/fitting/doc/combination_enum.rb +110 -0
  18. data/lib/fitting/doc/combination_one_of.rb +61 -0
  19. data/lib/fitting/doc/combination_optional.rb +54 -0
  20. data/lib/fitting/doc/combination_step.rb +48 -0
  21. data/lib/fitting/doc/content_type.rb +152 -0
  22. data/lib/fitting/doc/json_schema.rb +116 -0
  23. data/lib/fitting/doc/step.rb +102 -0
  24. data/lib/fitting/doc.rb +107 -0
  25. data/lib/fitting/host.rb +37 -0
  26. data/lib/fitting/log.rb +102 -0
  27. data/lib/fitting/nocov.rb +64 -0
  28. data/lib/fitting/prefix.rb +62 -0
  29. data/lib/fitting/railtie.rb +0 -1
  30. data/lib/fitting/records/spherical/request.rb +7 -4
  31. data/lib/fitting/records/spherical/response.rb +22 -16
  32. data/lib/fitting/records/tested/request.rb +6 -1
  33. data/lib/fitting/records/tested/response.rb +6 -1
  34. data/lib/fitting/rep/html.rb +32 -0
  35. data/lib/fitting/rep.rb +24 -0
  36. data/lib/fitting/report/action.rb +9 -15
  37. data/lib/fitting/report/actions.rb +22 -33
  38. data/lib/fitting/report/combination.rb +10 -6
  39. data/lib/fitting/report/combinations.rb +9 -29
  40. data/lib/fitting/report/prefix.rb +7 -24
  41. data/lib/fitting/report/prefixes.rb +11 -25
  42. data/lib/fitting/report/response.rb +12 -22
  43. data/lib/fitting/report/responses.rb +23 -27
  44. data/lib/fitting/report/tests.rb +4 -8
  45. data/lib/fitting/skip/action.rb +44 -0
  46. data/lib/fitting/skip/api.rb +29 -0
  47. data/lib/fitting/skip.rb +21 -0
  48. data/lib/fitting/version.rb +1 -1
  49. data/lib/fitting.rb +12 -28
  50. data/lib/tasks/fitting.rake +23 -84
  51. data/lib/templates/htmlcss/bootstrap-nightshade.min.css +12 -0
  52. data/lib/templates/htmlcss/bootstrap.min.js +7 -0
  53. data/lib/templates/htmlcss/darkmode.min.js +6 -0
  54. data/lib/templates/htmlcss/fitting.html +196 -0
  55. data/lib/templates/htmlcss/jquery-3.6.0.min.js +2 -0
  56. metadata +40 -39
  57. data/lib/fitting/configuration.rb +0 -17
  58. data/lib/fitting/records/spherical/requests.rb +0 -25
  59. data/lib/fitting/storage/responses.rb +0 -21
  60. data/lib/fitting/tests.rb +0 -31
  61. data/lib/tasks/fitting_outgoing.rake +0 -91
  62. data/lib/templates/bomboniere/.gitignore +0 -21
  63. data/lib/templates/bomboniere/.tool-versions +0 -1
  64. data/lib/templates/bomboniere/README.md +0 -19
  65. data/lib/templates/bomboniere/dist/css/app.aa2bcd8a.css +0 -1
  66. data/lib/templates/bomboniere/dist/css/chunk-vendors.ec5f6c3f.css +0 -1
  67. data/lib/templates/bomboniere/dist/favicon.ico +0 -0
  68. data/lib/templates/bomboniere/dist/index.html +0 -1
  69. data/lib/templates/bomboniere/dist/js/app.e5f1a5ec.js +0 -2
  70. data/lib/templates/bomboniere/dist/js/app.e5f1a5ec.js.map +0 -1
  71. data/lib/templates/bomboniere/dist/js/chunk-vendors.0f99b670.js +0 -13
  72. data/lib/templates/bomboniere/dist/js/chunk-vendors.0f99b670.js.map +0 -1
  73. data/lib/templates/bomboniere/package-lock.json +0 -9292
  74. data/lib/templates/bomboniere/package.json +0 -27
  75. data/lib/templates/bomboniere/public/favicon.ico +0 -0
  76. data/lib/templates/bomboniere/public/index.html +0 -17
  77. data/lib/templates/bomboniere/src/App.vue +0 -102
  78. data/lib/templates/bomboniere/src/assets/logo.png +0 -0
  79. data/lib/templates/bomboniere/src/components/HelloWorld.vue +0 -204
  80. data/lib/templates/bomboniere/src/main.js +0 -10
  81. data/lib/templates/bomboniere/src/router/index.js +0 -31
  82. data/lib/templates/bomboniere/src/views/About.vue +0 -5
  83. data/lib/templates/bomboniere/src/views/Action.vue +0 -173
  84. data/lib/templates/bomboniere/src/views/Home.vue +0 -17
  85. data/lib/templates/bomboniere/vue.config.js +0 -3
@@ -0,0 +1,116 @@
1
+ require 'fitting/doc/step'
2
+ require 'fitting/doc/combination_one_of'
3
+ require 'fitting/cover/json_schema_one_of'
4
+ require 'fitting/doc/combination_enum'
5
+ require 'fitting/cover/json_schema_enum'
6
+ require 'fitting/cover/json_schema'
7
+ require 'fitting/doc/combination_optional'
8
+ require 'json'
9
+ require 'json-schema'
10
+
11
+ module Fitting
12
+ class Doc
13
+ class JsonSchema < Step
14
+ class NotFound < RuntimeError; end
15
+
16
+ def initialize(json_schema, super_schema)
17
+ @super_schema = super_schema
18
+ @logs = []
19
+ @step_cover_size = 0
20
+ @step_key = json_schema
21
+ @next_steps = []
22
+ @oneOf = false
23
+ Fitting::Cover::JSONSchemaOneOf.new(json_schema).combi.each do |combination|
24
+ @oneOf = true
25
+ @next_steps.push(CombinationOneOf.new(combination[0], combination[1][0], combination[1][1], json_schema))
26
+ end
27
+ combinations = Fitting::Cover::JSONSchemaEnum.new(json_schema).combi
28
+ if combinations.size > 1
29
+ combinations.each do |comb|
30
+ @next_steps.push(CombinationEnum.new(comb[0], comb[1][0], comb[1][1], json_schema))
31
+ end
32
+ end
33
+
34
+ if json_schema['type'] != 'array'
35
+ combinations = Fitting::Cover::JSONSchema.new(json_schema).combi
36
+ combinations.each do |comb|
37
+ @next_steps.push(CombinationOptional.new(comb[0], comb[1][0], comb[1][1], json_schema))
38
+ end
39
+ end
40
+ end
41
+
42
+ def cover!(log)
43
+ if @super_schema
44
+ @step_cover_size += 1
45
+ @logs.push(log.body)
46
+ @next_steps.each { |combination| combination.cover!(log) }
47
+ elsif JSON::Validator.fully_validate(@step_key, log.body) == []
48
+ @step_cover_size += 1
49
+ @logs.push(log.body)
50
+ @next_steps.each { |combination| combination.cover!(log) }
51
+ else
52
+ raise Fitting::Doc::JsonSchema::NotFound.new "json-schema: #{::JSON.pretty_generate(@step_key)}\n\n"\
53
+ "body: #{::JSON.pretty_generate(log.body)}\n\n"\
54
+ "error #{::JSON.pretty_generate(JSON::Validator.fully_validate(@step_key, log.body))}"
55
+ end
56
+ rescue JSON::Schema::SchemaError => e
57
+ raise Fitting::Doc::JsonSchema::NotFound.new "json-schema: #{::JSON.pretty_generate(@step_key)}\n\n"\
58
+ "body: #{::JSON.pretty_generate(log.body)}\n\n"\
59
+ "error #{e.message}"
60
+ rescue Fitting::Doc::CombinationOneOf::NotFound => e
61
+ raise Fitting::Doc::JsonSchema::NotFound.new "#{e.message}\n\nsource json-schema: #{::JSON.pretty_generate(@step_key)}\n\n"
62
+ end
63
+
64
+ def logs
65
+ @logs
66
+ end
67
+
68
+ def mark_range(index, res)
69
+ start_index = index
70
+ end_index = start_index + 2
71
+
72
+ (start_index..end_index).each do |i|
73
+ res[i] = @step_cover_size
74
+ end
75
+
76
+ if @step_key["required"]
77
+ mark_required(end_index, res, @step_key)
78
+ end
79
+ end_index
80
+ end
81
+
82
+ def nocover!
83
+ @step_cover_size = nil
84
+ end
85
+
86
+ def to_hash
87
+ @step_key
88
+ end
89
+
90
+ def report(res, index)
91
+ @index_before = index
92
+ @res_before = [] + res
93
+
94
+ index = mark_range(index, res)
95
+ @index_medium = index
96
+ @res_medium = [] + res
97
+
98
+ if @next_steps != []
99
+ new_index = index
100
+ @next_steps.each do |next_step|
101
+ if @oneOf
102
+ res, new_index = next_step.report(res, new_index)
103
+ else
104
+ res, new_index = next_step.report(res, @index_before)
105
+ end
106
+ end
107
+ end
108
+
109
+ index += index_offset
110
+ @index_after = index
111
+ @res_after = [] + res
112
+ [res, index]
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,102 @@
1
+ module Fitting
2
+ class Doc
3
+ class Step
4
+ attr_accessor :step_cover_size, :step_key, :next_steps, :index_before, :index_medium, :index_after, :res_before, :res_medium, :res_after
5
+
6
+ def to_hash
7
+ {
8
+ @step_key => @next_steps.inject({}) { |sum, value| sum.merge!(value) }
9
+ }
10
+ end
11
+
12
+ def nocover!
13
+ @step_cover_size = nil
14
+ @next_steps.each do |next_step|
15
+ next_step.nocover!
16
+ end
17
+ end
18
+
19
+ def report(res, index)
20
+ @index_before = index
21
+ @res_before = [] + res
22
+
23
+ mark_range(index, res)
24
+ @index_medium = index
25
+ @res_medium = [] + res
26
+
27
+ if @next_steps != []
28
+ new_index = index + new_index_offset
29
+ @next_steps.each do |next_step|
30
+ if self.class == Fitting::Doc::CombinationOneOf
31
+ res, _new_index = next_step.report(res, new_index - 2)
32
+ else
33
+ res, new_index = next_step.report(res, new_index)
34
+ end
35
+ end
36
+ end
37
+
38
+ index += index_offset
39
+ @index_after = index
40
+ @res_after = [] + res
41
+ [res, index]
42
+ end
43
+
44
+ def mark_range(index, res)
45
+ res[index] = @step_cover_size
46
+ if @json_schema && @json_schema["required"]
47
+ mark_required(index, res, @json_schema)
48
+ end
49
+ end
50
+
51
+ def new_index_offset
52
+ 1
53
+ end
54
+
55
+ def index_offset
56
+ YAML.dump(@next_steps.inject({}) { |sum, value| sum.merge!(value) }).split("\n").size
57
+ end
58
+
59
+ def mark_required(index, res, schema)
60
+ start_index = index + YAML.dump(schema["properties"]).split("\n").size
61
+ end_index = start_index + YAML.dump(schema["required"]).split("\n").size - 1
62
+ (start_index..end_index).each do |i|
63
+ res[i] = @step_cover_size
64
+ end
65
+
66
+ return if schema["required"].nil?
67
+
68
+ schema["required"].each do |required|
69
+ required_index = YAML.dump(schema["properties"]).split("\n").index { |key| key == "#{required}:" }
70
+ break if required_index.nil?
71
+ res[index + required_index] = @step_cover_size
72
+ res[index + required_index + 1] = @step_cover_size
73
+ res[index + required_index + 2] = @step_cover_size if schema["properties"][required]["type"] == "string" && schema["properties"][required]["enum"]
74
+ if schema["properties"][required]["type"] == "object"
75
+ res[index + required_index + 2] = @step_cover_size
76
+ new_index = index + required_index + 2
77
+ mark_required(new_index, res, schema["properties"][required])
78
+ elsif schema["properties"][required]["type"] == "string" && schema["properties"][required]["enum"]
79
+ new_index = index + required_index + 2
80
+ mark_enum(new_index, res, schema["properties"][required])
81
+ end
82
+ end
83
+ end
84
+
85
+ def mark_enum(index, res, schema)
86
+ if schema["enum"].size == 1
87
+ res[index] = @step_cover_size
88
+ res[index + 1] = @step_cover_size
89
+ end
90
+ end
91
+
92
+ def valid?
93
+ end
94
+
95
+ def range
96
+ end
97
+
98
+ def next
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,107 @@
1
+ require 'fitting/doc/action'
2
+ require 'tomograph'
3
+
4
+ module Fitting
5
+ class Doc
6
+ class NotFound < RuntimeError; end
7
+
8
+ def self.all
9
+ apis = YAML.safe_load(File.read('.fitting.yml'))['APIs']
10
+ return [] unless apis
11
+ apis.map do |api|
12
+ if api['type'] == 'openapi2'
13
+ Tomograph::Tomogram.new(prefix: api['prefix'] || '', openapi2_json_path: api['path']).to_a.map do |action|
14
+ Fitting::Doc::Action.new(
15
+ api['host'],
16
+ api['prefix'] || '',
17
+ action.to_hash['method'],
18
+ action.to_hash['path'].path,
19
+ action.responses
20
+ )
21
+ end
22
+ elsif api['type'] == 'openapi3'
23
+ Tomograph::Tomogram.new(prefix: api['prefix'] || '', openapi3_yaml_path: api['path']).to_a.map do |action|
24
+ Fitting::Doc::Action.new(
25
+ api['host'],
26
+ api['prefix'] || '',
27
+ action.to_hash['method'],
28
+ action.to_hash['path'].path,
29
+ action.responses
30
+ )
31
+ end
32
+ elsif api['type'] == 'drafter'
33
+ Tomograph::Tomogram.new(prefix: api['prefix'] || '', drafter_yaml_path: api['path']).to_a.map do |action|
34
+ Fitting::Doc::Action.new(
35
+ api['host'],
36
+ api['prefix'] || '',
37
+ action.to_hash['method'],
38
+ action.to_hash['path'].path,
39
+ action.responses
40
+ )
41
+ end
42
+ elsif api['type'] == 'crafter'
43
+ Tomograph::Tomogram.new(prefix: api['prefix'] || '', crafter_yaml_path: api['path']).to_a.map do |action|
44
+ Fitting::Doc::Action.new(
45
+ api['host'],
46
+ api['prefix'] || '',
47
+ action.to_hash['method'],
48
+ action.to_hash['path'].path,
49
+ action.responses
50
+ )
51
+ end
52
+ elsif api['type'] == 'tomogram'
53
+ Tomograph::Tomogram.new(prefix: api['prefix'] || '', tomogram_json_path: api['path']).to_a.map do |action|
54
+ Fitting::Doc::Action.new(
55
+ api['host'],
56
+ api['prefix'] || '',
57
+ action.to_hash['method'],
58
+ action.to_hash['path'].path,
59
+ action.responses
60
+ )
61
+ end
62
+ end
63
+ end.flatten
64
+ end
65
+
66
+ def self.cover!(docs, log)
67
+ docs.each do |doc|
68
+ return if doc.cover!(log)
69
+ end
70
+ raise NotFound.new "log: #{log.method} #{log.host} #{log.url} #{log.status}"
71
+ rescue Fitting::Doc::Action::NotFound => e
72
+ raise NotFound.new "log error: #{e.message}"
73
+ end
74
+
75
+ def self.debug(docs, debug)
76
+ docs.each do |doc|
77
+ res = doc.debug(debug)
78
+ return res if res
79
+ end
80
+ raise NotFound
81
+ end
82
+
83
+ def self.report(docs)
84
+ all = 0
85
+ cov = 0
86
+ docs.each do |provid|
87
+ provid.to_hash.values.first.each do |prov|
88
+ if prov == nil
89
+ break
90
+ elsif prov == 0
91
+ all += 1
92
+ elsif prov > 0
93
+ all += 1
94
+ cov += 1
95
+ end
96
+ end
97
+ end
98
+ res = (cov.to_f / all.to_f * 100).round(2)
99
+ puts "Coverage: #{res}%"
100
+ if res == 100.00
101
+ exit 0
102
+ else
103
+ exit 1
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,37 @@
1
+ module Fitting
2
+ class Host
3
+ class Skip < RuntimeError; end
4
+ class NotFound < RuntimeError
5
+ attr_reader :log
6
+ def initialize(msg, log)
7
+ @log = log
8
+ super(msg)
9
+ end
10
+ end
11
+
12
+ def initialize(host, skip)
13
+ @host = host
14
+ @skip = skip
15
+ @cover = false
16
+ end
17
+
18
+ def self.find!(log)
19
+ yaml = YAML.safe_load(File.read('.fitting.yml'))
20
+ yaml['hosts']&.map do |host|
21
+ if log.host == host.first.first
22
+ return new(host.first.first, host.first.last)
23
+ end
24
+ end
25
+ raise NotFound.new(log.host, log)
26
+ end
27
+
28
+ def cover!
29
+ @cover = true
30
+ raise Skip if @skip == 'skip'
31
+ end
32
+
33
+ def to_s
34
+ @host
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,102 @@
1
+ module Fitting
2
+ class Log
3
+ def initialize(log, type)
4
+ @log = log
5
+ @type = type
6
+ @error = nil
7
+ @skip = false
8
+ end
9
+
10
+ def self.all
11
+ logs = []
12
+ Dir["log/fitting*.log"].each do |file_path|
13
+ testlog = File.read(file_path)
14
+ testlog.split("\n").select { |f| f.include?('incoming request ') }.each do |test|
15
+ logs.push(new(JSON.load(test.split('incoming request ')[1]), 'incoming'))
16
+ end
17
+ testlog.split("\n").select { |f| f.include?('outgoing request ') }.each do |test|
18
+ logs.push(new(JSON.load(test.split('outgoing request ')[1]), 'outgoing'))
19
+ end
20
+ end
21
+ logs.sort { |a, b| b.path <=> a.path }
22
+ end
23
+
24
+ def url
25
+ "#{host}#{path}"
26
+ end
27
+
28
+ def path
29
+ @log['path']
30
+ end
31
+
32
+ def method
33
+ @log['method']
34
+ end
35
+
36
+ def status
37
+ @log['response']['status'].to_s
38
+ end
39
+
40
+ def body
41
+ @log['response']['body']
42
+ end
43
+
44
+ def content_type
45
+ @log['response']['content_type']
46
+ end
47
+
48
+ def host
49
+ @log['host'] || 'www.example.com'
50
+ end
51
+
52
+ def type
53
+ @type
54
+ end
55
+
56
+ def access!
57
+ print "\e[32m.\e[0m"
58
+ end
59
+
60
+ def pending!
61
+ @skip = true
62
+ print "\e[33m*\e[0m"
63
+ end
64
+
65
+ def failure!(error)
66
+ @error = error
67
+ print "\e[31mF\e[0m"
68
+ end
69
+
70
+ def error
71
+ @error
72
+ end
73
+
74
+ def failure?
75
+ @error.present?
76
+ end
77
+
78
+ def self.failure(logs)
79
+ logs.select do |log|
80
+ log.failure?
81
+ end
82
+ end
83
+
84
+ def pending?
85
+ @skip
86
+ end
87
+
88
+ def self.pending(logs)
89
+ logs.select do |log|
90
+ log.pending?
91
+ end
92
+ end
93
+
94
+ def self.report(logs)
95
+ puts "\n\n"
96
+ Fitting::Log.failure(logs).each_with_index do |log, index|
97
+ puts "\e[31m #{index + 1}) #{log.error.class} #{log.error.message}\n\n\e[0m"
98
+ end
99
+ print "\e[31m#{logs.size} examples, #{Fitting::Log.failure(logs).size} failure, #{Fitting::Log.pending(logs).size} pending\e[0m\n"
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,64 @@
1
+ module Fitting
2
+ class NoCov
3
+ class NotFound < RuntimeError; end
4
+
5
+ def initialize(host, method, path, code, content_type, combination, combination_next)
6
+ @host = host
7
+ @method = method
8
+ @path = path
9
+ @code = code
10
+ @content_type = content_type
11
+ @combination = combination
12
+ @combination_next = combination_next
13
+ end
14
+
15
+ def self.all(yaml)
16
+ return [] unless yaml['NoCov']
17
+ yaml['NoCov'].map do |action|
18
+ new(action['host'], action['method'], action['path'], action['code'], action['content-type'], action['combination'], action['combination_next'])
19
+ end
20
+ end
21
+
22
+ def find(docs)
23
+ res = docs.find do |action|
24
+ action.host == @host && action.method == @method && action.path_match(@path)
25
+ end
26
+
27
+ if @code == nil
28
+ return res if res.present?
29
+ raise NotFound.new("host: #{@host}, method: #{@method}, path: #{@path}")
30
+ end
31
+
32
+ res_code = res.responses.find { |response| response.step_key == @code.to_s }
33
+
34
+ if @content_type == nil
35
+ return res_code if res_code.present?
36
+ raise NotFound.new("host: #{@host}, method: #{@method}, path: #{@path}, code: #{@code}")
37
+ end
38
+
39
+ res_content_type = res_code.next_steps.find { |content_type| content_type.step_key == @content_type.to_s }
40
+
41
+ if @combination == nil
42
+ return res_content_type if res_content_type.present?
43
+ raise NotFound.new("host: #{@host}, method: #{@method}, path: #{@path}, code: #{@code}, content-type: #{@content_type}")
44
+ end
45
+
46
+ res_json_schema = res_content_type.next_steps[0]
47
+ res_combination = res_json_schema.next_steps.find do |combination|
48
+ combination.step_key == @combination.to_s
49
+ end
50
+
51
+ if @combination_next == nil
52
+ return res_combination if res_combination
53
+ raise NotFound.new("host: #{@host}, method: #{@method}, path: #{@path}, code: #{@code}, content-type: #{@content_type}, combination: #{@combination}")
54
+ end
55
+
56
+ res_combination_next = res_combination.next_steps.find do |combination_next|
57
+ combination_next.step_key == @combination_next.to_s
58
+ end
59
+
60
+ return res_combination_next if res_combination_next
61
+ raise NotFound.new("host: #{@host}, method: #{@method}, path: #{@path}, code: #{@code}, content-type: #{@content_type}, combination: #{@combination}, combination_next: #{@combination_next}")
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,62 @@
1
+ require 'fitting/report/actions'
2
+
3
+ module Fitting
4
+ class Prefix
5
+ KEYS = {
6
+ 'openapi2' => :openapi2_json_path,
7
+ 'openapi3' => :openapi3_yaml_path,
8
+ 'drafter' => :drafter_yaml_path,
9
+ 'crafter' => :crafter_yaml_path,
10
+ 'tomogram' => :tomogram_json_path
11
+ }.freeze
12
+
13
+ attr_reader :name, :actions
14
+
15
+ def initialize(name, schema_paths, type, skip = false)
16
+ @prefix = name
17
+ @cover = false
18
+
19
+ @actions = Fitting::Report::Actions.new([])
20
+ raise Skip if skip
21
+
22
+ schema_paths.each do |path|
23
+ tomogram = Tomograph::Tomogram.new(prefix: name, KEYS[type] => path)
24
+
25
+ @actions.push(Fitting::Report::Actions.new(tomogram))
26
+ end
27
+ end
28
+
29
+ class Skip < RuntimeError; end
30
+
31
+ class NotFound < RuntimeError
32
+ attr_reader :log
33
+
34
+ def initialize(msg, log)
35
+ @log = log
36
+ super(msg)
37
+ end
38
+ end
39
+
40
+ def self.find(host:, log:)
41
+ yaml = YAML.safe_load(File.read('.fitting.yml'))
42
+
43
+ prefixes = yaml['hosts'].find{|h| h.first.first == host.to_s}.first.last['prefixes']
44
+ raise NotFound.new("host: #{log.host}, path: #{log.path}", log) unless prefixes
45
+
46
+ prefix = prefixes.find do |prefix|
47
+ prefix['name'].nil? || log.path[0..prefix['name'].size - 1] == prefix['name']
48
+ end
49
+ raise NotFound.new("host: #{log.host}, path: #{log.path}", log) unless prefix
50
+
51
+ new(prefix['name'], prefix['schema_paths'], prefix['type'], prefix['skip'])
52
+ end
53
+
54
+ def cover!
55
+ @cover = true
56
+ end
57
+
58
+ def cover?
59
+ @cover
60
+ end
61
+ end
62
+ end
@@ -4,7 +4,6 @@ module Fitting
4
4
  class MyRailtie < Rails::Railtie
5
5
  rake_tasks do
6
6
  load 'tasks/fitting.rake'
7
- load 'tasks/fitting_outgoing.rake'
8
7
  end
9
8
  end
10
9
  end
@@ -5,15 +5,16 @@ module Fitting
5
5
  class Records
6
6
  class Spherical
7
7
  class Request
8
- attr_reader :method, :path, :body, :response, :title, :group
8
+ attr_reader :method, :path, :body, :response, :title, :group, :host
9
9
 
10
- def initialize(method:, path:, body:, response:, title:, group:)
10
+ def initialize(method:, path:, body:, response:, title:, group:, host:)
11
11
  @method = method
12
12
  @path = path
13
13
  @body = body
14
14
  @response = response
15
15
  @title = title
16
16
  @group = group
17
+ @host = host
17
18
  end
18
19
 
19
20
  def to_hash
@@ -23,7 +24,8 @@ module Fitting
23
24
  body: body,
24
25
  response: response.to_hash,
25
26
  title: title,
26
- group: group
27
+ group: group,
28
+ host: host
27
29
  }
28
30
  end
29
31
 
@@ -39,7 +41,8 @@ module Fitting
39
41
  body: hash['body'],
40
42
  response: Fitting::Records::Spherical::Response.load(hash['response']),
41
43
  title: hash['title'],
42
- group: hash['group']
44
+ group: hash['group'],
45
+ host: hash['host']
43
46
  )
44
47
  end
45
48
  end
@@ -6,32 +6,38 @@ module Fitting
6
6
  class Response
7
7
  attr_reader :status, :body
8
8
 
9
- def initialize(status:, body:)
9
+ def initialize(status:, body:, content_type:)
10
10
  @status = status
11
11
  @body = body
12
+ @content_type = content_type
12
13
  end
13
14
 
14
15
  def to_hash
15
- {
16
- status: status,
17
- body: JSON.parse(body)
18
- }
19
- rescue JSON::ParserError
20
- {
21
- status: status,
22
- body: {}
23
- }
16
+ begin
17
+ parse_body = JSON.parse(body)
18
+ rescue JSON::ParserError
19
+ parse_body = {}
20
+ end
21
+
22
+ if @content_type == nil || @content_type == ''
23
+ {
24
+ status: status,
25
+ content_type: 'application/json',
26
+ body: parse_body
27
+ }
28
+ else
29
+ ct = @content_type.split("; ")
30
+ {
31
+ status: status,
32
+ content_type: ct.first,
33
+ body: parse_body
34
+ }
35
+ end
24
36
  end
25
37
 
26
38
  def to_json(*_args)
27
39
  JSON.dump(to_hash)
28
40
  end
29
-
30
- class << self
31
- def load(hash)
32
- new(status: hash['status'], body: hash['body'])
33
- end
34
- end
35
41
  end
36
42
  end
37
43
  end