webspicy 0.20.2 → 0.20.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/bin/webspicy +3 -4
  3. data/lib/finitio/webspicy/shared.fio +10 -0
  4. data/lib/webspicy.rb +22 -53
  5. data/lib/webspicy/configuration.rb +17 -0
  6. data/lib/webspicy/configuration/scope.rb +3 -2
  7. data/lib/webspicy/configuration/single_url.rb +35 -25
  8. data/lib/webspicy/configuration/single_yml_file.rb +7 -2
  9. data/lib/webspicy/specification.rb +0 -55
  10. data/lib/webspicy/specification/post/missing_condition_impl.rb +2 -2
  11. data/lib/webspicy/specification/post/unexpected_condition_impl.rb +2 -2
  12. data/lib/webspicy/specification/service.rb +1 -5
  13. data/lib/webspicy/specification/test_case.rb +0 -49
  14. data/lib/webspicy/support/colorize.rb +7 -1
  15. data/lib/webspicy/tester.rb +15 -19
  16. data/lib/webspicy/tester/fakesmtp.rb +1 -1
  17. data/lib/webspicy/tester/fakesmtp/email.rb +13 -0
  18. data/lib/webspicy/tester/reporter.rb +5 -0
  19. data/lib/webspicy/tester/reporter/documentation.rb +30 -8
  20. data/lib/webspicy/tester/reporter/error_count.rb +11 -7
  21. data/lib/webspicy/tester/reporter/file_progress.rb +2 -2
  22. data/lib/webspicy/tester/reporter/file_summary.rb +2 -2
  23. data/lib/webspicy/tester/reporter/progress.rb +4 -4
  24. data/lib/webspicy/tester/reporter/summary.rb +8 -7
  25. data/lib/webspicy/tester/result/errcondition_met.rb +1 -3
  26. data/lib/webspicy/tester/result/postcondition_met.rb +1 -3
  27. data/lib/webspicy/version.rb +1 -1
  28. data/lib/webspicy/web.rb +46 -0
  29. data/lib/webspicy/{formaldoc.fio → web/formaldoc.fio} +5 -13
  30. data/lib/webspicy/web/specification.rb +68 -0
  31. data/lib/webspicy/web/specification/file_upload.rb +39 -0
  32. data/lib/webspicy/web/specification/service.rb +13 -0
  33. data/lib/webspicy/web/specification/test_case.rb +58 -0
  34. data/spec/unit/configuration/scope/test_expand_example.rb +11 -5
  35. data/spec/unit/specification/pre/test_global_request_headers.rb +3 -3
  36. data/spec/unit/specification/service/test_dress_params.rb +2 -2
  37. data/spec/unit/test_configuration.rb +1 -0
  38. data/spec/unit/tester/fakesmtp/test_email.rb +93 -0
  39. data/spec/unit/web/specification/test_instantiate_url.rb +36 -0
  40. data/spec/unit/web/specification/test_url_placeholders.rb +23 -0
  41. data/tasks/test.rake +2 -1
  42. metadata +15 -10
  43. data/lib/webspicy/specification/file_upload.rb +0 -37
  44. data/spec/unit/specification/test_instantiate_url.rb +0 -34
  45. data/spec/unit/specification/test_url_placeholders.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0039cf2e5ebbb990cc29c6ed76e4eabf941feeb031f4761d30e120f32e31a41f'
4
- data.tar.gz: c743e9f1650e7d9a09bef50d54e2e35e261761b085456d4bd8b4f7a6060f5304
3
+ metadata.gz: 890e7c6106835b720e92b9282f0425006c4a5e0749f06dde5111ed47a08d5ab0
4
+ data.tar.gz: aa48c031524976b874a76a366994cc91245fc2ed68a9e63412960ff21447d2f9
5
5
  SHA512:
