webspicy 0.20.1 → 0.20.6

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 (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/fakesmtp/email.rb +13 -0
  21. data/lib/webspicy/tester/reporter.rb +5 -0
  22. data/lib/webspicy/tester/reporter/documentation.rb +30 -8
  23. data/lib/webspicy/tester/reporter/error_count.rb +11 -7
  24. data/lib/webspicy/tester/reporter/file_progress.rb +2 -2
  25. data/lib/webspicy/tester/reporter/file_summary.rb +2 -2
  26. data/lib/webspicy/tester/reporter/progress.rb +4 -4
  27. data/lib/webspicy/tester/reporter/summary.rb +8 -7
  28. data/lib/webspicy/tester/result.rb +2 -2
  29. data/lib/webspicy/tester/result/errcondition_met.rb +1 -3
  30. data/lib/webspicy/tester/result/postcondition_met.rb +1 -3
  31. data/lib/webspicy/version.rb +1 -1
  32. data/lib/webspicy/web.rb +46 -0
  33. data/lib/webspicy/{formaldoc.fio → web/formaldoc.fio} +5 -13
  34. data/lib/webspicy/web/invocation.rb +1 -0
  35. data/lib/webspicy/web/specification.rb +68 -0
  36. data/lib/webspicy/web/specification/file_upload.rb +39 -0
  37. data/lib/webspicy/web/specification/service.rb +13 -0
  38. data/lib/webspicy/web/specification/test_case.rb +58 -0
  39. data/spec/unit/configuration/scope/test_expand_example.rb +11 -5
  40. data/spec/unit/specification/pre/test_global_request_headers.rb +3 -3
  41. data/spec/unit/specification/service/test_dress_params.rb +2 -2
  42. data/spec/unit/test_configuration.rb +1 -0
  43. data/spec/unit/tester/fakesmtp/test_email.rb +93 -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 +28 -19
  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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 576301cb14f9cc4abcb10c8638e7b7994397e3bd91c0f3e48fea49ff356dc81d
4
- data.tar.gz: e19dc03f7daa686ec2c97f9f83b28249a7ccf16de852b5844bf68cf99291944e
3
+ metadata.gz: 013055707cad05016cb794561d47a0408d39d6f462387c9eb66d31542ff2218c
4
+ data.tar.gz: b4c4778275ec96271b711ea0956c539fa35bf12b04d635fbc5062698996e7902
5
5
  SHA512:
6
- metadata.gz: e85cdd2ad61ed8b3e4a7d0362cd6543d6107ff4bbdba3586a3145c911e6d76d17a96347c28b56283804979ffea0a33ab47ba5426074450bc25b51ad78819c316
7
- data.tar.gz: 3eb380f55e3f444f0cdd4268c00ef434b6f68ccca8cb10a3486be837a3d096dfd929d23b69d8ab872929995532491b9e3e41f1d44e2bff71ab078df10324a660
6
+ metadata.gz: fcc079537f13b76af0e433c8591529824ea1e4f8b255f1411963e88cbd4df6953598504413dc8ad3da6db3005cf2c49867e80790594e3fb56cab039f2de450c7
7
+ data.tar.gz: e4479277fcec22a0928ae75a0120bc5c0a9644e73be6bb75a577dd33a42a03c445996b9b846a33bd20e6e439b4047a8f3ab4a418abb965777b4ce047e1824d7e
data/bin/sandr ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require 'path'
3
+
4
+ def sandr(file)
5
+ file.write file.read.gsub(ARGV[0], ARGV[1])
6
+ end
7
+
8
+ Path.dir.parent.glob("lib/**/*.rb") do |file|
9
+ sandr(file)
10
+ end
11
+
12
+ Path.dir.parent.glob("spec/**/*.rb") do |file|
13
+ sandr(file)
14
+ end
data/bin/search ADDED
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ grep -Rn --color $1 lib spec
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'
@@ -10,11 +10,14 @@ module Webspicy
10
10
  attr_reader :target
11
11
 
12
12
  def instrument
13
+ return unless target.respond_to?(:instrument)
13
14
  target.instrument(test_case, client)
14
15
  end
15
16
 
16
17
  def check!
17
- target.check(invocation)
18
+ return unless target.respond_to?(:check)
19
+ res = target.check(invocation)
20
+ res ? fail!(res) : nil
18
21
  end
19
22
 
20
23
  def to_s