webspicy 0.15.2 → 0.15.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: efdf4060daab47d3319dd29b48ecd26013621e30f6c1d4f1c25b4f518ea7529c
4
- data.tar.gz: 52841690093e5d2c6aa109fb9713ed8b61aad46b692372bd2bef4bc9eeb13c33
3
+ metadata.gz: f4a2e0e1d1ccfacade6173f0ebe8119a71438aeb5403af05bdf08373f98630d7
4
+ data.tar.gz: 063a4f40b5e8244adc654bb0e60b2dccb67b930b0ec4fa18045e3b005392004d
5
5
  SHA512:
6
- metadata.gz: e6a7c5fae819129306949642fdb8dab129a490750988fd6ea5b7b65e1f54baec03736f5691487ee8d0008eee3688bd98a094260ef4dfa3f0538ca5fbcafda1e1
7
- data.tar.gz: 06e2831456be2cd7fb2dd3ac3cf9135bef1e8ae8aa683977d9670a5724b090d2104b1e8d57b6f3f3d20b88ca72e4e7077d0c99fb47a1123e9c6d1634290beb3c
6
+ metadata.gz: bdaaf1d7e90215b5f2f4d30ab0efd42ddf08f490dcaa77cba84a822b333020d63c34980420d9b9872c2db423635cf0d0fd0193a578826a31ad950795fa8a806e
7
+ data.tar.gz: 21a7cf4e9b0bbb8835284132edd029fd7221933d2cc0d044c8ca6f5fb81bfc406621cbefdd33422da1a3ce68a703a030965fd15b7da8e678693e25a78c1526e7
@@ -29,7 +29,8 @@ if ARGV.size != 1
29
29
  exit(-1)
30
30
  elsif (p = Path(ARGV.first)).exists?
31
31
  config = Webspicy::Configuration.dress(p)
32
- Webspicy::Tester.new(config).call
32
+ res = Webspicy::Tester.new(config).call
33
+ abort("Some tests failed") unless res == 0
33
34
  else
34
35
  puts "No such file or directory `#{ARGV.first}`"
35
36
  showhelp
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- webspicy (0.15.2)
4
+ webspicy (0.15.7)
5
5
  finitio (>= 0.8.0)
6
6
  http (>= 2)
7
7
  mustermann (~> 1.0)
@@ -119,6 +119,21 @@ patch '/todo/:id', :auth => :user do |id|
119
119
  end
120
120
  end
121
121
 
122
+ put '/todo/:id', :auth => :user do |id|
123
+ content_type :json
124
+ todo = settings.todolist.find{|todo| todo[:id] == Integer(id) }
125
+ if todo.nil?
126
+ status 404
127
+ {error: "No such todo"}.to_json
128
+ else
129
+ put = SCHEMA["TodoPut"].dress(loaded_body.merge(id: Integer(id)))
130
+ updated = todo.merge(put)
131
+ settings.todolist = settings.todolist.reject{|todo| todo[:id] == Integer(id) }
132
+ settings.todolist << updated
133
+ updated.to_json
134
+ end
135
+ end
136
+
122
137
  delete '/todo/:id', :auth => :admin do |id|
123
138
  content_type :json
124
139
  todo = settings.todolist.find{|todo| todo[:id] == Integer(id) }
@@ -10,6 +10,11 @@ TodoPatch = {
10
10
  description :? String
11
11
  }
12
12
 
