defra_ruby_mocks 1.0.0

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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +8 -0
  3. data/README.md +149 -0
  4. data/Rakefile +38 -0
  5. data/app/controllers/defra_ruby_mocks/application_controller.rb +17 -0
  6. data/app/controllers/defra_ruby_mocks/company_controller.rb +23 -0
  7. data/app/services/defra_ruby_mocks/base_service.rb +9 -0
  8. data/app/services/defra_ruby_mocks/companies_house_service.rb +54 -0
  9. data/app/views/defra_ruby_mocks/company/not_found.json.erb +8 -0
  10. data/app/views/defra_ruby_mocks/company/show.json.erb +3 -0
  11. data/config/routes.rb +8 -0
  12. data/lib/defra_ruby_mocks.rb +26 -0
  13. data/lib/defra_ruby_mocks/configuration.rb +39 -0
  14. data/lib/defra_ruby_mocks/engine.rb +13 -0
  15. data/lib/defra_ruby_mocks/version.rb +5 -0
  16. data/lib/tasks/changelog.rake +8 -0
  17. data/lib/tasks/defra_ruby_mocks_tasks.rake +8 -0
  18. data/spec/defra_ruby_mocks_spec.rb +44 -0
  19. data/spec/dummy/README.rdoc +28 -0
  20. data/spec/dummy/Rakefile +6 -0
  21. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  22. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  23. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  24. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  25. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  26. data/spec/dummy/bin/bundle +3 -0
  27. data/spec/dummy/bin/rails +4 -0
  28. data/spec/dummy/bin/rake +4 -0
  29. data/spec/dummy/bin/setup +29 -0
  30. data/spec/dummy/config.ru +4 -0
  31. data/spec/dummy/config/application.rb +27 -0
  32. data/spec/dummy/config/boot.rb +5 -0
  33. data/spec/dummy/config/environment.rb +5 -0
  34. data/spec/dummy/config/environments/development.rb +38 -0
  35. data/spec/dummy/config/environments/production.rb +76 -0
  36. data/spec/dummy/config/environments/test.rb +42 -0
  37. data/spec/dummy/config/initializers/assets.rb +11 -0
  38. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  39. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  40. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  41. data/spec/dummy/config/initializers/inflections.rb +16 -0
  42. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  43. data/spec/dummy/config/initializers/session_store.rb +3 -0
  44. data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  45. data/spec/dummy/config/initializers/wrap_parameters.rb +9 -0
  46. data/spec/dummy/config/locales/en.yml +23 -0
  47. data/spec/dummy/config/routes.rb +4 -0
  48. data/spec/dummy/config/secrets.yml +22 -0
  49. data/spec/dummy/log/development.log +0 -0
  50. data/spec/dummy/log/test.log +147 -0
  51. data/spec/dummy/public/404.html +67 -0
  52. data/spec/dummy/public/422.html +67 -0
  53. data/spec/dummy/public/500.html +66 -0
  54. data/spec/dummy/public/favicon.ico +0 -0
  55. data/spec/examples.txt +30 -0
  56. data/spec/lib/configuration_spec.rb +75 -0
  57. data/spec/rails_helper.rb +46 -0
  58. data/spec/requests/company_spec.rb +80 -0
  59. data/spec/services/companies_house_service_spec.rb +47 -0
  60. data/spec/spec_helper.rb +82 -0
  61. data/spec/support/helpers/configuration.rb +16 -0
  62. data/spec/support/pry.rb +7 -0
  63. data/spec/support/simplecov.rb +17 -0
  64. metadata +237 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a51d8ad9a6aacfc79ec4354df4b6ac22a95e4d3e
