virtuatable 0.5.0 → 3.2.3
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/lib/virtuatable/api/errors/base.rb +2 -0
- data/lib/virtuatable/api/responses.rb +20 -5
- data/lib/virtuatable/builders/base.rb +15 -20
- data/lib/virtuatable/builders/helpers/environment.rb +6 -2
- data/lib/virtuatable/builders/helpers/folders.rb +1 -0
- data/lib/virtuatable/builders/helpers/mongoid.rb +2 -0
- data/lib/virtuatable/builders/helpers/registration.rb +0 -7
- data/lib/virtuatable/builders/helpers/tests.rb +4 -1
- data/lib/virtuatable/builders/helpers.rb +1 -0
- data/lib/virtuatable/builders/tests.rb +5 -0
- data/lib/virtuatable/controllers/base.rb +22 -3
- data/lib/virtuatable/enhancers/base.rb +56 -0
- data/lib/virtuatable/enhancers/helpers/declarations.rb +34 -0
- data/lib/virtuatable/enhancers/helpers.rb +11 -0
- data/lib/virtuatable/enhancers.rb +13 -0
- data/lib/virtuatable/helpers/accounts.rb +8 -5
- data/lib/virtuatable/helpers/applications.rb +12 -8
- data/lib/virtuatable/helpers/declarators.rb +14 -11
- data/lib/virtuatable/helpers/parameters.rb +29 -0
- data/lib/virtuatable/helpers/routes.rb +3 -0
- data/lib/virtuatable/helpers/sessions.rb +20 -9
- data/lib/virtuatable/helpers.rb +1 -0
- data/lib/virtuatable/specs/factories/accounts.rb +54 -0
- data/lib/virtuatable/specs/factories/applications.rb +48 -0
- data/lib/virtuatable/specs/factories/groups.rb +50 -0
- data/lib/virtuatable/specs/factories/sessions.rb +38 -0
- data/lib/virtuatable/specs/factories.rb +15 -0
- data/lib/virtuatable/specs/shared/controllers.rb +195 -0
- data/lib/virtuatable/specs/shared.rb +11 -0
- data/lib/virtuatable/specs.rb +4 -85
- data/lib/virtuatable.rb +4 -0
- metadata +82 -114
- data/lib/virtuatable/helpers/gateways.rb +0 -23
- data/lib/virtuatable/version.rb +0 -5
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Virtuatable
|
4
|
+
module Specs
|
5
|
+
module Factories
|
6
|
+
# Factories concerning applications used in shared examples
|
7
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
8
|
+
module Applications
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
declare_loader :applications_factory, priority: 5
|
13
|
+
end
|
14
|
+
|
15
|
+
# rubocop:disable Metrics/MethodLength
|
16
|
+
def load_applications_factory!
|
17
|
+
# This avoids multiple re-declarations by setting a flag.
|
18
|
+
return if self.class.class_variable_defined?(:@@apps_declared)
|
19
|
+
|
20
|
+
FactoryBot.define do
|
21
|
+
factory :vt_empty_application, class: Arkaan::OAuth::Application do
|
22
|
+
# This factory creates an application with random value, useful
|
23
|
+
# to make simple requests on any route as all routes require
|
24
|
+
# the use of a valid application to be correctly called.
|
25
|
+
factory :random_application do
|
26
|
+
name { Faker::Alphanumeric.unique.alphanumeric(number: 16) }
|
27
|
+
app_key { BSON::ObjectId.new }
|
28
|
+
creator { association(:random_administrator) }
|
29
|
+
premium { false }
|
30
|
+
|
31
|
+
# This factory creates a premium application, mainly used for
|
32
|
+
# registration and authentication purpose.
|
33
|
+
factory :random_premium_app do
|
34
|
+
premium { true }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# rubocop:disable Style/ClassVars
|
41
|
+
@@apps_declared = true
|
42
|
+
# rubocop:enable Style/ClassVars
|
43
|
+
end
|
44
|
+
# rubocop:enable Metrics/MethodLength
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Virtuatable
|
4
|
+
module Specs
|
5
|
+
module Factories
|
6
|
+
# Factories concerning groups used in shared examples
|
7
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
8
|
+
module Groups
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
declare_loader :groups_factory, priority: 5
|
13
|
+
end
|
14
|
+
|
15
|
+
# rubocop:disable Metrics/MethodLength
|
16
|
+
def load_groups_factory!
|
17
|
+
# This avoids multiple re-declarations by setting a flag.
|
18
|
+
return if self.class.class_variable_defined?(:@@groups_declared)
|
19
|
+
|
20
|
+
FactoryBot.define do
|
21
|
+
factory :vt_empty_group, class: Arkaan::Permissions::Group do
|
22
|
+
# This creates a random group with access to zero routes. This group
|
23
|
+
# won't give the users it's associated to ANY access rights.
|
24
|
+
factory :random_group do
|
25
|
+
slug do
|
26
|
+
Faker::Alphanumeric.alphanumeric(
|
27
|
+
number: 16,
|
28
|
+
min_alpha: 16
|
29
|
+
)
|
30
|
+
end
|
31
|
+
is_default { false }
|
32
|
+
is_superuser { false }
|
33
|
+
# We do NOT set the is_superuser flag to true as this factory is made to
|
34
|
+
# test permissions when the route is in the list of accessible routes.
|
35
|
+
factory :random_admin_group do
|
36
|
+
routes { Virtuatable::Application.instance.builder.service.routes.to_a }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# rubocop:disable Style/ClassVars
|
43
|
+
@@groups_declared = true
|
44
|
+
# rubocop:enable Style/ClassVars
|
45
|
+
end
|
46
|
+
# rubocop:enable Metrics/MethodLength
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Virtuatable
|
4
|
+
module Specs
|
5
|
+
module Factories
|
6
|
+
# This module creates the factories concerning accounts, with or
|
7
|
+
# without rights, and with random values for each field.
|
8
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
9
|
+
module Sessions
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
included do
|
13
|
+
declare_loader :sessions_factory, priority: 5
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_sessions_factory!
|
17
|
+
# This avoids multiple re-declarations by setting a flag.
|
18
|
+
return if self.class.class_variable_defined?(:@@sessions_declared)
|
19
|
+
|
20
|
+
FactoryBot.define do
|
21
|
+
factory :vt_empty_session, class: Arkaan::Authentication::Session do
|
22
|
+
# Creates a random account with no particular right. This
|
23
|
+
# is useful to see when a user is NOT authorized to access
|
24
|
+
# a resource. Add groups to access resources.
|
25
|
+
factory :random_session do
|
26
|
+
session_id { BSON::ObjectId.new }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# rubocop:disable Style/ClassVars
|
32
|
+
@@sessions_declared = true
|
33
|
+
# rubocop:enable Style/ClassVars
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Virtuatable
|
4
|
+
module Specs
|
5
|
+
# This module holds standard factories you can use in services to
|
6
|
+
# easily create new elements.
|
7
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com
|
8
|
+
module Factories
|
9
|
+
autoload :Accounts, 'virtuatable/specs/factories/accounts'
|
10
|
+
autoload :Applications, 'virtuatable/specs/factories/applications'
|
11
|
+
autoload :Groups, 'virtuatable/specs/factories/groups'
|
12
|
+
autoload :Sessions, 'virtuatable/specs/factories/sessions'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Virtuatable
|
4
|
+
module Specs
|
5
|
+
module Shared
|
6
|
+
# This module loads the shared examples about a controller and/or a route.
|
7
|
+
# These examples can be included to ensure the basic behaviours for a route
|
8
|
+
# are implemented in each micro-service, without the hassle of rewriting it.
|
9
|
+
#
|
10
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
11
|
+
# rubocop:disable Metrics/ModuleLength
|
12
|
+
module Controllers
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
|
15
|
+
@declared = false
|
16
|
+
|
17
|
+
included do
|
18
|
+
declare_loader :controller_specs, priority: 6
|
19
|
+
end
|
20
|
+
|
21
|
+
# This method is automatically called when loading the application with
|
22
|
+
# the load_test! method in the builder.
|
23
|
+
# rubocop:disable Metrics/AbcSize
|
24
|
+
# rubocop:disable Metrics/MethodLength
|
25
|
+
def load_controller_specs!
|
26
|
+
# This avoids multiple re-declarations by setting a flag.
|
27
|
+
return if self.class.class_variable_defined?(:@@controllers_declared)
|
28
|
+
|
29
|
+
service = Virtuatable::Application.instance.builder.service
|
30
|
+
|
31
|
+
# Shared examples for a standard route of the application.
|
32
|
+
# These examples are configurable with a configuration hash given as
|
33
|
+
# third parameters, available configuration keys are :
|
34
|
+
# - :premium to know if the route is only accessible to premium apps
|
35
|
+
# - :authenticated to know if the route needs authentication or not
|
36
|
+
# rubocop:disable Metrics/BlockLength
|
37
|
+
RSpec.shared_examples 'a route' do |verb, path|
|
38
|
+
# These two variables are NOT declared in let! blocks so that we're able
|
39
|
+
# to use them as traditional Ruby variable in if: options of describe blocks.
|
40
|
+
service = Virtuatable::Application.instance.builder.service
|
41
|
+
route = service.routes.find_by(verb: verb, path: path)
|
42
|
+
|
43
|
+
let!(:verb) { route.verb }
|
44
|
+
let!(:path) { route.path }
|
45
|
+
|
46
|
+
# This user has no right to access anything because he has no group.
|
47
|
+
let!(:account) { create(:random_account) }
|
48
|
+
# A standard application to be able to make basic requests.
|
49
|
+
let!(:application) { create(:random_premium_app, premium: route.premium) }
|
50
|
+
|
51
|
+
# Tests written for each and every route
|
52
|
+
describe 'Standard routes behaviours' do
|
53
|
+
# Error scenario :
|
54
|
+
# - The user makes a request on the API without giving an application key
|
55
|
+
# - The API fails and returns an error code
|
56
|
+
describe 'The Application key is not given' do
|
57
|
+
before do
|
58
|
+
public_send verb, path
|
59
|
+
end
|
60
|
+
it 'Returns a 400 (Bad Request) status code' do
|
61
|
+
expect(last_response.status).to be 400
|
62
|
+
end
|
63
|
+
it 'Returns the correct body' do
|
64
|
+
expect(last_response.body).to include_json(
|
65
|
+
status: 400,
|
66
|
+
field: 'app_key',
|
67
|
+
error: 'required'
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Error scenario :
|
73
|
+
# - The user makes a request on the API and gives an unknown application key
|
74
|
+
# - The API fails and returns an error code
|
75
|
+
describe 'The application key is unknown' do
|
76
|
+
before do
|
77
|
+
public_send verb, path, { app_key: BSON::ObjectId.new }
|
78
|
+
end
|
79
|
+
it 'Returns a 404 (Not Found) status code' do
|
80
|
+
expect(last_response.status).to be 404
|
81
|
+
end
|
82
|
+
it 'Returns the correct body' do
|
83
|
+
expect(last_response.body).to include_json(
|
84
|
+
status: 404,
|
85
|
+
field: 'app_key',
|
86
|
+
error: 'unknown'
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'Authenticated route behaviours', if: route.authenticated do
|
93
|
+
let!(:session) { create(:random_session, account: account) }
|
94
|
+
|
95
|
+
# Error scenario :
|
96
|
+
# - The user request an authenticated route without providing a session ID
|
97
|
+
# - The API fails and return an error code
|
98
|
+
describe 'The session ID is not given' do
|
99
|
+
before do
|
100
|
+
public_send verb, path, { app_key: application.app_key }
|
101
|
+
end
|
102
|
+
it 'Returns a 400 (Bad Request) status code' do
|
103
|
+
expect(last_response.status).to be 400
|
104
|
+
end
|
105
|
+
it 'Returns the correct body' do
|
106
|
+
expect(last_response.body).to include_json(
|
107
|
+
status: 400,
|
108
|
+
field: 'session_id',
|
109
|
+
error: 'required'
|
110
|
+
)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Error scenario :
|
115
|
+
# - The user request an authenticated route with an unknown session ID
|
116
|
+
# - The API fails and return an error code
|
117
|
+
describe 'The session ID is unknown' do
|
118
|
+
before do
|
119
|
+
public_send verb, path, {
|
120
|
+
app_key: application.app_key,
|
121
|
+
session_id: BSON::ObjectId.new
|
122
|
+
}
|
123
|
+
end
|
124
|
+
it 'Returns a 404 (Not Found) status code' do
|
125
|
+
expect(last_response.status).to be 404
|
126
|
+
end
|
127
|
+
it 'Returns the correct body' do
|
128
|
+
expect(last_response.body).to include_json(
|
129
|
+
status: 404,
|
130
|
+
field: 'session_id',
|
131
|
+
error: 'unknown'
|
132
|
+
)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Error scenario :
|
137
|
+
# - The user request an authenticated route with a valid session ID
|
138
|
+
# - The user has no right to access the route
|
139
|
+
# - The API fails and return an error code
|
140
|
+
describe 'The user has no right to access the resource' do
|
141
|
+
before do
|
142
|
+
public_send verb, path, {
|
143
|
+
app_key: application.app_key,
|
144
|
+
session_id: session.session_id
|
145
|
+
}
|
146
|
+
end
|
147
|
+
it 'Returns a 403 (Forbidden) status code' do
|
148
|
+
expect(last_response.status).to be 403
|
149
|
+
end
|
150
|
+
it 'Returns the correct body' do
|
151
|
+
expect(last_response.body).to include_json(
|
152
|
+
status: 403,
|
153
|
+
field: 'session_id',
|
154
|
+
error: 'forbidden'
|
155
|
+
)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Error scenario :
|
161
|
+
# - A user tries to make a request on a premium route with an non-premium app
|
162
|
+
# - The API fails and return an error code
|
163
|
+
describe 'A non-premium application accesses a premium route', if: route.premium do
|
164
|
+
let!(:forbidden_app) { create(:random_application) }
|
165
|
+
|
166
|
+
before do
|
167
|
+
public_send verb, path, {
|
168
|
+
app_key: forbidden_app.app_key
|
169
|
+
}
|
170
|
+
end
|
171
|
+
it 'Returns a 403 (Forbidden) status code' do
|
172
|
+
expect(last_response.status).to be 403
|
173
|
+
end
|
174
|
+
it 'Returns the correct body' do
|
175
|
+
expect(last_response.body).to include_json(
|
176
|
+
status: 403,
|
177
|
+
field: 'app_key',
|
178
|
+
error: 'forbidden'
|
179
|
+
)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
# rubocop:enable Metrics/BlockLength
|
184
|
+
|
185
|
+
# rubocop:disable Style/ClassVars
|
186
|
+
@@controllers_declared = true
|
187
|
+
# rubocop:enable Style/ClassVars
|
188
|
+
end
|
189
|
+
# rubocop:enable Metrics/MethodLength
|
190
|
+
# rubocop:enable Metrics/AbcSize
|
191
|
+
end
|
192
|
+
# rubocop:enable Metrics/ModuleLength
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Virtuatable
|
4
|
+
module Specs
|
5
|
+
# This module holds the shared examples used in services to automate tests.
|
6
|
+
# @author Vincent Courtois <courtois.vincent@outlook.com
|
7
|
+
module Shared
|
8
|
+
autoload :Controllers, 'virtuatable/specs/shared/controllers'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/virtuatable/specs.rb
CHANGED
@@ -1,92 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Virtuatable
|
4
|
-
# This module holds
|
4
|
+
# This module holds declarations for shared examples and factories used
|
5
|
+
# in service, in particular to test the standard behaviour of a route.
|
5
6
|
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
6
7
|
module Specs
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# Includes all the shared examples you could need, describing the basic behaviour of a route.
|
11
|
-
def self.include_shared_examples
|
12
|
-
if !@@declared
|
13
|
-
RSpec.shared_examples 'a route' do |_verb, _path|
|
14
|
-
let(:verb) { _verb }
|
15
|
-
let(:path) { _path }
|
16
|
-
|
17
|
-
def do_request(parameters)
|
18
|
-
public_send verb.to_sym, path, parameters
|
19
|
-
end
|
20
|
-
|
21
|
-
describe 'common errors' do
|
22
|
-
describe 'bad request errors' do
|
23
|
-
describe 'no token error' do
|
24
|
-
before do
|
25
|
-
do_request(app_key: 'test_key')
|
26
|
-
end
|
27
|
-
it 'Raises a bad request (400) error when the parameters don\'t contain the token of the gateway' do
|
28
|
-
expect(last_response.status).to be 400
|
29
|
-
end
|
30
|
-
it 'returns the correct response if the parameters do not contain a gateway token' do
|
31
|
-
expect(last_response.body).to include_json(
|
32
|
-
status: 400,
|
33
|
-
field: 'token',
|
34
|
-
error: 'required'
|
35
|
-
)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
describe 'no application key error' do
|
39
|
-
before do
|
40
|
-
do_request({token: 'test_token'})
|
41
|
-
end
|
42
|
-
it 'Raises a bad request (400) error when the parameters don\'t contain the application key' do
|
43
|
-
expect(last_response.status).to be 400
|
44
|
-
end
|
45
|
-
it 'returns the correct response if the parameters do not contain a gateway token' do
|
46
|
-
expect(last_response.body).to include_json(
|
47
|
-
status: 400,
|
48
|
-
field: 'app_key',
|
49
|
-
error: 'required'
|
50
|
-
)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
describe 'not_found errors' do
|
55
|
-
describe 'application not found' do
|
56
|
-
before do
|
57
|
-
do_request({token: 'test_token', app_key: 'another_key'})
|
58
|
-
end
|
59
|
-
it 'Raises a not found (404) error when the key doesn\'t belong to any application' do
|
60
|
-
expect(last_response.status).to be 404
|
61
|
-
end
|
62
|
-
it 'returns the correct response if the parameters do not contain a gateway token' do
|
63
|
-
expect(last_response.body).to include_json(
|
64
|
-
status: 404,
|
65
|
-
field: 'app_key',
|
66
|
-
error: 'unknown'
|
67
|
-
)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
describe 'gateway not found' do
|
71
|
-
before do
|
72
|
-
do_request({token: 'other_token', app_key: 'test_key'})
|
73
|
-
end
|
74
|
-
it 'Raises a not found (404) error when the gateway does\'nt exist' do
|
75
|
-
expect(last_response.status).to be 404
|
76
|
-
end
|
77
|
-
it 'returns the correct body when the gateway doesn\'t exist' do
|
78
|
-
expect(last_response.body).to include_json(
|
79
|
-
status: 404,
|
80
|
-
field: 'token',
|
81
|
-
error: 'unknown'
|
82
|
-
)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
@@declared = true
|
89
|
-
end
|
90
|
-
end
|
8
|
+
autoload :Factories, 'virtuatable/specs/factories'
|
9
|
+
autoload :Shared, 'virtuatable/specs/shared'
|
91
10
|
end
|
92
11
|
end
|
data/lib/virtuatable.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'require_all'
|
4
|
+
require 'arkaan'
|
5
|
+
|
3
6
|
# Main module of the application, containing each other one.
|
4
7
|
# @author Vincent Courtois <courtois.vincent@outlook.com>
|
5
8
|
module Virtuatable
|
@@ -7,6 +10,7 @@ module Virtuatable
|
|
7
10
|
autoload :Application, 'virtuatable/application'
|
8
11
|
autoload :Builders, 'virtuatable/builders'
|
9
12
|
autoload :Controllers, 'virtuatable/controllers'
|
13
|
+
autoload :Enhancers, 'virtuatable/enhancers'
|
10
14
|
autoload :Helpers, 'virtuatable/helpers'
|
11
15
|
autoload :Loader, 'virtuatable/application'
|
12
16
|
autoload :Specs, 'virtuatable/specs'
|