13
+ TodoPut = {
14
+ id : Integer
15
+ description : String
16
+ }
17
+
13
18
  ErrorSchema = {
14
19
  error: String
15
20
  }
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: |-
3
+ Todo
4
+
5
+ url: |-
6
+ /todo/{id}
7
+
8
+ services:
9
+ - method: |-
10
+ PUT
11
+
12
+ description: |-
13
+ Update a single Todo item
14
+
15
+ preconditions:
16
+ - Must be authenticated
17
+
18
+ input_schema: |-
19
+ TodoPut
20
+
21
+ output_schema: |-
22
+ Todo
23
+
24
+ error_schema: |-
25
+ ErrorSchema
26
+
27
+ default_example:
28
+ expected:
29
+ content_type: application/json
30
+ status: 200
31
+
32
+ examples:
33
+
34
+ - description: |-
35
+ when requested on an existing TODO
36
+ params:
37
+ id: 1
38
+ description: 'hello world'
39
+ assert:
40
+ - "pathFD('', description: 'hello world')"
41
+
42
+ counterexamples:
43
+
44
+ - description: |-
45
+ when requested on an unexisting TODO
46
+ params:
47
+ id: 999254654
48
+ description: 'hello world'
49
+ expected:
50
+ content_type: application/json
51
+ status: 404
52
+ assert:
53
+ - "pathFD('', error: 'No such todo')"
54
+
55
+ - description: |-
56
+ when violating the Put data type
57
+ params:
58
+ id: 1
59
+ description: 'hello world'
60
+ nosuchone: 'foobar'
61
+ dress_params:
62
+ false
63
+ expected:
64
+ content_type: application/json
65
+ status: 400
@@ -14,6 +14,7 @@ module Webspicy
14
14
  ### Load library
15
15
  ###
16
16
 
17
+ require 'webspicy/support'
17
18
  require 'webspicy/configuration'
18
19
  require 'webspicy/file_upload'
19
20
  require 'webspicy/scope'
@@ -107,6 +107,18 @@ module Webspicy
107
107
  @last_response
108
108
  end
109
109
 
110
+ def put(url, params = {}, headers = nil, body = nil)
111
+ info_request("PUT", url, params, headers, body)
112
+
113
+ headers ||= {}
114
+ headers['Content-Type'] ||= 'application/json'
115
+ @last_response = HTTP[headers].put(url, body: params.to_json)
116
+
117
+ debug_response(@last_response)
118
+
119
+ @last_response
120
+ end
121
+
110
122
  def post_form(url, params = {}, headers = nil, body = nil)
111
123
  info_request("POST", url, params, headers, body)
112
124
 
@@ -126,6 +126,19 @@ module Webspicy
126
126
  @last_response
127
127
  end
128
128
 
129
+ def put(url, params = {}, headers = nil, body = nil)
130
+ handler = get_handler(headers)
131
+
132
+ info_request("PUT", url, params, headers, body)
133
+
134
+ handler.put(url, params.to_json, {"CONTENT_TYPE" => "application/json"})
135
+ @last_response = handler.last_response
136
+
137
+ debug_response(@last_response)
138
+
139
+ @last_response
140
+ end
141
+
129
142
  def post_form(url, params = {}, headers = nil, body = nil)
130
143
  handler = get_handler(headers)
131
144
 
@@ -11,6 +11,7 @@ module Webspicy
11
11
  @postconditions = []
12
12
  @listeners = Hash.new{|h,k| h[k] = [] }
13
13
  @rspec_options = default_rspec_options
14
+ @run_examples = default_run_examples
14
15
  @run_counterexamples = default_run_counterexamples
15
16
  @file_filter = default_file_filter
16
17
  @service_filter = default_service_filter
@@ -94,6 +95,23 @@ module Webspicy
94
95
  !children.empty?
95
96
  end
96
97
 
98
+ # Sets whether examples have to be ran or not.
99
+ def run_examples=(run_examples)
100
+ @run_examples = run_examples
101
+ end
102
+ attr_reader :run_examples
103
+
104
+ # Whether counter examples must be ran or not.
105
+ def run_examples?
106
+ @run_examples
107
+ end
108
+
109
+ # Returns the defaut value for run_examples
110
+ def default_run_examples
111
+ ENV['ROBUST'].nil? || (ENV['ROBUST'] != 'only')
112
+ end
113
+ private :default_run_examples
114
+
97
115
  # Sets whether counter examples have to be ran or not.
98
116
  def run_counterexamples=(run_counterexamples)
99
117
  @run_counterexamples = run_counterexamples
