vwo-ruby-sdk 1.0.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.
data/lib/vwo.rb ADDED
@@ -0,0 +1,349 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'vwo/get_settings'
4
+ require_relative 'vwo/custom_logger'
5
+ require_relative 'vwo/common/utils'
6
+ require_relative 'vwo/common/enums'
7
+ require_relative 'vwo/common/campaign_utils'
8
+ require_relative 'vwo/common/impression_utils'
9
+ require_relative 'vwo/common/constants'
10
+ require_relative 'vwo/project_config_manager'
11
+ require_relative 'vwo/decision_service'
12
+ require_relative 'vwo/event_dispatcher'
13
+
14
+ # Class encapsulating all SDK functionality.
15
+ class VWO
16
+ attr_accessor :is_valid
17
+
18
+ include Common::Enums
19
+ include Common::Validations
20
+ include Common::CampaignUtils
21
+ include Common::ImpressionUtils
22
+ include Common::CONSTANTS
23
+
24
+ FILE = FileNameEnum::VWO
25
+
26
+ # VWO init method for managing custom projects.
27
+ # Setting various services on the instance
28
+ # To be accessible by its member functions
29
+ #
30
+ # @param[Numeric|String] :account_id Account Id in VWO
31
+ # @param[String] :sdk_key Unique sdk key for user,
32
+ # can be retrieved from our website
33
+ # @param[Object] :logger Optional component which provides a log method
34
+ # to log messages. By default everything would be logged.
35
+ # @param[Object] :user_profile_service Optional component which provides
36
+ # methods to store and manage user profiles.
37
+ # @param[Boolean] :is_development_mode To specify whether the request
38
+ # to our server should be sent or not.
39
+ # @param[String] :settings_file Settings File Content if already present
40
+
41
+ def initialize(
42
+ account_id,
43
+ sdk_key,
44
+ logger = nil,
45
+ user_profile_service = nil,
46
+ is_development_mode = false,
47
+ settings_file = nil
48
+ )
49
+ @account_id = account_id
50
+ @sdk_key = sdk_key
51
+ @user_profile_service = user_profile_service
52
+ @is_development_mode = is_development_mode
53
+
54
+ # Verify and assign a/the logger (Pending)
55
+ @logger = CustomLogger.get_instance(logger)
56
+ # Verify the settings_file for json object and correct schema
57
+
58
+ unless valid_settings_file?(get_settings(settings_file))
59
+ @logger.log(
60
+ LogLevelEnum::ERROR,
61
+ format(LogMessageEnum::ErrorMessages::SETTINGS_FILE_CORRUPTED, file: FILE)
62
+ )
63
+ @is_valid = false
64
+ return
65
+ end
66
+ @is_valid = true
67
+
68
+ # Initialize the ProjectConfigManager if settings_file provided is valid
69
+ @config = VWO::ProjectConfigManager.new(get_settings)
70
+
71
+ @logger.log(
72
+ LogLevelEnum::DEBUG,
73
+ format(LogMessageEnum::DebugMessages::VALID_CONFIGURATION, file: FILE)
74
+ )
75
+
76
+ # Process the settings file
77
+ @config.process_settings_file
78
+ @settings_file = @config.get_settings_file
79
+
80
+ # Assign DecisionService to vwo
81
+ @decision_service = DecisionService.new(@settings_file, user_profile_service)
82
+
83
+ # Assign event dispatcher
84
+ if is_development_mode
85
+ @logger.log(
86
+ LogLevelEnum::DEBUG,
87
+ format(LogMessageEnum::DebugMessages::SET_DEVELOPMENT_MODE, file: FILE)
88
+ )
89
+ end
90
+ @event_dispatcher = EventDispatcher.new(is_development_mode)
91
+
92
+ # Log successfully initialized SDK
93
+ @logger.log(
94
+ LogLevelEnum::DEBUG,
95
+ format(LogMessageEnum::DebugMessages::SDK_INITIALIZED, file: FILE)
96
+ )
97
+ end
98
+
99
+ # VWO get_settings method to get settings for a particular account_id
100
+ # It will memoize the settings to avoid another http call on re-invocation of this method
101
+ def get_settings(settings_file = nil)
102
+ @settings ||=
103
+ settings_file || VWO::GetSettings.new(@account_id, @sdk_key).get
104
+ @settings
105
+ end
106
+
107
+ # This API method: Gets the variation assigned for the user
108
+ # For the campaign and send the metrics to VWO server
109
+ #
110
+ # 1. Validates the arguments being passed
111
+ # 2. Checks if user is eligible to get bucketed into the campaign,
112
+ # 3. Assigns the deterministic variation to the user(based on userId),
113
+ # If user becomes part of campaign
114
+ # If userProfileService is used, it will look into it for the
115
+ # Variation and if found, no further processing is done
116
+ # 4. Sends an impression call to VWO server to track user
117
+ #
118
+ # @param[String] :campaign_test_key Unique campaign test key
119
+ # @param[String] :user_id ID assigned to a user
120
+ # @return[String|None] If variation is assigned then variation-name
121
+ # otherwise None in case of user not becoming part
122
+
123
+ def activate(campaign_test_key, user_id)
124
+ # Validate input parameters
125
+ unless valid_string?(campaign_test_key) && valid_string?(user_id)
126
+ @logger.log(
127
+ LogLevelEnum::ERROR,
128
+ format(LogMessageEnum::ErrorMessages::ACTIVATE_API_MISSING_PARAMS, file: FILE)
129
+ )
130
+ return
131
+ end
132
+
133
+ # Validate project config manager
134
+ unless @is_valid
135
+ @logger.log(
136
+ LogLevelEnum::ERROR,
137
+ format(LogMessageEnum::ErrorMessages::ACTIVATE_API_CONFIG_CORRUPTED, file: FILE)
138
+ )
139
+ return
140
+ end
141
+
142
+ # Get the campaign settings
143
+ campaign = get_campaign(@settings_file, campaign_test_key)
144
+
145
+ # Validate campaign
146
+ unless campaign && campaign['status'] == STATUS_RUNNING
147
+ # Campaign is invalid
148
+ @logger.log(
149
+ LogLevelEnum::ERROR,
150
+ format(LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING, file: FILE, campaign_test_key: campaign_test_key, api: 'activate')
151
+ )
152
+ return
153
+ end
154
+
155
+ # Once the matching RUNNING campaign is found, assign the
156
+ # deterministic variation to the user_id provided
157
+ variation_id, variation_name = @decision_service.get(
158
+ user_id,
159
+ campaign,
160
+ campaign_test_key
161
+ )
162
+
163
+ # Check if variation_name has been assigned
164
+ unless valid_value?(variation_name)
165
+ # log invalid variation key
166
+ @logger.log(
167
+ LogLevelEnum::INFO,
168
+ format(LogMessageEnum::InfoMessages::INVALID_VARIATION_KEY, file: FILE, user_id: user_id, campaign_test_key: campaign_test_key)
169
+ )
170
+ return
171
+ end
172
+
173
+ # Variation found, dispatch log to DACDN
174
+ properties = build_event(
175
+ @settings_file,
176
+ campaign['id'],
177
+ variation_id,
178
+ user_id
179
+ )
180
+ @event_dispatcher.dispatch(properties)
181
+ variation_name
182
+ end
183
+
184
+ # This API method: Gets the variation assigned for the
185
+ # user for the campaign
186
+ #
187
+ # 1. Validates the arguments being passed
188
+ # 2. Checks if user is eligible to get bucketed into the campaign,
189
+ # 3. Assigns the deterministic variation to the user(based on user_id),
190
+ # If user becomes part of campaign
191
+ # If userProfileService is used, it will look into it for the
192
+ # variation and if found, no further processing is done
193
+ #
194
+ # @param[String] :campaign_test_key Unique campaign test key
195
+ # @param[String] :user_id ID assigned to a user
196
+ #
197
+ # @@return[String|Nil] If variation is assigned then variation-name
198
+ # Otherwise null in case of user not becoming part
199
+ #
200
+ def get_variation(campaign_test_key, user_id)
201
+ # Check for valid arguments
202
+ unless valid_string?(campaign_test_key) && valid_string?(user_id)
203
+ # log invalid params
204
+ @logger.log(
205
+ LogLevelEnum::ERROR,
206
+ format(LogMessageEnum::ErrorMessages::GET_VARIATION_API_MISSING_PARAMS, file: FILE)
207
+ )
208
+ return
209
+ end
210
+
211
+ # Validate project config manager
212
+ unless @is_valid
213
+ @logger.log(
214
+ LogLevelEnum::ERROR,
215
+ format(LogMessageEnum::ErrorMessages::ACTIVATE_API_CONFIG_CORRUPTED, file: FILE)
216
+ )
217
+ return
218
+ end
219
+
220
+ # Get the campaign settings
221
+ campaign = get_campaign(@settings_file, campaign_test_key)
222
+
223
+ # Validate campaign
224
+ if campaign.nil? || campaign['status'] != STATUS_RUNNING
225
+ # log campaigns invalid
226
+ @logger.log(
227
+ LogLevelEnum::ERROR,
228
+ format(LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING, file: FILE, campaign_test_key: campaign_test_key, api: 'get_variation')
229
+ )
230
+ return
231
+ end
232
+
233
+ _variation_id, variation_name = @decision_service.get(
234
+ user_id,
235
+ campaign,
236
+ campaign_test_key
237
+ )
238
+
239
+ # Check if variation_name has been assigned
240
+ unless valid_value?(variation_name)
241
+ # log invalid variation key
242
+ @logger.log(
243
+ LogLevelEnum::INFO,
244
+ format(LogMessageEnum::InfoMessages::INVALID_VARIATION_KEY, file: FILE, user_id: user_id, campaign_test_key: campaign_test_key)
245
+ )
246
+ return
247
+ end
248
+
249
+ variation_name
250
+ end
251
+
252
+ # This API method: Marks the conversion of the campaign
253
+ # for a particular goal
254
+ # 1. validates the arguments being passed
255
+ # 2. Checks if user is eligible to get bucketed into the campaign,
256
+ # 3. Gets the assigned deterministic variation to the
257
+ # user(based on user_d), if user becomes part of campaign
258
+ # 4. Sends an impression call to VWO server to track goal data
259
+ #
260
+ # @param[String] :campaign_test_key Unique campaign test key
261
+ # @param[String] :user_id ID assigned to a user
262
+ # @param[String] :goal_identifier Unique campaign's goal identifier
263
+ # @param[Numeric|String] :revenue_value Revenue generated on triggering the goal
264
+ #
265
+ def track(campaign_test_key, user_id, goal_identifier, *args)
266
+ if args.is_a?(Array)
267
+ revenue_value = args[0]
268
+ elsif args.is_a?(Hash)
269
+ revenue_value = args['revenue_value']
270
+ end
271
+
272
+ # Check for valid args
273
+ unless valid_string?(campaign_test_key) && valid_string?(user_id) && valid_string?(goal_identifier)
274
+ # log invalid params
275
+ @logger.log(
276
+ LogLevelEnum::ERROR,
277
+ format(LogMessageEnum::ErrorMessages::TRACK_API_MISSING_PARAMS, file: FILE)
278
+ )
279
+ return false
280
+ end
281
+
282
+ unless @is_valid
283
+ @logger.log(
284
+ LogLevelEnum::ERROR,
285
+ format(LogMessageEnum::ErrorMessages::ACTIVATE_API_CONFIG_CORRUPTED, file: FILE)
286
+ )
287
+ return false
288
+ end
289
+
290
+ # Get the campaign settings
291
+ campaign = get_campaign(@settings_file, campaign_test_key)
292
+
293
+ # Validate campaign
294
+ if campaign.nil? || campaign['status'] != STATUS_RUNNING
295
+ # log error
296
+ @logger.log(
297
+ LogLevelEnum::ERROR,
298
+ format(LogMessageEnum::ErrorMessages::CAMPAIGN_NOT_RUNNING, file: FILE, campaign_test_key: campaign_test_key, api: 'track')
299
+ )
300
+ return false
301
+ end
302
+
303
+ campaign_id = campaign['id']
304
+ variation_id, variation_name = @decision_service.get_variation_allotted(user_id, campaign)
305
+
306
+ if variation_name
307
+ goal = get_campaign_goal(@settings_file, campaign['key'], goal_identifier)
308
+
309
+ if goal.nil?
310
+ @logger.log(
311
+ LogLevelEnum::ERROR,
312
+ format(
313
+ LogMessageEnum::ErrorMessages::TRACK_API_GOAL_NOT_FOUND,
314
+ file: FILE, goal_identifier: goal_identifier,
315
+ user_id: user_id,
316
+ campaign_test_key: campaign_test_key
317
+ )
318
+ )
319
+ return false
320
+ elsif goal['type'] == GOALTYPES::REVENUE && !valid_value?(revenue_value)
321
+ @logger.log(
322
+ LogLevelEnum::ERROR,
323
+ format(
324
+ LogMessageEnum::ErrorMessages::TRACK_API_REVENUE_NOT_PASSED_FOR_REVENUE_GOAL,
325
+ file: FILE,
326
+ user_id: user_id,
327
+ goal_identifier: goal_identifier,
328
+ campaign_test_key: campaign_test_key
329
+ )
330
+ )
331
+ return false
332
+ end
333
+
334
+ revenue_value = nil if goal['type'] == GOALTYPES::CUSTOM
335
+
336
+ properties = build_event(
337
+ @settings_file,
338
+ campaign_id,
339
+ variation_id,
340
+ user_id,
341
+ goal['id'],
342
+ revenue_value
343
+ )
344
+ @event_dispatcher.dispatch(properties)
345
+ return true
346
+ end
347
+ false
348
+ end
349
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vwo-ruby-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - VWO
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-09-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: coveralls
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.23
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.23
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.70'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.70'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json-schema
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.8'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: murmurhash3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.1'
69
+ description: A Ruby SDK for VWO full-stack testing.
70
+ email:
71
+ - dev@wingify.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/vwo.rb
77
+ - lib/vwo/bucketing_service.rb
78
+ - lib/vwo/common/campaign_utils.rb
79
+ - lib/vwo/common/constants.rb
80
+ - lib/vwo/common/enums.rb
81
+ - lib/vwo/common/function_utils.rb
82
+ - lib/vwo/common/impression_utils.rb
83
+ - lib/vwo/common/requests.rb
84
+ - lib/vwo/common/schemas/settings_file.rb
85
+ - lib/vwo/common/utils.rb
86
+ - lib/vwo/common/uuid_utils.rb
87
+ - lib/vwo/common/validations.rb
88
+ - lib/vwo/custom_logger.rb
89
+ - lib/vwo/decision_service.rb
90
+ - lib/vwo/event_dispatcher.rb
91
+ - lib/vwo/get_settings.rb
92
+ - lib/vwo/project_config_manager.rb
93
+ - lib/vwo/user_profile.rb
94
+ homepage: https://vwo.com/fullstack/server-side-testing/
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.5.2.3
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Ruby SDK for VWO full-stack testing
118
+ test_files: []