webspicy 0.16.1 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -5
  3. data/bin/webspicy +6 -1
  4. data/doc/1-black-box-scene.md +109 -0
  5. data/doc/2-black-box-testing.md +27 -0
  6. data/doc/3-specification-importance.md +41 -0
  7. data/doc/4-sequence-diagram.md +82 -0
  8. data/lib/webspicy.rb +15 -4
  9. data/lib/webspicy/configuration.rb +57 -8
  10. data/lib/webspicy/configuration/scope.rb +22 -16
  11. data/lib/webspicy/formaldoc.fio +3 -1
  12. data/lib/webspicy/specification.rb +12 -10
  13. data/lib/webspicy/specification/condition.rb +23 -0
  14. data/lib/webspicy/specification/errcondition.rb +17 -0
  15. data/lib/webspicy/specification/postcondition.rb +1 -0
  16. data/lib/webspicy/specification/precondition.rb +1 -0
  17. data/lib/webspicy/specification/precondition/robust_to_invalid_input.rb +1 -1
  18. data/lib/webspicy/specification/service.rb +38 -25
  19. data/lib/webspicy/specification/test_case.rb +10 -17
  20. data/lib/webspicy/support.rb +22 -0
  21. data/lib/webspicy/support/data_object.rb +25 -0
  22. data/lib/webspicy/support/hooks.rb +65 -0
  23. data/lib/webspicy/support/world.rb +47 -0
  24. data/lib/webspicy/tester.rb +120 -61
  25. data/lib/webspicy/tester/asserter.rb +9 -4
  26. data/lib/webspicy/tester/assertions.rb +8 -9
  27. data/lib/webspicy/tester/client.rb +22 -42
  28. data/lib/webspicy/tester/failure.rb +6 -0
  29. data/lib/webspicy/tester/file_checker.rb +22 -0
  30. data/lib/webspicy/tester/invocation.rb +15 -196
  31. data/lib/webspicy/tester/reporter.rb +85 -0
  32. data/lib/webspicy/tester/reporter/composite.rb +38 -0
  33. data/lib/webspicy/tester/reporter/documentation.rb +67 -0
  34. data/lib/webspicy/tester/reporter/error_count.rb +25 -0
  35. data/lib/webspicy/tester/reporter/exceptions.rb +60 -0
  36. data/lib/webspicy/tester/reporter/file_progress.rb +22 -0
  37. data/lib/webspicy/tester/reporter/file_summary.rb +42 -0
  38. data/lib/webspicy/tester/reporter/progress.rb +28 -0
  39. data/lib/webspicy/tester/reporter/summary.rb +62 -0
  40. data/lib/webspicy/tester/result.rb +139 -0
  41. data/lib/webspicy/tester/result/assert_met.rb +29 -0
  42. data/lib/webspicy/tester/result/check.rb +33 -0
  43. data/lib/webspicy/tester/result/errcondition_met.rb +29 -0
  44. data/lib/webspicy/tester/result/error_schema_met.rb +24 -0
  45. data/lib/webspicy/tester/result/output_schema_met.rb +24 -0
  46. data/lib/webspicy/tester/result/postcondition_met.rb +29 -0
  47. data/lib/webspicy/tester/result/response_header_met.rb +43 -0
  48. data/lib/webspicy/tester/result/response_status_met.rb +25 -0
  49. data/lib/webspicy/version.rb +2 -2
  50. data/lib/webspicy/web.rb +4 -0
  51. data/lib/webspicy/web/client.rb +15 -0
  52. data/lib/webspicy/{tester → web}/client/http_client.rb +34 -14
  53. data/lib/webspicy/{tester → web}/client/rack_test_client.rb +3 -3
  54. data/lib/webspicy/{tester → web}/client/support.rb +2 -2
  55. data/lib/webspicy/web/invocation.rb +65 -0
  56. data/lib/webspicy/web/mocker.rb +90 -0
  57. data/lib/webspicy/web/mocker/config.ru +6 -0
  58. data/lib/webspicy/{openapi.rb → web/openapi.rb} +0 -0
  59. data/lib/webspicy/web/openapi/generator.rb +129 -0
  60. data/spec/unit/configuration/scope/test_each_service.rb +2 -2
  61. data/spec/unit/configuration/scope/test_each_specification.rb +7 -7
  62. data/spec/unit/specification/test_condition.rb +26 -0
  63. data/spec/unit/support/hooks/test_fire_after_each.rb +53 -0
  64. data/spec/unit/{tester/client/test_around.rb → support/hooks/test_fire_around.rb} +15 -10
  65. data/spec/unit/support/hooks/test_fire_before_each.rb +53 -0
  66. data/spec/unit/support/world/fixtures/array.json +8 -0
  67. data/spec/unit/support/world/fixtures/queue.rb +1 -0
  68. data/spec/unit/support/world/fixtures/single.json +11 -0
  69. data/spec/unit/support/world/fixtures/yaml.yml +3 -0
  70. data/spec/unit/support/world/test_world.rb +56 -0
  71. data/spec/unit/test_configuration.rb +50 -1
  72. data/spec/unit/tester/test_asserter.rb +198 -3
  73. data/spec/unit/tester/test_assertions.rb +8 -6
  74. data/spec/unit/web/mocker/test_mocker.rb +35 -0
  75. data/spec/unit/web/openapi/test_generator.rb +31 -0
  76. metadata +72 -61
  77. data/examples/restful/Gemfile +0 -5
  78. data/examples/restful/Gemfile.lock +0 -105
  79. data/examples/restful/Rakefile +0 -25
  80. data/examples/restful/app.rb +0 -180
  81. data/examples/restful/webspicy/config.rb +0 -23
  82. data/examples/restful/webspicy/rack.rb +0 -7
  83. data/examples/restful/webspicy/real.rb +0 -8
  84. data/examples/restful/webspicy/schema.fio +0 -20
  85. data/examples/restful/webspicy/support/must_be_an_admin.rb +0 -20
  86. data/examples/restful/webspicy/support/must_be_authenticated.rb +0 -48
  87. data/examples/restful/webspicy/support/todo_removed.rb +0 -18
  88. data/examples/restful/webspicy/todo/deleteTodo.yml +0 -52
  89. data/examples/restful/webspicy/todo/getTodo.yml +0 -50
  90. data/examples/restful/webspicy/todo/getTodoSingleServiceFormat.yml +0 -46
  91. data/examples/restful/webspicy/todo/getTodos.yml +0 -36
  92. data/examples/restful/webspicy/todo/options.yml +0 -32
  93. data/examples/restful/webspicy/todo/patchTodo.yml +0 -66
  94. data/examples/restful/webspicy/todo/postCsv.yml +0 -43
  95. data/examples/restful/webspicy/todo/postFile.yml +0 -40
  96. data/examples/restful/webspicy/todo/postTodos.yml +0 -51
  97. data/examples/restful/webspicy/todo/putTodo.yml +0 -65
  98. data/examples/restful/webspicy/todo/todos.csv +0 -4
  99. data/examples/single_spec/spec.yml +0 -59
  100. data/examples/website/config.rb +0 -2
  101. data/examples/website/schema.fio +0 -1
  102. data/examples/website/specification/get-http.yml +0 -34
  103. data/examples/website/specification/get-https.yml +0 -34
  104. data/lib/webspicy/checker.rb +0 -25
  105. data/lib/webspicy/mocker.rb +0 -88
  106. data/lib/webspicy/openapi/generator.rb +0 -127
  107. data/lib/webspicy/tester/rspec_asserter.rb +0 -108
  108. data/lib/webspicy/tester/rspec_matchers.rb +0 -104
  109. data/spec/unit/mocker/test_mocker.rb +0 -32
  110. data/spec/unit/openapi/test_generator.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 445a2cc26015bc9a25efcbef22a2611aedc4d6fa5ff57fdbeac0aeed8447cdb6