@@ -249,36 +267,36 @@ module Webspicy
249
267
  # Installs a listener that will be called before all tests
250
268
  #
251
269
  # The `listener` must respond to `call`.
252
- def before_all(&listener)
253
- register_listener(:before_all, listener)
270
+ def before_all(l = nil, &listener)
271
+ register_listener(:before_all, l || listener)
254
272
  end
255
273
 
256
274
  # Installs a listener that will be called before each web service invocation.
257
275
  #
258
276
  # The `listener` must respond to `call`.
259
- def before_each(&listener)
260
- register_listener(:before_each, listener)
277
+ def before_each(l = nil, &listener)
278
+ register_listener(:before_each, l || listener)
261
279
  end
262
280
 
263
281
  # Installs a listener that will be called after all tests
264
282
  #
265
283
  # The `listener` must respond to `call`.
266
- def after_all(&listener)
267
- register_listener(:after_all, listener)
284
+ def after_all(l = nil, &listener)
285
+ register_listener(:after_all, l || listener)
268
286
  end
269
287
 
270
288
  # Installs a listener that will be called after each web service invocation.
271
289
  #
272
290
  # The `listener` must respond to `call`.
273
- def after_each(&listener)
274
- register_listener(:after_each, listener)
291
+ def after_each(l = nil, &listener)
292
+ register_listener(:after_each, l || listener)
275
293
  end
276
294
 
277
295
  # Installs a listener that will be called around each web service invocation.
278
296
  #
279
297
  # The `listener` must respond to `call`.
280
- def around_each(&listener)
281
- register_listener(:around_each, listener)
298
+ def around_each(l = nil, &listener)
299
+ register_listener(:around_each, l || listener)
282
300
  end
283
301
 
284
302
  # Installs a listener that will be called right after all precondition
@@ -1,7 +1,7 @@
1
1
  @import finitio/data
2
2
 
3
3
  Method =
4
- String( s | s =~ /^(GET|POST|POST_FORM|PUT|DELETE|PATCH|OPTIONS)$/ )
4
+ String( s | s =~ /^(GET|POST|POST_FORM|PUT|DELETE|PATCH|PUT|OPTIONS)$/ )
5
5
 
6
6
  Tag = String( s | s.length > 0 )
7
7
 
@@ -51,7 +51,7 @@ TestCase =
51
51
  requester :? String
52
52
  metadata :? { ...: .Object }
53
53
  expected :? {
54
- status :? Integer
54
+ status :? StatusRange
55
55
  content_type :? String|Nil
56
56
  error :? String
57
57
  headers :? .Hash
@@ -61,3 +61,7 @@ TestCase =
61
61
  }
62
62
 
63
63
  Params = .Array|.Hash
64
+
65
+ StatusRange = .Webspicy::Support::StatusRange
66
+ <int> Integer
67
+ <str> String(s | s =~ /^\dxx$/ )
@@ -57,7 +57,7 @@ module Webspicy
57
57
 
58
58
  def best_status_code(service)
59
59
  if ex = service.examples.first
60
- ex.expected_status || 200
60
+ (ex.expected_status && ex.expected_status.to_i) || 200
61
61
  else
62
62
  200
63
63
  end
@@ -51,8 +51,7 @@ module Webspicy
51
51
  preconditions.map{|pre|
52
52
  pre.counterexamples(self).map{|tc|
53
53
  tc = Webspicy.test_case(tc, Webspicy.current_scope)
54
- tc.service = self
55
- tc
54
+ tc.bind(self, true)
56
55
  }
57
56
  }.flatten
58
57
  end
@@ -107,13 +106,13 @@ module Webspicy
107
106
 
108
107
  def bind_examples
109
108
  (@raw[:examples] ||= []).each do |ex|
110
- ex.service = self
109
+ ex.bind(self, false)
111
110
  end
112
111
  end
113
112
 
114
113
  def bind_counterexamples
115
114
  (@raw[:counterexamples] ||= []).each do |ex|
