pacto 0.3.1 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +29 -7
  4. data/.travis.yml +8 -1
  5. data/CONTRIBUTING.md +3 -6
  6. data/Gemfile +13 -2
  7. data/Guardfile +4 -4
  8. data/Procfile +1 -0
  9. data/README.md +47 -13
  10. data/Rakefile +66 -19
  11. data/TODO.md +33 -10
  12. data/bin/pacto +4 -0
  13. data/changelog.md +30 -0
  14. data/docs/configuration.md +69 -0
  15. data/docs/consumer.md +18 -0
  16. data/docs/cops.md +39 -0
  17. data/docs/forensics.md +66 -0
  18. data/docs/generation.md +65 -0
  19. data/docs/rake_tasks.md +10 -0
  20. data/docs/rspec.md +0 -0
  21. data/docs/samples.md +133 -0
  22. data/docs/server.md +34 -0
  23. data/docs/server_cli.md +18 -0
  24. data/docs/stenographer.md +20 -0
  25. data/features/configuration/strict_matchers.feature +10 -10
  26. data/features/evolve/existing_services.feature +12 -10
  27. data/features/generate/generation.feature +11 -11
  28. data/features/steps/pacto_steps.rb +17 -12
  29. data/features/stub/templates.feature +4 -4
  30. data/features/support/env.rb +21 -9
  31. data/features/validate/meta_validation.feature +9 -17
  32. data/features/validate/validation.feature +5 -6
  33. data/lib/pacto.rb +41 -33
  34. data/lib/pacto/actor.rb +5 -0
  35. data/lib/pacto/actors/from_examples.rb +67 -0
  36. data/lib/pacto/actors/json_generator.rb +20 -0
  37. data/lib/pacto/cli.rb +75 -0
  38. data/lib/pacto/cli/helpers.rb +20 -0
  39. data/lib/pacto/consumer.rb +80 -0
  40. data/lib/pacto/consumer/faraday_driver.rb +34 -0
  41. data/lib/pacto/contract.rb +48 -20
  42. data/lib/pacto/contract_builder.rb +125 -0
  43. data/lib/pacto/contract_factory.rb +31 -12
  44. data/lib/pacto/contract_files.rb +1 -0
  45. data/lib/pacto/contract_set.rb +12 -0
  46. data/lib/pacto/cops.rb +46 -0
  47. data/lib/pacto/cops/body_cop.rb +23 -0
  48. data/lib/pacto/cops/request_body_cop.rb +10 -0
  49. data/lib/pacto/cops/response_body_cop.rb +10 -0
  50. data/lib/pacto/{validators/response_header_validator.rb → cops/response_header_cop.rb} +9 -15
  51. data/lib/pacto/cops/response_status_cop.rb +18 -0
  52. data/lib/pacto/core/configuration.rb +16 -5
  53. data/lib/pacto/core/contract_registry.rb +13 -32
  54. data/lib/pacto/core/hook.rb +1 -0
  55. data/lib/pacto/core/http_middleware.rb +23 -0
  56. data/lib/pacto/core/investigation_registry.rb +60 -0
  57. data/lib/pacto/core/modes.rb +1 -0
  58. data/lib/pacto/core/pacto_request.rb +59 -0
  59. data/lib/pacto/core/pacto_response.rb +41 -0
  60. data/lib/pacto/dash.rb +9 -0
  61. data/lib/pacto/erb_processor.rb +1 -0
  62. data/lib/pacto/exceptions/invalid_contract.rb +1 -0
  63. data/lib/pacto/extensions.rb +3 -16
  64. data/lib/pacto/forensics/investigation_filter.rb +90 -0
  65. data/lib/pacto/forensics/investigation_matcher.rb +80 -0
  66. data/lib/pacto/generator.rb +31 -53
  67. data/lib/pacto/generator/filters.rb +8 -7
  68. data/lib/pacto/generator/hint.rb +26 -0
  69. data/lib/pacto/generator/native_contract_generator.rb +74 -0
  70. data/lib/pacto/hooks/erb_hook.rb +2 -1
  71. data/lib/pacto/investigation.rb +49 -0
  72. data/lib/pacto/logger.rb +1 -0
  73. data/lib/pacto/meta_schema.rb +12 -6
  74. data/lib/pacto/native_contract_factory.rb +60 -0
  75. data/lib/pacto/observers/stenographer.rb +42 -0
  76. data/lib/pacto/provider.rb +27 -0
  77. data/lib/pacto/rake_task.rb +25 -70
  78. data/lib/pacto/request_clause.rb +31 -29
  79. data/lib/pacto/request_pattern.rb +20 -3
  80. data/lib/pacto/resettable.rb +22 -0
  81. data/lib/pacto/response_clause.rb +5 -12
  82. data/lib/pacto/rspec.rb +38 -31
  83. data/lib/pacto/server.rb +4 -0
  84. data/lib/pacto/stubs/uri_pattern.rb +21 -11
  85. data/lib/pacto/stubs/webmock_adapter.rb +69 -34
  86. data/lib/pacto/swagger_contract_factory.rb +90 -0
  87. data/lib/pacto/test_helper.rb +37 -0
  88. data/lib/pacto/ui.rb +32 -2
  89. data/lib/pacto/uri.rb +2 -1
  90. data/lib/pacto/version.rb +2 -1
  91. data/pacto-server.gemspec +24 -0
  92. data/pacto.gemspec +13 -9
  93. data/resources/contract_schema.json +46 -18
  94. data/resources/draft-04.json +150 -0
  95. data/sample_apis/album/cover_api.rb +12 -0
  96. data/sample_apis/config.ru +25 -0
  97. data/sample_apis/echo_api.rb +26 -0
  98. data/sample_apis/files_api.rb +50 -0
  99. data/sample_apis/hello_api.rb +14 -0
  100. data/sample_apis/ping_api.rb +11 -0
  101. data/sample_apis/reverse_api.rb +20 -0
  102. data/samples/README.md +11 -0
  103. data/samples/Rakefile +2 -0
  104. data/samples/configuration.rb +33 -0
  105. data/samples/consumer.rb +15 -0
  106. data/samples/contracts/README.md +1 -0
  107. data/samples/contracts/contract.js +93 -0
  108. data/samples/contracts/get_album_cover.json +48 -0
  109. data/samples/contracts/localhost/api/echo.json +37 -0
  110. data/samples/contracts/localhost/api/ping.json +38 -0
  111. data/samples/cops.rb +30 -0
  112. data/samples/forensics.rb +54 -0
  113. data/samples/generation.rb +48 -0
  114. data/samples/rake_tasks.sh +7 -0
  115. data/samples/rspec.rb +1 -0
  116. data/samples/samples.rb +92 -0
  117. data/samples/scripts/bootstrap +2 -0
  118. data/samples/scripts/wrapper +11 -0
  119. data/samples/server.rb +24 -0
  120. data/samples/server_cli.sh +12 -0
  121. data/samples/stenographer.rb +17 -0
  122. data/spec/coveralls_helper.rb +1 -0
  123. data/spec/fabricators/contract_fabricator.rb +94 -0
  124. data/spec/fabricators/http_fabricator.rb +48 -0
  125. data/spec/fabricators/webmock_fabricator.rb +24 -0
  126. data/spec/{unit/data → fixtures/contracts}/contract.json +2 -2
  127. data/spec/fixtures/contracts/contract_with_examples.json +58 -0
  128. data/spec/{unit/data → fixtures/contracts}/simple_contract.json +5 -3
  129. data/spec/{integration/data → fixtures/contracts}/strict_contract.json +5 -3
  130. data/spec/{integration/data → fixtures/contracts}/templating_contract.json +3 -2
  131. data/spec/{integration/data/simple_contract.json → fixtures/deprecated_contracts/deprecated_contract.json} +2 -1
  132. data/spec/fixtures/swagger/petstore.yaml +101 -0
  133. data/spec/integration/e2e_spec.rb +19 -20
  134. data/spec/integration/forensics/integration_matcher_spec.rb +90 -0
  135. data/spec/integration/rspec_spec.rb +22 -25
  136. data/spec/integration/templating_spec.rb +7 -6
  137. data/spec/pacto/dummy_server.rb +4 -0
  138. data/spec/pacto/{server → dummy_server}/dummy.rb +7 -6
  139. data/spec/pacto/dummy_server/jruby_workaround_helper.rb +23 -0
  140. data/spec/pacto/{server → dummy_server}/playback_servlet.rb +3 -2
  141. data/spec/spec_helper.rb +16 -7
  142. data/spec/unit/actors/from_examples_spec.rb +70 -0
  143. data/spec/unit/actors/json_generator_spec.rb +105 -0
  144. data/spec/unit/pacto/actor_spec.rb +23 -0
  145. data/spec/unit/pacto/configuration_spec.rb +7 -6
  146. data/spec/unit/pacto/consumer/faraday_driver_spec.rb +40 -0
  147. data/spec/unit/pacto/contract_builder_spec.rb +89 -0
  148. data/spec/unit/pacto/contract_factory_spec.rb +62 -11
  149. data/spec/unit/pacto/contract_files_spec.rb +1 -0
  150. data/spec/unit/pacto/contract_set_spec.rb +36 -0
  151. data/spec/unit/pacto/contract_spec.rb +51 -39
  152. data/spec/unit/pacto/cops/body_cop_spec.rb +107 -0
  153. data/spec/unit/pacto/{validators/response_header_validator_spec.rb → cops/response_header_cop_spec.rb} +30 -19
  154. data/spec/unit/pacto/cops/response_status_cop_spec.rb +26 -0
  155. data/spec/unit/pacto/cops_spec.rb +75 -0
  156. data/spec/unit/pacto/core/configuration_spec.rb +6 -5
  157. data/spec/unit/pacto/core/contract_registry_spec.rb +16 -83
  158. data/spec/unit/pacto/core/http_middleware_spec.rb +36 -0
  159. data/spec/unit/pacto/core/investigation_spec.rb +62 -0
  160. data/spec/unit/pacto/core/modes_spec.rb +5 -4
  161. data/spec/unit/pacto/erb_processor_spec.rb +3 -2
  162. data/spec/unit/pacto/extensions_spec.rb +10 -20
  163. data/spec/unit/pacto/generator/filters_spec.rb +11 -10
  164. data/spec/unit/pacto/generator/native_contract_generator_spec.rb +171 -0
  165. data/spec/unit/{hooks → pacto/hooks}/erb_hook_spec.rb +18 -11
  166. data/spec/unit/pacto/investigation_registry_spec.rb +77 -0
  167. data/spec/unit/pacto/logger_spec.rb +6 -5
  168. data/spec/unit/pacto/meta_schema_spec.rb +5 -4
  169. data/spec/unit/pacto/native_contract_factory_spec.rb +26 -0
  170. data/spec/unit/pacto/pacto_spec.rb +13 -28
  171. data/spec/unit/pacto/request_clause_spec.rb +16 -51
  172. data/spec/unit/pacto/request_pattern_spec.rb +6 -5
  173. data/spec/unit/pacto/response_clause_spec.rb +6 -19
  174. data/spec/unit/pacto/server/playback_servlet_spec.rb +21 -18
  175. data/spec/unit/pacto/stubs/observers/stenographer_spec.rb +33 -0
  176. data/spec/unit/pacto/stubs/uri_pattern_spec.rb +39 -11
  177. data/spec/unit/pacto/stubs/webmock_adapter_spec.rb +67 -117
  178. data/spec/unit/pacto/swagger_contract_factory_spec.rb +56 -0
  179. data/spec/unit/pacto/uri_spec.rb +1 -0
  180. data/tasks/release.rake +57 -0
  181. metadata +247 -76
  182. data/.rubocop-todo.yml +0 -24
  183. data/.ruby-gemset +0 -1
  184. data/.ruby-version +0 -1
  185. data/CHANGELOG +0 -12
  186. data/features/validate/body_only.feature +0 -85
  187. data/lib/pacto/contract_list.rb +0 -17
  188. data/lib/pacto/contract_validator.rb +0 -29
  189. data/lib/pacto/core/validation_registry.rb +0 -40
  190. data/lib/pacto/stubs/webmock_helper.rb +0 -69
  191. data/lib/pacto/validation.rb +0 -54
  192. data/lib/pacto/validators/body_validator.rb +0 -49
  193. data/lib/pacto/validators/request_body_validator.rb +0 -26
  194. data/lib/pacto/validators/response_body_validator.rb +0 -26
  195. data/lib/pacto/validators/response_status_validator.rb +0 -24
  196. data/spec/pacto/server.rb +0 -2
  197. data/spec/unit/pacto/contract_list_spec.rb +0 -35
  198. data/spec/unit/pacto/contract_validator_spec.rb +0 -85
  199. data/spec/unit/pacto/core/validation_registry_spec.rb +0 -76
  200. data/spec/unit/pacto/core/validation_spec.rb +0 -60
  201. data/spec/unit/pacto/generator_spec.rb +0 -132
  202. data/spec/unit/pacto/stubs/webmock_helper_spec.rb +0 -20
  203. data/spec/unit/pacto/validators/body_validator_spec.rb +0 -118
  204. data/spec/unit/pacto/validators/response_status_validator_spec.rb +0 -20
