Skip to content

Commit

Permalink
feat(opt-out): opt-out of tracking by VWO without removing code
Browse files Browse the repository at this point in the history
  • Loading branch information
Abbas-khaliq authored and softvar committed Dec 23, 2021
1 parent 217f3e0 commit d86fb82
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 11 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- For events architecture accounts, tracking same goal across multiple campaigns will not send multiple tracking calls. Instead, one single `POST` call would be made to track the same goal across multiple different campaigns running on the same environment.

- Multiple custom dimension can be pushed via `push` API. For events architecture enabled account, only one single asynchronous call would be made to track multiple custom dimensions.
```ruby

```ruby
custom_dimension_map = {
browser: 'chrome',
price: '20'
}
vwo_client_instance.push(custom_dimension_map, user_id)
```
```

## [1.24.1] - 2021-12-09

Expand Down
99 changes: 92 additions & 7 deletions lib/vwo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def initialize(
options = {}
)
options = convert_to_symbol_hash(options)
@is_opted_out = false
@account_id = account_id
@sdk_key = sdk_key
@user_storage = user_storage
Expand Down Expand Up @@ -208,6 +209,10 @@ def get_settings(settings_file = nil)
# VWO get_settings method to get settings for a particular account_id
def get_and_update_settings_file

if is_opted_out(ApiMethods::GET_AND_UPDATE_SETTINGS_FILE)
return false
end

unless @is_instance_valid
@logger.log(
LogLevelEnum::ERROR,
Expand All @@ -217,7 +222,7 @@ def get_and_update_settings_file
api_name: ApiMethods.GET_AND_UPDATE_SETTINGS_FILE
)
)
return
return false
end

latest_settings = @settings_file_manager.get_settings_file(true)
Expand Down Expand Up @@ -267,6 +272,10 @@ def get_and_update_settings_file
# otherwise null in case of user not becoming part

def activate(campaign_key, user_id, options = {})
if is_opted_out(ApiMethods::ACTIVATE)
return nil
end

