webspicy 0.15.8 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -24
  3. data/bin/webspicy +30 -14
  4. data/examples/restful/Gemfile.lock +38 -23
  5. data/examples/restful/Rakefile +0 -1
  6. data/examples/restful/app.rb +4 -1
  7. data/examples/restful/webspicy/config.rb +8 -0
  8. data/examples/restful/webspicy/rack.rb +1 -1
  9. data/examples/restful/webspicy/real.rb +1 -1
  10. data/examples/restful/webspicy/schema.fio +2 -2
  11. data/examples/restful/webspicy/support/must_be_authenticated.rb +2 -2
  12. data/examples/restful/webspicy/support/todo_removed.rb +18 -0
  13. data/examples/restful/webspicy/todo/deleteTodo.yml +4 -1
  14. data/examples/restful/webspicy/todo/getTodoSingleServiceFormat.yml +46 -0
  15. data/examples/restful/webspicy/todo/options.yml +1 -1
  16. data/examples/restful/webspicy/todo/patchTodo.yml +3 -0
  17. data/examples/restful/webspicy/todo/postFile.yml +1 -1
  18. data/examples/single_spec/spec.yml +59 -0
  19. data/examples/website/config.rb +2 -0
  20. data/examples/website/schema.fio +1 -0
  21. data/examples/website/specification/get-http.yml +34 -0
  22. data/examples/website/specification/get-https.yml +34 -0
  23. data/lib/finitio/webspicy/scalars.fio +25 -0
  24. data/lib/webspicy.rb +48 -17
  25. data/lib/webspicy/checker.rb +2 -2
  26. data/lib/webspicy/configuration.rb +70 -14
  27. data/lib/webspicy/configuration/scope.rb +162 -0
  28. data/lib/webspicy/configuration/single_url.rb +58 -0
  29. data/lib/webspicy/configuration/single_yml_file.rb +30 -0
  30. data/lib/webspicy/formaldoc.fio +23 -8
  31. data/lib/webspicy/mocker.rb +8 -8
  32. data/lib/webspicy/openapi.rb +1 -0
  33. data/lib/webspicy/openapi/generator.rb +127 -0
  34. data/lib/webspicy/{resource.rb → specification.rb} +26 -5
  35. data/lib/webspicy/specification/file_upload.rb +37 -0
  36. data/lib/webspicy/specification/postcondition.rb +16 -0
  37. data/lib/webspicy/specification/precondition.rb +19 -0
  38. data/lib/webspicy/specification/precondition/global_request_headers.rb +35 -0
  39. data/lib/webspicy/specification/precondition/robust_to_invalid_input.rb +68 -0
  40. data/lib/webspicy/{resource → specification}/service.rb +11 -6
  41. data/lib/webspicy/specification/test_case.rb +139 -0
  42. data/lib/webspicy/support.rb +1 -0
  43. data/lib/webspicy/support/colorize.rb +28 -0
  44. data/lib/webspicy/support/status_range.rb +6 -1
  45. data/lib/webspicy/tester.rb +16 -11
  46. data/lib/webspicy/tester/asserter.rb +3 -2
  47. data/lib/webspicy/tester/assertions.rb +5 -1
  48. data/lib/webspicy/tester/client.rb +63 -0
  49. data/lib/webspicy/tester/client/http_client.rb +154 -0
  50. data/lib/webspicy/tester/client/rack_test_client.rb +188 -0
  51. data/lib/webspicy/tester/client/support.rb +65 -0
  52. data/lib/webspicy/tester/invocation.rb +218 -0
  53. data/lib/webspicy/tester/rspec_asserter.rb +108 -0
  54. data/lib/webspicy/tester/rspec_matchers.rb +104 -0
  55. data/lib/webspicy/version.rb +2 -2
  56. data/spec/{unit/spec_helper.rb → spec_helper.rb} +0 -0
  57. data/spec/unit/configuration/scope/test_each_service.rb +49 -0
  58. data/spec/unit/configuration/scope/test_each_specification.rb +68 -0
  59. data/spec/unit/configuration/scope/test_expand_example.rb +65 -0
  60. data/spec/unit/configuration/scope/test_to_real_url.rb +82 -0
  61. data/spec/unit/openapi/test_generator.rb +28 -0
  62. data/spec/unit/specification/precondition/test_global_request_headers.rb +42 -0
  63. data/spec/unit/{resource → specification}/service/test_dress_params.rb +2 -2
  64. data/spec/unit/specification/test_case/test_mutate.rb +24 -0
  65. data/spec/unit/{resource → specification}/test_instantiate_url.rb +5 -5
  66. data/spec/unit/{resource → specification}/test_url_placeholders.rb +4 -4
  67. data/spec/unit/test_configuration.rb +24 -7
  68. data/spec/unit/tester/client/test_around.rb +61 -0
  69. data/spec/unit/tester/test_asserter.rb +51 -0
  70. data/spec/unit/tester/test_assertions.rb +4 -4
  71. data/tasks/test.rake +3 -1
  72. metadata +83 -34
  73. data/lib/webspicy/client.rb +0 -61
  74. data/lib/webspicy/client/http_client.rb +0 -145
  75. data/lib/webspicy/client/rack_test_client.rb +0 -181
  76. data/lib/webspicy/client/support.rb +0 -48
  77. data/lib/webspicy/file_upload.rb +0 -35
  78. data/lib/webspicy/postcondition.rb +0 -14
  79. data/lib/webspicy/precondition.rb +0 -15
  80. data/lib/webspicy/resource/service/invocation.rb +0 -212
  81. data/lib/webspicy/resource/service/test_case.rb +0 -132
  82. data/lib/webspicy/scope.rb +0 -160
  83. data/spec/unit/client/test_around.rb +0 -59
  84. data/spec/unit/scope/test_each_resource.rb +0 -66
  85. data/spec/unit/scope/test_each_service.rb +0 -47
  86. data/spec/unit/scope/test_expand_example.rb +0 -63
  87. data/spec/unit/scope/test_to_real_url.rb +0 -80
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1d234226f15d51777e61c010557ed1691660613cd87ba11ce19844b2f7cc812
4
- data.tar.gz: 40fcd4639ce847f7f69f3471ef9676c64e8e6be489388563d5abd51ca1bf39d7
3
+ metadata.gz: 70bfa6517173d1f121b9ebe968ac5970e41b2f6846384b152d288eb2f4913cb7
4
+ data.tar.gz: 0e5b728db6ecd9eb3ccb42d166317911a03092d41cf4778f1058960aa0e92bab
5
5
  SHA512:
