webspicy 0.20.0 → 0.20.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sandr +14 -0
  3. data/bin/search +2 -0
  4. data/bin/webspicy +3 -4
  5. data/lib/finitio/webspicy/shared.fio +10 -0
  6. data/lib/webspicy.rb +22 -53
  7. data/lib/webspicy/configuration.rb +17 -0
  8. data/lib/webspicy/configuration/scope.rb +3 -2
  9. data/lib/webspicy/configuration/single_url.rb +35 -25
  10. data/lib/webspicy/configuration/single_yml_file.rb +7 -2
  11. data/lib/webspicy/specification.rb +0 -55
  12. data/lib/webspicy/specification/oldies/bridge.rb +4 -1
  13. data/lib/webspicy/specification/post/missing_condition_impl.rb +2 -2
  14. data/lib/webspicy/specification/post/unexpected_condition_impl.rb +2 -2
  15. data/lib/webspicy/specification/service.rb +4 -5
  16. data/lib/webspicy/specification/test_case.rb +3 -49
  17. data/lib/webspicy/support/colorize.rb +7 -1
  18. data/lib/webspicy/tester.rb +21 -20
  19. data/lib/webspicy/tester/assertions.rb +2 -2
  20. data/lib/webspicy/tester/reporter.rb +5 -0
  21. data/lib/webspicy/tester/reporter/documentation.rb +26 -8
  22. data/lib/webspicy/tester/reporter/error_count.rb +11 -7
  23. data/lib/webspicy/tester/reporter/file_progress.rb +2 -2
  24. data/lib/webspicy/tester/reporter/file_summary.rb +2 -2
  25. data/lib/webspicy/tester/reporter/progress.rb +4 -4
  26. data/lib/webspicy/tester/reporter/summary.rb +8 -7
  27. data/lib/webspicy/tester/result.rb +2 -2
  28. data/lib/webspicy/tester/result/errcondition_met.rb +1 -3
  29. data/lib/webspicy/tester/result/error_schema_met.rb +1 -0
  30. data/lib/webspicy/tester/result/output_schema_met.rb +1 -0
  31. data/lib/webspicy/tester/result/postcondition_met.rb +1 -3
  32. data/lib/webspicy/version.rb +1 -1
  33. data/lib/webspicy/web.rb +46 -0
  34. data/lib/webspicy/{formaldoc.fio → web/formaldoc.fio} +5 -13
  35. data/lib/webspicy/web/invocation.rb +7 -3
  36. data/lib/webspicy/web/specification.rb +68 -0
  37. data/lib/webspicy/web/specification/file_upload.rb +39 -0
  38. data/lib/webspicy/web/specification/service.rb +13 -0
  39. data/lib/webspicy/web/specification/test_case.rb +58 -0
  40. data/spec/unit/configuration/scope/test_expand_example.rb +11 -5
  41. data/spec/unit/specification/pre/test_global_request_headers.rb +3 -3
  42. data/spec/unit/specification/service/test_dress_params.rb +2 -2
  43. data/spec/unit/test_configuration.rb +1 -0
  44. data/spec/unit/web/specification/test_instantiate_url.rb +36 -0
  45. data/spec/unit/web/specification/test_url_placeholders.rb +23 -0
  46. data/tasks/test.rake +2 -1
  47. metadata +24 -16
  48. data/lib/webspicy/specification/file_upload.rb +0 -37
  49. data/spec/unit/specification/test_instantiate_url.rb +0 -34
  50. data/spec/unit/specification/test_url_placeholders.rb +0 -21
@@ -96,13 +96,13 @@ module Webspicy
96
96
 
97
97
  def check_postconditions!
98
98
  service.postconditions.each do |c|
99
- check_one! Result::PostconditionMet.new(self, c.bind(tester))
99
+ check_one! Result::PostconditionMet.new(self, tester.bind_condition(c))
100
100
  end
101
101
  end
102
102
 
103
103
  def check_errconditions!
104
104
  service.errconditions.each do |c|
105
- check_one! Result::ErrconditionMet.new(self, c.bind(tester))
105
+ check_one! Result::ErrconditionMet.new(self, tester.bind_condition(c))
106
106
  end
107
107
  end
108
108
 
@@ -18,9 +18,7 @@ module Webspicy
18
18
  end
19
19
 
20
20
  def call
21
- if err = post.check!
22
- _! err
23
- end
21
+ post.check!
24
22
  end
25
23
 
26
24
  end # class ErrconditionMet