unless @is_instance_valid
@logger.log(
LogLevelEnum::ERROR,
Expand Down Expand Up @@ -444,6 +453,10 @@ def activate(campaign_key, user_id, options = {})
# Otherwise null in case of user not becoming part
#
def get_variation_name(campaign_key, user_id, options = {})
if is_opted_out(ApiMethods::GET_VARIATION_NAME)
return nil
end

unless @is_instance_valid
@logger.log(
LogLevelEnum::ERROR,
Expand Down Expand Up @@ -555,6 +568,10 @@ def get_variation_name(campaign_key, user_id, options = {})
#

def track(campaign_key, user_id, goal_identifier, options = {})
if is_opted_out(ApiMethods::TRACK)
return false
end

unless @is_instance_valid
@logger.log(
LogLevelEnum::ERROR,
Expand Down Expand Up @@ -786,6 +803,10 @@ def track(campaign_key, user_id, goal_identifier, options = {})
# @return[Boolean] true if user becomes part of feature test/rollout, otherwise false.

def feature_enabled?(campaign_key, user_id, options = {})
if is_opted_out(ApiMethods::IS_FEATURE_ENABLED)
return false
end

unless @is_instance_valid
@logger.log(
LogLevelEnum::ERROR,
Expand Down Expand Up @@ -983,13 +1004,17 @@ def feature_enabled?(campaign_key, user_id, options = {})
#

def get_feature_variable_value(campaign_key, variable_key, user_id, options = {})
if is_opted_out(ApiMethods::GET_FEATURE_VARIABLE_VALUE)
return nil
end

unless @is_instance_valid
@logger.log(
LogLevelEnum::ERROR,
format(
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
file: FILE,
api_name: ApiMethods.GET_FEATURE_VARIABLE_VALUE
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
)
)
return
Expand Down Expand Up @@ -1137,16 +1162,20 @@ def get_feature_variable_value(campaign_key, variable_key, user_id, options = {}
# @return true if call is made successfully, else false

def push(tag_key, tag_value, user_id = nil)
if is_opted_out(ApiMethods::PUSH)
return false
end

unless @is_instance_valid
@logger.log(
LogLevelEnum::ERROR,
format(
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
file: FILE,
api_name: ApiMethods.PUSH
api_name: ApiMethods::PUSH
)
)
return
return false
end

# Argument reshuffling.
Expand Down Expand Up @@ -1245,6 +1274,10 @@ def is_eligible_to_send_impression()
end

def flush_events
if is_opted_out(ApiMethods::FLUSH_EVENTS)
return false
end

unless @is_instance_valid
@logger.log(
LogLevelEnum::ERROR,
Expand All @@ -1254,10 +1287,13 @@ def flush_events
api_name: ApiMethods::FLUSH_EVENTS
)
)
return
return false
end
result = false
if defined?(@batch_events) && !@batch_events_queue.nil?
result = @batch_events_queue.flush(manual: true)
@batch_events_queue.kill_thread
end
result = @batch_events_queue.flush(manual: true)
@batch_events_queue.kill_thread
result
rescue StandardError => e
@logger.log(
Expand Down Expand Up @@ -1294,6 +1330,55 @@ def get_goal_type_to_track(options)
goal_type_to_track
end

# Manually opting out of VWO SDK, No tracking will happen
#
# return[bool]
#
def set_opt_out
@logger.log(
LogLevelEnum::INFO,
format(
LogMessageEnum::InfoMessages::OPT_OUT_API_CALLED,
file: FILE
)
)
if defined?(@batch_events) && !@batch_events_queue.nil?
@batch_events_queue.flush(manual: true)
@batch_events_queue.kill_thread
end

@is_opted_out = true
@settings_file = nil
@user_storage = nil
@event_dispatcher = nil
@variation_decider = nil
@config = nil
@usage_stats = nil
@batch_event_dispatcher = nil
@batch_events_queue = nil
@batch_events = nil

return @is_opted_out
end


# Check if VWO SDK is manually opted out
# @param[String] :api_name api_name is used in logging
# @return[bool]
def is_opted_out(api_name)
if @is_opted_out
@logger.log(
LogLevelEnum::INFO,
format(
LogMessageEnum::InfoMessages::API_NOT_ENABLED,
file: FILE,
api: api_name
)
)
end
return @is_opted_out
end

def is_event_arch_enabled
return @settings_file.key?('isEventArchEnabled') && @settings_file['isEventArchEnabled']
end
Expand Down
3 changes: 2 additions & 1 deletion lib/vwo/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module CONSTANTS
HTTP_PROTOCOL = 'http://'
HTTPS_PROTOCOL = 'https://'
URL_NAMESPACE = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'
SDK_VERSION = '1.25.0'
SDK_VERSION = '1.28.0'
SDK_NAME = 'ruby'
VWO_DELIMITER = '_vwo_'
MAX_EVENTS_PER_REQUEST = 5000
Expand Down Expand Up @@ -102,6 +102,7 @@ module ApiMethods
PUSH = 'push'
GET_AND_UPDATE_SETTINGS_FILE = 'get_and_update_settings_file'
FLUSH_EVENTS = 'flush_events'
OPT_OUT = 'opt_out'
end

module PushApi
Expand Down
2 changes: 2 additions & 0 deletions lib/vwo/enums.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ module InfoMessages
GOT_ELIGIBLE_CAMPAIGNS = "(%<file>s): Got %<no_of_eligible_campaigns>s eligible winners out of %<no_of_group_campaigns>s from the Group:%<group_name>s and for User ID:%<user_id>s"
CALLED_CAMPAIGN_NOT_WINNER = "(%<file>s): Campaign:%<campaign_key>s does not qualify from the mutually exclusive group:%<group_name>s for User ID:%<user_id>s"
OTHER_CAMPAIGN_SATISFIES_WHITELISTING_OR_STORAGE = "(%<file>s): Campaign:%<campaign_key>s of Group:%<group_name>s satisfies %<type>s for User ID:%<user_id>s"
OPT_OUT_API_CALLED = "(%<file>s): You have opted out for not tracking i.e. all API calls will stop functioning and will simply early return"
API_NOT_ENABLED = "(%<file>s): %<api>s API is disabled as you opted out for tracking. Reinitialize the SDK to enable the normal functioning of all APIs."
end

# Warning Messages
Expand Down
46 changes: 45 additions & 1 deletion tests/test_vwo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ def flush_callback(events)

def test_flush_events_with_corrupted_vwo_instance
set_up('EMPTY_SETTINGS_FILE')
assert_equal(@vwo.flush_events, nil)
assert_equal(@vwo.flush_events, false)
end

def test_flush_events_raises_exception
Expand Down Expand Up @@ -1603,4 +1603,48 @@ def test_get_variation_as_user_hash_passes_whitelisting
}
assert_equal(vwo_instance.get_variation_name('AB_T_100_W_25_25_25_25', 'Rohit'), 'Variation-1')
end

def test_set_opt_out_api
set_up('T_50_W_50_50_WS')
assert_equal(@vwo.set_opt_out, true)
end

def test_apis_when_set_opt_out_called
set_up('T_50_W_50_50_WS')

assert_equal(@vwo.set_opt_out, true)
assert_equal(@vwo.activate('T_50_W_50_50_WS', 'Ashley', {}), nil)
assert_equal(@vwo.get_variation_name('T_50_W_50_50_WS', 'Ashley', {}), nil)
goal_identifier = 'ddd'
assert_equal(@vwo.track('T_50_W_50_50_WS', 'Ashley', goal_identifier, {}), false)
assert_equal(@vwo.feature_enabled?('T_50_W_50_50_WS', 'Ashley', {}), false)
assert_equal(@vwo.get_feature_variable_value('FT_T_75_W_10_20_30_40_WS', 'STRING_VARIABLE', 'Ashley', {}), nil)
assert_equal(@vwo.get_and_update_settings_file, false)
assert_equal(@vwo.push('tagKey', 'tagValue', 'Ashley'), false)
assert_equal(@vwo.flush_events, false)
end

def test_apis_when_set_opt_out_called_with_event_batch
def flush_callback(events)
end

options = {
batch_events: {
events_per_request: 3,
request_time_interval: 5
}
}
vwo_instance = initialize_vwo_with_batch_events_option('AB_T_50_W_50_50', options)

assert_equal(vwo_instance.set_opt_out, true)
assert_equal(vwo_instance.activate('T_50_W_50_50_WS', 'Ashley', {}), nil)
assert_equal(vwo_instance.get_variation_name('T_50_W_50_50_WS', 'Ashley', {}), nil)
goal_identifier = 'ddd'
assert_equal(vwo_instance.track('T_50_W_50_50_WS', 'Ashley', goal_identifier, {}), false)
assert_equal(vwo_instance.feature_enabled?('T_50_W_50_50_WS', 'Ashley', {}), false)
assert_equal(vwo_instance.get_feature_variable_value('FT_T_75_W_10_20_30_40_WS', 'STRING_VARIABLE', 'Ashley', {}), nil)
assert_equal(vwo_instance.get_and_update_settings_file, false)
assert_equal(vwo_instance.push('tagKey', 'tagValue', 'Ashley'), false)
assert_equal(vwo_instance.flush_events, false)
end
end

0 comments on commit d86fb82

Please sign in to comment.