6
- metadata.gz: c4d0ec9a0567955bac41c5ee887164e783799e2baf66966fabff404147376c29192a4b28090c7d816a20fd15bc7e470b20136e253b9b1a7d663ac57de4958d99
7
- data.tar.gz: 4ddccde82357c81066108133b0e5b63ea8b5a0b714556b56b4d4743ba26aaaf17a9187633061dc2f721b88833cdfb536f795d8256aa158723c4fa5a255957144
6
+ metadata.gz: 51e6fbe8ad57cb2795435a3c194e142d1f5e822289be923aeebfd9c89ef9440a6fd7dea2fb58bb9e8d8bdd490b1025201dfb12b4d000d7d6604e422de1007dcf
7
+ data.tar.gz: 3fe5b84bd684564321712412c2bc0f918944d22dbe665ea119d0a478d181a6ac9483de2c1352e8b0f98b484e1cd361f0193afcf42c6ee6c0095811feec86c555
data/README.md CHANGED
@@ -1,46 +1,93 @@
1
1
  # Webspicy
2
2
 
3
- A description, specification and test framework for web services seen as black
4
- box software operations.
3
+ A specification and test framework for web services seen as black-box software
4
+ operations. Webspicy yields a better test coverage for a smaller testing effort,
5
+ because software quality matters.
6
+
7
+ See webspicy in action and make the tutorial on https://yourbackendisbroken.dev
5
8
 
6
9
  ## Features
7
10
 
8
- * Declarative description of RESTful web-services + their tests
11
+ * Declarative specification of HTTP web services + their tests
12
+
13
+ * Framework/language agnostic: `webspicy` is written in Ruby, but can be used
14
+ to test web services for backends written in any language / framework.
15
+
16
+ * Black box testing: `webspicy` focuses on web services seen as blackboxes. It
17
+ has no knowledge of the implementation, and focuses on HTTP and input/output
18
+ data instead. Investing in such testing makes those tests more stable and
19
+ your API design better.
9
20
 
10
- * Framework/language agnostic: Webspicy is written in Ruby, but can be used to
11
- test web services in any language / framework.
21
+ * Formal and human-friendly data schema with strong data matching semantics,
22
+ thanks to finitio.io
12
23
 