4
- data.tar.gz: 94e713312855382b55b55d6a1709635900426bc8d9929fefa22d79207cbb5ae0
3
+ metadata.gz: 614e5904931375bd6f4df435d33736cde757e752d0d759fbc3af4e185b9cd9e4
4
+ data.tar.gz: 8d63e07e93809bd5139300e5206f0a3b3204e86d77faea60a29302e5787413d1
5
5
  SHA512:
6
- metadata.gz: 33afca9646dec9268ed8fc5581f9a10cd73fce7cd170b8f999bb43d6c66e94f1decc9161803134d7885d5ee27a1f4d262511faaed7ffb3b9da4ba92e93b95ee2
7
- data.tar.gz: e11ab7abb09d9a8796e9946b2424b9bd11c46e82f9ab43219fdfec2ba969580fa5a6d5e89d202d17494f9f7d659990efdd8428f0a730770d5d1ccccbc79996f1
6
+ metadata.gz: 33d6a69e097e14a90f8b69edb4833a4a1325cec38513bf8f88d017b31847e08b310acce50dc7fb3d3cbdeefdff76b3497b489adbc2e965c7e8b12f0228a63524
7
+ data.tar.gz: 0d6cf55d54a6bb94b48511f9c178a1e5e673772749784b3c7c720d9413670dc1e93029cfa0687efd8fced6f91eb699ea5cae4ab15e40a674dea7843712dec114
data/README.md CHANGED
@@ -1,11 +1,13 @@
1
+ [![Build Status](https://travis-ci.com/enspirit/webspicy.svg?branch=master)](https://travis-ci.com/enspirit/webspicy)
1
2
  # Webspicy
2
3
 
3
4
  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.
5
+ operations. Webspicy yields a better test coverage for a smaller testing effort.
6
6
 
7
7
  See webspicy in action and make the tutorial on https://yourbackendisbroken.dev
8
8
 
9
+ Have a look at `doc/*.md` for vocabulary and vision as well as `ROADMAP.md`.
10
+
9
11
  ## Features
10
12
 
11
13
  * Declarative specification of HTTP web services + their tests
@@ -19,7 +21,7 @@ See webspicy in action and make the tutorial on https://yourbackendisbroken.dev
19
21
  your API design better.
20
22
 
21
23
  * Formal and human-friendly data schema with strong data matching semantics,
22
- thanks to finitio.io
24
+ thanks to [http://finitio.io](http://finitio.io)
23
25
 
24
26
  * Test instrumentation and generation, based on PRE & POST contracts.
25
27
 
@@ -30,6 +32,10 @@ See webspicy in action and make the tutorial on https://yourbackendisbroken.dev
30
32
  * Extra goodies: when a specification is written, it can also be used for
31
33
  mocking the API, generating an openapi file, etc.
32
34
 
35
+ ## Is this used on real-world cases?
36
+
37
+ Yes, `webspicy` is currently used on a dozen production components. Our biggest specification has 324 specification files for thousands of tests, 35% of them being generated.
38
+
33
39
  ## Getting started with the commandline
34
40
 
35
41
  To install webspicy on your developer computer, install ruby then:
@@ -60,7 +66,7 @@ to use our `:tester` docker image. Just mount your test suite as a volume
60
66
  in `/home/app` and you are good to go:
61
67
 
62
68
  ```
63
- docker run -v path/to/tests:/formalspec enspirit/webspicy-tester
69
+ docker run -v path/to/tests:/formalspec enspirit/webspicy:tester
64
70
  ```
65
71
 
66
72
  If your plan is to test a backend that runs on your own machine (vs.
@@ -69,7 +75,7 @@ you will need to add some networking option, as shown below. Please
69
75
  refer to Docker documentation.
70
76
 
71
77
  ```
72
- docker run -v path/to/tests:/formalspec --network=host enspirit/webspicy-tester
78
+ docker run -v path/to/tests:/formalspec --network=host enspirit/webspicy:tester
73
79
  ```
74
80
 
75
81
  ## Contributing
data/bin/webspicy CHANGED
@@ -9,6 +9,7 @@
9
9
  #/
10
10
  #/ Options:
11
11
  #/ -h, --help Show this help message
12
+ #/ -k, --insecure Allow insecure server connections when using SSL
12
13
  #/ -v, --version Show webspicy version
13
14
  #/ --debug Same as LOG_LEVEL=DEBUG, takes precedence
14
15
  #/
@@ -19,6 +20,7 @@
19
20
  #/ - METHOD=GET|POST|DELETE... execute only tests matching the HTTP verb
20
21
  #/ - TAG=... execute only tests matching the given tag
21
22
  #/ - FAILFAST=yes|no stop executing tests on first failure
23
+ #/ - INSECURE=yes|no allow insecure server connections when using SSL
22
24
  #/
23
25
  require 'webspicy'
24
26
  require 'webspicy/tester'
@@ -37,6 +39,9 @@ ARGV.options do |opts|
37
39
  puts "webspicy v#{Webspicy::VERSION}, (c) Enspirit SRL"
38
40
  exit(0)
39
41
  }
42
+ opts.on('-k', '--insecure') {
43
+ ENV['INSECURE'] = 'yes'
44
+ }
40
45
  opts.on("--debug") {
41
46
  ENV['LOG_LEVEL'] = 'DEBUG'
42
47
  Webspicy::LOGGER.level = Logger.const_get(ENV['LOG_LEVEL'])
@@ -51,4 +56,4 @@ end
51
56
 
52
57
  config = Webspicy::Configuration.dress(ARGV[0])
53
58
  res = Webspicy::Tester.new(config).call
54
- abort("Some tests failed") unless res == 0
59
+ abort("#{res} errors occured") unless res == 0
@@ -0,0 +1,109 @@
1
+ # Setting the black-box scene
2
+
3
+ This document sets the black-box testing & specification scene. We start with the testing vocabulary (that is probably well known) and gradually introduce specification concepts (that are a bit less).
4
+
5
+ ## Test object
6
+
7
+ The `Test object` is the software under test, generally a backend component exposing web services. As `webspicy` is also used for documentation & specification, we sometimes call it the `Specification object` or `Documentation object`.
8
+
9
+ The test object is seen as a black-box: its specification and testing are in terms of observable behavior, not driven by the internal structure or implementation.
10
+
11
+ ## Test item
12
+
13
+ A `Test item` (resp. `Specification item`) is an individual element to be tested (resp. specified). `webspicy` is generally used to test web services invoked thanks to HTTP. If we abstract from HTTP details - and see it as the request/response invocation protocol only - test items are high-level software operations called with input/output data.
14
+
15
+ ## Test case
16
+
17
+ A `Test case` is a complete setting for invoking a test item, together with assertions on the result. The setting includes a `Current system state` and a `Request` (that contains `Input` data). The result covers the `Resulting system state`, and a `Response` (that contains `Output` data).
18
+
19
+ ## Test suite
20
+
21
+ A `Test suite` of an object is the set of all its test cases.
22
+
23
+ ## System state
24
+
25
+ Most of the time we are interested in (deterministic) *stateful* testing. That is, we consider that the behavior of a test item is not only influenced by the `Input` data but also by the current system state.
26
+
27
+ The `System state` covers the content of all stateful components the test object interacts with in its environment: files, databases, caches, buses, etc.
28
+
29
+ For effective testing, one needs to be able to control and check the system state easily.
30
+
31
+ ## Current system state
32
+
33
+ A `Current system state` is the state of the system just before invoking a test item.
34
+
35
+ ## Resulting system state
36
+
37
+ A `Resulting system state` is the state of the system just after invoking a test item from an current state.
38
+
39
+ ## Request
40
+
41
+ A `Request` is what is sent to a test object to invoke a test item. When test items are web services, it is a HTTP request specifically.
42
+
43
+ ## Response
44
+
45
+ A `Response` is what is received from the test object in return from a test item invocation request. When test items are web services, it is a HTTP response specifically.
46
+
47
+ ## Input
48
+
49
+ The `Input` is the data on which a high-level operation is executed. In a similar way that a high-level operation abstracts from web services details, the input abstracts from HTTP request details.
50
+
51
+ ## Output
52
+
53
+ The `Output` is the data returned by a high-level operation after execution. In a similar way that a high-level operation abstracts from web services details, the output abstracts from HTTP response details.
54
+
55
+ ## Precondition
56
+
57
+ A `Precondition` is a necessary condition to be met for the test item to execute successfully when invoked. A precondition can refer to the current state, the request, and/or the input.
58
+
59
+ The set of preconditions of an item is sometimes written `PRE`.
60
+
61
+ ## Postcondition
62
+
63
+ A `Postcondition` is a condition that is guaranteed by the test item (if implemented correctly) when invoked while its preconditions holds. A postcondition can refer to the current state (before execution), the request, the input, the resulting state, the response, and/or the output.
64
+
65
+ ## Input schema
66
+
67
+ The `Input schema` is a formal definition of the set of valid input data of a test item (hence the underlying high-level operation). The input schema is a `webspicy` formal shortcut for a precondition stating that "input data must be valid, that is ...".
68
+
69
+ (The input schema can also be seen as the signature of the high-level operation.)
70
+
71
+ ## Output schema
72
+
73
+ The `Output schema` is a formal definition of the set of possible output data of a test item (idem). The output schema is a `webspicy` formal shortcut for a postcondition stating that "output data is valid, that is ...".
74
+
75
+ (The output schema can also be seen as the return type of the high-level operation.)
76
+
77
+ ## Ideal specification
78
+
79
+ An `Ideal specification` is a formal identification of an item, together with the set of its pre and post conditions. By nature the ideal specification covers the input and output schema.
80
+
81
+ ## Example
82
+
83
+ An `Example` is a positive test case. That is, it is the description of an invocation setting that meets all preconditions of a test item together with assertions on the successful result.
84
+
85
+ ## Counterexample
86
+
87
+ A `Counterexample` is a negative test case. That is, it is the description of an invocation setting that violates at least one precondition, together with assertions on the error result.
88
+
89
+ ## Errcondition
90
+
91
+ An `Errcondition` is a condition that is guaranteed by the test item (if implemented correctly) when invoked while at least one precondition is violated. An errcondition can refer to the current state (before execution), the request, the input, the resulting state, the response, and/or the output.
92
+
93
+ An item is said to be robust when it has strong errconditions: it guarantees some behavior and results even in case of execution failures.
94
+
95
+ ## Error schema
96
+
97
+ The `Error schema` is a formal definition of the set of possible output data of a test item when it fails to execute successfully, typically because a precondition is violated. The error schema is a `webspicy` formal shortcut for an errcondition stating that "error data must be valid, that is ...".
98
+
99
+ ## Exceptional specification
100
+
101
+ An `Exceptional specification` is a formal identification of an item, together with the set of its pre and err conditions. By nature the exceptional specification covers the input and err schema.
102
+
103
+ ## Item specification
104
+
105
+ An `Item specification` is the set of its ideal and exception specications. Therefore it includes all schema, pre, post and err conditions.
106
+
107
+ ## Specification
108
+
109
+ A `Specification` of an object is the set of all its item specifications.
@@ -0,0 +1,27 @@
1
+ # Black-box testing
2
+
3
+ We define here what we call `black-box testing`, using the vocabulary installed previously.
4
+
5
+ ## Objective
6
+
7
+ Black-box testing aims at checking whether a test object (actually its implementation) meets its specification. It does so by looking at the object's observable behavior only.
8
+
9
+ ## Method
10
+
11
+ Testing is never exhaustive and gives no correctness guarantees. As one says, testing can only show the presence of defects, not their absence.
12
+
13
+ In practice, black-box testing meets its objective by checking whether:
14
+
15
+ * all positive test cases (i.e. examples) yield successful executions meeting the postconditions.
16
+
17
+ * all negative test cases (i.e. counterexamples) yield unsuccessful executions meeting the errconditions.
18
+
19
+ ## Prerequisites
20
+
21
+ Applying black-box testing to web services requires at least:
22
+
23
+ * A test item: a web service endpoint
24
+ * A specification: pre, post and err conditions of the web service
25
+ * Test cases: examples and counterexamples of web service usage
26
+
27
+ The second element, i.e. the *specification*, is both important and useful. Modern test frameworks leave the specification implicit (not written at all) or informal (written as code documentation). We think this is both a mistake and a lost opportunity. We will explain why in next section.
@@ -0,0 +1,41 @@
1
+ # On the importance of the specification
2
+
3
+ Modern software development methods and frameworks, especially Test-Driven (TDD) and Behavior-Driven Development (BDD), use tests extensively. As their name suggests, they use tests to *drive* the development. In fact, it is a major contribution of Agile methods to software development: driving the development by tests invites the developer to improve his code through testing and thereby also improves test coverage as a side effect of the development itself.
4
+
5
+ However this is not the traditional objective of software testing, which is to test the implementation's conformance to a specification. This yields strange situations where a lot of tests are written while the specification is not:
6
+
7
+ * Most of the time the specification is implicit: it is simply not written at all,
8
+ * Sometimes the specification is written as informal comments on the tested method or class,
9
+ * Some test frameworks even suggest that the set of tests *is* the specification, which is notably wrong.
10
+
11
+ ## What is a specification?
12
+
13
+ As a reminder, a `Specification` is the set of `PRE-`, `POST-` and `ERR-` `conditions` defining the contract between the test item (e.g. a web service) and its consumer. In short,
14
+
15
+ - if the consumer calls the service while the `PRE` are met, then the service guarantees that the `POST` are met.
16
+ - if the consumer calls the service while a `PRE` is not met, and the service is robust, then it guarantees that the `ERR` are met.
17
+
18
+ ## Advantages of an explicit specification
19
+
20
+ Having a explicit specification has traditional advantages:
21
+
22
+ - It documents the software, generally in a better and more consise way than a full test suite
23
+ - It enables reasoning about correctness: if you don't know the contractual conditions you can't actually know whether the test suite passes by chance of because the software implementation is correct
24
+
25
+ Beyond those, specifications can also be used somewhat "against the grain", in the test item / specification / test-case triangle. This is the reason why `webspicy` exists, as we want to explore the following advantages in the specific context of API testing:
26
+
27
+ - A specification can be used to make tests easier to write
28
+ * by instrumenting positive test cases so that preconditions are met with almost no effort from the tester
29
+ * by generating current system states automatically, instead of having to script them
30
+
31
+ - A specification can be used to generate test cases automatically
32
+ * generating examples aims at testing correctness
33
+ * generating counterexamples aims at testing robustness & security
34
+
35
+ - A specification can be used as a roadmap
36
+ * documenting unchecked preconditions highlights robustness weakenesses and calls for counterexamples
37
+ * documenting unmet postconditions highlights bugs and call for examples
38
+
39
+ - A specification may capture best practices and conventions
40
+ * Pre and post-conditions can sometimes be reused across different softwares, when they apply to conventions such as RESTful APIs
41
+
@@ -0,0 +1,82 @@
1
+ ```
2
+ @startuml
3
+ participant Tester
4
+ participant Client
5
+ participant Result
6
+ participant PrePost
7
+ participant Config
8
+ Tester -> Config : before_all(Scope, Client)
9
+ group * test case
10
+ Tester -> Config : before_each(TestCase, Client)
11
+ Tester -> Client : instrument(TestCase)
12
+ group * pre/post/err
13
+ Client -> PrePost : instrument(TestCase, Client)
14
+ end
15
+ Client -> Config : instrument(TestCase, Client)
16
+ Tester -> Client : call(TestCase)
17
+ Tester -> Result : check_response!
18
+ Tester -> Result : check_output!
19
+ Tester -> Result : check_assertions!
20
+ Tester -> Result : check_postconditions!
21
+ group * post/err
22
+ Result -> PrePost : check(Invocation)
23
+ end
24
+ Tester -> Config : after_each(TestCase, Client)
25
+ end
26
+ Tester -> Config : after_all(Scope, Client)
27
+ @enduml
28
+ ```
29
+
30
+ ┌──────┐ ┌──────┐ ┌──────┐ ┌───────┐ ┌──────┐
31
+ │Tester│ │Client│ │Result│ │PrePost│ │Config│
32
+ └──┬───┘ └──┬───┘ └──┬───┘ └───┬───┘ └──┬───┘
33
+ │ │ │ │ │
34
+ │ │ before_all(Scope, Client) │ │
35
+ │───────────────────────────────────────────────────────────────────────────>│
36
+ │ │ │ │ │
37
+ ╔══════════════╤═══════════════════╪═════════════════╪══════════════════╪═════════════════╪═════════════╗
38
+ ║ * TEST CASE │ │ │ │ │ ║
39
+ ╟──────────────┘ │ before_each(TestCase, Client) │ │ ║
40
+ ║ │───────────────────────────────────────────────────────────────────────────>│ ║
41
+ ║ │ │ │ │ │ ║
42
+ ║ │ instrument(TestCase)│ │ │ │ ║
43
+ ║ │────────────────────>│ │ │ │ ║
44
+ ║ │ │ │ │ │ ║
45
+ ║ │ ╔════════════╪════╤════════════╪══════════════════╪═════════════╗ │ ║
46
+ ║ │ ║ * PRE/POST/ERR │ │ │ ║ │ ║
47
+ ║ │ ╟─────────────────┘ │ │ ║ │ ║
48
+ ║ │ ║ │ instrument(TestCase, Client) │ ║ │ ║
49
+ ║ │ ║ │───────────────────────────────────>│ ║ │ ║
50
+ ║ │ ╚════════════╪═════════════════╪══════════════════╪═════════════╝ │ ║
51
+ ║ │ │ │ │ │ ║
52
+ ║ │ │ instrument(TestCase, Client) │ ║
53
+ ║ │ │─────────────────────────────────────────────────────>│ ║
54
+ ║ │ │ │ │ │ ║
55
+ ║ │ call(TestCase) │ │ │ │ ║
56
+ ║ │────────────────────>│ │ │ │ ║
57
+ ║ │ │ │ │ │ ║
58
+ ║ │ check_response! │ │ │ ║
59
+ ║ │──────────────────────────────────────>│ │ │ ║
60
+ ║ │ check_output! │ │ │ ║
61
+ ║ │──────────────────────────────────────>│ │ │ ║
62
+ ║ │ check_assertions! │ │ │ ║
63
+ ║ │──────────────────────────────────────>│ │ │ ║
64
+ ║ │ check_postconditions! │ │ │ ║
65
+ ║ │──────────────────────────────────────>│ │ │ ║
66
+ ║ │ │ │ │ │ ║
67
+ ║ │ │ ╔═════════════╤═════════════════╪═════════════╗ │ ║
68
+ ║ │ │ ║ * POST/ERR │ │ ║ │ ║
69
+ ║ │ │ ╟─────────────┘ │ ║ │ ║
70
+ ║ │ │ ║ │ check(Invocation)│ ║ │ ║
71
+ ║ │ │ ║ │─────────────────>│ ║ │ ║
72
+ ║ │ │ ╚════════════╪══════════════════╪═════════════╝ │ ║
73
+ ║ │ │ │ │ │ ║
74
+ ║ │ │ after_each(TestCase, Client) │ │ ║
75
+ ║ │───────────────────────────────────────────────────────────────────────────>│ ║
76
+ ╚════════════╪═════════════════════╪═════════════════╪══════════════════╪═════════════════╪═════════════╝
77
+ │ │ │ │ │
78
+ │ │ after_all(Scope, Client) │ │
79
+ │───────────────────────────────────────────────────────────────────────────>│
80
+ ┌──┴───┐ ┌──┴───┐ ┌──┴───┐ ┌───┴───┐ ┌──┴───┐
81
+ │Tester│ │Client│ │Result│ │PrePost│ │Config│
82
+ └──────┘ └──────┘ └──────┘ └───────┘ └──────┘
data/lib/webspicy.rb CHANGED
@@ -5,11 +5,11 @@ require 'finitio'
5
5
  require 'logger'
6
6
  require 'ostruct'
7
7
  require 'yaml'
8
- require 'rspec'
9
8
  require 'rack/test'
10
9
  require 'mustermann'
11
10
  require 'colorized_string'
12
11
  require 'securerandom'
12
+ require 'forwardable'
13
13
  module Webspicy
14
14
 
15
15
  ###
@@ -20,20 +20,24 @@ module Webspicy
20
20
  require 'webspicy/support'
21
21
  require 'webspicy/specification'
22
22
  require 'webspicy/configuration'
23
- require 'webspicy/checker'
24
23
  require 'webspicy/tester'
24
+ require 'webspicy/web'
25
+
26
+ class Error < StandardError; end
27
+ class TimeoutError < Error; end
25
28
 
26
29
  ###
27
30
  ### Backward compatibility
28
31
  ###
29
32
  Client = Tester::Client
30
- HttpClient = Tester::HttpClient
31
- RackTestClient = Tester::RackTestClient
33
+ HttpClient = Web::HttpClient
34
+ RackTestClient = Web::RackTestClient
32
35
  Resource = Specification
33
36
  Precondition = Specification::Precondition
34
37
  Postcondition = Specification::Postcondition
35
38
  FileUpload = Specification::FileUpload
36
39
  Scope = Configuration::Scope
40
+ Checker = Tester::FileChecker
37
41
 
38
42
  ###
39
43
  ### About folders
@@ -52,6 +56,12 @@ module Webspicy
52
56
  FIO
53
57
  FORMALDOC = Finitio.system(Path.dir/("webspicy/formaldoc.fio"))
54
58
 
59
+ ###
60
+ ### Exceptions that we let pass during testing
61
+ ###
62
+
63
+ PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, SystemExit]
64
+
55
65
  # Returns a default scope instance.
56
66
  def default_scope
57
67
  Configuration::Scope.new(Configuration.new)
@@ -62,6 +72,7 @@ module Webspicy
62
72
  raw = YAML.load(raw) if raw.is_a?(String)
63
73
  with_scope(scope) do
64
74
  r = FORMALDOC["Specification"].dress(raw)
75
+ r.config = scope.config
65
76
  r.located_at!(file) if file
66
77
  r
67
78
  end
@@ -3,14 +3,29 @@ module Webspicy
3
3
 
4
4
  LISTENER_KINDS = [ :before_all, :before_each, :after_all, :after_each, :around_each ]
5
5
 
6
- def initialize(folder = Path.pwd, parent = nil)
7
- @folder = folder
6
+ class << self
7
+ attr_accessor :default_folder
8
+
9
+ def with_default_folder(f)
10
+ old = default_folder
11
+ @default_folder = f
12
+ yield.tap{
13
+ @default_folder = old
14
+ }
15
+ end
16
+ end
17
+
18
+ def initialize(folder = Configuration.default_folder || Path.pwd, parent = nil)
19
+ @folder = folder.expand_path
8
20
  @parent = parent
9
21
  @children = []
10
22
  @preconditions = []
11
23
  @postconditions = []
24
+ @errconditions = []
25
+ @insecure = default_insecure
12
26
  @listeners = Hash.new{|h,k| h[k] = [] }
13
27
  @rspec_options = default_rspec_options
28
+ @failfast = default_failfast
14
29
  @run_examples = default_run_examples
15
30
  @run_counterexamples = default_run_counterexamples
16
31
  @run_generated_counterexamples = default_run_generated_counterexamples
@@ -23,14 +38,16 @@ module Webspicy
23
38
  :success => :green
24
39
  }
25
40
  @scope_factory = ->(config){ Scope.new(config) }
26
- @client = Tester::HttpClient
27
- Path.require_tree(folder/'support') if (folder/'support').exists?
41
+ @client = Web::HttpClient
42
+ Path.require_tree(@folder/'support') if (@folder/'support').exists?
43
+ @world = Support::World.new(folder/'world', self)
28
44
  yield(self) if block_given?
29
45
  end
30
46
  attr_accessor :folder
31
47
  protected :folder=
32
48
 
33
49
  attr_accessor :colors
50
+ attr_reader :world
34
51
 
35
52
  def self.dress(arg, &bl)
36
53
  case arg
@@ -43,9 +60,11 @@ module Webspicy
43
60
  when ->(f){ Path(f).exists? }
44
61
  arg = Path(arg)
45
62
  if arg.file? && arg.ext == ".rb"
46
- c = Kernel.instance_eval arg.read, arg.to_s
47
- yield(c) if block_given?
48
- c
63
+ Configuration.with_default_folder(arg.parent) do
64
+ c = Kernel.instance_eval arg.read, arg.to_s
65
+ yield(c) if block_given?
66
+ c
67
+ end
49
68
  elsif arg.file? && arg.ext == '.yml'
50
69
  folder = arg.backfind("[config.rb]")
51
70
  if folder && folder.exists?
@@ -81,7 +100,7 @@ module Webspicy
81
100
  config.each_scope(&bl)
82
101
  end
83
102
  else
84
- yield factor_scope
103
+ yield(factor_scope)
85
104
  end
86
105
  end
87
106
 
@@ -126,6 +145,13 @@ module Webspicy
126
145
  attr_accessor :postconditions
127
146
  protected :postconditions=
128
147
 
148
+ # Registers an errcondition matcher
149
+ def errcondition(clazz)
150
+ errconditions << clazz
151
+ end
152
+ attr_accessor :errconditions
153
+ protected :errconditions=
154
+
129
155
  # Returns whether this configuration has children configurations or not
130
156
  def has_children?
131
157
  !children.empty?
@@ -369,6 +395,28 @@ module Webspicy
369
395
  attr_accessor :rspec_options
370
396
  protected :rspec_options=
371
397
 
398
+ # Returns the default value for failfast
399
+ #
400
+ # The following environment variables <-> option are supported:
401
+ #
402
+ # - FAILFAST=yes <-> true
403
+ #
404
+ def default_failfast
405
+ ENV['FAILFAST'] == 'yes' || ENV['FAILFAST'] == "1"
406
+ end
407
+ attr_accessor :failfast
408
+
409
+ # Returns the default value to use for insecure.
410
+ #
411
+ # The following environment variables <-> option are supported:
412
+ #
413
+ # - INSECURE=yes <-> true
414
+ #
415
+ def default_insecure
416
+ ENV['INSECURE'] == 'yes' || ENV['INSECURE'] == "1"
417
+ end
418
+ attr_accessor :insecure
419
+
372
420
  # Returns the default rspec options.
373
421
  #
374
422
  # By default rspec colors are enabled and the format set to 'documentation'.
@@ -422,6 +470,7 @@ module Webspicy
422
470
  d.children = []
423
471
  d.preconditions = self.preconditions.dup
424
472
  d.postconditions = self.postconditions.dup
473
+ d.errconditions = self.errconditions.dup
425
474
  d.rspec_options = self.rspec_options.dup
426
475
  d.listeners = LISTENER_KINDS.inject({}){|ls,kind|
427
476
  ls.merge(kind => self.listeners(kind).dup)