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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f109a4af811b6581467d20b04bc580c1f2a3c209
4
- data.tar.gz: 73ffe5b91db4ffa77db9de146b29c8162aaef2db
3
+ metadata.gz: b2a00510f91eb1597a6677ddd7db7342293cbead
4
+ data.tar.gz: c1328d1480d86fa91731d575eadd820038ac51d5
5
5
  SHA512:
6
- metadata.gz: 355d7520d371d4cf3a19cb42def9ff1eee21e70eefe6e001b2e0558d6a26dfca1abd9a48d9c184f33ff2bf4ec0d338497729acfa749d73736c490106018509ed
7
- data.tar.gz: f99bbc820678763fd8caee43d27ea3ee78f6bb02591c3a0bc833889d754421b088a7b218615ea9940b97bc7dbf94cf2073105772fcf1c8dcfe4bcd3ff5fafdda
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
- echo "Success!"
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 save_pact_files_to_s3()
5
+ function publish_pact_file_to_pact_broker()
6
6
  {
7
- echo "Saving pact files to S3..."
8
- folder=${1:-latest}
9
- aws s3 cp pacts s3://ci-asset-cache/pacts/${JOB_NAME}/${folder} --recursive --only-show-errors --region us-east-1
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
- save_pact_files_to_s3
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
- - .:/usr/src/app/
6
+ - .:/app
7
+ - bundler-config:/home/docker/.rvm/gems/ruby-2.4.0
7
8
 
8
9
  contracts-testrunner:
9
10
  volumes:
10
- - .:/usr/src/app/
11
+ - .:/app
12
+ - bundler-config:/home/docker/.rvm/gems/ruby-2.4.0
13
+
14
+ volumes:
15
+ bundler-config: {}
data/docker-compose.yml CHANGED
@@ -8,3 +8,8 @@ services:
8
8
  build:
9
9
  context: .
10
10
  dockerfile: Dockerfile.contracts
11
+ volumes:
12
+ - pacts:/usr/src/app/pacts
13
+
14
+ volumes:
15
+ pacts: {}
@@ -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, path, request_options = {})
74
+ def make_request(method, url, request_options = {})
69
75
  self.class.send(
70
76
  method,
71
- "#{uri}#{path}",
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, path, request_options)
84
+ def make_paginated_request(method, url, request_options)
79
85
  entities = []
80
- request_path = path
86
+ request_url = url
81
87
 
82
- until request_path.nil? do
83
- resp = make_request(method, request_path, request_options)
88
+ until request_url.nil? do
89
+ resp = make_request(method, request_url, request_options)
84
90
  entities.concat(resp.parsed_response)
85
- request_path = next_page(resp)
91
+ request_url = next_page(resp)
86
92
  end
87
93
  entities
88
94
  end
@@ -1,3 +1,3 @@
1
1
  module QuizApiClient
2
- VERSION = '2.4.0'.freeze
2
+ VERSION = '2.4.1'.freeze
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require 'httparty'
2
2
  require 'jwt'
3
+ require 'link_header'
3
4
 
4
5
  module QuizApiClient
5
6
  class Client
@@ -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.12.0'
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.0
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-09-28 00:00:00.000000000 Z
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.12.0
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.12.0
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.6.13
236
+ rubygems_version: 2.5.1
223
237
  signing_key:
224
238
  specification_version: 4
225
239
  summary: Ruby client for quiz_api