13
- * Black box testing: Webspicy focuses on web services seen as blackboxes. It has
14
- no knowledge of the implementation, and focuses on HTTP and input/output data
15
- instead. Investing in such testing makes those tests more stable and your API
16
- better.
24
+ * Test instrumentation and generation, based on PRE & POST contracts.
17
25
 
18
- * Test instrumentation and generation, based on declarative PRE & POST
19
- conditions.
26
+ * Extra goodness for Rubyists: being written in ruby, `webspicy` also supports
27
+ testing Rack applications directly (through rack/test), which boosts the
28
+ test suite.
20
29
 
21
- * Extra goodness for Rubyists: being written in ruby, Webspicy also supports
22
- testing Rack applications directly (through rack/test)
30
+ * Extra goodies: when a specification is written, it can also be used for
31
+ mocking the API, generating an openapi file, etc.
23
32
 
24
- ## Getting started
33
+ ## Getting started with the commandline
25
34
 
26
- Please have a look at the example first. It contains a simple Sinatra application
27
- with GET and POST restful services tested with the framework. The Rakefile contains
28
- the necessary tasks to run those tests.
35
+ To install webspicy on your developer computer, install ruby then:
29
36
 
30
- ## Executing the tests using the command line
37
+ ```
38
+ gem install webspicy
39
+ ```
31
40
 
32
- Please have a look at the examples first. Then:
41
+ Then execute webspicy help to see the options.
33
42
 
34
43
  ```
35
44
  webspicy --help
36
- webspicy path/to/your/config.rb
37
45
  ```
38
46
 
39
- ## Using the docker image
47
+ ## Using the docker image(s)
48
+
49
+ If you just want to play with the commandline tool without having to
50
+ install ruby & webspicy, you can use the docker image we provide for
51
+ the commandline:
52
+
53
+ ```
54
+ docker run enspirit/webspicy --help
55
+ ```
56
+
57
+ If you have a specification & test suite somewhere, an easy way to run the
58
+ whole suite (or integrate it in your continuous integration pipeline) is
59
+ to use our `:tester` docker image. Just mount your test suite as a volume
60
+ in `/home/app` and you are good to go:
40
61
 
41
- A docker image running your tests is provided. It expects a volume with the
42
- tests to run put in `/home/app`.
62
+ ```
63
+ docker run -v path/to/tests:/formalspec enspirit/webspicy-tester
64
+ ```
65
+
66
+ If your plan is to test a backend that runs on your own machine (vs.
67
+ publicly on the Internet or inside the default docker network),
68
+ you will need to add some networking option, as shown below. Please
69
+ refer to Docker documentation.
43
70
 
44
71
  ```
45
- docker run enspirit/webspicy -v path/to/tests:/home/app
72
+ docker run -v path/to/tests:/formalspec --network=host enspirit/webspicy-tester
46
73
  ```