116
- ex.service = self
115
+ ex.bind(self, true)
117
116
  end
118
117
  end
119
118
 
@@ -12,6 +12,32 @@ module Webspicy
12
12
 
13
13
  attr_reader :service, :test_case, :response, :client
14
14
 
15
+ def errors
16
+ @errors ||= begin
17
+ errs = [
18
+ [:expected_status_unmet, true],
19
+ [:expected_content_type_unmet, !test_case.is_expected_status?(204)],
20
+ [:expected_headers_unmet, test_case.has_expected_headers?],
21
+ [:expected_schema_unmet, !test_case.is_expected_status?(204)],
22
+ [:assertions_unmet, test_case.has_assertions?],
23
+ [:postconditions_unmet, test_case.service.has_postconditions? && !test_case.counterexample?],
24
+ [:expected_error_unmet, test_case.has_expected_error?]
25
+ ].map do |(expectation,only_if)|
26
+ next unless only_if
27
+ begin
28
+ self.send(expectation)
29
+ rescue => ex
30
+ ex.message
31
+ end
32
+ end
33
+ errs.compact
34
+ end
35
+ end
36
+
37
+ def has_error?
38
+ !errors.empty?
39
+ end
40
+
15
41
  ### Getters on response
16
42
 
17
43
  def response_code
@@ -27,7 +53,7 @@ module Webspicy
27
53
  end
28
54
 
29
55
  def is_expected_success?
30
- test_case.expected_status >= 200 && test_case.expected_status < 300
56
+ test_case.expected_status.to_i >= 200 && test_case.expected_status.to_i < 300
31
57
  end
32
58
 
33
59
  def is_success?
@@ -47,7 +73,7 @@ module Webspicy
47
73
  def expected_status_unmet
48
74
  expected = test_case.expected_status
49
75
  got = response.status
50
- expected == got ? nil : "#{expected} != #{got}"
76
+ expected === got ? nil : "#{expected} !== #{got}"
51
77
  end
52
78
 
53
79
  def meets_expected_status?
@@ -63,7 +89,7 @@ module Webspicy
63
89
  if ect.nil?
64
90
  got.nil? ? nil : "#{ect} != #{got}"
65
91
  else
66
- ect.to_s == got.to_s ? nil : "#{ect} != #{got}"
92
+ got.to_s.start_with?(ect.to_s) ? nil : "#{ect} != #{got}"
67
93
  end
68
94
  end
69
95
 
@@ -5,8 +5,20 @@ module Webspicy
5
5
 
6
6
  def initialize(raw)
7
7
  @raw = raw
8
+ @counterexample = nil
9
+ end
10
+ attr_reader :service
11
+ attr_reader :counterexample
12
+
13
+ def bind(service, counterexample)
14
+ @service = service
15
+ @counterexample = counterexample
16
+ self
17
+ end
18
+
19
+ def counterexample?
20
+ !!@counterexample
8
21
  end
9
- attr_accessor :service
10
22
 
11
23
  def resource
12
24
  service.resource
@@ -70,7 +82,7 @@ module Webspicy
70
82
  end
71
83
 
72
84
  def is_expected_status?(status)
73
- expected_status == status
85
+ expected_status === status
74
86
  end
75
87
 
76
88
  def expected_error
@@ -46,23 +46,26 @@ module Webspicy
46
46
  resource.services.select(&to_filter_proc(config.service_filter)).each(&bl)
47
47
  end
48
48
 
49
- def each_example(service)
50
- service.examples.select(&to_filter_proc(config.test_case_filter)).each{|e|
51
- yield(expand_example(service, e), false)
52
- }
49
+ def each_example(service, &bl)
50
+ service.examples
51
+ .map{|e| expand_example(service, e) }
52
+ .select(&to_filter_proc(config.test_case_filter))
53
+ .each(&bl) if config.run_examples?
53
54
  end
54
55
 
55
56
  def each_counterexamples(service, &bl)
