quiz_api_client 2.4.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|