mno-enterprise-core 2.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.
- checksums.yaml +7 -0
- data/LICENSE +1 -0
- data/Rakefile +12 -0
- data/app/assets/images/mno_enterprise/main-logo.png +0 -0
- data/app/controllers/mno_enterprise/application_controller.rb +116 -0
- data/app/helpers/mno_enterprise/application_helper.rb +67 -0
- data/app/helpers/mno_enterprise/impersonate_helper.rb +27 -0
- data/app/models/mno_enterprise/ability.rb +6 -0
- data/app/models/mno_enterprise/app.rb +72 -0
- data/app/models/mno_enterprise/app_instance.rb +36 -0
- data/app/models/mno_enterprise/app_instances_sync.rb +6 -0
- data/app/models/mno_enterprise/arrears_situation.rb +6 -0
- data/app/models/mno_enterprise/audit_event.rb +21 -0
- data/app/models/mno_enterprise/base_resource.rb +228 -0
- data/app/models/mno_enterprise/credit_card.rb +40 -0
- data/app/models/mno_enterprise/deletion_request.rb +35 -0
- data/app/models/mno_enterprise/impac/dashboard.rb +36 -0
- data/app/models/mno_enterprise/impac/dashboard_provisioner.rb +5 -0
- data/app/models/mno_enterprise/impac/kpi.rb +9 -0
- data/app/models/mno_enterprise/impac/widget.rb +13 -0
- data/app/models/mno_enterprise/invoice.rb +53 -0
- data/app/models/mno_enterprise/org_invite.rb +50 -0
- data/app/models/mno_enterprise/organization.rb +33 -0
- data/app/models/mno_enterprise/team.rb +50 -0
- data/app/models/mno_enterprise/tenant.rb +5 -0
- data/app/models/mno_enterprise/tenant_invoice.rb +5 -0
- data/app/models/mno_enterprise/user.rb +183 -0
- data/app/pdf/mno_enterprise/invoice_pdf.rb +516 -0
- data/config/initializers/audit_log.rb +5 -0
- data/config/locales/devise.en.yml +60 -0
- data/config/routes.rb +2 -0
- data/config/styleguide.yml +106 -0
- data/lib/accountingjs_serializer.rb +51 -0
- data/lib/devise/controllers/extension_helpers.rb +52 -0
- data/lib/devise/extension_routes.rb +11 -0
- data/lib/devise/hooks/password_expirable.rb +5 -0
- data/lib/devise/models/password_expirable.rb +28 -0
- data/lib/devise/models/remote_authenticatable.rb +48 -0
- data/lib/devise/strategies/remote_authenticatable.rb +44 -0
- data/lib/devise_extension.rb +36 -0
- data/lib/faraday/adapter/net_http_no_proxy.rb +19 -0
- data/lib/generators/mno_enterprise/database_extension/USAGE +11 -0
- data/lib/generators/mno_enterprise/database_extension/database_extension_generator.rb +36 -0
- data/lib/generators/mno_enterprise/database_extension/templates/model.rb +9 -0
- data/lib/generators/mno_enterprise/dummy/dummy_generator.rb +98 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/application.rb.erb +9 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/boot.rb.erb +6 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/database.yml +22 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/routes.rb +8 -0
- data/lib/generators/mno_enterprise/dummy/templates/rails/test-env.rb +45 -0
- data/lib/generators/mno_enterprise/install/install_generator.rb +140 -0
- data/lib/generators/mno_enterprise/install/templates/Procfile +1 -0
- data/lib/generators/mno_enterprise/install/templates/config/initializers/mno_enterprise.rb +135 -0
- data/lib/generators/mno_enterprise/install/templates/config/mno_enterprise_styleguide.yml +104 -0
- data/lib/generators/mno_enterprise/install/templates/javascripts/mno_enterprise_extensions.js +7 -0
- data/lib/generators/mno_enterprise/install/templates/stylesheets/main.less_erb +25 -0
- data/lib/generators/mno_enterprise/install/templates/stylesheets/theme.less_erb +59 -0
- data/lib/generators/mno_enterprise/install/templates/stylesheets/variables.less +337 -0
- data/lib/generators/mno_enterprise/install/templates/tasks/sprites.rake +14 -0
- data/lib/generators/mno_enterprise/puma_stack/puma_stack_generator.rb +58 -0
- data/lib/generators/mno_enterprise/templates/scripts/monit/app-server.conf +8 -0
- data/lib/generators/mno_enterprise/templates/scripts/nginx/app +51 -0
- data/lib/generators/mno_enterprise/templates/scripts/puma.rb +25 -0
- data/lib/generators/mno_enterprise/templates/scripts/setup.sh +27 -0
- data/lib/generators/mno_enterprise/templates/scripts/upstart/app-web-hotrestart.conf +26 -0
- data/lib/generators/mno_enterprise/templates/scripts/upstart/app-web-server.conf +34 -0
- data/lib/generators/mno_enterprise/templates/scripts/upstart/app-web.conf +2 -0
- data/lib/generators/mno_enterprise/templates/scripts/upstart/app.conf +11 -0
- data/lib/her_extension/her_orm_adapter.rb +54 -0
- data/lib/her_extension/middleware/mnoe_api_v1_parse_json.rb +54 -0
- data/lib/her_extension/model/associations/association.rb +61 -0
- data/lib/her_extension/model/associations/association_proxy.rb +34 -0
- data/lib/her_extension/model/associations/has_many_association.rb +115 -0
- data/lib/her_extension/model/attributes.rb +43 -0
- data/lib/her_extension/model/orm.rb +59 -0
- data/lib/her_extension/model/parse.rb +40 -0
- data/lib/her_extension/model/relation.rb +92 -0
- data/lib/her_extension/validations/remote_uniqueness_validation.rb +33 -0
- data/lib/html_processor.rb +106 -0
- data/lib/mandrill_client.rb +58 -0
- data/lib/mno-enterprise-core.rb +1 -0
- data/lib/mno_enterprise/concerns.rb +4 -0
- data/lib/mno_enterprise/concerns/controllers.rb +6 -0
- data/lib/mno_enterprise/concerns/controllers/angular_csrf.rb +59 -0
- data/lib/mno_enterprise/concerns/controllers/auth.rb +9 -0
- data/lib/mno_enterprise/concerns/controllers/auth/confirmations_controller.rb +187 -0
- data/lib/mno_enterprise/concerns/controllers/auth/passwords_controller.rb +54 -0
- data/lib/mno_enterprise/concerns/controllers/auth/registrations_controller.rb +136 -0
- data/lib/mno_enterprise/concerns/controllers/auth/sessions_controller.rb +54 -0
- data/lib/mno_enterprise/concerns/controllers/auth/unlocks_controller.rb +50 -0
- data/lib/mno_enterprise/concerns/models.rb +6 -0
- data/lib/mno_enterprise/concerns/models/ability.rb +108 -0
- data/lib/mno_enterprise/concerns/models/app_instance.rb +100 -0
- data/lib/mno_enterprise/concerns/models/organization.rb +102 -0
- data/lib/mno_enterprise/core.rb +279 -0
- data/lib/mno_enterprise/database_extendable.rb +57 -0
- data/lib/mno_enterprise/engine.rb +33 -0
- data/lib/mno_enterprise/testing_support/ability_test_helper.rb +10 -0
- data/lib/mno_enterprise/testing_support/common_rake.rb +19 -0
- data/lib/mno_enterprise/testing_support/factories.rb +13 -0
- data/lib/mno_enterprise/testing_support/factories/app_instances.rb +30 -0
- data/lib/mno_enterprise/testing_support/factories/apps.rb +45 -0
- data/lib/mno_enterprise/testing_support/factories/arrears_situation.rb +14 -0
- data/lib/mno_enterprise/testing_support/factories/audit_event.rb +15 -0
- data/lib/mno_enterprise/testing_support/factories/credit_card.rb +33 -0
- data/lib/mno_enterprise/testing_support/factories/deletion_request.rb +17 -0
- data/lib/mno_enterprise/testing_support/factories/impac/dashboards.rb +15 -0
- data/lib/mno_enterprise/testing_support/factories/impac/kpis.rb +20 -0
- data/lib/mno_enterprise/testing_support/factories/impac/widgets.rb +15 -0
- data/lib/mno_enterprise/testing_support/factories/invoices.rb +51 -0
- data/lib/mno_enterprise/testing_support/factories/org_invite.rb +24 -0
- data/lib/mno_enterprise/testing_support/factories/organizations.rb +25 -0
- data/lib/mno_enterprise/testing_support/factories/team.rb +17 -0
- data/lib/mno_enterprise/testing_support/factories/tenant.rb +12 -0
- data/lib/mno_enterprise/testing_support/factories/tenant_invoice.rb +29 -0
- data/lib/mno_enterprise/testing_support/factories/users.rb +48 -0
- data/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb +49 -0
- data/lib/mno_enterprise/testing_support/mno_enterprise_api_test_helper.rb +167 -0
- data/lib/mno_enterprise/testing_support/mnoe_faraday_test_adapter.rb +173 -0
- data/lib/mno_enterprise/testing_support/organizations_shared_helpers.rb +175 -0
- data/lib/mno_enterprise/testing_support/user_action_shared.rb +47 -0
- data/lib/mno_enterprise/version.rb +3 -0
- data/lib/tasks/mno_enterprise_tasks.rake +22 -0
- data/spec/controllers/mno_enterprise/angular_csrf_spec.rb +42 -0
- data/spec/lib/her_extension/her_orm_adapter.rb +7 -0
- data/spec/lib/her_extension/model/relation_spec.rb +7 -0
- data/spec/lib/mandrill_client_spec.rb +64 -0
- data/spec/mno_enterprise_spec.rb +79 -0
- data/spec/models/mno_enterprise/app_instance_spec.rb +7 -0
- data/spec/models/mno_enterprise/app_spec.rb +62 -0
- data/spec/models/mno_enterprise/base_resource_spec.rb +28 -0
- data/spec/models/mno_enterprise/deletion_request_spec.rb +26 -0
- data/spec/models/mno_enterprise/invoice_spec.rb +7 -0
- data/spec/models/mno_enterprise/organization_spec.rb +7 -0
- data/spec/models/mno_enterprise/user_spec.rb +44 -0
- data/spec/rails_helper.rb +73 -0
- data/spec/spec_helper.rb +78 -0
- metadata +421 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Read about factories at https://github.com/thoughtbot/factory_girl
|
|
2
|
+
|
|
3
|
+
FactoryGirl.define do
|
|
4
|
+
factory :mno_enterprise_team, :class => 'MnoEnterprise::Team' do
|
|
5
|
+
|
|
6
|
+
factory :team, class: MnoEnterprise::Team do
|
|
7
|
+
sequence(:id)
|
|
8
|
+
sequence(:name) { |n| "Team#{n}" }
|
|
9
|
+
|
|
10
|
+
created_at 3.days.ago
|
|
11
|
+
updated_at 1.hour.ago
|
|
12
|
+
|
|
13
|
+
# Properly build the resource with Her
|
|
14
|
+
initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
FactoryGirl.define do
|
|
2
|
+
|
|
3
|
+
factory :tenant, class: MnoEnterprise::Tenant do
|
|
4
|
+
last_portfolio_amount Money.new(65644,'AUD')
|
|
5
|
+
last_customers_invoicing_amount Money.new(687994,'AUD')
|
|
6
|
+
last_customers_outstanding_amount Money.new(178986,'AUD')
|
|
7
|
+
last_commission_amount Money.new(412345,'AUD')
|
|
8
|
+
|
|
9
|
+
# Properly build the resource with Her
|
|
10
|
+
initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Read about factories at https://github.com/thoughtbot/factory_girl
|
|
2
|
+
|
|
3
|
+
FactoryGirl.define do
|
|
4
|
+
factory :mno_enterprise_tenant_invoice, :class => 'TenantInvoice' do
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
factory :tenant_invoice, class: MnoEnterprise::TenantInvoice do
|
|
8
|
+
sequence(:id)
|
|
9
|
+
sequence(:slug) { |n| "201504-NU#{n}" }
|
|
10
|
+
organization_id 265
|
|
11
|
+
|
|
12
|
+
started_at 28.days.ago
|
|
13
|
+
ended_at 3.days.ago
|
|
14
|
+
created_at 3.days.ago
|
|
15
|
+
updated_at 1.hour.ago
|
|
16
|
+
paid_at nil
|
|
17
|
+
|
|
18
|
+
total_commission_amount Money.new(0,'AUD')
|
|
19
|
+
total_portfolio_amount Money.new(0,'AUD')
|
|
20
|
+
non_commissionable_amount Money.new(0,'AUD')
|
|
21
|
+
mno_commission_amount Money.new(0,'AUD')
|
|
22
|
+
|
|
23
|
+
# Properly build the resource with Her
|
|
24
|
+
initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Read about factories at https://github.com/thoughtbot/factory_girl
|
|
2
|
+
|
|
3
|
+
# This is an API resource factory generating a Hash to be used in API stubs
|
|
4
|
+
# Use as such: build(:api_user)
|
|
5
|
+
# See http://stackoverflow.com/questions/10032760/how-to-define-an-array-hash-in-factory-girl
|
|
6
|
+
FactoryGirl.define do
|
|
7
|
+
|
|
8
|
+
factory :user, class: MnoEnterprise::User do
|
|
9
|
+
sequence(:id)
|
|
10
|
+
sequence(:uid) { |n| "usr-fda9#{n}" }
|
|
11
|
+
name "John"
|
|
12
|
+
surname "Doe"
|
|
13
|
+
sequence(:email) { |n| "john.doe#{n}@maestrano.com" }
|
|
14
|
+
company "Doe Inc."
|
|
15
|
+
phone "449 789 456"
|
|
16
|
+
phone_country_code "AU"
|
|
17
|
+
geo_country_code "AU"
|
|
18
|
+
geo_state_code "NSW"
|
|
19
|
+
geo_city "Sydney"
|
|
20
|
+
created_at 2.days.ago
|
|
21
|
+
updated_at 2.days.ago
|
|
22
|
+
sso_session "1fdd5sf5a73D7sd1as2a4sd541"
|
|
23
|
+
admin_role false
|
|
24
|
+
|
|
25
|
+
confirmation_sent_at 2.days.ago
|
|
26
|
+
confirmation_token "wky763pGjtzWR7dP44PD"
|
|
27
|
+
confirmed_at 1.days.ago
|
|
28
|
+
|
|
29
|
+
trait :unconfirmed do
|
|
30
|
+
confirmed_at nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
trait :admin do
|
|
34
|
+
admin_role true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
trait :with_deletion_request do
|
|
38
|
+
deletion_request { build(:deletion_request).attributes }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
trait :with_organizations do
|
|
42
|
+
organizations { [build(:organization).attributes] }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Properly build the resource with Her
|
|
46
|
+
initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module MnoEnterprise::TestingSupport::JpiV1TestHelper
|
|
2
|
+
|
|
3
|
+
# Expect 'user' to be assigned
|
|
4
|
+
shared_examples "jpi v1 protected action" do
|
|
5
|
+
context "with guest user" do
|
|
6
|
+
it "prevents access" do
|
|
7
|
+
sign_out user
|
|
8
|
+
expect(subject).to_not be_successful
|
|
9
|
+
expect(subject.code).to eq('401')
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context 'with signed in user' do
|
|
14
|
+
it "authorizes access" do
|
|
15
|
+
sign_in user
|
|
16
|
+
expect(subject).to be_successful
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Expect 'user' to be assigned
|
|
22
|
+
# Expect 'ability' to be assigned
|
|
23
|
+
shared_examples "jpi v1 authorizable action" do
|
|
24
|
+
context "with guest user" do
|
|
25
|
+
it "prevents access" do
|
|
26
|
+
sign_out user
|
|
27
|
+
expect(subject).to_not be_successful
|
|
28
|
+
expect(subject.code).to eq('401')
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context 'with unauthorized signed in user' do
|
|
33
|
+
it "prevents access" do
|
|
34
|
+
sign_in user
|
|
35
|
+
allow(ability).to receive(:can?).with(any_args).and_return(false)
|
|
36
|
+
expect(subject).to_not be_successful
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'with authorized signed in user' do
|
|
41
|
+
it "authorizes access" do
|
|
42
|
+
sign_in user
|
|
43
|
+
allow(ability).to receive(:can?).with(any_args).and_return(true)
|
|
44
|
+
expect(subject).to be_successful
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
module MnoEnterpriseApiTestHelper
|
|
2
|
+
|
|
3
|
+
# Take a resource and transform it into a Hash describing
|
|
4
|
+
# the resource as if it had been returned by the MnoEnterprise
|
|
5
|
+
# API server
|
|
6
|
+
def from_api(res)
|
|
7
|
+
{ data: serialize_type(res), metadata: {pagination: {count: entity_count(res)}} }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def serialize_type(res)
|
|
11
|
+
case
|
|
12
|
+
when res.kind_of?(Array)
|
|
13
|
+
return res.map { |e| serialize_type(e) }
|
|
14
|
+
when res.kind_of?(MnoEnterprise::BaseResource)
|
|
15
|
+
hash = res.attributes.dup
|
|
16
|
+
hash.each do |k,v|
|
|
17
|
+
hash[k] = serialize_type(v)
|
|
18
|
+
end
|
|
19
|
+
return hash
|
|
20
|
+
when res.kind_of?(Hash)
|
|
21
|
+
hash = res.dup
|
|
22
|
+
hash.each do |k,v|
|
|
23
|
+
hash[k] = serialize_type(v)
|
|
24
|
+
end
|
|
25
|
+
return hash
|
|
26
|
+
when res.kind_of?(Money)
|
|
27
|
+
return { cents: res.cents, currency: res.currency_as_string }
|
|
28
|
+
when res.respond_to?(:iso8601)
|
|
29
|
+
return res.iso8601
|
|
30
|
+
else
|
|
31
|
+
return res
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def entity_count(res)
|
|
36
|
+
case
|
|
37
|
+
when res.kind_of?(Array)
|
|
38
|
+
return res.count
|
|
39
|
+
when res.kind_of?(Hash)
|
|
40
|
+
return res.count
|
|
41
|
+
else
|
|
42
|
+
return 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Reset all API stubs.
|
|
47
|
+
# Called before each test (see spec_helper)
|
|
48
|
+
def api_stub_reset
|
|
49
|
+
@_api_stub = nil
|
|
50
|
+
@_stub_list = {}
|
|
51
|
+
api_stub_configure(Her::API.new)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Example usage:
|
|
55
|
+
#
|
|
56
|
+
# Without opts, it yields a faraday stub object which you can configure
|
|
57
|
+
# manually:
|
|
58
|
+
#
|
|
59
|
+
# You can also pass the response stub via opts
|
|
60
|
+
# api_stub_for(User,
|
|
61
|
+
# path: '/users/popular',
|
|
62
|
+
# response: [{ id: 1, name: "Tobias Fünke" }, { id: 2, name: "Lindsay Fünke" }]
|
|
63
|
+
# )
|
|
64
|
+
#
|
|
65
|
+
# You can also specify the response code:
|
|
66
|
+
# api_stub_for(User,
|
|
67
|
+
# path: '/users/popular',
|
|
68
|
+
# code: 200,
|
|
69
|
+
# response: [{ id: 1, name: "Tobias Fünke" }, { id: 2, name: "Lindsay Fünke" }]
|
|
70
|
+
# )
|
|
71
|
+
def api_stub_for(klass, opts = {})
|
|
72
|
+
real_opts = klass
|
|
73
|
+
if klass.is_a?(Class)
|
|
74
|
+
warn("DEPRECATION WARNING: api_stub_for(MyClass,{ some: 'opts'}) is deprecated. Please use api_stub_for({ some: 'opts' }) from now on")
|
|
75
|
+
real_opts = opts
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
set_api_stub
|
|
79
|
+
api_stub_add(real_opts)
|
|
80
|
+
api_stub_configure(@_api_stub)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
# Set a stub api on the provider class
|
|
85
|
+
def set_api_stub
|
|
86
|
+
return @_api_stub if @_api_stub
|
|
87
|
+
@_api_stub = Her::API.new
|
|
88
|
+
allow(MnoEnterprise::BaseResource).to receive(:her_api).and_return(@_api_stub = Her::API.new)
|
|
89
|
+
@_api_stub
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Add a stub to the api
|
|
93
|
+
# E.g.:
|
|
94
|
+
# {
|
|
95
|
+
# path: '/users/popular',
|
|
96
|
+
# code: 200,
|
|
97
|
+
# response: [{ id: 1, name: "Tobias Fünke" }, { id: 2, name: "Lindsay Fünke" }]
|
|
98
|
+
# }
|
|
99
|
+
def api_stub_add(orig_opts)
|
|
100
|
+
@_stub_list ||= {}
|
|
101
|
+
opts = orig_opts.dup
|
|
102
|
+
|
|
103
|
+
# Expand options so that: { put: '/path' } becomes { path: '/path', method: :put }
|
|
104
|
+
unless opts[:method] && opts[:path]
|
|
105
|
+
[:get,:put,:post,:delete].each do |verb|
|
|
106
|
+
if path = opts.delete(verb)
|
|
107
|
+
opts[:path] = path
|
|
108
|
+
opts[:method] = verb
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
key = opts.to_param
|
|
114
|
+
@_stub_list[key] = opts
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Configure the api and apply a list of stubs
|
|
118
|
+
def api_stub_configure(api)
|
|
119
|
+
# This block should match the her.rb initializer
|
|
120
|
+
api.setup MnoEnterprise.send(:api_options).merge(url: "http://localhost:65000") do |c|
|
|
121
|
+
# Request
|
|
122
|
+
c.use Faraday::Request::BasicAuthentication, MnoEnterprise.tenant_id, MnoEnterprise.tenant_key
|
|
123
|
+
c.use Faraday::Request::UrlEncoded
|
|
124
|
+
|
|
125
|
+
# Response
|
|
126
|
+
c.use Her::Middleware::MnoeApiV1ParseJson
|
|
127
|
+
|
|
128
|
+
# Add stubs on the test adapter
|
|
129
|
+
c.use MnoeFaradayTestAdapter do |receiver|
|
|
130
|
+
@_stub_list.each do |key,stub|
|
|
131
|
+
params = stub[:params] && stub[:params].any? ? "?#{stub[:params].to_param}" : ""
|
|
132
|
+
path = "#{stub[:path]}#{params}"
|
|
133
|
+
|
|
134
|
+
receiver.send(stub[:method] || :get,path) { |env|
|
|
135
|
+
body = Rack::Utils.parse_nested_query(env.body)
|
|
136
|
+
|
|
137
|
+
# respond_with takes a model in argument and automatically responds with
|
|
138
|
+
# a json representation of the model
|
|
139
|
+
# If the action is an update, it attempts to update the model
|
|
140
|
+
if model = stub[:respond_with]
|
|
141
|
+
model.assign_attributes(body['data']) if stub[:method] == :put && model.respond_to?(:assign_attributes) && body['data']
|
|
142
|
+
resp = from_api(model)
|
|
143
|
+
else
|
|
144
|
+
if stub[:response].is_a?(Proc)
|
|
145
|
+
args = stub[:response].arity > 0 ? [body] : []
|
|
146
|
+
resp = stub[:response].call(*args)
|
|
147
|
+
else
|
|
148
|
+
resp = stub[:response] || {}
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Response code
|
|
153
|
+
if stub[:code].is_a?(Proc)
|
|
154
|
+
args = stub[:code].arity > 0 ? [body] : []
|
|
155
|
+
resp_code = stub[:code].call(*args)
|
|
156
|
+
else
|
|
157
|
+
resp_code = stub[:code] || 200
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
[resp_code, {}, resp.to_json]
|
|
162
|
+
}
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Adapter and modified from: https://github.com/lostisland/faraday/blob/master/lib/faraday/adapter/test.rb
|
|
2
|
+
#
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# test = Faraday::Connection.new do
|
|
6
|
+
# use MnoeFaradayTestAdapter do |stub|
|
|
7
|
+
# stub.get '/nigiri/sake.json' do
|
|
8
|
+
# [200, {}, 'hi world']
|
|
9
|
+
# end
|
|
10
|
+
# end
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# resp = test.get '/nigiri/sake.json'
|
|
14
|
+
# resp.body # => 'hi world'
|
|
15
|
+
#
|
|
16
|
+
class MnoeFaradayTestAdapter < Faraday::Adapter
|
|
17
|
+
attr_accessor :stubs
|
|
18
|
+
|
|
19
|
+
class Stubs
|
|
20
|
+
class NotFound < StandardError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def initialize
|
|
24
|
+
# {:get => [Stub, Stub]}
|
|
25
|
+
@stack, @consumed = {}, {}
|
|
26
|
+
yield(self) if block_given?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def empty?
|
|
30
|
+
@stack.empty?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def match(request_method, path, headers, body)
|
|
34
|
+
return false if !@stack.key?(request_method)
|
|
35
|
+
stack = @stack[request_method]
|
|
36
|
+
consumed = (@consumed[request_method] ||= [])
|
|
37
|
+
|
|
38
|
+
if stub = matches?(stack, path, headers, body)
|
|
39
|
+
consumed << stack.delete(stub)
|
|
40
|
+
stub
|
|
41
|
+
else
|
|
42
|
+
matches?(consumed, path, headers, body)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def get(path, headers = {}, &block)
|
|
47
|
+
new_stub(:get, path, headers, &block)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def head(path, headers = {}, &block)
|
|
51
|
+
new_stub(:head, path, headers, &block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def post(path, body=nil, headers = {}, &block)
|
|
55
|
+
new_stub(:post, path, headers, body, &block)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def put(path, body=nil, headers = {}, &block)
|
|
59
|
+
new_stub(:put, path, headers, body, &block)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def patch(path, body=nil, headers = {}, &block)
|
|
63
|
+
new_stub(:patch, path, headers, body, &block)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def delete(path, headers = {}, &block)
|
|
67
|
+
new_stub(:delete, path, headers, &block)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def options(path, headers = {}, &block)
|
|
71
|
+
new_stub(:options, path, headers, &block)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Raises an error if any of the stubbed calls have not been made.
|
|
75
|
+
def verify_stubbed_calls
|
|
76
|
+
failed_stubs = []
|
|
77
|
+
@stack.each do |method, stubs|
|
|
78
|
+
unless stubs.size == 0
|
|
79
|
+
failed_stubs.concat(stubs.map {|stub|
|
|
80
|
+
"Expected #{method} #{stub}."
|
|
81
|
+
})
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
raise failed_stubs.join(" ") unless failed_stubs.size == 0
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
protected
|
|
88
|
+
|
|
89
|
+
def new_stub(request_method, path, headers = {}, body=nil, &block)
|
|
90
|
+
normalized_path = Faraday::Utils.normalize_path(path)
|
|
91
|
+
(@stack[request_method] ||= []) << Stub.new(normalized_path, headers, body, block)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def matches?(stack, path, headers, body)
|
|
95
|
+
stack.detect { |stub| stub.matches?(path, headers, body) }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class Stub < Struct.new(:path, :params, :headers, :body, :block)
|
|
100
|
+
def initialize(full, headers, body, block)
|
|
101
|
+
path, query = full.split('?')
|
|
102
|
+
params = query ?
|
|
103
|
+
Faraday::Utils.parse_nested_query(query) :
|
|
104
|
+
{}
|
|
105
|
+
super(path, params, headers, body, block)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def matches?(request_uri, request_headers, request_body)
|
|
109
|
+
request_path, request_query = request_uri.split('?')
|
|
110
|
+
request_params = request_query ?
|
|
111
|
+
Faraday::Utils.parse_nested_query(request_query) :
|
|
112
|
+
{}
|
|
113
|
+
request_path == path &&
|
|
114
|
+
params_match?(request_params) &&
|
|
115
|
+
(body.to_s.size.zero? || request_body == body) &&
|
|
116
|
+
headers_match?(request_headers)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def params_match?(request_params)
|
|
120
|
+
params_deep_equal?(params,request_params)
|
|
121
|
+
# params.keys.all? do |key|
|
|
122
|
+
# request_params[key] == params[key]
|
|
123
|
+
# end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def params_deep_equal?(src,dst)
|
|
127
|
+
src.keys.all? do |key|
|
|
128
|
+
if src[key] && dst[key] && src[key].is_a?(Hash) && dst[key].is_a?(Hash)
|
|
129
|
+
params_deep_equal?(src[key],dst[key])
|
|
130
|
+
else
|
|
131
|
+
(src[key] == '**' && dst[key]) || src[key] == dst[key]
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def headers_match?(request_headers)
|
|
137
|
+
headers.keys.all? do |key|
|
|
138
|
+
request_headers[key] == headers[key]
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def to_s
|
|
143
|
+
"#{path} #{body}"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def initialize(app, stubs=nil, &block)
|
|
148
|
+
super(app)
|
|
149
|
+
@stubs = stubs || Stubs.new
|
|
150
|
+
configure(&block) if block
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def configure
|
|
154
|
+
yield(stubs)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def call(env)
|
|
158
|
+
super
|
|
159
|
+
normalized_path = Faraday::Utils.normalize_path(env[:url])
|
|
160
|
+
params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder
|
|
161
|
+
|
|
162
|
+
if stub = stubs.match(env[:method], normalized_path, env.request_headers, env[:body])
|
|
163
|
+
env[:params] = (query = env[:url].query) ?
|
|
164
|
+
params_encoder.decode(query) :
|
|
165
|
+
{}
|
|
166
|
+
status, headers, body = stub.block.call(env)
|
|
167
|
+
save_response(env, status, body, headers)
|
|
168
|
+
else
|
|
169
|
+
raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
|
|
170
|
+
end
|
|
171
|
+
@app.call(env)
|
|
172
|
+
end
|
|
173
|
+
end
|