74
+
75
+ ## Contributing
76
+
77
+ Please use github issues for questions and bugs, and pull requests for
78
+ submitting improvement proposals and new features.
79
+
80
+ ## Contributors
81
+
82
+ * Bernard Lambeau (blambeau)
83
+ * Louis Lambeau (llambeau)
84
+ * Yoann Guyot (ygu)
85
+ * Felix Holmgren (@felixyz)
86
+
87
+ Enspirit (https://enspirit.be) and Klaro App (https://klaro.cards) are
88
+ both actively using, contributing and funding work on this library.
89
+ Please contact Bernard Lambeau for any question.
90
+
91
+ ## Licence
92
+
93
+ Webspicy is distributed under a MIT Licence, by Enspirit SRL.
@@ -1,15 +1,25 @@
1
1
  #!/usr/bin/env ruby
2
- #/ Document and test RESTful webservices
3
- #/ (c) Enspirit SPRL. Distributed under MIT licence.
4
- #/ Usage: webspicy [options] path/to/config.rb
2
+ #/
3
+ #/ Document & test web services as black-box operations.
4
+ #/ (c) Enspirit SRL. Distributed under MIT licence.
5
+ #/
6
+ #/ Usage: webspicy [options] URL # run default test againt url
7
+ #/ Usage: webspicy [options] path/to/config.rb # run whole test suite
8
+ #/ Usage: webspicy [options] path/to/spec.yml # run a single test
9
+ #/
10
+ #/ Options:
11
+ #/ -h, --help Show this help message
12
+ #/ -v, --version Show webspicy version
13
+ #/ --debug Same as LOG_LEVEL=DEBUG, takes precedence
5
14
  #/
6
15
  #/ Recognized env vars:
7
- #/ - ROBUST=no do not execute counterexamples
16
+ #/ - ROBUST=no|only|generated execute no counterexamples (only them, only generated ones)
8
17
  #/ - LOG_LEVEL=INFO|DEBUG|... set log level to the appropriate level
9
18
  #/ - RESOURCE=... restrict to .yml test files matching the pattern
10
- #/ - METHOD=GET|POST|DELETE... execute only tests matching the verb
19
+ #/ - METHOD=GET|POST|DELETE... execute only tests matching the HTTP verb
11
20
  #/ - TAG=... execute only tests matching the given tag
12
21
  #/ - FAILFAST=yes|no stop executing tests on first failure
22
+ #/
13
23
  require 'webspicy'
14
24
  require 'webspicy/tester'
15
25
  require 'optparse'
@@ -20,19 +30,25 @@ def showhelp
20
30
  end
21
31
 
22
32
  ARGV.options do |opts|
23
- opts.on_tail("-h", "--help"){ showhelp }
33
+ opts.on_tail("-h", "--help"){
34
+ showhelp
35
+ }
36
+ opts.on("-v", "--version"){
37
+ puts "webspicy v#{Webspicy::VERSION}, (c) Enspirit SRL"
38
+ exit(0)
39
+ }
40
+ opts.on("--debug") {
41
+ ENV['LOG_LEVEL'] = 'DEBUG'
42
+ Webspicy::LOGGER.level = Logger.const_get(ENV['LOG_LEVEL'])
43
+ }
24
44
  opts.parse!
25
45
  end
26
46
 
27
47
  if ARGV.size != 1
28
48
  showhelp
29
49
  exit(-1)
30
- elsif (p = Path(ARGV.first)).exists?
31
- config = Webspicy::Configuration.dress(p)
32
- res = Webspicy::Tester.new(config).call
33
- abort("Some tests failed") unless res == 0
34
- else
35
- puts "No such file or directory `#{ARGV.first}`"
36
- showhelp
37
- exit(-1)
38
50
  end
51
+
52
+ config = Webspicy::Configuration.dress(ARGV[0])
53
+ res = Webspicy::Tester.new(config).call
54
+ abort("Some tests failed") unless res == 0
@@ -1,12 +1,14 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- webspicy (0.15.8)
5
- finitio (>= 0.8.0)
4
+ webspicy (0.16.0)
5
+ colorize (~> 0.8.1)
6
+ finitio (~> 0.9.0)
6
7
  http (>= 2)
7
8
  mustermann (~> 1.0)
8
9
  mustermann-contrib
9
- path (>= 1.3)
10
+ openapi3_parser (~> 0.8.2)
11
+ path (~> 2.0)
10
12
  rack-robustness (~> 1.1, >= 1.1.0)
11
13
  rack-test (~> 0.6.3)
12
14
  rspec (~> 3.7)
@@ -18,6 +20,10 @@ GEM
18
20
  addressable (2.7.0)
19
21
  public_suffix (>= 2.0.2, < 5.0)
20
22
  citrus (3.0.2)
23
+ colorize (0.8.1)
24
+ commonmarker (0.21.0)
25
+ ruby-enum (~> 0.5)
26
+ concurrent-ruby (1.1.7)
21
27
  diff-lcs (1.4.4)
22
28
  domain_name (0.5.20190701)
23
29
  unf (>= 0.0.5, < 1.0.0)
@@ -25,7 +31,7 @@ GEM
25
31
  ffi-compiler (1.0.1)
26
32
  ffi (>= 1.0.0)
27
33
  rake
28
- finitio (0.8.0)
34
+ finitio (0.9.0)
29
35
  citrus (>= 2.4, < 4.0)
30
36
  hansi (0.2.0)
31
37
  http (4.4.1)
@@ -36,42 +42,50 @@ GEM
36
42
  http-cookie (1.0.3)
37
43
  domain_name (~> 0.5)
38
44
  http-form_data (2.3.0)
39
- http-parser (1.2.1)
40
- ffi-compiler (>= 1.0, < 2.0)
45
+ http-parser (1.2.2)
46
+ ffi-compiler
47
+ i18n (1.8.5)
48
+ concurrent-ruby (~> 1.0)
41
49
  mustermann (1.1.1)
42
50
  ruby2_keywords (~> 0.0.1)
43
51
  mustermann-contrib (1.1.1)
44
52
  hansi (~> 0.2.0)
45
53
  mustermann (= 1.1.1)
54
+ openapi3_parser (0.8.2)
55
+ commonmarker (~> 0.17)
56
+ psych (~> 3.1)
46
57
  path (2.0.1)
47
- public_suffix (4.0.5)
58
+ psych (3.2.1)
59
+ public_suffix (4.0.6)
48
60
  rack (2.2.3)
49
- rack-protection (2.0.8.1)
61
+ rack-protection (2.1.0)
50
62
  rack
51
63
  rack-robustness (1.1.0)
52
64
  rack-test (0.6.3)
53
65
  rack (>= 1.0)
54
66
  rake (12.3.3)
55
- rspec (3.9.0)
56
- rspec-core (~> 3.9.0)
57
- rspec-expectations (~> 3.9.0)
58
- rspec-mocks (~> 3.9.0)
59
- rspec-core (3.9.2)
60
- rspec-support (~> 3.9.3)
61
- rspec-expectations (3.9.2)
67
+ rspec (3.10.0)
68
+ rspec-core (~> 3.10.0)
69
+ rspec-expectations (~> 3.10.0)
70
+ rspec-mocks (~> 3.10.0)
71
+ rspec-core (3.10.0)
72
+ rspec-support (~> 3.10.0)
73
+ rspec-expectations (3.10.0)
62
74
  diff-lcs (>= 1.2.0, < 2.0)
63
- rspec-support (~> 3.9.0)
64
- rspec-mocks (3.9.1)
75
+ rspec-support (~> 3.10.0)
76
+ rspec-mocks (3.10.0)
65
77
  diff-lcs (>= 1.2.0, < 2.0)
66
- rspec-support (~> 3.9.0)
67
- rspec-support (3.9.3)
78
+ rspec-support (~> 3.10.0)
79
+ rspec-support (3.10.0)
68
80
  rspec_junit_formatter (0.4.1)
69
81
  rspec-core (>= 2, < 4, != 2.12.0)
82
+ ruby-enum (0.8.0)
83
+ i18n
70
84
  ruby2_keywords (0.0.2)
71
- sinatra (2.0.8.1)
85
+ sinatra (2.1.0)
72
86
  mustermann (~> 1.0)
73
- rack (~> 2.0)
74
- rack-protection (= 2.0.8.1)
87
+ rack (~> 2.2)
88
+ rack-protection (= 2.1.0)
75
89
  tilt (~> 2.0)
76
90
  tilt (2.0.10)
77
91
  unf (0.1.4)
@@ -80,6 +94,7 @@ GEM
80
94
 
81
95
  PLATFORMS
82
96
  ruby
97
+ x86_64-darwin-15
83
98
 
84
99
  DEPENDENCIES
85
100
  rake (~> 12)
@@ -87,4 +102,4 @@ DEPENDENCIES
87
102
  webspicy!
88
103
 
89
104
  BUNDLED WITH
90
- 2.0.2
105
+ 2.2.1
@@ -1,6 +1,5 @@
1
1
  $LOAD_PATH.unshift File.expand_path("..", __FILE__)
2
2
  require 'app'
3
- require 'webspicy'
4
3
 
5
4
  desc "Checks all .yml definition files"
6
5
  task :check do
@@ -1,3 +1,4 @@
1
+ require 'webspicy'
1
2
  require 'sinatra'
2
3
  require 'json'
3
4
  require 'path'
@@ -65,6 +66,7 @@ post '/reset' do
65
66
  end
66
67
 
67
68
  get '/todo/' do
69
+ raise unless request.env['HTTP_ACCEPT'] == 'application/json'
68
70
  content_type :json
69
71
  settings.todolist.to_json
70
72
  end
@@ -94,6 +96,7 @@ post '/todo/', :auth => :user do
94
96
  end
95
97
 
96
98
  get '/todo/:id' do |id|
99
+ raise unless request.env['HTTP_ACCEPT'] == 'application/json'
97
100
  content_type :json
98
101
  todo = settings.todolist.find{|todo| todo[:id] == Integer(id) }
99
102
  if todo.nil?
@@ -111,7 +114,7 @@ patch '/todo/:id', :auth => :user do |id|
111
114
  status 404
112
115
  {error: "No such todo"}.to_json
113
116
  else
114
- patch = SCHEMA["TodoPatch"].dress(loaded_body)
117
+ patch = SCHEMA["TodoPatch"].dress(loaded_body.merge("id" => Integer(id)))
115
118
  patched = todo.merge(patch)
116
119
  settings.todolist = settings.todolist.reject{|todo| todo[:id] == Integer(id) }
117
120
  settings.todolist << patched
@@ -4,6 +4,14 @@ def webspicy_config(&bl)
4
4
  c.precondition MustBeAuthenticated
5
5
  c.precondition MustBeAnAdmin
6
6
 
7
+ c.precondition Webspicy::Specification::Precondition::GlobalRequestHeaders.new({
8
+ 'Accept' => 'application/json'
9
+ }){|service| service.method == "GET" }
10
+
11
+ c.precondition Webspicy::Specification::Precondition::RobustToInvalidInput.new
12
+
13
+ c.postcondition TodoRemoved
14
+
7
15
  c.instrument do |tc, client|
8
16
  role = tc.metadata[:role]
9
17
  tc.headers['Authorization'] = "Bearer #{role}" if role
@@ -1,6 +1,6 @@
1
1
  require_relative 'config'
2
2
  webspicy_config do |c|
3
- c.client = Webspicy::RackTestClient.for(::Sinatra::Application)
3
+ c.client = Webspicy::Tester::RackTestClient.for(::Sinatra::Application)
4
4
  c.before_each do |_,client|
5
5
  client.api.post "/reset"
6
6
  end
@@ -1,7 +1,7 @@
1
1
  require_relative 'config'
2
2
  webspicy_config do |c|
3
3
  c.host = "http://127.0.0.1:4567"
4
- c.client = Webspicy::HttpClient
4
+ c.client = Webspicy::Tester::HttpClient
5
5
  c.before_each do |_,client|
6
6
  client.api.post "http://127.0.0.1:4567/reset"
7
7
  end
@@ -1,4 +1,4 @@
1
- @import finitio/data
1
+ @import webspicy/scalars
2
2
 
3
3
  Todo = {
4
4
  id : Integer
@@ -6,7 +6,7 @@ Todo = {
6
6
  }
7
7
 
8
8
  TodoPatch = {
9
- id :? Integer
9
+ id : Integer
10
10
  description :? String
11
11
  }
12
12
 
@@ -30,7 +30,7 @@ class MustBeAuthenticated
30
30
  def counterexample(description, role, expected, status = 401)
31
31
  YAML.load <<-YML.gsub(/^\s+[#][ ]/, "")
32
32
  # description: |-
33
- # (#{self.class.name}) #{description}
33
+ # #{description} (#{self.class.name} PRE)
34
34
  # params:
35
35
  # id: 1
36
36
  # dress_params:
@@ -41,7 +41,7 @@ class MustBeAuthenticated
41
41
  # content_type: application/json
42
42
  # status: #{status}
43
43
  # assert:
44
- # - "pathFD('', error: '#{expected}')"
44
+ # - "pathFD('', error: '#{expected}')"
45
45
  YML
46
46
  end
47
47
 
@@ -0,0 +1,18 @@
1
+ class TodoRemoved
2
+ include Webspicy::Specification::Postcondition
3
+
4
+ def self.match(service, descr)
5
+ return TodoRemoved.new if descr =~ /The todo has been removed/
6
+ end
7
+
8
+ def check(invocation)
9
+ client = invocation.client
10
+ id = invocation.test_case.params['id']
11
+ url = "/todo/#{id}"
12
+ response = client.api.get(url, {}, {
13
+ "Accept" => "application/json"
14
+ })
15
+ return nil if response.status == 404
16
+ "Todo `#{id}` was not deleted, it has been found"
17
+ end
18
+ end
@@ -15,13 +15,16 @@ services:
15
15
  preconditions:
16
16
  - Must be an admin
17
17
 
18
+ postconditions:
19
+ - The todo has been removed
20
+
18
21
  input_schema: |-
19
22
  {
20
23
  id: Integer
21
24
  }
22
25
 
23
26
  output_schema: |-
24
- .
27
+ Any
25
28
 
26
29
  error_schema: |-
27
30
  ErrorSchema