6
- metadata.gz: d9a039f3919a201378847ab7db291dcd72a345d594d11900e941f65c6c9e211825851778c4dea9969c2dc1ed88d80ae177af03f977e9437eba15471acd111127
7
- data.tar.gz: 61347ee21583f15bb966e279221604fe6b7f89c2a2833bc7dfa92d062ff238b2f26949b89674c97eb651d09d435610d5bf5689bf8596b4ed75a6ea4e4a1a981c
6
+ metadata.gz: 4e881fd94d9bcc3aae7a90f558a95c85affcc12655e56bc816c64a4ede8519a24bacc7ef9a7edb03195aeae0c61d62e3575a7b0ec99b26773138b3b5dcd0ead0
7
+ data.tar.gz: 72f0902d4121bea8bbe994038191dc7f688547dc90aad9ffc7ed94ff12d7dc925daba4aaafcf3e1736d845406c38411774e500c750a34addbdf0dbf42d2bf38f
data/bin/webspicy CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  #/
3
3
  #/ Document & test web services as black-box operations.
4
- #/ (c) Enspirit SRL. Distributed under MIT licence.
4
+ #/ Webspicy vVERSION, (c) Enspirit SRL. Distributed under MIT licence.
5
5
  #/
6
6
  #/ Usage: webspicy [options] URL # run default test againt url
7
7
  #/ Usage: webspicy [options] path/to/config.rb # run whole test suite
@@ -28,7 +28,7 @@ require 'optparse'
28
28
 
29
29
  def showhelp
30
30
  file = __FILE__
31
- exec "grep ^#/<'#{file}'|cut -c4-"
31
+ exec "grep ^#/<'#{file}'|cut -c4-|sed s/VERSION/#{Webspicy::VERSION}/g"
32
32
  end
33
33
 
34
34
  ARGV.options do |opts|
@@ -55,5 +55,4 @@ if ARGV.size != 1
55
55
  end
56
56
 
57
57
  config = Webspicy::Configuration.dress(ARGV[0])
58
- res = Webspicy::Tester.new(config).call
59
- abort("#{res} errors occured") unless res == 0
58
+ Webspicy::Tester.new(config).call!
@@ -0,0 +1,10 @@
1
+ @import finitio/data
2
+
3
+ Tag = String( s | s.length > 0 )
4
+
5
+ Schema =
6
+ .Finitio::System <fio> String
7
+ \( s | ::Webspicy.schema(s) )
8
+ \( s | raise "Unsupported" )
9
+
10
+ Params = .Array|.Hash
data/lib/webspicy.rb CHANGED
@@ -7,7 +7,7 @@ require 'ostruct'
7
7
  require 'yaml'
8
8
  require 'rack/test'
9
9
  require 'mustermann'
10
- require 'colorized_string'
10
+ require 'paint'
11
11
  require 'securerandom'
12
12
  require 'forwardable'
13
13
  module Webspicy
@@ -21,22 +21,10 @@ module Webspicy
21
21
  require 'webspicy/specification'
22
22
  require 'webspicy/configuration'
23
23
  require 'webspicy/tester'
24
- require 'webspicy/web'
25
24
 
26
25
  class Error < StandardError; end
27
26
  class TimeoutError < Error; end
28
27
 
29
- ###
30
- ### Backward compatibility
31
- ###
32
- Client = Tester::Client
33
- HttpClient = Web::HttpClient
34
- RackTestClient = Web::RackTestClient
35
- Resource = Specification
36
- FileUpload = Specification::FileUpload
37
- Scope = Configuration::Scope
38
- Checker = Tester::FileChecker
39
-
40
28
  ###
41
29
  ### About folders
42
30
  ###
@@ -49,10 +37,11 @@ module Webspicy
49
37
  ### About formal doc and specifications defined there
50
38
  ###
51
39
  Finitio.stdlib_path(Path.dir/"finitio")
40
+
52
41
  DEFAULT_SYSTEM = Finitio.system(<<~FIO)
53
42
  @import webspicy/scalars
54
43
  FIO
55
- FORMALDOC = Finitio.system(Path.dir/("webspicy/formaldoc.fio"))
44
+
56
45
 
57
46
  ###
58
47
  ### Exceptions that we let pass during testing
@@ -66,45 +55,6 @@ module Webspicy
66
55
  end
67
56
  module_function :default_scope
68
57
 