4
+ data.tar.gz: f97be7da287ba2987204dea1cc6ae72b188aa454
5
+ SHA512:
6
+ metadata.gz: 4251aedd24958f9cb6bac0f0fc6378f741f8fbf798e87f07e4cce3379c2c276bbd5ce28ec6a89b8d8cef378eb8a9182679c4f53d823763df38c0d7b49ed45b87
7
+ data.tar.gz: d9ea74e870ab67ad6cca27b328a41ac7ddb0e132f435c718a596b91f1f0f9161067364497fc43b546b2fbff94c8a59a25a597976d65385d9fb3e166d4b7a1e07
data/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ The Open Government Licence (OGL) Version 3
2
+
3
+ Copyright (c) 2019 Environment Agency
4
+
5
+ This source code is licensed under the Open Government Licence v3.0. To view this
6
+ licence, visit www.nationalarchives.gov.uk/doc/open-government-licence/version/3
7
+ or write to the Information Policy Team, The National Archives, Kew, Richmond,
8
+ Surrey, TW9 4DU.
@@ -0,0 +1,149 @@
1
+ # Defra Ruby Mocks
2
+
3
+ [![Build Status](https://travis-ci.com/DEFRA/defra-ruby-mocks.svg?branch=master)](https://travis-ci.com/DEFRA/defra-ruby-mocks)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/8b14cc1e0e1c1d6a33cc/maintainability)](https://codeclimate.com/github/DEFRA/defra-ruby-mocks/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/8b14cc1e0e1c1d6a33cc/test_coverage)](https://codeclimate.com/github/DEFRA/defra-ruby-mocks/test_coverage)
6
+ [![security](https://hakiri.io/github/DEFRA/defra-ruby-mocks/master.svg)](https://hakiri.io/github/DEFRA/defra-ruby-mocks/master)
7
+ [![Licence](https://img.shields.io/badge/Licence-OGLv3-blue.svg)](http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3)
8
+
9
+ A Rails Engine used by the [Ruby services team](https://github.com/DEFRA/ruby-services-team) in their digital services.
10
+
11
+ We use it to mock external services such as Companies House, so we can performance test our services and not get in trouble!
12
+
13
+ When mounted in an app, it will add additional endpoints which when called will 'mock' the functionality of the external service.
14
+
15
+ Things to note
16
+
17
+ - We have gone with an engine rather than an additional service, to simplify management of mocking in our environments
18
+ - The mocks do not replicate all functionality an external service provides, only the features we use in our services
19
+
20
+ ## Prerequisites
21
+
22
+ Make sure you already have:
23
+
24
+ - Ruby 2.4.2
25
+ - [Bundler](http://bundler.io/) – for installing Ruby gems
26
+
27
+ ## Mounting the engine
28
+
29
+ Add the engine to your Gemfile:
30
+
31
+ ```ruby
32
+ gem "defra_ruby_mocks",
33
+ git: "https://github.com/DEFRA/defra-ruby-mocks"
34
+ ```
35
+
36
+ Install it with `bundle install`.
37
+
38
+ Then mount the engine in your routes.rb file:
39
+
40
+ ```ruby
41
+ Rails.application.routes.draw do
42
+ mount DefraRubyMocks::Engine => "/mocks"
43
+ end
44
+ ```
45
+
46
+ The engine should now be mounted at `/mocks` of your project. You can change `"/mocks"` to a different route if you'd prefer it to be elsewhere.
47
+
48
+ ## Configuration
49
+
50
+ For the mock routes to be accessible you'll also need to enable them.
51
+
52
+ ```ruby
53
+ # config/initializers/defra_ruby_mocks.rb
54
+ require "defra_ruby_mocks"
55
+
56
+ DefraRubyMocks.configure do |config|
57
+ config.enable = true
58
+ config.delay = 1000
59
+ end
60
+ ```
61
+
62
+ To protect against having them enabled when in production, by default the engine will not allow access unless they have been enabled in the config.
63
+
64
+ We also provide an option to control how long the mock should delay before responding. The default is 1000ms (1 second).
65
+
66
+ ## Mocks
67
+
68
+ The project currently mocks the following services.
69
+
70
+ ### Companies House
71
+
72
+ When mounted into an app you can make requests to `/mocks/company/[company number]` to get a response that matches what our apps expect.
73
+
74
+ This is an important distinction to note. When our apps like the [Waste Exemptions front office](https://github.com/DEFRA/waste-exemptions-front-office) make a real request to Companies House, they get a lot more information back in the JSON reponse. However the only thing they are interested in is the value of `"company_status"`.
75
+
76
+ So rather than maintain a lot of unused JSON data, the mock just returns that bit of the JSON.
77
+
78
+ ```bash
79
+ curl http://localhost:3000/mocks/company/SC123456
80
+ {
81
+ "company_status": "active"
82
+ }
83
+ ```
84
+
85
+ #### Company numbers
86
+
87
+ As long as the request is for a valid number the mock will return the status as `"active"`. (see <https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/426891/uniformResourceIdentifiersCustomerGuide.pdf> for details of valid number formats).
88
+
89
+ The exceptions to this are the 'special' numbers listed below. Use them if you are looking for alternate responses.
90
+
91
+ - `05868270` will return `"dissolved"`
92
+ - `04270505` will return `"administration"`
93
+ - `99999999` will mock a not found result and return a 404 error
94
+ - `88888888` will return `"liquidation"`
95
+ - `77777777` will return `"receivership"`
96
+ - `66666666` will return `"converted-closed"`
97
+ - `55555555` will return `"voluntary-arrangement"`
98
+ - `44444444` will return `"insolvency-proceedings"`
99
+ - `33333333` will return `"open"`
100
+ - `22222222` will return `"closed"`
101
+
102
+ The list of possible statuses was taken from
103
+
104
+ - [Companies House API](https://developer.companieshouse.gov.uk/api/docs/company/company_number/companyProfile-resource.html)
105
+ - [Companies House API enumerations](https://github.com/companieshouse/api-enumerations/blob/master/constants.yml)
106
+
107
+ ## Installation
108
+
109
+ You don't need to do this if you're just mounting the engine without making any changes.
110
+
111
+ However, if you want to edit the engine, you'll have to install it locally.
112
+
113
+ Clone the repo and drop into the project:
114
+
115
+ ```bash
116
+ git clone https://github.com/DEFRA/defra-ruby-mocks.git && cd defra-ruby-mocks
117
+ ```
118
+
119
+ Then install the dependencies with `bundle install`.
120
+
121
+ ## Testing the engine
122
+
123
+ The engine is mounted in a dummy Rails 4 app (in /spec/dummy) so we can properly test its behaviour.
124
+
125
+ The test suite is written in RSpec.
126
+
127
+ To run all the tests, use `bundle exec rspec`.
128
+
129
+ ## Contributing to this project
130
+
131
+ If you have an idea you'd like to contribute please log an issue.
132
+
133
+ All contributions should be submitted via a pull request.
134
+
135
+ ## License
136
+
137
+ THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
138
+
139
+ <http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3>
140
+
141
+ The following attribution statement MUST be cited in your products and applications when using this information.
142
+
143
+ > Contains public sector information licensed under the Open Government license v3
144
+
145
+ ### About the license
146
+
147
+ The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
148
+
149
+ It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "bundler/setup"
5
+ rescue LoadError
6
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
+ end
8
+
9
+ require "rdoc/task"
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = "rdoc"
13
+ rdoc.title = "DefraRubyMocks"
14
+ rdoc.options << "--line-numbers"
15
+ rdoc.rdoc_files.include("README.rdoc")
16
+ rdoc.rdoc_files.include("lib/**/*.rb")
17
+ end
18
+
19
+ load "rails/tasks/statistics.rake"
20
+
21
+ Dir[File.join(File.dirname(__FILE__), "lib/tasks/**/*.rake")].each { |f| load f }
22
+
23
+ Bundler::GemHelper.install_tasks
24
+
25
+ # This is wrapped to prevent an error when rake is called in environments where
26
+ # rspec may not be available, e.g. production. As such we don't need to handle
27
+ # the error.
28
+ # rubocop:disable Lint/HandleExceptions
29
+ begin
30
+ require "rspec/core/rake_task"
31
+
32
+ RSpec::Core::RakeTask.new(:spec)
33
+
34
+ task default: :spec
35
+ rescue LoadError
36
+ # no rspec available
37
+ end
38
+ # rubocop:enable Lint/HandleExceptions
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyMocks
4
+ class ApplicationController < ActionController::Base
5
+ protect_from_forgery with: :exception
6
+ before_action :delay_response
7
+
8
+ private
9
+
10
+ def delay_response
11
+ # sleep() expects the time to be specified in seconds, but we allow delay
12
+ # to be specified in milliseconds. Dividing by 1000 converts milliseconds
13
+ # to seconds.
14
+ sleep(DefraRubyMocks.configuration.delay / 1000)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyMocks
4
+ class CompanyController < ApplicationController
5
+
6
+ before_action :set_default_response_format
7
+
8
+ def show
9
+ @status = CompaniesHouseService.run(params[:id])
10
+
11
+ respond_to :json
12
+ rescue NotFoundError
13
+ render "not_found", status: 404
14
+ end
15
+
16
+ private
17
+
18
+ def set_default_response_format
19
+ request.format = :json
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyMocks
4
+ class BaseService
5
+ def self.run(attrs = nil)
6
+ new.run(attrs)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyMocks
4
+ class NotFoundError < StandardError
5
+ end
6
+
7
+ class CompaniesHouseService < BaseService
8
+
9
+ # Examples we need to validate are
10
+ # 10997904, 09764739
11
+ # SC534714, CE000958
12
+ # IP00141R, IP27702R, SP02252R
13
+ # https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/426891/uniformResourceIdentifiersCustomerGuide.pdf
14
+ VALID_COMPANIES_HOUSE_REGISTRATION_NUMBER_REGEX = Regexp.new(
15
+ /\A(\d{8,8}$)|([a-zA-Z]{2}\d{6}$)|([a-zA-Z]{2}\d{5}[a-zA-Z]{1}$)\z/i
16
+ ).freeze
17
+
18
+ NOT_FOUND = "99999999"
19
+
20
+ def self.special_company_numbers
21
+ {
22
+ "05868270" => "dissolved",
23
+ "04270505" => "administration",
24
+ "88888888" => "liquidation",
25
+ "77777777" => "receivership",
26
+ "66666666" => "converted-closed",
27
+ "55555555" => "voluntary-arrangement",
28
+ "44444444" => "insolvency-proceedings",
29
+ "33333333" => "open",
30
+ "22222222" => "closed"
31
+ }
32
+ end
33
+
34
+ def run(company_number)
35
+ raise NotFoundError unless valid_company_number?(company_number)
36
+ raise NotFoundError if company_number == NOT_FOUND
37
+
38
+ return specials[company_number] if specials.key?(company_number)
39
+
40
+ "active"
41
+ end
42
+
43
+ private
44
+
45
+ def valid_company_number?(company_number)
46
+ company_number.match?(VALID_COMPANIES_HOUSE_REGISTRATION_NUMBER_REGEX)
47
+ end
48
+
49
+ def specials
50
+ self.class.special_company_numbers
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,8 @@
1
+ {
2
+ "errors": [
3
+ {
4
+ "type": "ch:service",
5
+ "error": "company-profile-not-found"
6
+ }
7
+ ]
8
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "company_status": "<%= @status %>"
3
+ }
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ DefraRubyMocks::Engine.routes.draw do
4
+ get "/company/:id",
5
+ to: "company#show",
6
+ as: "company",
7
+ constraints: ->(_request) { DefraRubyMocks.configuration.enabled? }
8
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "defra_ruby_mocks/engine"
4
+
5
+ module DefraRubyMocks
6
+ # Enable the ability to configure the gem from its host app, rather than
7
+ # reading directly from env vars. Derived from
8
+ # https://robots.thoughtbot.com/mygem-configure-block
9
+ class << self
10
+ attr_writer :configuration
11
+
12
+ def configuration
13
+ @configuration ||= Configuration.new
14
+ end
15
+
16
+ # Added for testing. Without we cannot test both a config object with and
17
+ # with set values in the same rspec session
18
+ def reset_configuration
19
+ @configuration = nil
20
+ end
21
+ end
22
+
23
+ def self.configure
24
+ yield(configuration)
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyMocks
4
+ class Configuration
5
+
6
+ DEFAULT_DELAY = 1000
7
+
8
+ attr_reader :delay
9
+
10
+ def initialize
11
+ @enable = false
12
+ @delay = DEFAULT_DELAY
13
+ end
14
+
15
+ # Controls whether the mocks are enabled. Only if set to true will the mock
16
+ # pages be accessible
17
+ def enable=(arg)
18
+ # We implement our own setter to handle values being passed in as strings
19
+ # rather than booleans
20
+ parsed = arg.to_s.downcase
21
+
22
+ @enable = parsed == "true"
23
+ end
24
+
25
+ def enabled?
26
+ @enable
27
+ end
28
+
29
+ # Set a delay in milliseconds for the mocks to respond.
30
+ # Defaults to 1000 (1 sec)
31
+ def delay=(arg)
32
+ # We implement our own setter to handle values being passed in as strings
33
+ # rather than integers
34
+ @delay = arg.to_i
35
+
36
+ @delay = DEFAULT_DELAY if @delay.zero?
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "configuration"
4
+
5
+ module DefraRubyMocks
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace DefraRubyMocks
8
+
9
+ config.generators do |g|
10
+ g.test_framework :rspec
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DefraRubyMocks
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "github_changelog_generator/task"
4
+
5
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
6
+ config.user = "DEFRA"
7
+ config.project = "defra-ruby-mocks"
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # namespace :defra_ruby_mocks do
4
+ # desc "Explaining what the task does"
5
+ # task :test do
6
+ # # Task goes here
7
+ # end
8
+ # end