56
- service.counterexamples.select(&to_filter_proc(config.test_case_filter)).each{|e|
57
- yield(expand_example(service, e), true)
58
- } if config.run_counterexamples?
57
+ service.counterexamples
58
+ .map{|e| expand_example(service, e) }
59
+ .select(&to_filter_proc(config.test_case_filter))
60
+ .each(&bl) if config.run_counterexamples?
59
61
  end
60
62
 
61
63
  def each_generated_counterexamples(service, &bl)
62
64
  Webspicy.with_scope(self) do
63
- service.generated_counterexamples.select(&to_filter_proc(config.test_case_filter)).each{|e|
64
- yield(expand_example(service, e), true)
65
- }
65
+ service.generated_counterexamples
66
+ .map{|e| expand_example(service, e) }
67
+ .select(&to_filter_proc(config.test_case_filter))
68
+ .each(&bl) if config.run_counterexamples?
66
69
  end if config.run_counterexamples?
67
70
  end
68
71
 
@@ -128,8 +131,7 @@ module Webspicy
128
131
  h1 = service.default_example.to_info
129
132
  h2 = example.to_info
130
133
  ex = Resource::Service::TestCase.new(merge_maps(h1, h2))
131
- ex.service = service
132
- ex
134
+ ex.bind(service, example.counterexample?)
133
135
  end
134
136
 
135
137
  def merge_maps(h1, h2)
@@ -0,0 +1 @@
1
+ require_relative 'support/status_range'
@@ -0,0 +1,50 @@
1
+ module Webspicy
2
+ module Support
3
+ class StatusRange
4
+
5
+ def initialize(range)
6
+ @range = range
7
+ end
8
+ attr_reader :range
9
+
10
+ def self.int(i)
11
+ new(i..i)
12
+ end
13
+
14
+ def to_int
15
+ @range.first
16
+ end
17
+
18
+ def self.str(s)
19
+ from = s[/^(\d)/,1].to_i * 100
20
+ new(from...from+100)
21
+ end
22
+
23
+ def to_str
24
+ "#{@range.first/100}xx"
25
+ end
26
+
27
+ def to_i
28
+ @range.first
29
+ end
30
+
31
+ def ===(status)
32
+ range === status
33
+ end
34
+
35
+ def ==(other)
36
+ other.is_a?(StatusRange) && self.range == other.range
37
+ end
38
+ alias :eql? :==
39
+
40
+ def hash
41
+ @range.hash
42
+ end
43
+
44
+ def to_s
45
+ @range.to_s
46
+ end
47
+
48
+ end # class StatusRange
49
+ end # module Support
50
+ end # module Webspicy
@@ -45,16 +45,16 @@ module Webspicy
45
45
 
46
46
  def rspec_service!(on, service, client, scope)
47
47
  on.describe service do
48
- scope.each_testcase(service) do |test_case, counterexample|
48
+ scope.each_testcase(service) do |test_case|
49
49
  describe test_case do
50
- include_examples 'a successful test case invocation', client, test_case, counterexample
50
+ include_examples 'a successful test case invocation', client, test_case
51
51
  end
52
52
  end
53
53
  end
54
54
  end
55
55
 
56
56
  def rspec_config!
57
- RSpec.shared_examples "a successful test case invocation" do |client, test_case, counterexample|
57
+ RSpec.shared_examples "a successful test case invocation" do |client, test_case|
58
58
 
59
59
  around(:each) do |example|
60
60
  client.around(test_case) do
@@ -63,7 +63,8 @@ module Webspicy
63
63
  client.instrument(test_case)
64
64
  @invocation = client.call(test_case)
65
65
  example.run
66
- client.after(test_case)
66
+ client.after(test_case, @invocation)
67
+ @invocation
67
68
  end
68
69
  end
69
70
 
@@ -73,24 +74,8 @@ module Webspicy
73
74
 
74
75
  it 'works' do
75
76
  raise "Test not ran" unless invocation.done?