69
- def specification(raw, file = nil, scope = default_scope)
70
- raw = YAML.load(raw) if raw.is_a?(String)
71
- with_scope(scope) do
72
- r = FORMALDOC["Specification"].dress(raw)
73
- r.config = scope.config
74
- r.located_at!(file) if file
75
- r
76
- end
77
- rescue Finitio::Error => ex
78
- handle_finitio_error(ex, scope)
79
- end
80
- module_function :specification
81
-
82
- def service(raw, scope = default_scope)
83
- with_scope(scope) do
84
- FORMALDOC["Service"].dress(raw)
85
- end
86
- rescue Finitio::Error => ex
87
- handle_finitio_error(ex)
88
- end
89
- module_function :service
90
-
91
- def test_case(raw, scope = default_scope)
92
- with_scope(scope) do
93
- FORMALDOC["TestCase"].dress(raw)
94
- end
95
- rescue Finitio::Error => ex
96
- handle_finitio_error(ex)
97
- end
98
- module_function :test_case
99
-
100
- def handle_finitio_error(ex, scope)
101
- # msg = "#{ex.message}:\n #{ex.root_cause.message}"
102
- # msg = Support::Colorize.colorize_error(msg, scope.config)
103
- # fatal(msg)
104
- raise
105
- end
106
- module_function :handle_finitio_error
107
-
108
58
  #
109
59
  # Yields the block after having installed `scope` globally.
110
60
  #
@@ -185,4 +135,23 @@ module Webspicy
185
135
  end
186
136
  module_function :fatal
187
137
 
138
+ require 'webspicy/web'
139
+
140
+ ###
141
+ ### Backward compatibility
142
+ ###
143
+ Client = Tester::Client
144
+ HttpClient = Web::HttpClient
145
+ RackTestClient = Web::RackTestClient
146
+ Resource = Specification
147
+ FileUpload = Web::Specification::FileUpload
148
+ Scope = Configuration::Scope
149
+ Checker = Tester::FileChecker
150
+
151
+ [:specification, :service, :test_case].each do |meth|
152
+ define_method(meth) do |*args, &bl|
153
+ Webspicy::Web.send(meth, *args, &bl)
154
+ end
155
+ module_function(meth)
156
+ end
188
157
  end
@@ -33,12 +33,16 @@ module Webspicy
33
33
  @service_filter = default_service_filter
34
34
  @test_case_filter = default_test_case_filter
35
35
  @colors = {
36
+ :section => :magenta,
36
37
  :highlight => :cyan,
37
38
  :error => :red,
38
39
  :success => :green
39
40
  }
41
+ @colorize = true
42
+ @factory = Webspicy::Web
40
43
  @scope_factory = ->(config){ Scope.new(config) }
41
44
  @client = Web::HttpClient
45
+ @reporter = default_reporter
42
46
  Path.require_tree(@folder/'support') if (@folder/'support').exists?
43
47
  @world = Support::World.new(folder/'world', self)
44
48
  yield(self) if block_given?
@@ -47,6 +51,8 @@ module Webspicy
47
51
  protected :folder=
48
52
 
49
53
  attr_accessor :colors
54
+ attr_accessor :colorize
55
+
50
56
  attr_reader :world
51
57
 
52
58
  def self.dress(arg, &bl)
@@ -104,6 +110,7 @@ module Webspicy
104
110
  end
105
111
  end
106
112
 
113
+ attr_accessor :factory
107
114
  attr_accessor :scope_factory
108
115
 
109
116
  def factor_scope
@@ -434,6 +441,16 @@ module Webspicy
434
441
  end
435
442
  private :default_rspec_options
436
443
 
444
+ # Returns the default reporter to use.
445
+ def default_reporter
446
+ @reporter = Tester::Reporter::Composite.new
447
+ @reporter << Tester::Reporter::Documentation.new
448
+ @reporter << Tester::Reporter::Exceptions.new
449
+ @reporter << Tester::Reporter::Summary.new
450
+ @reporter << Tester::Reporter::ErrorCount.new
451
+ end
452
+ attr_accessor :reporter
453
+
437
454
  # Returns the Data system to use for parsing schemas