@@ -12,6 +12,7 @@ module Webspicy
12
12
  end
13
13
 
14
14
  def call
15
+ return unless invocation.is_structured_output?
15
16
  output = invocation.loaded_body
16
17
  service.error_schema.dress(output)
17
18
  rescue Finitio::TypeError => ex
@@ -12,6 +12,7 @@ module Webspicy
12
12
  end
13
13
 
14
14
  def call
15
+ return unless invocation.is_structured_output?
15
16
  output = invocation.loaded_body
16
17
  service.output_schema.dress(output)
17
18
  rescue Finitio::TypeError => ex
@@ -18,9 +18,7 @@ module Webspicy
18
18
  end
19
19
 
20
20
  def call
21
- if err = post.check!
22
- _! err
23
- end
21
+ post.check!
24
22
  end
25
23
 
26
24
  end # class PostconditionMet
@@ -2,7 +2,7 @@ module Webspicy
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 20
5
- TINY = 0
5
+ TINY = 5
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
data/lib/webspicy/web.rb CHANGED
@@ -1,3 +1,49 @@
1
+ module Webspicy
2
+ module Web
3
+
4
+ require_relative 'web/specification'
5
+
6
+ FORMALDOC = Finitio.system(Path.dir/("web/formaldoc.fio"))
7
+
8
+ def specification(raw, file = nil, scope = Webspicy.default_scope)
9
+ raw = YAML.load(raw) if raw.is_a?(String)
10
+ Webspicy.with_scope(scope) do
11
+ r = FORMALDOC["Specification"].dress(raw)
12
+ r.config = scope.config
13
+ r.located_at!(file) if file
14
+ r
15
+ end
16
+ rescue Finitio::Error => ex
17
+ handle_finitio_error(ex)
18
+ end
19
+ module_function :specification
20
+
21
+ def service(raw, scope = Webspicy.default_scope)
22
+ Webspicy.with_scope(scope) do
23
+ FORMALDOC["Service"].dress(raw)
24
+ end
25
+ rescue Finitio::Error => ex
26
+ handle_finitio_error(ex)
27
+ end
28
+ module_function :service
29
+
30
+ def test_case(raw, scope = Webspicy.default_scope)
31
+ Webspicy.with_scope(scope) do
32
+ FORMALDOC["TestCase"].dress(raw)
33
+ end
34
+ rescue Finitio::Error => ex
35
+ handle_finitio_error(ex)
36
+ end
37
+ module_function :test_case
38
+
39
+ def handle_finitio_error(ex)
40
+ puts ex.root_cause.message
41
+ raise ex
42
+ end
43
+ module_function :handle_finitio_error
44
+
45
+ end # module Web
46
+ end # module Webspicy
1
47
  require_relative 'web/client'
2
48
  require_relative 'web/invocation'
3
49
  require_relative 'web/mocker'
@@ -1,23 +1,17 @@
1
1
  @import finitio/data
2
+ @import webspicy/shared
2
3
 
3
4
  Method =
4
5
  String( s | s =~ /^(GET|POST|POST_FORM|PUT|DELETE|PATCH|PUT|OPTIONS)$/ )
5
6
 
6
- Tag = String( s | s.length > 0 )
7
-
8
- Schema =
9
- .Finitio::System <fio> String
10
- \( s | ::Webspicy.schema(s) )
11
- \( s | raise "Unsupported" )
12
-
13
7
  FileUpload =
