punk 0.1.4 → 0.2.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +9 -0
  3. data/.github/workflows/test.yml +26 -1
  4. data/.rdoc_options +23 -0
  5. data/.rgignore +1 -0
  6. data/.rspec +2 -0
  7. data/Gemfile +5 -6
  8. data/Gemfile.lock +16 -29
  9. data/README.md +1 -1
  10. data/VERSION +1 -1
  11. data/app/migrations/001_lets_punk.rb +3 -0
  12. data/app/routes/hello.rb +4 -0
  13. data/env/.gitignore +3 -0
  14. data/env/spec/test.sh +3 -0
  15. data/lib/punk/actions/.keep +0 -0
  16. data/lib/punk/actions/groups/list.rb +24 -0
  17. data/lib/punk/actions/sessions/clear.rb +21 -0
  18. data/lib/punk/actions/sessions/create.rb +64 -0
  19. data/lib/punk/actions/sessions/list.rb +18 -0
  20. data/lib/punk/actions/sessions/verify.rb +24 -0
  21. data/lib/punk/actions/tenants/list.rb +18 -0
  22. data/lib/punk/actions/users/list_group.rb +18 -0
  23. data/lib/punk/actions/users/list_tenant.rb +18 -0
  24. data/lib/punk/actions/users/show.rb +18 -0
  25. data/lib/punk/commands/list.rb +12 -6
  26. data/lib/punk/config/defaults.json +3 -0
  27. data/lib/punk/config/schema.json +3 -0
  28. data/lib/punk/core/app.rb +4 -6
  29. data/lib/punk/core/commander.rb +7 -4
  30. data/lib/punk/core/exec.rb +2 -0
  31. data/lib/punk/core/load.rb +0 -1
  32. data/lib/punk/framework/command.rb +5 -1
  33. data/lib/punk/framework/plugins/validation.rb +0 -14
  34. data/lib/punk/helpers/loggable.rb +1 -1
  35. data/lib/punk/migrations/001_punk.rb +103 -0
  36. data/lib/punk/models/.keep +0 -0
  37. data/lib/punk/models/group.rb +20 -0
  38. data/lib/punk/models/group_user_metadata.rb +17 -0
  39. data/lib/punk/models/identity.rb +29 -0
  40. data/lib/punk/models/session.rb +89 -0
  41. data/lib/punk/models/tenant.rb +19 -0
  42. data/lib/punk/models/tenant_user_metadata.rb +17 -0
  43. data/lib/punk/models/user.rb +31 -0
  44. data/lib/punk/routes/groups.rb +31 -0
  45. data/lib/punk/routes/plivo.rb +4 -0
  46. data/lib/punk/routes/sessions.rb +108 -0
  47. data/lib/punk/routes/swagger.rb +9 -0
  48. data/lib/punk/routes/tenants.rb +29 -0
  49. data/lib/punk/routes/users.rb +36 -0
  50. data/lib/punk/services/.keep +0 -0
  51. data/lib/punk/services/challenge_claim.rb +46 -0
  52. data/lib/punk/services/create_identities.rb +25 -0
  53. data/lib/punk/services/generate_swagger.rb +25 -0
  54. data/lib/punk/services/prove_claim.rb +29 -0
  55. data/lib/punk/services/secret.rb +9 -0
  56. data/lib/punk/templates/groups/list.jbuilder +7 -0
  57. data/lib/punk/templates/plivo.slim +16 -0
  58. data/lib/punk/templates/sessions/list.jbuilder +6 -0
  59. data/lib/punk/templates/sessions/pending.jbuilder +4 -0
  60. data/lib/punk/templates/tenants/list.jbuilder +7 -0
  61. data/lib/punk/templates/tenants/list.slim +8 -0
  62. data/lib/punk/templates/users/list.jbuilder +7 -0
  63. data/lib/punk/templates/users/list.rcsv +4 -0
  64. data/lib/punk/templates/users/show.jbuilder +5 -0
  65. data/lib/punk/views/groups/list.rb +22 -0
  66. data/lib/punk/views/plivo_store.rb +15 -0
  67. data/lib/punk/views/sessions/list.rb +22 -0
  68. data/lib/punk/views/sessions/pending.rb +28 -0
  69. data/lib/punk/views/tenants/list.rb +22 -0
  70. data/lib/punk/views/users/list.rb +22 -0
  71. data/lib/punk/views/users/show.rb +22 -0
  72. data/lib/punk/workers/.keep +0 -0
  73. data/lib/punk/workers/expire_sessions.rb +9 -0
  74. data/lib/punk/workers/geocode_session_worker.rb +48 -0
  75. data/lib/punk/workers/identify_session_worker.rb +45 -0
  76. data/lib/punk/workers/secret.rb +18 -0
  77. data/lib/punk/workers/send_email_worker.rb +51 -0
  78. data/lib/punk/workers/send_sms_worker.rb +40 -0
  79. data/punk.gemspec +140 -14
  80. data/schema.psql +345 -0
  81. data/spec/actions/groups/punk/list_groups_action_spec.rb +36 -0
  82. data/spec/actions/sessions/punk/clear_session_action_spec.rb +29 -0
  83. data/spec/actions/sessions/punk/create_session_action_spec.rb +33 -0
  84. data/spec/actions/sessions/punk/list_sessions_action_spec.rb +26 -0
  85. data/spec/actions/sessions/punk/verify_session_action_spec.rb +59 -0
  86. data/spec/actions/tenants/punk/list_tenants_action_spec.rb +25 -0
  87. data/spec/actions/users/punk/list_group_users_action_spec.rb +26 -0
  88. data/spec/actions/users/punk/list_tenant_users_action_spec.rb +26 -0
  89. data/spec/factories/group.rb +12 -0
  90. data/spec/factories/group_user_metadata.rb +10 -0
  91. data/spec/factories/identity.rb +19 -0
  92. data/spec/factories/session.rb +12 -0
  93. data/spec/factories/tenant.rb +10 -0
  94. data/spec/factories/tenant_user_metadata.rb +10 -0
  95. data/spec/factories/user.rb +12 -0
  96. data/spec/lib/commands/auth_spec.rb +11 -0
  97. data/spec/lib/commands/generate_spec.rb +7 -0
  98. data/spec/lib/commands/http_spec.rb +23 -0
  99. data/spec/lib/commands/list_spec.rb +7 -0
  100. data/spec/lib/commands/swagger_spec.rb +7 -0
  101. data/spec/lib/engine/punk_env_spec.rb +13 -0
  102. data/spec/lib/engine/punk_exec_spec.rb +9 -0
  103. data/spec/lib/engine/punk_init_spec.rb +9 -0
  104. data/spec/lib/engine/punk_store_spec.rb +10 -0
  105. data/spec/lib/punk.env +7 -0
  106. data/spec/models/punk/group_spec.rb +50 -0
  107. data/spec/models/punk/group_user_metadata_spec.rb +61 -0
  108. data/spec/models/punk/identity_spec.rb +61 -0
  109. data/spec/models/punk/session_spec.rb +156 -0
  110. data/spec/models/punk/tenant_spec.rb +51 -0
  111. data/spec/models/punk/tenant_user_metadata_spec.rb +61 -0
  112. data/spec/models/punk/user_spec.rb +115 -0
  113. data/spec/routes/groups/get_groups_spec.rb +33 -0
  114. data/spec/routes/plivo/get_plivo_spec.rb +11 -0
  115. data/spec/routes/sessions/delete_session_spec.rb +11 -0
  116. data/spec/routes/sessions/get_sessions_spec.rb +30 -0
  117. data/spec/routes/sessions/patch_session_spec.rb +11 -0
  118. data/spec/routes/sessions/post_session_spec.rb +11 -0
  119. data/spec/routes/swagger/get_swagger_spec.rb +12 -0
  120. data/spec/routes/tenants/get_tenants_spec.rb +31 -0
  121. data/spec/routes/users/get_users_spec.rb +60 -0
  122. data/spec/services/punk/challenge_claim_service_spec.rb +7 -0
  123. data/spec/services/punk/create_identities_service_spec.rb +14 -0
  124. data/spec/services/punk/generate_swagger_service_spec.rb +7 -0
  125. data/spec/services/punk/prove_claim_service_spec.rb +7 -0
  126. data/spec/services/punk/secret_service_spec.rb +7 -0
  127. data/spec/spec_helper.rb +122 -0
  128. data/spec/vcr_cassettes/PUNK_GeocodeSessionWorker/updates_the_session_data.yml +57 -0
  129. data/spec/vcr_cassettes/PUNK_IdentifySessionWorker/updates_the_session_data.yml +112 -0
  130. data/spec/views/punk/plivo_store_spec.rb +7 -0
  131. data/spec/views/sessions/punk/list_sessions_view_spec.rb +7 -0
  132. data/spec/views/sessions/punk/pending_session_view_spec.rb +7 -0
  133. data/spec/views/tenants/punk/list_tenants_view_spec.rb +7 -0
  134. data/spec/views/users/punk/list_groups_view_spec.rb +7 -0
  135. data/spec/views/users/punk/list_users_view_spec.rb +7 -0
  136. data/spec/workers/punk/expire_sessions_worker_spec.rb +31 -0
  137. data/spec/workers/punk/geocode_session_worker_spec.rb +14 -0
  138. data/spec/workers/punk/identify_session_worker_spec.rb +15 -0
  139. data/spec/workers/punk/secret_worker_spec.rb +20 -0
  140. data/spec/workers/punk/send_email_worker_spec.rb +46 -0
  141. data/spec/workers/punk/send_sms_worker_spec.rb +33 -0
  142. metadata +148 -11
  143. data/lib/punk/views/all.rb +0 -4
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK::ListGroupsAction do
4
+ let(:user) { create(:user) }
5
+ let(:tenant) { create(:tenant) }
6
+
7
+ context 'with no user provided' do
8
+ it 'returns a validation error' do
9
+ view = described_class.run(tenant: tenant).result.render(:json)
10
+ expect(view).to match('user is not present')
11
+ end
12
+ end
13
+
14
+ context 'with no tenant provided' do
15
+ it 'returns a validation error' do
16
+ view = described_class.run(user: user).result.render(:json)
17
+ expect(view).to match('tenant is not present')
18
+ end
19
+ end
20
+
21
+ context 'with valid arguments' do
22
+ let(:groups) { create_list(:group, 3, tenant: tenant) }
23
+
24
+ before do
25
+ user.add_tenant(tenant)
26
+ groups[0].add_user(user)
27
+ groups[1].add_user(user)
28
+ end
29
+
30
+ it 'returns groups for the tenant that the user is a member of' do
31
+ expect(tenant.groups.count).to eq(3)
32
+ view = JSON.parse(described_class.run(user: user, tenant: tenant).result.render(:json))
33
+ expect(view.map { |h| h['id'] }.sort).to eq([groups[0].id, groups[1].id].sort)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK::ClearSessionAction do
4
+ context 'with no session provided' do
5
+ it 'returns a validation error' do
6
+ view = described_class.run.result.render(:json)
7
+ expect(view).to match('session is not present')
8
+ expect(view).to match('session is empty')
9
+ end
10
+ end
11
+
12
+ context 'with an inactive session provided' do
13
+ it 'returns a validation error' do
14
+ session = create(:session)
15
+ view = described_class.run(session: session).result.render(:json)
16
+ expect(view).to match('session is not in active state')
17
+ expect(view).to match('session may not clear')
18
+ end
19
+ end
20
+
21
+ context 'with an active session provided' do
22
+ it 'clears the session' do
23
+ session = create(:session, state: :active)
24
+ view = described_class.run(session: session).result.render(:json)
25
+ expect(view).to match('You have been logged out')
26
+ expect(session.deleted?).to be(true)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK::CreateSessionAction do
4
+ let(:remote_addr) { Faker::Internet.ip_v4_address }
5
+ let(:user_agent) { Faker::Internet.user_agent }
6
+
7
+ context 'with no claim provided' do
8
+ it 'returns a validation error' do
9
+ view = described_class.run(remote_addr: remote_addr, user_agent: user_agent).result.render(:json)
10
+ expect(view).to match('claim is not present')
11
+ end
12
+ end
13
+
14
+ context 'with an email claim provided' do
15
+ it 'created an identity and a session' do
16
+ email = Faker::Internet.email
17
+ view = described_class.run(claim: email, remote_addr: remote_addr, user_agent: user_agent).result.render(:json)
18
+ session = PUNK::Session.find(slug: ActiveSupport::JSON.decode(view)['slug'])
19
+ expect(session.identity.claim_type).to eq(:email)
20
+ expect(session.identity.claim).to eq(email)
21
+ end
22
+ end
23
+
24
+ context 'with a phone claim provided' do
25
+ it 'created an identity and a session' do
26
+ phone = generate(:phone)
27
+ view = described_class.run(claim: phone, remote_addr: remote_addr, user_agent: user_agent).result.render(:json)
28
+ session = PUNK::Session.find(slug: ActiveSupport::JSON.decode(view)['slug'])
29
+ expect(session.identity.claim_type).to eq(:phone)
30
+ expect(session.identity.claim).to eq(phone)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK::ListSessionsAction do
4
+ context 'with no user provided' do
5
+ it 'returns a validation error' do
6
+ view = described_class.run.result.render(:json)
7
+ expect(view).to match('user is not present')
8
+ end
9
+ end
10
+
11
+ context 'with a user provided' do
12
+ let(:user) { create(:user) }
13
+ let(:identity) { create(:identity, user: user) }
14
+
15
+ before do
16
+ create_list(:session, 3, state: 'active')
17
+ create_list(:session, 3, state: 'active', identity: identity)
18
+ end
19
+
20
+ it 'returns active sessions that the user belongs to' do
21
+ expect(PUNK::Session.count).to eq(6)
22
+ view = JSON.parse(described_class.run(user: user).result.render(:json))
23
+ expect(view.map { |h| h['id'] }.sort).to eq(user.active_sessions.map(&:id).sort)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK::VerifySessionAction do
4
+ context 'with no session provided' do
5
+ it 'returns a validation error' do
6
+ view = described_class.run.result.render(:json)
7
+ expect(view).to match('session is not present')
8
+ end
9
+ end
10
+
11
+ context 'with no secret provided' do
12
+ it 'returns a validation error' do
13
+ session = create(:session)
14
+ view = described_class.run(session: session).result.render(:json)
15
+ expect(view).to match('secret is not present')
16
+ end
17
+ end
18
+
19
+ context 'with an inactive session provided' do
20
+ it 'returns a validation error' do
21
+ session = create(:session)
22
+ view = described_class.run(session: session, secret: 'xyzzy').result.render(:json)
23
+ expect(view).to match('session is not in pending state')
24
+ expect(view).to match('session may not verify')
25
+ end
26
+ end
27
+
28
+ context 'with a pending session provided' do
29
+ let(:session) { create(:session) }
30
+
31
+ before do
32
+ allow_any_instance_of(PUNK::SecretService).to receive(:process).and_return("xyzzy") # rubocop:disable RSpec/AnyInstance
33
+ PUNK::ChallengeClaimService.run(session: session)
34
+ end
35
+
36
+ it 'returns an error if the secret is not correct' do
37
+ expect { described_class.run(session: session, secret: 'qwerty') }.to raise_error(PUNK::BadRequest, "Secret is incorrect")
38
+ end
39
+
40
+ it 'expires the session after three failed attempts' do
41
+ described_class.run(session: session, secret: 'qwerty') rescue nil # rubocop:disable Style/RescueModifier
42
+ described_class.run(session: session, secret: 'qwerty') rescue nil # rubocop:disable Style/RescueModifier
43
+ expect { described_class.run(session: session, secret: 'qwerty') }.to raise_error(PUNK::BadRequest, "Too many attempts")
44
+ end
45
+
46
+ it 'expires the session if it is more than five minutes old' do
47
+ Timecop.travel(5.minutes.from_now)
48
+ view = described_class.run(session: session, secret: 'xyzzy').result.render(:json)
49
+ expect(view).to match('session may not verify')
50
+ expect(session.expired?).to be(true)
51
+ end
52
+
53
+ it 'verifies the session if the secret is correct' do
54
+ view = described_class.run(session: session, secret: 'xyzzy').result.render(:json)
55
+ expect(view).to match('We have succesfully verified your identity')
56
+ expect(session.active?).to be(true)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK::ListTenantsAction do
4
+ context 'with no user provided' do
5
+ it 'returns a validation error' do
6
+ view = described_class.run.result.render(:json)
7
+ expect(view).to match('user is not present')
8
+ end
9
+ end
10
+
11
+ context 'with a user provided' do
12
+ let(:user) { create(:user) }
13
+
14
+ before do
15
+ create_list(:tenant, 3)
16
+ 3.times { create(:tenant).add_user(user) }
17
+ end
18
+
19
+ it 'returns tenants that the user belongs to' do
20
+ expect(PUNK::Tenant.count).to eq(6)
21
+ view = JSON.parse(described_class.run(user: user).result.render(:json))
22
+ expect(view.map { |h| h['id'] }.sort).to eq(user.tenants.map(&:id).sort)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK::ListGroupUsersAction do
4
+ context 'with no group provided' do
5
+ it 'returns a validation error' do
6
+ view = described_class.run.result.render(:json)
7
+ expect(view).to match('group is not present')
8
+ end
9
+ end
10
+
11
+ context 'with valid arguments' do
12
+ let(:group) { create(:group) }
13
+ let(:users) { create_list(:user, 3) }
14
+
15
+ before do
16
+ create_list(:user, 2)
17
+ users.each { |user| group.add_user(user) }
18
+ end
19
+
20
+ it 'returns users that are members of the given group' do
21
+ expect(PUNK::User.count).to eq(5)
22
+ view = JSON.parse(described_class.run(group: group).result.render(:json))
23
+ expect(view.map { |h| h['id'] }.sort).to eq(group.users.map(&:id).sort)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK::ListTenantUsersAction do
4
+ context 'with no tenant provided' do
5
+ it 'returns a validation error' do
6
+ view = described_class.run.result.render(:json)
7
+ expect(view).to match('tenant is not present')
8
+ end
9
+ end
10
+
11
+ context 'with valid arguments' do
12
+ let(:tenant) { create(:tenant) }
13
+ let(:users) { create_list(:user, 3) }
14
+
15
+ before do
16
+ create_list(:user, 2)
17
+ users.each { |user| tenant.add_user(user) }
18
+ end
19
+
20
+ it 'returns users that are members of the given tenant' do
21
+ expect(PUNK::User.count).to eq(5)
22
+ view = JSON.parse(described_class.run(tenant: tenant).result.render(:json))
23
+ expect(view.map { |h| h['id'] }.sort).to eq(tenant.users.map(&:id).sort)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :group, class: 'PUNK::Group' do
5
+ to_create(&:save)
6
+
7
+ tenant
8
+
9
+ name { Faker::Name.name }
10
+ icon { Faker::Internet.url }
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :group_user_metadata, class: 'PUNK::GroupUserMetadata' do
5
+ to_create(&:save)
6
+
7
+ group
8
+ user
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :identity, class: 'PUNK::Identity' do
5
+ to_create(&:save)
6
+
7
+ user
8
+
9
+ claim_type { ['email', 'phone'].sample }
10
+ claim do
11
+ case claim_type
12
+ when 'email'
13
+ Faker::Internet.email
14
+ when 'phone'
15
+ generate(:phone)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :session, class: 'PUNK::Session' do
5
+ to_create(&:save)
6
+
7
+ identity
8
+
9
+ remote_addr { Faker::Internet.ip_v4_address }
10
+ user_agent { Faker::Internet.user_agent }
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :tenant, class: 'PUNK::Tenant' do
5
+ to_create(&:save)
6
+
7
+ name { Faker::Name.name }
8
+ icon { Faker::Internet.url }
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :tenant_user_metadata, class: 'PUNK::TenantUserMetadata' do
5
+ to_create(&:save)
6
+
7
+ tenant
8
+ user
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :user, class: 'PUNK::User' do
5
+ to_create(&:save)
6
+
7
+ name { Faker::Name.name }
8
+ icon { Faker::Internet.url }
9
+ email { Faker::Internet.email }
10
+ phone { generate(:phone) }
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # describe 'auth', type: :feature do
4
+ # describe 'login command', type: :feature do
5
+ # it 'displays "not yet implemented"'
6
+ # end
7
+
8
+ # describe 'logout command', type: :feature do
9
+ # it 'displays "not yet implemented"'
10
+ # end
11
+ # end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'generate command', type: :feature do
4
+ context 'when no tests have been written' do
5
+ it 'displays "not yet implemented"'
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # describe 'http', type: :feature do
4
+ # describe 'GET command', type: :feature do
5
+ # it 'displays "not yet implemented"'
6
+ # end
7
+
8
+ # describe 'PATCH command', type: :feature do
9
+ # it 'displays "not yet implemented"'
10
+ # end
11
+
12
+ # describe 'POST command', type: :feature do
13
+ # it 'displays "not yet implemented"'
14
+ # end
15
+
16
+ # describe 'PUT command', type: :feature do
17
+ # it 'displays "not yet implemented"'
18
+ # end
19
+
20
+ # describe 'DELETE command', type: :feature do
21
+ # it 'displays "not yet implemented"'
22
+ # end
23
+ # end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'list command', type: :feature do
4
+ context 'when no tests have been written' do
5
+ it 'displays "not yet implemented"'
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'swagger command', type: :feature do
4
+ context 'when no tests have been written' do
5
+ it 'displays "not yet implemented"'
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe PUNK do
4
+ describe '.env' do
5
+ it 'loads environment' do
6
+ expect(described_class.get.trace).to eq('spec_test')
7
+ end
8
+
9
+ it 'loads configuration' do
10
+ expect(described_class.env.to_sym).to eq(:test)
11
+ end
12
+ end
13
+ end