76
- fails = [
77
- [:expected_status_unmet, true],
78
- [:expected_content_type_unmet, !test_case.is_expected_status?(204)],
79
- [:expected_headers_unmet, test_case.has_expected_headers?],
80
- [:expected_schema_unmet, !test_case.is_expected_status?(204)],
81
- [:assertions_unmet, test_case.has_assertions?],
82
- [:postconditions_unmet, test_case.service.has_postconditions? && !counterexample],
83
- [:expected_error_unmet, test_case.has_expected_error?]
84
- ].map do |(expectation,only_if)|
85
- next unless only_if
86
- begin
87
- invocation.send(expectation)
88
- rescue => ex
89
- ex.message
90
- end
91
- end
92
- fails = fails.compact
93
- raise "\n* " + fails.join("\n* ") + "\n" unless fails.empty?
77
+ errors = invocation.errors
78
+ raise "\n* " + errors.join("\n* ") + "\n" unless errors.empty?
94
79
  end
95
80
  end
96
81
  end
@@ -2,7 +2,7 @@ module Webspicy
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 15
5
- TINY = 2
5
+ TINY = 7
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
@@ -53,7 +53,7 @@ module Webspicy
53
53
  expect(subject).to be_a(Resource::Service::TestCase)
54
54
  expect(subject.description).to eql("Hello world")
55
55
  expect(subject.expected).to eql({
56
- status: 200,
56
+ status: Support::StatusRange.int(200),
57
57
  content_type: "application/json"
58
58
  })
59
59
  end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+ module Webspicy
3
+ module Support
4
+ describe StatusRange do
5
+
6
+ it 'has a int information contract' do
7
+ expect(StatusRange.int(100).range).to eql(100..100)
8
+ expect(StatusRange.int(100).to_int).to eql(100)
9
+ end
10
+
11
+ it 'has a str information contract' do
12
+ expect(StatusRange.str("3xx").range).to eql(300...400)
13
+ expect(StatusRange.str("3xx").to_str).to eql("3xx")
14
+ end
15
+
16
+ it 'has a to_i that returns the first status of the range' do
17
+ expect(StatusRange.int(300).to_i).to eql(300)
18
+ expect(StatusRange.str("3xx").to_i).to eql(300)
19
+ end
20
+
21
+ it 'has a matching method' do
22
+ expect(StatusRange.str("3xx") === 300).to eql(true)
23
+ expect(StatusRange.str("3xx") === 302).to eql(true)
24
+ expect(StatusRange.str("3xx") === 400).to eql(false)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webspicy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.2
4
+ version: 0.15.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-28 00:00:00.000000000 Z
11
+ date: 2020-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -206,6 +206,7 @@ files:
206
206
  - examples/restful/webspicy/todo/postCsv.yml
207
207
  - examples/restful/webspicy/todo/postFile.yml
208
208
  - examples/restful/webspicy/todo/postTodos.yml
209
+ - examples/restful/webspicy/todo/putTodo.yml
209
210
  - examples/restful/webspicy/todo/todos.csv
210
211
  - lib/webspicy.rb
211
212
  - lib/webspicy/checker.rb
@@ -224,6 +225,8 @@ files:
224
225
  - lib/webspicy/resource/service/invocation.rb
225
226
  - lib/webspicy/resource/service/test_case.rb
226
227
  - lib/webspicy/scope.rb
228
+ - lib/webspicy/support.rb
229
+ - lib/webspicy/support/status_range.rb
227
230
  - lib/webspicy/tester.rb
228
231
  - lib/webspicy/tester/asserter.rb
229
232
  - lib/webspicy/tester/assertions.rb
@@ -239,6 +242,7 @@ files:
239
242
  - spec/unit/scope/test_expand_example.rb
240
243
  - spec/unit/scope/test_to_real_url.rb
241
244
  - spec/unit/spec_helper.rb
245
+ - spec/unit/support/test_status_range.rb
242
246
  - spec/unit/test_configuration.rb
243
247
  - spec/unit/tester/test_assertions.rb
244
248
  - tasks/gem.rake