438
455
  #
439
456
  # The data system associated with a configuration is build when the
@@ -23,6 +23,7 @@ module Webspicy
23
23
  folder = config.folder
24
24
  world = config.folder/"world"
25
25
  fs = folder.glob("**/*.yml").reject{|f| f.to_s.start_with?(world.to_s) }
26
+ fs = fs.sort
26
27
  fs = fs.select(&to_filter_proc(config.file_filter)) if apply_filter
27
28
  fs.each do |file|
28
29
  yield file, folder
@@ -34,7 +35,7 @@ module Webspicy
34
35
  def each_specification(apply_filter = true, &bl)
35
36
  return enum_for(:each_specification, apply_filter) unless block_given?
36
37
  each_specification_file(apply_filter) do |file, folder|
37
- yield Webspicy.specification(file.load, file, self)
38
+ yield config.factory.specification(file.load, file, self)
38
39
  end
39
40
  end
40
41
 
@@ -137,7 +138,7 @@ module Webspicy
137
138
  return example unless service.default_example
138
139
  h1 = service.default_example.to_info
139
140
  h2 = example.to_info
140
- ex = Specification::TestCase.new(merge_maps(h1, h2))
141
+ ex = config.factory.test_case(merge_maps(h1, h2), self)
141
142
  ex.bind(service, example.counterexample?)
142
143
  end
143
144
 
@@ -10,37 +10,47 @@ module Webspicy
10
10
  end
11
11
  attr_reader :url
12
12
 
13
- def each_specification(&bl)
13
+ def each_specification_file(*args, &bl)
14
+ return enum_for(:each_specification_file) unless block_given?
15
+ yield Path.tempfile(["specification",".yml"]).tap{|f|
16
+ f.write(specification_src)
17
+ }
18
+ end
19
+
20
+ def each_specification(*args, &bl)
14
21
  return enum_for(:each_specification) unless block_given?
15
- spec = <<~YML
22
+ yield config.factory.specification(specification_src, nil, self)
23
+ end
24
+
25
+ def specification_src
26
+ <<~YML.tap{|s| Webspicy.debug(s) }
16
27
  ---
17
- name: |-
18
- Default specification
28
+ description: |-
29
+ Getting #{url}
30
+
19
31
  url: |-
20
32
  #{url}
21
33
 
22
- services:
23
- - method: |-
24
- GET
25
- description: |-
26
- Getting #{url}
27
-
28
- input_schema: |-
29
- Any
30
- output_schema: |-
31
- Any
32
- error_schema: |-
33
- Any
34
-
35
- examples:
36
- - description: |-
37
- it returns a 200
38
- params: {}
39
- expected:
40
- status: 200
34
+ method: |-
35
+ GET
36
+
37
+ input_schema: |-
38
+ Any
39
+
40
+ output_schema: |-
41
+ Any
42
+
43
+ error_schema: |-
44
+ Any
45
+
46
+ examples:
47
+
48
+ - description: |-
49
+ it returns a 200
50
+ params: {}
51
+ expected:
52
+ status: 200
41
53
  YML
42
- Webspicy.debug(spec)
43
- yield Webspicy.specification(spec, nil, self)
44
54
  end
45
55
 
46
56
  end # class SingleUrlScope
@@ -10,9 +10,14 @@ module Webspicy
10
10
  end
11
11
  attr_reader :file
12
12
 
13
- def each_specification(&bl)
13
+ def each_specification_file(*args, &bl)
14
+ return enum_for(:each_specification_file) unless block_given?
15
+ yield(file)
16
+ end
17
+
18
+ def each_specification(*args, &bl)
14
19
  return enum_for(:each_specification) unless block_given?
15
- yield Webspicy.specification(file.read, nil, self)
20
+ yield config.factory.specification(file.read, nil, self)
16
21
  end
17
22
 
18
23
  end # class SingleYmlFileScope
@@ -10,21 +10,6 @@ module Webspicy
10
10
  attr_accessor :config
11
11
  attr_reader :location
12
12
 
