virtuatable 0.5.0 → 3.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|