quiz_api_client 2.4.0 → 2.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +50 -0
- data/Rakefile +32 -0
- data/bin/contracts +9 -7
- data/build.sh +11 -6
- data/docker-compose.dev.override.yml +7 -2
- data/docker-compose.yml +5 -0
- data/lib/quiz_api_client/http_client.rb +19 -13
- data/lib/quiz_api_client/version.rb +1 -1
- data/lib/quiz_api_client.rb +1 -0
- data/quiz_api_client.gemspec +2 -1
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2a00510f91eb1597a6677ddd7db7342293cbead
|
4
|
+
data.tar.gz: c1328d1480d86fa91731d575eadd820038ac51d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a3445f192bd75c78fdd3f42f46c2d254ab191bbb9e7c805b77da90244072b8d1467d0001af3591187f8257558bb1adb00e4d5e85c4018cbe180b77e33fc3d5e
|
7
|
+
data.tar.gz: 7eb2997e14243ce80868d28995892c7aeb73f85807c16e3e6f98a1017f7dc33365c29199892c3d4fbd95a9669ff434d387cb99e0fd92ef6dfb0a2e501a143a71
|
data/README.md
CHANGED
@@ -179,3 +179,53 @@ Then, run `rake spec` to run the tests.
|
|
179
179
|
You can also run `rake console` for an interactive prompt that will allow you to experiment.
|
180
180
|
|
181
181
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
182
|
+
|
183
|
+
When you add or modify a service, be sure to add or modify contract tests!
|
184
|
+
|
185
|
+
## Contract Tests
|
186
|
+
|
187
|
+
We use [Pact](https://docs.pact.io/) for our contract testing. To generate
|
188
|
+
a Pact file, run `bin/contracts`.
|
189
|
+
|
190
|
+
The `bin/contracts` script will generate the Pact file and place it in the
|
191
|
+
pacts/ directory. It will also attempt to publish the Pact file to a local
|
192
|
+
Pact Broker.
|
193
|
+
|
194
|
+
### Development Workflow:
|
195
|
+
|
196
|
+
1. In the quiz_api repo, spin up the Quiz API service with `bin/dev-setup`
|
197
|
+
2. In the quiz_pact_broker repo, spin up a Pact Broker with `bin/dev-setup`
|
198
|
+
3. In the quiz_api repo, write Pact provider states in the
|
199
|
+
spec/service_consumers/quiz_api_client_ruby/ directory as needed
|
200
|
+
4. In this repo's spec/contracts/ directory, write or modify a contract test
|
201
|
+
5. In this repo, run `bin/contracts` to generate a Pact file and publish it to
|
202
|
+
the Pact Broker
|
203
|
+
6. In the quiz_api repo, run `bin/contracts` to pull the new Pact file from
|
204
|
+
the Pact Broker and run the updated contract tests against the Quiz API service
|
205
|
+
|
206
|
+
Bonus: You can view your Pact file in the Pact Broker at http://pact-broker.docker
|
207
|
+
along with some cool goodies!
|
208
|
+
|
209
|
+
### Debugging Failures
|
210
|
+
|
211
|
+
Pact has some basic RSpec output for failed specs. It also keeps a log in
|
212
|
+
`log/pact.log` and offers general pointers for debugging.
|
213
|
+
|
214
|
+
Above all, learn the Pact [basics](https://docs.pact.io/documentation/matching.html).
|
215
|
+
|
216
|
+
### What should contract tests cover?
|
217
|
+
|
218
|
+
The aim of contract testing here is *not* to test all functional requirements
|
219
|
+
of the Quiz API service. Rather, the goal is to ensure changes to the Quiz API
|
220
|
+
service don't break its clients. We can best accomplish this with the
|
221
|
+
following contract test coverage:
|
222
|
+
|
223
|
+
- Basic happy path requests for all endpoints (POST, GET, PUT, DELETE)
|
224
|
+
- Basic error paths for all endpoints (verify the error messages and/or HTTP
|
225
|
+
response codes are accurate)
|
226
|
+
- Resource state management; for example, when a quiz attempt is submitted but
|
227
|
+
not yet graded
|
228
|
+
- Special edge case errors
|
229
|
+
|
230
|
+
Again, what *not* to test: the functional behavior of the service; for
|
231
|
+
example, a series of sequential API calls to test a full user scenario.
|
data/Rakefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
|
+
require 'pact_broker/client/tasks'
|
2
3
|
require 'rspec/core/rake_task'
|
3
4
|
|
4
5
|
RSpec::Core::RakeTask.new(:spec)
|
@@ -17,3 +18,34 @@ task :console do
|
|
17
18
|
ARGV.clear
|
18
19
|
Pry.start
|
19
20
|
end
|
21
|
+
|
22
|
+
# see https://github.com/pact-foundation/pact_broker-client/blob/master/README.md
|
23
|
+
PactBroker::Client::PublicationTask.new(:local) do |task|
|
24
|
+
require 'quiz_api_client'
|
25
|
+
|
26
|
+
task.consumer_version = QuizApiClient::VERSION
|
27
|
+
task.pattern = 'pacts/*.json'
|
28
|
+
|
29
|
+
task.pact_broker_base_url = 'http://pact-broker.docker'
|
30
|
+
task.pact_broker_basic_auth = { username: 'pact', password: 'broker' }
|
31
|
+
|
32
|
+
# tag the pact with the git branch name
|
33
|
+
task.tag = `git rev-parse --abbrev-ref HEAD`.strip
|
34
|
+
puts "Pact file tagged with: #{task.tag}"
|
35
|
+
end
|
36
|
+
|
37
|
+
PactBroker::Client::PublicationTask.new(:jenkins_post_merge) do |task|
|
38
|
+
require 'quiz_api_client'
|
39
|
+
|
40
|
+
task.consumer_version = QuizApiClient::VERSION
|
41
|
+
task.pattern = 'pacts/*.json'
|
42
|
+
|
43
|
+
task.pact_broker_base_url = ENV.fetch('PACT_BROKER_BASE_URL')
|
44
|
+
task.pact_broker_basic_auth = {
|
45
|
+
username: ENV.fetch('PACT_BROKER_BASIC_AUTH_USERNAME'),
|
46
|
+
password: ENV.fetch('PACT_BROKER_BASIC_AUTH_PASSWORD')
|
47
|
+
}
|
48
|
+
|
49
|
+
task.tag = 'master'
|
50
|
+
puts "Pact file tagged with: #{task.tag}"
|
51
|
+
end
|
data/bin/contracts
CHANGED
@@ -4,16 +4,18 @@ function print_results() {
|
|
4
4
|
exit_code=$?
|
5
5
|
set +e
|
6
6
|
|
7
|
-
docker-compose rm -fv contracts-testrunner
|
8
|
-
|
9
7
|
if [[ "$exit_code" == "0" ]]; then
|
10
|
-
echo ""
|
11
|
-
|
8
|
+
echo "Success! Open http://pact-broker.docker to view your published pact file."
|
9
|
+
else
|
10
|
+
echo "Oops! Something went wrong."
|
12
11
|
fi
|
12
|
+
|
13
|
+
docker cp contracts:/usr/src/app/log . &> /dev/null
|
14
|
+
docker cp contracts:/usr/src/app/pacts . &> /dev/null
|
15
|
+
|
16
|
+
docker-compose rm -fv contracts-testrunner &> /dev/null
|
13
17
|
}
|
14
18
|
trap print_results INT TERM EXIT
|
15
19
|
set -e
|
16
20
|
|
17
|
-
docker-compose run --name contracts contracts-testrunner bundle && bundle exec rspec spec/contracts
|
18
|
-
docker cp contracts:/usr/src/app/log .
|
19
|
-
docker cp contracts:/usr/src/app/pacts .
|
21
|
+
docker-compose run --name contracts contracts-testrunner bash -c "bundle && bundle exec rspec spec/contracts && bundle exec rake pact:publish:local"
|
data/build.sh
CHANGED
@@ -2,11 +2,15 @@
|
|
2
2
|
|
3
3
|
set -ex
|
4
4
|
|
5
|
-
function
|
5
|
+
function publish_pact_file_to_pact_broker()
|
6
6
|
{
|
7
|
-
echo "
|
8
|
-
|
9
|
-
|
7
|
+
echo "Publishing pact file to Pact Broker..."
|
8
|
+
|
9
|
+
docker-compose run --rm \
|
10
|
+
-e PACT_BROKER_BASE_URL=${PACT_BROKER_BASE_URL} \
|
11
|
+
-e PACT_BROKER_BASIC_AUTH_USERNAME=${PACT_BROKER_BASIC_AUTH_USERNAME} \
|
12
|
+
-e PACT_BROKER_BASIC_AUTH_PASSWORD=${PACT_BROKER_BASIC_AUTH_PASSWORD} \
|
13
|
+
contracts-testrunner bundle exec rake pact:publish:jenkins_post_merge
|
10
14
|
}
|
11
15
|
|
12
16
|
function cleanup() {
|
@@ -23,12 +27,13 @@ docker-compose build --pull
|
|
23
27
|
echo "Running test suite..."
|
24
28
|
docker-compose run --name coverage testrunner $@
|
25
29
|
|
26
|
-
echo
|
30
|
+
echo
|
27
31
|
echo "Running contract tests..."
|
28
32
|
docker-compose run --name contracts -T contracts-testrunner bundle exec rspec spec/contracts
|
29
33
|
docker cp contracts:/usr/src/app/pacts .
|
30
34
|
docker cp contracts:/usr/src/app/log .
|
35
|
+
echo
|
31
36
|
|
32
37
|
if [[ "${GERRIT_EVENT_TYPE}" == "change-merged" ]]; then
|
33
|
-
|
38
|
+
publish_pact_file_to_pact_broker
|
34
39
|
fi
|
@@ -3,8 +3,13 @@ version: '2'
|
|
3
3
|
services:
|
4
4
|
testrunner:
|
5
5
|
volumes:
|
6
|
-
- .:/
|
6
|
+
- .:/app
|
7
|
+
- bundler-config:/home/docker/.rvm/gems/ruby-2.4.0
|
7
8
|
|
8
9
|
contracts-testrunner:
|
9
10
|
volumes:
|
10
|
-
- .:/
|
11
|
+
- .:/app
|
12
|
+
- bundler-config:/home/docker/.rvm/gems/ruby-2.4.0
|
13
|
+
|
14
|
+
volumes:
|
15
|
+
bundler-config: {}
|
data/docker-compose.yml
CHANGED
@@ -15,25 +15,31 @@ module QuizApiClient
|
|
15
15
|
initialize_logger(log_level) if logging
|
16
16
|
end
|
17
17
|
|
18
|
+
def url_for(path)
|
19
|
+
url = URI(uri)
|
20
|
+
url.path = path
|
21
|
+
url.to_s
|
22
|
+
end
|
23
|
+
|
18
24
|
def get(path, all: false, query: {})
|
19
|
-
return make_request :get, path, query: query unless all
|
20
|
-
make_paginated_request :get, path, query: query
|
25
|
+
return make_request :get, url_for(path), query: query unless all
|
26
|
+
make_paginated_request :get, url_for(path), query: query
|
21
27
|
end
|
22
28
|
|
23
29
|
def post(path, body = {})
|
24
|
-
make_request :post, path, body: body.to_json
|
30
|
+
make_request :post, url_for(path), body: body.to_json
|
25
31
|
end
|
26
32
|
|
27
33
|
def patch(path, body = {})
|
28
|
-
make_request :patch, path, body: body.to_json
|
34
|
+
make_request :patch, url_for(path), body: body.to_json
|
29
35
|
end
|
30
36
|
|
31
37
|
def put(path, body = {})
|
32
|
-
make_request :put, path, body: body.to_json
|
38
|
+
make_request :put, url_for(path), body: body.to_json
|
33
39
|
end
|
34
40
|
|
35
41
|
def delete(path)
|
36
|
-
make_request :delete, path
|
42
|
+
make_request :delete, url_for(path)
|
37
43
|
end
|
38
44
|
|
39
45
|
private
|
@@ -65,24 +71,24 @@ module QuizApiClient
|
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
68
|
-
def make_request(method,
|
74
|
+
def make_request(method, url, request_options = {})
|
69
75
|
self.class.send(
|
70
76
|
method,
|
71
|
-
|
77
|
+
url,
|
72
78
|
default_request_data.merge(request_options)
|
73
79
|
)
|
74
80
|
rescue HTTParty::Error, Errno::ECONNREFUSED, Net::ReadTimeout => e
|
75
81
|
raise RequestFailed, e.message
|
76
82
|
end
|
77
83
|
|
78
|
-
def make_paginated_request(method,
|
84
|
+
def make_paginated_request(method, url, request_options)
|
79
85
|
entities = []
|
80
|
-
|
86
|
+
request_url = url
|
81
87
|
|
82
|
-
until
|
83
|
-
resp = make_request(method,
|
88
|
+
until request_url.nil? do
|
89
|
+
resp = make_request(method, request_url, request_options)
|
84
90
|
entities.concat(resp.parsed_response)
|
85
|
-
|
91
|
+
request_url = next_page(resp)
|
86
92
|
end
|
87
93
|
entities
|
88
94
|
end
|
data/lib/quiz_api_client.rb
CHANGED
data/quiz_api_client.gemspec
CHANGED
@@ -48,7 +48,8 @@ Gem::Specification.new do |spec|
|
|
48
48
|
spec.add_development_dependency 'bundler', '~> 1.12'
|
49
49
|
spec.add_development_dependency 'simplecov'
|
50
50
|
spec.add_development_dependency 'webmock'
|
51
|
-
spec.add_development_dependency 'pact', '~> 1.
|
51
|
+
spec.add_development_dependency 'pact', '~> 1.16.0'
|
52
|
+
spec.add_development_dependency 'pact_broker-client', '~> 1.6.0'
|
52
53
|
spec.add_development_dependency 'rake', '~> 10.0'
|
53
54
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
54
55
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quiz_api_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wang
|
@@ -19,7 +19,7 @@ authors:
|
|
19
19
|
autorequire:
|
20
20
|
bindir: exe
|
21
21
|
cert_chain: []
|
22
|
-
date: 2017-
|
22
|
+
date: 2017-11-10 00:00:00.000000000 Z
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|
25
25
|
name: httparty
|
@@ -111,14 +111,28 @@ dependencies:
|
|
111
111
|
requirements:
|
112
112
|
- - "~>"
|
113
113
|
- !ruby/object:Gem::Version
|
114
|
-
version: 1.
|
114
|
+
version: 1.16.0
|
115
115
|
type: :development
|
116
116
|
prerelease: false
|
117
117
|
version_requirements: !ruby/object:Gem::Requirement
|
118
118
|
requirements:
|
119
119
|
- - "~>"
|
120
120
|
- !ruby/object:Gem::Version
|
121
|
-
version: 1.
|
121
|
+
version: 1.16.0
|
122
|
+
- !ruby/object:Gem::Dependency
|
123
|
+
name: pact_broker-client
|
124
|
+
requirement: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - "~>"
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: 1.6.0
|
129
|
+
type: :development
|
130
|
+
prerelease: false
|
131
|
+
version_requirements: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - "~>"
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: 1.6.0
|
122
136
|
- !ruby/object:Gem::Dependency
|
123
137
|
name: rake
|
124
138
|
requirement: !ruby/object:Gem::Requirement
|
@@ -219,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
233
|
version: '0'
|
220
234
|
requirements: []
|
221
235
|
rubyforge_project:
|
222
|
-
rubygems_version: 2.
|
236
|
+
rubygems_version: 2.5.1
|
223
237
|
signing_key:
|
224
238
|
specification_version: 4
|
225
239
|
summary: Ruby client for quiz_api
|