@@ -0,0 +1,15 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'pacto'
3
+ Pacto.load_contracts 'contracts', 'http://localhost:5000'
4
+ WebMock.allow_net_connect!
5
+
6
+ interactions = Pacto.simulate_consumer :my_client do
7
+ request 'Ping'
8
+ request 'Echo', body: ->(body) { body.reverse },
9
+ headers: (proc do |headers|
10
+ headers['Content-Type'] = 'text/json'
11
+ headers['Accept'] = 'none'
12
+ headers
13
+ end)
14
+ end
15
+ puts interactions
@@ -0,0 +1 @@
1
+ This folder contains sample contracts.
@@ -0,0 +1,93 @@
1
+ // Pacto Contracts describe the constraints we want to put on interactions between a consumer and a provider. It sets some expectations about the headers expected for both the request and response, the expected response status code. It also uses [json-schema](http://json-schema.org/) to define the allowable request body (if one should exist) and response body.
2
+ {
3
+ // The Request section comes first. In this case, we're just describing a simple get request that does not require any parameters or a request body.
4
+ "request": {
5
+ "headers": {
6
+ // A request must exactly match these headers for Pacto to believe the request matches the contract, unless `Pacto.configuration.strict_matchers` is false.
7
+ "Accept": "application/vnd.github.beta+json",
8
+ "Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
9
+ },
10
+ // The `method` and `path` are required. The `path` may be an [rfc6570 URI template](http://tools.ietf.org/html/rfc6570) for more flexible matching.
11
+ "method": "get",
12
+ "path": "/repos/thoughtworks/pacto/readme"
13
+ },
14
+ "response": {
15
+ "headers": {
16
+ "Content-Type": "application/json; charset=utf-8",
17
+ "Status": "200 OK",
18
+ "Cache-Control": "public, max-age=60, s-maxage=60",
19
+ "Etag": "\"fc8e78b0a9694de66d47317768b20820\"",
20
+ "Vary": "Accept, Accept-Encoding",
21
+ "Access-Control-Allow-Credentials": "true",
22
+ "Access-Control-Expose-Headers": "ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval",
23
+ "Access-Control-Allow-Origin": "*"
24
+ },
25
+ "status": 200,
26
+ "body": {
27
+ "$schema": "http://json-schema.org/draft-03/schema#",
28
+ "description": "Generated from https://api.github.com/repos/thoughtworks/pacto/readme with shasum 3ae59164c6d9f84c0a81f21fb63e17b3b8ce6894",
29
+ "type": "object",
30
+ "required": true,
31
+ "properties": {
32
+ "name": {
33
+ "type": "string",
34
+ "required": true
35
+ },
36
+ "path": {
37
+ "type": "string",
38
+ "required": true
39
+ },
40
+ "sha": {
41
+ "type": "string",
42
+ "required": true
43
+ },
44
+ "size": {
45
+ "type": "integer",
46
+ "required": true
47
+ },
48
+ "url": {
49
+ "type": "string",
50
+ "required": true
51
+ },
52
+ "html_url": {
53
+ "type": "string",
54
+ "required": true
55
+ },
56
+ "git_url": {
57
+ "type": "string",
58
+ "required": true
59
+ },
60
+ "type": {
61
+ "type": "string",
62
+ "required": true
63
+ },
64
+ "content": {
65
+ "type": "string",
66
+ "required": true
67
+ },
68
+ "encoding": {
69
+ "type": "string",
70
+ "required": true
71
+ },
72
+ "_links": {
73
+ "type": "object",
74
+ "required": true,
75
+ "properties": {
76
+ "self": {
77
+ "type": "string",
78
+ "required": true
79
+ },
80
+ "git": {
81
+ "type": "string",
82
+ "required": true
83
+ },
84
+ "html": {
85
+ "type": "string",
86
+ "required": true
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "request": {
3
+ "headers": {
4
+ },
5
+ "http_method": "get",
6
+ "path": "/api/album/{id}/cover"
7
+ },
8
+ "response": {
9
+ "headers": {
10
+ "Content-Type": "application/json"
11
+ },
12
+ "status": 200,
13
+ "schema": {
14
+ "$schema": "http://json-schema.org/draft-03/schema#",
15
+ "description": "Generated from http://localhost:5000/api/album/1/cover with shasum db640385d2b346db760dbfd78058101663197bcf",
16
+ "type": "object",
17
+ "required": true,
18
+ "properties": {
19
+ "cover": {
20
+ "type": "string",
21
+ "required": true
22
+ }
23
+ }
24
+ }
25
+ },
26
+ "examples": {
27
+ "default": {
28
+ "request": {
29
+ "method": "get",
30
+ "uri": "http://localhost:5000/api/album/1/cover",
31
+ "headers": {
32
+ "User-Agent": "Faraday v0.9.0",
33
+ "Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
34
+ "Accept": "*/*"
35
+ }
36
+ },
37
+ "response": {
38
+ "status": 200,
39
+ "headers": {
40
+ "Content-Type": "application/json",
41
+ "Content-Length": "17"
42
+ },
43
+ "body": "{\"cover\":\"image\"}"
44
+ }
45
+ }
46
+ },
47
+ "name": "Get Album Cover"
48
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "Echo",
3
+ "request": {
4
+ "headers": {
5
+ "Content-Type": "text/plain"
6
+ },
7
+ "http_method": "post",
8
+ "path": "/api/echo",
9
+ "schema": {
10
+ "$schema": "http://json-schema.org/draft-03/schema#",
11
+ "oneOf": [
12
+ { "type": "string", "required": true },
13
+ { "type": "object", "required": true }
14
+ ]
15
+ }
16
+ },
17
+ "response": {
18
+ "status": 201,
19
+ "schema": {
20
+ "$schema": "http://json-schema.org/draft-03/schema#",
21
+ "oneOf": [
22
+ { "type": "string", "required": true },
23
+ { "type": "object", "required": true }
24
+ ]
25
+ }
26
+ },
27
+ "examples": {
28
+ "foo": {
29
+ "request": {
30
+ "body": "foo"
31
+ },
32
+ "response": {
33
+ "body": "foo"
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "Ping",
3
+ "request": {
4
+ "headers": {
5
+ },
6
+ "http_method": "get",
7
+ "path": "/api/ping"
8
+ },
9
+ "response": {
10
+ "headers": {
11
+ "Content-Type": "application/json"
12
+ },
13
+ "status": 200,
14
+ "schema": {
15
+ "$schema": "http://json-schema.org/draft-03/schema#",
16
+ "description": "Generated from http://localhost:9292/api/ping with shasum 2cf3478c18e3ce877fb823ed435cb75b4a801aaa",
17
+ "type": "object",
18
+ "required": true,
19
+ "properties": {
20
+ "ping": {
21
+ "type": "string",
22
+ "required": true
23
+ }
24
+ }
25
+ }
26
+ },
27
+ "examples": {
28
+ "default": {
29
+ "request": {
30
+ },
31
+ "response": {
32
+ "body": {
33
+ "ping": "pong - from the example!"
34
+ }
35
+ }
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,30 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'pacto'
3
+ Pacto.configure do |c|
4
+ c.contracts_path = 'contracts'
5
+ end
6
+ Pacto.validate!
7
+
8
+ # You can create a custom cop that investigates the request/response and sees if it complies with a
9
+ # contract. The cop should return a list of citations if it finds any problems.
10
+ class MyCustomCop
11
+ def investigate(_request, _response, contract)
12
+ citations = []
13
+ citations << 'Contract must have a request schema' if contract.request.schema.empty?
14
+ citations << 'Contract must have a response schema' if contract.response.schema.empty?
15
+ citations
16
+ end
17
+ end
18
+
19
+ Pacto::Cops.active_cops << MyCustomCop.new
20
+
21
+ contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
22
+ contracts.stub_providers
23
+ puts contracts.simulate_consumers
24
+
25
+ # Or you can completely replace the default set of validators
26
+ Pacto::Cops.registered_cops.clear
27
+ Pacto::Cops.register_cop Pacto::Cops::ResponseBodyCop
28
+
29
+ contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
30
+ puts contracts.simulate_consumers
@@ -0,0 +1,54 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # Pacto has a few RSpec matchers to help you ensure a **consumer** and **producer** are
3
+ # interacting properly. First, let's setup the rspec suite.
4
+ require 'rspec/autorun' # Not generally needed
5
+ require 'pacto/rspec'
6
+ WebMock.allow_net_connect!
7
+ Pacto.validate!
8
+ Pacto.load_contracts('contracts', 'http://localhost:5000').stub_providers
9
+
10
+ # It's usually a good idea to reset Pacto between each scenario. `Pacto.reset` just clears the
11
+ # data and metrics about which services were called. `Pacto.clear!` also resets all configuration
12
+ # and plugins.
13
+ RSpec.configure do |c|
14
+ c.after(:each) { Pacto.reset }
15
+ end
16
+
17
+ # Pacto provides some RSpec matchers related to contract testing, like making sure
18
+ # Pacto didn't received any unrecognized requests (`have_unmatched_requests`) and that
19
+ # the HTTP requests matched up with the terms of the contract (`have_failed_investigations`).
20
+ describe Faraday do
21
+ let(:connection) { described_class.new(url: 'http://localhost:5000') }
22
+
23
+ it 'passes contract tests' do
24
+ connection.get '/api/ping'
25
+ expect(Pacto).to_not have_failed_investigations
26
+ expect(Pacto).to_not have_unmatched_requests
27
+ end
28
+ end
29
+
30
+ # There are also some matchers for collaboration testing, so you can make sure each scenario is
31
+ # calling the expected services and sending the right type of data.
32
+ describe Faraday do
33
+ let(:connection) { described_class.new(url: 'http://localhost:5000') }
34
+ before(:each) do
35
+ connection.get '/api/ping'
36
+
37
+ connection.post do |req|
38
+ req.url '/api/echo'
39
+ req.headers['Content-Type'] = 'application/json'
40
+ req.body = '{"foo": "bar"}'
41
+ end
42
+ end
43
+
44
+ it 'calls the ping service' do
45
+ expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping').against_contract('Ping')
46
+ end
47
+
48
+ it 'sends data to the echo service' do
49
+ expect(Pacto).to have_investigated('Ping').with_response(body: hash_including('ping' => 'pong - from the example!'))
50
+ expect(Pacto).to have_investigated('Echo').with_request(body: hash_including('foo' => 'bar'))
51
+ echoed_body = { 'foo' => 'bar' }
52
+ expect(Pacto).to have_investigated('Echo').with_request(body: echoed_body).with_response(body: echoed_body)
53
+ end
54
+ end
@@ -0,0 +1,48 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # Some generation related [configuration](configuration.rb).
3
+ require 'pacto'
4
+ WebMock.allow_net_connect!
5
+ Pacto.configure do |c|
6
+ c.contracts_path = 'contracts'
7
+ end
8
+ WebMock.allow_net_connect!
9
+
10
+ # Once we call `Pacto.generate!`, Pacto will record contracts for all requests it detects.
11
+ Pacto.generate!
12
+
13
+ # Now, if we run any code that makes an HTTP call (using an
14
+ # [HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))
15
+ # then Pacto will generate a Contract based on the HTTP request/response.
16
+ #
17
+ # This code snippet will generate a Contract and save it to `contracts/samples/contracts/localhost/api/ping.json`.
18
+ require 'faraday'
19
+ conn = Faraday.new(url: 'http://localhost:5000')
20
+ response = conn.get '/api/ping'
21
+ # We're getting back real data from GitHub, so this should be the actual file encoding.
22
+ puts response.body
23
+
24
+ # The generated contract will contain expectations based on the request/response we observed,
25
+ # including a best-guess at an appropriate json-schema. Our heuristics certainly aren't foolproof,
26
+ # so you might want to customize schema!
27
+
28
+ # Here's another sample that sends a post request.
29
+ conn.post do |req|
30
+ req.url '/api/echo'
31
+ req.headers['Content-Type'] = 'application/json'
32
+ req.body = '{"red fish": "blue fish"}'
33
+ end
34
+
35
+ # You can provide hints to Pacto to help it generate contracts. For example, Pacto doesn't have
36
+ # a good way to know a good name and correct URI template for the service. That means that Pacto
37
+ # will not know if two similar requests are for the same service or two different services, and
38
+ # will be forced to give names based on the URI that are not good display names.
39
+
40
+ # The hint below tells Pacto that requests to http://localhost:5000/album/1/cover and http://localhost:5000/album/2/cover
41
+ # are both going to the same service, which is known as "Get Album Cover". This hint will cause Pacto to
42
+ # generate a Contract for "Get Album Cover" and save it to `contracts/get_album_cover.json`, rather than two
43
+ # contracts that are stored at `contracts/localhost/album/1/cover.json` and `contracts/localhost/album/2/cover.json`.
44
+ Pacto::Generator.configure do |c|
45
+ c.hint 'Get Album Cover', http_method: :get, host: 'http://localhost:5000', path: '/api/album/{id}/cover'
46
+ end
47
+ conn.get '/api/album/1/cover'
48
+ conn.get '/api/album/2/cover'
@@ -0,0 +1,7 @@
1
+ # # Rake tasks
2
+
3
+ # ## This is a test!
4
+ # [That](www.google.com) markdown works
5
+ bundle exec rake pacto:meta_validate['contracts']
6
+
7
+ bundle exec rake pacto:validate['http://localhost:5000','contracts']
@@ -0,0 +1 @@
1
+ # -*- encoding : utf-8 -*-
@@ -0,0 +1,92 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # # Overview
3
+ # Welcome to the Pacto usage samples!
4
+ # This document gives a quick overview of the main features.
5
+ #
6
+ # You can browse the Table of Contents (upper right corner) to view additional samples.
7
+ #
8
+ # In addition to this document, here are some highlighted samples:
9
+ # <ul>
10
+ # <li><a href="configuration">Configuration</a>: Shows all available configuration options</li>
11
+ # <li><a href="generation">Generation</a>: More details on generation</li>
12
+ # <li><a href="rspec">RSpec</a>: More samples for RSpec expectations</li>
13
+ # </ul>
14
+
15
+ # You can also find other samples using the Table of Content (upper right corner), including sample contracts.
16
+
17
+ # # Getting started
18
+ # Once you've installed the Pacto gem, you just require it. If you want, you can also require the Pacto rspec expectations.
19
+ require 'pacto'
20
+ require 'pacto/rspec'
21
+ # Pacto will disable live connections, so you will get an error if
22
+ # your code unexpectedly calls an service that was not stubbed. If you
23
+ # want to re-enable connections, run `WebMock.allow_net_connect!`
24
+ WebMock.allow_net_connect!
25
+
26
+ # Pacto can be configured via a block. The `contracts_path` option tells Pacto where it should load or save contracts. See the [Configuration](configuration.html) for all the available options.
27
+ Pacto.configure do |c|
28
+ c.contracts_path = 'contracts'
29
+ end
30
+
31
+ # # Generating a Contract
32
+
33
+ # Calling `Pacto.generate!` enables contract generation.
34
+ # Pacto.generate!
35
+
36
+ # Now, if we run any code that makes an HTTP call (using an
37
+ # [HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))
38
+ # then Pacto will generate a Contract based on the HTTP request/response.
39
+ #
40
+ # We're using the sample APIs in the sample_apis directory.
41
+ require 'faraday'
42
+ conn = Faraday.new(url: 'http://localhost:5000')
43
+ response = conn.get '/api/ping'
44
+ # This is the real request, so you should see {"ping":"pong"}
45
+ puts response.body
46
+
47
+ # # Testing providers by simulating consumers
48
+
49
+ # The generated contract will contain expectations based on the request/response we observed,
50
+ # including a best-guess at an appropriate json-schema. Our heuristics certainly aren't foolproof,
51
+ # so you might want to modify the output!
52
+
53
+ # We can load the contract and validate it, by sending a new request and making sure
54
+ # the response matches the JSON schema. Obviously it will pass since we just recorded it,
55
+ # but if the service has made a change, or if you alter the contract with new expectations,
56
+ # then you will see a contract investigation message.
57
+ contracts = Pacto.load_contracts('contracts', 'http://localhost:5000')
58
+ contracts.simulate_consumers
59
+
60
+ # # Stubbing providers for consumer testing
61
+ # We can also use Pacto to stub the service based on the contract.
62
+ contracts.stub_providers
63
+ # The stubbed data won't be very realistic, the default behavior is to return the simplest data
64
+ # that complies with the schema. That basically means that you'll have "bar" for every string.
65
+ response = conn.get '/api/ping'
66
+ # You're now getting stubbed data. You should see {"ping":"bar"} unless you recorded with
67
+ # the `defaults` option enabled, in which case you will still seee {"ping":"pong"}.
68
+ puts response.body
69
+
70
+ # # Collaboration tests with RSpec
71
+
72
+ # Pacto comes with rspec matchers
73
+ require 'pacto/rspec'
74
+
75
+ # It's probably a good idea to reset Pacto between each rspec scenario
76
+ RSpec.configure do |c|
77
+ c.after(:each) { Pacto.clear! }
78
+ end
79
+
80
+ # Load your contracts, and stub them if you'd like.
81
+ Pacto.load_contracts('contracts', 'http://localhost:5000').stub_providers
82
+ # You can turn on investigation mode so Pacto will detect and validate HTTP requests.
83
+ Pacto.validate!
84
+
85
+ describe 'my_code' do
86
+ it 'calls a service' do
87
+ conn = Faraday.new(url: 'http://localhost:5000')
88
+ response = conn.get '/api/ping'
89
+ # The have_validated matcher makes sure that Pacto received and successfully validated a request
90
+ expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping')
91
+ end
92
+ end