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.
Files changed (42) hide show
  1. data/.travis.yml +4 -2
  2. data/Appraisals +1 -1
  3. data/Gemfile +2 -1
  4. data/Gemfile.lock +4 -1
  5. data/gemfiles/rails32.gemfile +3 -2
  6. data/gemfiles/rails32.gemfile.lock +4 -5
  7. data/gemfiles/rails4.gemfile +2 -1
  8. data/gemfiles/rails4.gemfile.lock +3 -1
  9. data/gemfiles/rails41.gemfile +2 -1
  10. data/gemfiles/rails41.gemfile.lock +3 -1
  11. data/gemfiles/rails42.gemfile +2 -1
  12. data/gemfiles/rails42.gemfile.lock +3 -1
  13. data/lib/vanity.rb +11 -5
  14. data/lib/vanity/adapters.rb +20 -0
  15. data/lib/vanity/adapters/abstract_adapter.rb +0 -18
  16. data/lib/vanity/autoconnect.rb +1 -0
  17. data/lib/vanity/configuration.rb +211 -0
  18. data/lib/vanity/connection.rb +100 -0
  19. data/lib/vanity/frameworks.rb +2 -0
  20. data/lib/vanity/frameworks/rails.rb +7 -5
  21. data/lib/vanity/helpers.rb +1 -0
  22. data/{config → lib/vanity}/locales/vanity.en.yml +0 -0
  23. data/{config → lib/vanity}/locales/vanity.pt-BR.yml +0 -0
  24. data/lib/vanity/playground.rb +138 -338
  25. data/lib/vanity/vanity.rb +166 -0
  26. data/lib/vanity/version.rb +1 -1
  27. data/test/configuration_test.rb +90 -0
  28. data/test/connection_test.rb +46 -0
  29. data/test/data/redis.yml.url +2 -0
  30. data/test/data/vanity.yml.activerecord +6 -0
  31. data/test/data/vanity.yml.mock +4 -0
  32. data/test/data/vanity.yml.redis +5 -0
  33. data/test/data/vanity.yml.redis-erb +3 -0
  34. data/test/experiment/ab_test.rb +1 -1
  35. data/test/experiment/base_test.rb +1 -1
  36. data/test/frameworks/rails/rails_test.rb +34 -30
  37. data/test/metric/remote_test.rb +8 -8
  38. data/test/playground_test.rb +1 -27
  39. data/test/templates_test.rb +3 -2
  40. data/test/test_helper.rb +24 -12
  41. data/test/vanity_test.rb +130 -0
  42. 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
@@ -1,5 +1,5 @@
1
1
  module Vanity
2
- VERSION = "2.0.0.beta8"
2
+ VERSION = "2.0.0.beta9"
3
3
 
4
4
  module Version
5
5
  version = VERSION.to_s.split(".").map { |i| i.to_i }
@@ -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
@@ -0,0 +1,2 @@
1
+ development: localhost:6379/0
2
+ test: localhost:6379/15
@@ -0,0 +1,6 @@
1
+ development:
2
+ adapter: active_record
3
+ active_record_adapter: default
4
+ test:
5
+ adapter: active_record
6
+ active_record_adapter: default
@@ -0,0 +1,4 @@
1
+ development:
2
+ adapter: mock
3
+ test:
4
+ adapter: mock
@@ -0,0 +1,5 @@
1
+ test:
2
+ adapter: redis
3
+ collecting: false
4
+ production:
5
+ adapter: redis
@@ -0,0 +1,3 @@
1
+ production:
2
+ adapter: redis
3
+ connection: redis://<%= ENV["REDIS_USER"] %>:<%= ENV["REDIS_PASSWORD"] %>@<%= ENV["REDIS_HOST"] %>:<%= ENV["REDIS_PORT"] %>/0
@@ -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.playground.use_js!
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
- new_playground
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 load path and connection configuration" do
3
+ describe "deprecated Rails load_path and deprecated connection configuration" do
4
4
 
5
5
  it "load_path" do
6
- assert_equal File.expand_path("tmp/experiments"), load_rails("", <<-RB)
6
+ assert_equal "./experiments", load_rails("", <<-RB)
7
7
  $stdout << Vanity.playground.load_path
8
8
  RB
9
9
  end
10
10
 
11
- it "settable_load_path" do
12
- assert_equal File.expand_path("tmp/predictions"), load_rails(%Q{\nVanity.playground.load_path = "predictions"\n}, <<-RB)
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 "absolute_load_path" do
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 "default_connection" do
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 "connection_from_string" do
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 "connection_from_yaml" do
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 "connection_from_yaml_url" do
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 "connection_from_yaml_with_erb" do
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 "connection_from_redis_yml" do
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
- assert_equal "redis://internal.local:6379/0", load_rails("", <<-RB)
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 "mongo_connection_from_yaml" do
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' #TODO this doesn't get tested on CI
140
- it "mongodb_replica_set_connection" do
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 "connection_from_yaml_missing" do
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 RuntimeError => e
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 "collection_from_vanity_yaml" do
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 "collection_true_in_production_by_default" do
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 "collection_false_in_production_when_configured" do
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 "collection_true_in_development_by_default" do
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 "collection_true_in_development_when_configured" do
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 "playground_loads_if_connected" do
230
+ it "playground loads experiments if connected" do
231
231
  assert_equal "{}", load_rails("", <<-RB)
232
- $stdout << Vanity.playground.instance_variable_get(:@experiments).inspect
232
+ $stdout << Vanity.playground.experiments.inspect
233
233
  RB
234
234
  end
235
235
 
236
- it "playground_does_not_load_if_not_connected" do
237
- ENV['VANITY_DISABLED'] = '1'
238
- assert_equal "nil", load_rails("", <<-RB)
239
- $stdout << Vanity.playground.instance_variable_get(:@experiments).inspect
240
- RB
241
- ENV['VANITY_DISABLED'] = nil
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")