13
- def self.info(raw)
14
- new(raw)
15
- end
16
-
17
- def self.singleservice(raw)
18
- converted = {
19
- name: raw[:name] || "Unamed specification",
20
- url: raw[:url],
21
- services: [
22
- Webspicy.service(raw.reject{|k| k==:url or k==:name }, Webspicy.current_scope)
23
- ]
24
- }
25
- info(converted)
26
- end
27
-
28
13
  def located_at!(location)
29
14
  @location = Path(location)
30
15
  end
@@ -39,51 +24,12 @@ module Webspicy
39
24
  @raw[:name]
40
25
  end
41
26
 
42
- def url
43
- @raw[:url]
44
- end
45
-
46
- def url_pattern
47
- @url_pattern ||= Mustermann.new(url, type: :template)
48
- end
49
-
50
27
  def services
51
28
  @raw[:services] || []
52
29
  end
53
30
 
54
- def url_placeholders
55
- url.scan(/\{([a-zA-Z]+(\.[a-zA-Z]+)*)\}/).map{|x| x.first }
56
- end
57
-
58
- def instantiate_url(params)
59
- url, rest = self.url, params.dup
60
- url_placeholders.each do |placeholder|
61
- value, rest = extract_placeholder_value(rest, placeholder)
62
- url = url.gsub("{#{placeholder}}", value.to_s)
63
- end
64
- [ url, rest ]
65
- end
66
-
67
- def to_singleservice
68
- raise NotImplementedError
69
- end
70
-
71
31
  private
72
32
 
73
- def extract_placeholder_value(params, placeholder, split = nil)
74
- return extract_placeholder_value(params, placeholder, placeholder.split(".")) unless split
75
-
76
- key = [ split.first, split.first.to_sym ].find{|k| params.has_key?(k) }
77
- raise "Missing URL parameter `#{placeholder}`" unless key
78
-
79
- if split.size == 1
80
- [ params[key], params.dup.delete_if{|k| k == key } ]
81
- else
82
- value, rest = extract_placeholder_value(params[key], placeholder, split[1..-1])
83
- [ value, params.merge(key => rest) ]
84
- end
85
- end
86
-
87
33
  def bind_services
88
34
  services.each do |s|
89
35
  s.specification = self
@@ -99,4 +45,3 @@ require_relative 'specification/post'
99
45
  require_relative 'specification/err'
100
46
  require_relative 'specification/oldies'
101
47
  require_relative 'specification/test_case'
102
- require_relative 'specification/file_upload'
@@ -4,9 +4,9 @@ module Webspicy
4
4
  class MissingConditionImpl
5
5
  include Post
6
6
 
7
- def check
7
+ def check!
8
8
  msg = matching_description.gsub(/\(x\)/, "<!>")
9
- raise "#{msg} (not instrumented)"
9
+ fail!("#{msg} (not instrumented)")
10
10
  end
11
11
 
12
12
  end # class MissingConditionImpl
@@ -4,9 +4,9 @@ module Webspicy
4
4
  class UnexpectedConditionImpl
5
5
  include Post
6
6
 
7
- def check
7
+ def check!
8
8
  msg = matching_description.gsub(/\( \)/, "<x>")
9
- raise "#{msg} (is instrumented)"
9
+ fail!("#{msg} (is instrumented)")
10
10
  end
11
11
 
12
12
  end # class UnexpectedConditionImpl
@@ -21,10 +21,6 @@ module Webspicy
21
21
  specification.config
22
22
  end
23
23
 
24
- def method
25
- @raw[:method]
26
- end
27
-
28
24
  def description
29
25
  @raw[:description]
30
26
  end
@@ -68,7 +64,7 @@ module Webspicy
68
64
  def generated_counterexamples
69
65
  preconditions.map{|pre|
70
66
  pre.counterexamples(self).map{|tc|
71
- tc = Webspicy.test_case(tc, Webspicy.current_scope)
67
+ tc = config.factory.test_case(tc, Webspicy.current_scope)
72
68
  tc.bind(self, true)
73
69
  }
74
70
  }.flatten