vanity 2.0.0.beta8 → 2.0.0.beta9
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -2
- data/Appraisals +1 -1
- data/Gemfile +2 -1
- data/Gemfile.lock +4 -1
- data/gemfiles/rails32.gemfile +3 -2
- data/gemfiles/rails32.gemfile.lock +4 -5
- data/gemfiles/rails4.gemfile +2 -1
- data/gemfiles/rails4.gemfile.lock +3 -1
- data/gemfiles/rails41.gemfile +2 -1
- data/gemfiles/rails41.gemfile.lock +3 -1
- data/gemfiles/rails42.gemfile +2 -1
- data/gemfiles/rails42.gemfile.lock +3 -1
- data/lib/vanity.rb +11 -5
- data/lib/vanity/adapters.rb +20 -0
- data/lib/vanity/adapters/abstract_adapter.rb +0 -18
- data/lib/vanity/autoconnect.rb +1 -0
- data/lib/vanity/configuration.rb +211 -0
- data/lib/vanity/connection.rb +100 -0
- data/lib/vanity/frameworks.rb +2 -0
- data/lib/vanity/frameworks/rails.rb +7 -5
- data/lib/vanity/helpers.rb +1 -0
- data/{config → lib/vanity}/locales/vanity.en.yml +0 -0
- data/{config → lib/vanity}/locales/vanity.pt-BR.yml +0 -0
- data/lib/vanity/playground.rb +138 -338
- data/lib/vanity/vanity.rb +166 -0
- data/lib/vanity/version.rb +1 -1
- data/test/configuration_test.rb +90 -0
- data/test/connection_test.rb +46 -0
- data/test/data/redis.yml.url +2 -0
- data/test/data/vanity.yml.activerecord +6 -0
- data/test/data/vanity.yml.mock +4 -0
- data/test/data/vanity.yml.redis +5 -0
- data/test/data/vanity.yml.redis-erb +3 -0
- data/test/experiment/ab_test.rb +1 -1
- data/test/experiment/base_test.rb +1 -1
- data/test/frameworks/rails/rails_test.rb +34 -30
- data/test/metric/remote_test.rb +8 -8
- data/test/playground_test.rb +1 -27
- data/test/templates_test.rb +3 -2
- data/test/test_helper.rb +24 -12
- data/test/vanity_test.rb +130 -0
- metadata +25 -5
@@ -0,0 +1,166 @@
|
|
1
|
+
#
|
2
|
+
# Run time configuration and helpers
|
3
|
+
#
|
4
|
+
module Vanity
|
5
|
+
# Returns the current configuration.
|
6
|
+
#
|
7
|
+
# @see Vanity::Configuration
|
8
|
+
# @since 2.0.0
|
9
|
+
def self.configuration(set_if_needed=true)
|
10
|
+
if @configuration
|
11
|
+
@configuration
|
12
|
+
elsif set_if_needed
|
13
|
+
configure!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @since 2.0.0
|
18
|
+
def self.configure!
|
19
|
+
@configuration = Configuration.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# @since 2.0.0
|
23
|
+
def self.reset!
|
24
|
+
@configuration = nil
|
25
|
+
configuration
|
26
|
+
end
|
27
|
+
|
28
|
+
# This is the preferred way to configure Vanity.
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# Vanity.configure do |config|
|
32
|
+
# config.use_js = true
|
33
|
+
# end
|
34
|
+
# @since 2.0.0
|
35
|
+
def self.configure
|
36
|
+
yield(configuration)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @since 2.0.0
|
40
|
+
def self.logger
|
41
|
+
configuration.logger
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the Vanity context. For example, when using Rails this would be
|
45
|
+
# the current controller, which can be used to get/set the vanity identity.
|
46
|
+
def self.context
|
47
|
+
Thread.current[:vanity_context]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sets the Vanity context. For example, when using Rails this would be
|
51
|
+
# set by the set_vanity_context before filter (via Vanity::Rails#use_vanity).
|
52
|
+
def self.context=(context)
|
53
|
+
Thread.current[:vanity_context] = context
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Datastore connection management
|
58
|
+
#
|
59
|
+
|
60
|
+
# Returns the current connection. Establishes new connection is necessary.
|
61
|
+
#
|
62
|
+
# @since 2.0.0
|
63
|
+
def self.connection(connect_if_needed=true)
|
64
|
+
if @connection
|
65
|
+
@connection
|
66
|
+
elsif connect_if_needed
|
67
|
+
connect!
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# This is the preferred way to programmatically create a new connection (or
|
72
|
+
# switch to a new connection). If no connection was established, the
|
73
|
+
# playground will create a new one by calling this method with no arguments.
|
74
|
+
#
|
75
|
+
# @since 2.0.0
|
76
|
+
# @see Vanity::Connection
|
77
|
+
def self.connect!(spec_or_nil=nil)
|
78
|
+
spec_or_nil ||= configuration.connection_params
|
79
|
+
|
80
|
+
# Legacy redis.yml fallback
|
81
|
+
if spec_or_nil.nil?
|
82
|
+
redis_url = configuration.redis_url_from_file
|
83
|
+
|
84
|
+
if redis_url
|
85
|
+
spec_or_nil = redis_url
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Legacy special config variables permitted in connection spec
|
90
|
+
update_configuration_from_connection_params(spec_or_nil)
|
91
|
+
|
92
|
+
@connection = Connection.new(spec_or_nil)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Destroys a connection
|
96
|
+
#
|
97
|
+
# @since 2.0.0
|
98
|
+
def self.disconnect!
|
99
|
+
if @connection
|
100
|
+
@connection.disconnect!
|
101
|
+
@connection = nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.reconnect!
|
106
|
+
disconnect!
|
107
|
+
connect!
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Experiment metadata
|
112
|
+
#
|
113
|
+
|
114
|
+
# The playground instance.
|
115
|
+
#
|
116
|
+
# @see Vanity::Playground
|
117
|
+
def self.playground(load_if_needed=true)
|
118
|
+
if @playground
|
119
|
+
@playground
|
120
|
+
elsif load_if_needed
|
121
|
+
load!
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Loads all metrics and experiments. Called during initialization. In the
|
126
|
+
# case of Rails, use the Rails logger and look for templates at
|
127
|
+
# app/views/vanity.
|
128
|
+
#
|
129
|
+
# @since 2.0.0
|
130
|
+
def self.load!
|
131
|
+
@playground = Playground.new
|
132
|
+
end
|
133
|
+
|
134
|
+
# @since 2.0.0
|
135
|
+
def self.unload!
|
136
|
+
@playground = nil
|
137
|
+
end
|
138
|
+
|
139
|
+
# Reloads all metrics and experiments. Rails calls this for each request in
|
140
|
+
# development mode.
|
141
|
+
#
|
142
|
+
# @since 2.0.0
|
143
|
+
def self.reload!
|
144
|
+
unload!
|
145
|
+
load!
|
146
|
+
end
|
147
|
+
|
148
|
+
class << self
|
149
|
+
# @since 2.0.0
|
150
|
+
attr_writer :configuration
|
151
|
+
|
152
|
+
# @since 2.0.0
|
153
|
+
attr_writer :playground
|
154
|
+
|
155
|
+
# @since 2.0.0
|
156
|
+
attr_writer :connection
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def update_configuration_from_connection_params(spec_or_nil) # # :nodoc:
|
161
|
+
return unless spec_or_nil.respond_to?(:has_key?)
|
162
|
+
|
163
|
+
configuration.collecting = spec_or_nil[:collecting] if spec_or_nil.has_key?(:collecting)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/lib/vanity/version.rb
CHANGED
@@ -0,0 +1,90 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Vanity::Configuration do
|
4
|
+
let(:config) { Vanity::Configuration.new }
|
5
|
+
|
6
|
+
it "returns default values" do
|
7
|
+
assert_equal Vanity::Configuration.new.collecting, Vanity::Configuration::DEFAULTS[:collecting]
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "overriding defaults" do
|
11
|
+
it "returns overridden values" do
|
12
|
+
config.collecting = true
|
13
|
+
assert_equal config.collecting, true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "connection_params" do
|
18
|
+
before do
|
19
|
+
FakeFS.activate!
|
20
|
+
end
|
21
|
+
|
22
|
+
after do
|
23
|
+
FakeFS.deactivate!
|
24
|
+
FakeFS::FileSystem.clear
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "using the default config file & path" do
|
28
|
+
it "returns the connection params" do
|
29
|
+
FileUtils.mkpath "./config"
|
30
|
+
File.open("./config/vanity.yml", "w") do |f|
|
31
|
+
f.write VanityTestHelpers::VANITY_CONFIGS["vanity.yml.mock"]
|
32
|
+
end
|
33
|
+
|
34
|
+
mock_connection_hash = { adapter: "mock" }
|
35
|
+
assert_equal mock_connection_hash, config.connection_params
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "accepts a file name" do
|
40
|
+
FileUtils.mkpath "./config"
|
41
|
+
File.open("./config/vanity.yml", "w") do |f|
|
42
|
+
f.write VanityTestHelpers::VANITY_CONFIGS["vanity.yml.mock"]
|
43
|
+
end
|
44
|
+
|
45
|
+
mock_connection_hash = { adapter: "mock" }
|
46
|
+
assert_equal mock_connection_hash, config.connection_params("vanity.yml")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns connection strings" do
|
50
|
+
FileUtils.mkpath "./config"
|
51
|
+
File.open("./config/redis.yml", "w") do |f|
|
52
|
+
f.write VanityTestHelpers::VANITY_CONFIGS["redis.yml.url"]
|
53
|
+
end
|
54
|
+
|
55
|
+
mock_connection_string = "localhost:6379/15"
|
56
|
+
assert_equal mock_connection_string, config.connection_params("redis.yml")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns nil if the file doesn't exist" do
|
60
|
+
FileUtils.mkpath "./config"
|
61
|
+
assert_nil config.connection_params
|
62
|
+
end
|
63
|
+
|
64
|
+
it "raises an error if the environment isn't configured" do
|
65
|
+
FileUtils.mkpath "./config"
|
66
|
+
File.open("./config/vanity.yml", "w") do |f|
|
67
|
+
f.write VanityTestHelpers::VANITY_CONFIGS["vanity.yml.mock"]
|
68
|
+
end
|
69
|
+
|
70
|
+
config.environment = "staging"
|
71
|
+
assert_raises(Vanity::Configuration::MissingEnvironment) {
|
72
|
+
config.connection_params
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
it "symbolizes hash keys" do
|
77
|
+
FileUtils.mkpath "./config"
|
78
|
+
File.open("./config/vanity.yml", "w") do |f|
|
79
|
+
f.write VanityTestHelpers::VANITY_CONFIGS["vanity.yml.activerecord"]
|
80
|
+
end
|
81
|
+
|
82
|
+
ar_connection_values = [:adapter, :active_record_adapter]
|
83
|
+
assert_equal ar_connection_values, config.connection_params.keys
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "setup_locales" do
|
88
|
+
it "adds vanity locales to the gem"
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Vanity::Connection do
|
4
|
+
describe "#new" do
|
5
|
+
it "establishes connection with default specification" do
|
6
|
+
Vanity::Adapters.expects(:establish_connection).with(adapter: "redis")
|
7
|
+
Vanity::Connection.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "establishes connection given a connection specification" do
|
11
|
+
Vanity::Adapters.expects(:establish_connection).with(adapter: "mock")
|
12
|
+
Vanity::Connection.new(adapter: "mock")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can skip connection" do
|
16
|
+
Vanity::Autoconnect.stubs(:playground_should_autoconnect?).returns(false)
|
17
|
+
connection = Vanity::Connection.new(adapter: "mock")
|
18
|
+
assert !connection.connected?
|
19
|
+
end
|
20
|
+
|
21
|
+
it "parses from a string" do
|
22
|
+
Vanity::Adapters.expects(:establish_connection).with(
|
23
|
+
adapter: 'redis',
|
24
|
+
username: 'user',
|
25
|
+
password: 'secrets',
|
26
|
+
host: 'redis.local',
|
27
|
+
port: 6379,
|
28
|
+
path: '/5',
|
29
|
+
params: nil
|
30
|
+
)
|
31
|
+
Vanity::Connection.new("redis://user:secrets@redis.local:6379/5")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raises an error for invalid specification hashes" do
|
35
|
+
assert_raises(Vanity::Connection::InvalidSpecification) {
|
36
|
+
Vanity::Connection.new("adapter" => "mock")
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
it "allows a redis connection to be specified" do
|
41
|
+
redis = stub("Redis")
|
42
|
+
Vanity::Adapters.expects(:establish_connection).with(adapter: :redis, redis: redis)
|
43
|
+
Vanity::Connection.new(redis: redis)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/test/experiment/ab_test.rb
CHANGED
@@ -138,7 +138,7 @@ class AbTestTest < ActionController::TestCase
|
|
138
138
|
# -- use_js! --
|
139
139
|
|
140
140
|
def test_choose_does_not_record_participant_when_using_js
|
141
|
-
Vanity.
|
141
|
+
Vanity.configuration.use_js = true
|
142
142
|
ids = (0...10).to_a
|
143
143
|
new_ab_test :foobar do
|
144
144
|
alternatives "foo", "bar"
|
@@ -111,7 +111,7 @@ describe Vanity::Experiment::Base do
|
|
111
111
|
new_ab_test(:ice_cream_flavor) { metrics :happiness }
|
112
112
|
end
|
113
113
|
|
114
|
-
|
114
|
+
vanity_reset
|
115
115
|
metric :happiness
|
116
116
|
new_ab_test(:ice_cream_flavor) { metrics :happiness }
|
117
117
|
assert_equal past.to_time.to_i, experiment(:ice_cream_flavor).created_at.to_i
|
@@ -1,20 +1,20 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
|
-
describe "Rails
|
3
|
+
describe "deprecated Rails load_path and deprecated connection configuration" do
|
4
4
|
|
5
5
|
it "load_path" do
|
6
|
-
assert_equal
|
6
|
+
assert_equal "./experiments", load_rails("", <<-RB)
|
7
7
|
$stdout << Vanity.playground.load_path
|
8
8
|
RB
|
9
9
|
end
|
10
10
|
|
11
|
-
it "
|
12
|
-
assert_equal
|
11
|
+
it "settable load_path" do
|
12
|
+
assert_equal "predictions", load_rails(%Q{\nVanity.playground.load_path = "predictions"\n}, <<-RB)
|
13
13
|
$stdout << Vanity.playground.load_path
|
14
14
|
RB
|
15
15
|
end
|
16
16
|
|
17
|
-
it "
|
17
|
+
it "absolute load_path" do
|
18
18
|
Dir.mktmpdir do |dir|
|
19
19
|
assert_equal dir, load_rails(%Q{\nVanity.playground.load_path = "#{dir}"\n}, <<-RB)
|
20
20
|
$stdout << Vanity.playground.load_path
|
@@ -23,19 +23,19 @@ $stdout << Vanity.playground.load_path
|
|
23
23
|
end
|
24
24
|
|
25
25
|
if ENV['DB'] == 'redis'
|
26
|
-
it "
|
26
|
+
it "default connection" do
|
27
27
|
assert_equal "redis://127.0.0.1:6379/0", load_rails("", <<-RB)
|
28
28
|
$stdout << Vanity.playground.connection
|
29
29
|
RB
|
30
30
|
end
|
31
31
|
|
32
|
-
it "
|
32
|
+
it "connection from string" do
|
33
33
|
assert_equal "redis://192.168.1.1:6379/5", load_rails(%Q{\nVanity.playground.establish_connection "redis://192.168.1.1:6379/5"\n}, <<-RB)
|
34
34
|
$stdout << Vanity.playground.connection
|
35
35
|
RB
|
36
36
|
end
|
37
37
|
|
38
|
-
it "
|
38
|
+
it "connection from yaml" do
|
39
39
|
begin
|
40
40
|
FileUtils.mkpath "tmp/config"
|
41
41
|
@original_env = ENV["RAILS_ENV"]
|
@@ -57,7 +57,7 @@ $stdout << Vanity.playground.connection
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
it "
|
60
|
+
it "connection from yaml url" do
|
61
61
|
begin
|
62
62
|
FileUtils.mkpath "tmp/config"
|
63
63
|
@original_env = ENV["RAILS_ENV"]
|
@@ -76,7 +76,7 @@ $stdout << Vanity.playground.connection
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
it "
|
79
|
+
it "connection from yaml with erb" do
|
80
80
|
begin
|
81
81
|
FileUtils.mkpath "tmp/config"
|
82
82
|
@original_env = ENV["RAILS_ENV"]
|
@@ -99,13 +99,13 @@ $stdout << Vanity.playground.connection
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
|
-
it "
|
102
|
+
it "connection from redis yml" do
|
103
103
|
begin
|
104
104
|
FileUtils.mkpath "tmp/config"
|
105
105
|
yml = File.open("tmp/config/redis.yml", "w")
|
106
106
|
yml << "production: internal.local:6379\n"
|
107
107
|
yml.flush
|
108
|
-
|
108
|
+
assert_match %r{redis://internal.local:6379/0\Z}, load_rails("", <<-RB)
|
109
109
|
$stdout << Vanity.playground.connection
|
110
110
|
RB
|
111
111
|
ensure
|
@@ -115,7 +115,7 @@ $stdout << Vanity.playground.connection
|
|
115
115
|
end
|
116
116
|
|
117
117
|
if ENV['DB'] == 'mongo'
|
118
|
-
it "
|
118
|
+
it "mongo connection from yaml" do
|
119
119
|
begin
|
120
120
|
FileUtils.mkpath "tmp/config"
|
121
121
|
File.open("tmp/config/vanity.yml", "w") do |io|
|
@@ -136,8 +136,8 @@ $stdout << Vanity.playground.connection
|
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
|
-
unless ENV['CI'] == 'true' #
|
140
|
-
it "
|
139
|
+
unless ENV['CI'] == 'true' # See http://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
|
140
|
+
it "mongodb replica set connection" do
|
141
141
|
begin
|
142
142
|
FileUtils.mkpath "tmp/config"
|
143
143
|
File.open("tmp/config/vanity.yml", "w") do |io|
|
@@ -165,7 +165,7 @@ $stdout << Vanity.playground.connection.mongo.class
|
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
168
|
-
it "
|
168
|
+
it "connection from yaml missing" do
|
169
169
|
begin
|
170
170
|
FileUtils.mkpath "tmp/config"
|
171
171
|
File.open("tmp/config/vanity.yml", "w") do |io|
|
@@ -176,7 +176,7 @@ production:
|
|
176
176
|
end
|
177
177
|
|
178
178
|
assert_equal "No configuration for development", load_rails("\nbegin\n", <<-RB, "development")
|
179
|
-
rescue
|
179
|
+
rescue => e
|
180
180
|
$stdout << e.message
|
181
181
|
end
|
182
182
|
RB
|
@@ -185,7 +185,7 @@ end
|
|
185
185
|
end
|
186
186
|
end
|
187
187
|
|
188
|
-
it "
|
188
|
+
it "collection from vanity yaml" do
|
189
189
|
begin
|
190
190
|
FileUtils.mkpath "tmp/config"
|
191
191
|
File.open("tmp/config/vanity.yml", "w") do |io|
|
@@ -203,42 +203,46 @@ $stdout << Vanity.playground.collecting?
|
|
203
203
|
end
|
204
204
|
end
|
205
205
|
|
206
|
-
it "
|
206
|
+
it "collection true in production by default" do
|
207
207
|
assert_equal "true", load_rails("", <<-RB)
|
208
208
|
$stdout << Vanity.playground.collecting?
|
209
209
|
RB
|
210
210
|
end
|
211
211
|
|
212
|
-
it "
|
212
|
+
it "collection false in production when configured" do
|
213
213
|
assert_equal "false", load_rails("\nVanity.playground.collecting = false\n", <<-RB)
|
214
214
|
$stdout << Vanity.playground.collecting?
|
215
215
|
RB
|
216
216
|
end
|
217
217
|
|
218
|
-
it "
|
218
|
+
it "collection true in development by default" do
|
219
219
|
assert_equal "true", load_rails("", <<-RB, "development")
|
220
220
|
$stdout << Vanity.playground.collecting?
|
221
221
|
RB
|
222
222
|
end
|
223
223
|
|
224
|
-
it "
|
224
|
+
it "collection true in development when configured" do
|
225
225
|
assert_equal "true", load_rails("\nVanity.playground.collecting = true\n", <<-RB, "development")
|
226
226
|
$stdout << Vanity.playground.collecting?
|
227
227
|
RB
|
228
228
|
end
|
229
229
|
|
230
|
-
it "
|
230
|
+
it "playground loads experiments if connected" do
|
231
231
|
assert_equal "{}", load_rails("", <<-RB)
|
232
|
-
$stdout << Vanity.playground.
|
232
|
+
$stdout << Vanity.playground.experiments.inspect
|
233
233
|
RB
|
234
234
|
end
|
235
235
|
|
236
|
-
it "
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
236
|
+
it "playground does not instantiate connection if disabled" do
|
237
|
+
begin
|
238
|
+
ENV['VANITY_DISABLED'] = '1'
|
239
|
+
assert_equal "false", load_rails("", <<-RB)
|
240
|
+
Vanity.playground.experiments.inspect
|
241
|
+
$stdout << !!Vanity.playground.connected?
|
242
|
+
RB
|
243
|
+
ensure
|
244
|
+
ENV['VANITY_DISABLED'] = nil
|
245
|
+
end
|
242
246
|
end
|
243
247
|
|
244
248
|
def load_rails(before_initialize, after_initialize, env="production")
|