14
- .Webspicy::FileUpload <info> {
8
+ .Webspicy::Web::Specification::FileUpload <info> {
15
9
  path : String
16
10
  content_type : String
17
11
  param_name :? String
18
12
  }
19
13
 
20
- Specification = .Webspicy::Specification
14
+ Specification = .Webspicy::Web::Specification
21
15
  <info> {
22
16
  name: String
23
17
  url: String
@@ -41,7 +35,7 @@ Specification = .Webspicy::Specification
41
35
  }
42
36
 
43
37
  Service =
44
- .Webspicy::Specification::Service <info> {
38
+ .Webspicy::Web::Specification::Service <info> {
45
39
  method : Method
46
40
  description : String
47
41
  preconditions :? [String]|String
@@ -57,7 +51,7 @@ Service =
57
51
  }
58
52
 
59
53
  TestCase =
60
- .Webspicy::Specification::TestCase <info> {
54
+ .Webspicy::Web::Specification::TestCase <info> {
61
55
  description :? String
62
56
  dress_params :? Boolean
63
57
  params :? Params
@@ -77,8 +71,6 @@ TestCase =
77
71
  tags :? [Tag]
78
72
  }
79
73
 
80
- Params = .Array|.Hash
81
-
82
74
  StatusRange = .Webspicy::Support::StatusRange
83
75
  <int> Integer
84
76
  <str> String(s | s =~ /^\dxx$/ )
@@ -36,11 +36,14 @@ module Webspicy
36
36
  response.body.to_s
37
37
  end
38
38
 
39
- def loaded_output
39
+ def is_structured_output?
40
40
  ct = response.content_type || test_case.expected_content_type
41
41
  ct = ct.mime_type if ct.respond_to?(:mime_type)
42
- case ct
43
- when %r{json}
42
+ ct =~ /json/
43
+ end
44
+
45
+ def loaded_output
46
+ if is_structured_output?
44
47
  raise "Body empty while expected" if raw_output.empty?
45
48
  @loaded_output ||= ::JSON.parse(response.body)
46
49
  else
@@ -50,6 +53,7 @@ module Webspicy
50
53
  alias :loaded_body :loaded_output
51
54
 
52
55
  def output
56
+ return loaded_output unless is_structured_output?
53
57
  schema = is_expected_success? ? service.output_schema : service.error_schema
54
58
  begin
55
59
  schema.dress(loaded_output)
@@ -0,0 +1,68 @@
1
+ module Webspicy
2
+ module Web
3
+ class Specification < Webspicy::Specification
4
+
5
+ class << self
6
+ def info(raw)
7
+ new(raw)
8
+ end
9
+
10
+ def singleservice(raw)
11
+ converted = {
12
+ name: raw[:name] || "Unamed specification",
13
+ url: raw[:url],
14
+ services: [
15
+ Webspicy::Web.service(raw.reject{|k| k==:url or k==:name }, Webspicy.current_scope)
16
+ ]
17
+ }
18
+ info(converted)
19
+ end
20
+ end
21
+
22
+ def url
23
+ @raw[:url]
24
+ end
25
+
26
+ def url_pattern
27
+ @url_pattern ||= Mustermann.new(url, type: :template)
28
+ end
29
+
30
+ def url_placeholders
31
+ url.scan(/\{([a-zA-Z]+(\.[a-zA-Z]+)*)\}/).map{|x| x.first }
32
+ end
33
+
34
+ def instantiate_url(params)
35
+ url, rest = self.url, params.dup
36
+ url_placeholders.each do |placeholder|
37
+ value, rest = extract_placeholder_value(rest, placeholder)
38
+ url = url.gsub("{#{placeholder}}", value.to_s)
39
+ end
40
+ [ url, rest ]
41
+ end
42
+
43
+ def to_singleservice
44
+ raise NotImplementedError
45
+ end
46
+
47
+ private
48
+
49
+ def extract_placeholder_value(params, placeholder, split = nil)
50
+ return extract_placeholder_value(params, placeholder, placeholder.split(".")) unless split
51
+
52
+ key = [ split.first, split.first.to_sym ].find{|k| params.has_key?(k) }
53
+ raise "Missing URL parameter `#{placeholder}`" unless key
54
+
55
+ if split.size == 1
56
+ [ params[key], params.dup.delete_if{|k| k == key } ]
57
+ else
58
+ value, rest = extract_placeholder_value(params[key], placeholder, split[1..-1])
59
+ [ value, params.merge(key => rest) ]
60
+ end
61
+ end
62
+
63
+ end # class Specification
64
+ end # module Web
65
+ end # module Webspicy
66
+ require_relative 'specification/service'
67
+ require_relative 'specification/test_case'
68
+ require_relative 'specification/file_upload'
@@ -0,0 +1,39 @@
1
+ module Webspicy
2
+ module Web
3
+ class Specification
4
+ class FileUpload
5
+
6
+ def initialize(raw)
7
+ @path = raw[:path]
8
+ @content_type = raw[:content_type]
9
+ @param_name = raw[:param_name] || "file"
10
+ end
11
+
12
+ attr_reader :path, :content_type, :param_name
13
+
14
+ def self.info(raw)
15
+ new(raw)
16
+ end
17
+
18
+ def locate(specification)
19
+ FileUpload.new({
20
+ path: specification.locate(path),
21
+ content_type: content_type
22
+ })
23
+ end
24
+
25
+ def to_info
26
+ { path: path.to_s,
27
+ content_type: content_type,
28
+ param_name: param_name }
29
+ end
30
+
31
+ def to_s
32
+ "FileUpload(#{to_info})"
33
+ end
34
+ alias :inspect :to_s
35
+
36
+ end # class FileUpload
37
+ end # class Specification
38
+ end # module Web
39
+ end # module Webspicy
@@ -0,0 +1,13 @@
1
+ module Webspicy
2
+ module Web
3
+ class Specification
4
+ class Service < Webspicy::Specification::Service
5
+
6
+ def method
7
+ @raw[:method]
8
+ end
9
+
10
+ end # class Service
11
+ end # class Specification
12
+ end # module Web
13
+ end # module Webspicy
@@ -0,0 +1,58 @@
1
+ module Webspicy
2
+ module Web
3
+ class Specification
4
+ class TestCase < Webspicy::Specification::TestCase
5
+
6
+ def headers
7
+ @raw[:headers] ||= {}
8
+ end
9
+
10
+ def dress_params
11
+ @raw.fetch(:dress_params){ true }
12
+ end
13
+ alias :dress_params? :dress_params
14
+
15
+ def params
16
+ @raw[:params] || {}
17
+ end
18
+
19
+ def body
20
+ @raw[:body]
21
+ end
22
+
23
+ def file_upload
24
+ @raw[:file_upload]
25
+ end
26
+
27
+ def located_file_upload
28
+ file_upload ? file_upload.locate(specification) : nil
29
+ end
30
+
31
+ def expected_content_type
32
+ expected[:content_type]
33
+ end
34
+
35
+ def expected_status
36
+ expected[:status]
37
+ end
38
+
39
+ def is_expected_status?(status)
40
+ expected_status === status
41
+ end
42
+
43
+ def has_expected_status?
44
+ not expected[:status].nil?
45
+ end
46
+
47
+ def expected_headers
48
+ expected[:headers] || {}
49
+ end
50
+
51
+ def has_expected_headers?
52
+ !expected_headers.empty?
53
+ end
54
+
55
+ end # class TestCase
56
+ end # class Specification
57
+ end # module Web
58
+ end # module Webspicy
@@ -3,11 +3,17 @@ module Webspicy
3
3
  class Configuration
4
4
  describe Scope, "expand_example" do
5
5
 
6
- subject{ Scope.new({}).send(:expand_example, service, example) }
6
+ let(:config){
7
+ Configuration.new(Path.dir)
8
+ }
9
+
10
+ subject{
11
+ Scope.new(config).send(:expand_example, service, example)
12
+ }
7
13
 
8
14
  context 'when the service has no default example' do
9
15
  let(:service) {
10
- Webspicy.service({
16
+ Webspicy::Web.service({
11
17
  method: "GET",
12
18
  description: "Test service",
13
19
  preconditions: "Foo",
@@ -18,7 +24,7 @@ module Webspicy
18
24
  }
19
25
 
20
26
  let(:example) {
21
- Webspicy.test_case({
27
+ Webspicy::Web.test_case({
22
28
  description: "Hello world"
23
29
  })
24
30
  }
@@ -30,7 +36,7 @@ module Webspicy
30
36
 
31
37
  context 'when the service has a default example' do
32
38
  let(:service) {
33
- Webspicy.service({
39
+ Webspicy::Web.service({
34
40
  method: "GET",
35
41
  description: "Test service",
36
42
  preconditions: "Foo",
@@ -44,7 +50,7 @@ module Webspicy
44
50
  }
45
51
 
46
52
  let(:example) {
47
- Webspicy.test_case({
53
+ Webspicy::Web.test_case({
48
54
  description: "Hello world",
49
55
  expected: { content_type: "application/json" }
50
56
  })
@@ -15,13 +15,13 @@ module Webspicy
15
15
 
16
16
  describe "instrument" do
17
17
  it 'injects the headers' do
18
- tc = TestCase.new({})
18
+ tc = Web::Specification::TestCase.new({})
19
19
  instrument(tc)
20
20
  expect(tc.headers['Accept']).to eql("application/json")
21
21
  end
22
22
 
23
23
  it 'keeps original headers unchanged' do
24
- tc = TestCase.new({
24
+ tc = Web::Specification::TestCase.new({
25
25
  headers: {
26
26
  'Content-Type' => 'text/plain'
27
27
  }
@@ -32,7 +32,7 @@ module Webspicy
32
32
  end
33
33
 
34
34
  it 'has low precedence' do
35
- tc = TestCase.new({
35
+ tc = Web::Specification::TestCase.new({
36
36
  headers: {
37
37
  'Accept' => 'text/plain'
38
38
  }