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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/virtuatable/api/errors/base.rb +2 -0
  3. data/lib/virtuatable/api/responses.rb +20 -5
  4. data/lib/virtuatable/builders/base.rb +15 -20
  5. data/lib/virtuatable/builders/helpers/environment.rb +6 -2
  6. data/lib/virtuatable/builders/helpers/folders.rb +1 -0
  7. data/lib/virtuatable/builders/helpers/mongoid.rb +2 -0
  8. data/lib/virtuatable/builders/helpers/registration.rb +0 -7
  9. data/lib/virtuatable/builders/helpers/tests.rb +4 -1
  10. data/lib/virtuatable/builders/helpers.rb +1 -0
  11. data/lib/virtuatable/builders/tests.rb +5 -0
  12. data/lib/virtuatable/controllers/base.rb +22 -3
  13. data/lib/virtuatable/enhancers/base.rb +56 -0
  14. data/lib/virtuatable/enhancers/helpers/declarations.rb +34 -0
  15. data/lib/virtuatable/enhancers/helpers.rb +11 -0
  16. data/lib/virtuatable/enhancers.rb +13 -0
  17. data/lib/virtuatable/helpers/accounts.rb +8 -5
  18. data/lib/virtuatable/helpers/applications.rb +12 -8
  19. data/lib/virtuatable/helpers/declarators.rb +14 -11
  20. data/lib/virtuatable/helpers/parameters.rb +29 -0
  21. data/lib/virtuatable/helpers/routes.rb +3 -0
  22. data/lib/virtuatable/helpers/sessions.rb +20 -9
  23. data/lib/virtuatable/helpers.rb +1 -0
  24. data/lib/virtuatable/specs/factories/accounts.rb +54 -0
  25. data/lib/virtuatable/specs/factories/applications.rb +48 -0
  26. data/lib/virtuatable/specs/factories/groups.rb +50 -0
  27. data/lib/virtuatable/specs/factories/sessions.rb +38 -0
  28. data/lib/virtuatable/specs/factories.rb +15 -0
  29. data/lib/virtuatable/specs/shared/controllers.rb +195 -0
  30. data/lib/virtuatable/specs/shared.rb +11 -0
  31. data/lib/virtuatable/specs.rb +4 -85
  32. data/lib/virtuatable.rb +4 -0
  33. metadata +82 -114
  34. data/lib/virtuatable/helpers/gateways.rb +0 -23
  35. 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
@@ -1,92 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Virtuatable
4
- # This module holds all the logic for the specs tools for all micro services (shared examples and other things).
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
- @@declared = false
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'