virtuatable 0.5.0 → 3.2.3

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