modesty 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. data/Gemfile +13 -0
  2. data/Gemfile.lock +18 -0
  3. data/LICENSE +21 -0
  4. data/README.md +121 -0
  5. data/Rakefile +29 -0
  6. data/VERSION +1 -0
  7. data/init.rb +1 -0
  8. data/lib/modesty.rb +26 -0
  9. data/lib/modesty/api.rb +14 -0
  10. data/lib/modesty/core_ext.rb +5 -0
  11. data/lib/modesty/core_ext/array.rb +21 -0
  12. data/lib/modesty/core_ext/fixnum.rb +5 -0
  13. data/lib/modesty/core_ext/hash.rb +39 -0
  14. data/lib/modesty/core_ext/string.rb +9 -0
  15. data/lib/modesty/core_ext/symbol.rb +33 -0
  16. data/lib/modesty/datastore.rb +51 -0
  17. data/lib/modesty/datastore/redis.rb +180 -0
  18. data/lib/modesty/experiment.rb +87 -0
  19. data/lib/modesty/experiment/base.rb +47 -0
  20. data/lib/modesty/experiment/builder.rb +48 -0
  21. data/lib/modesty/experiment/console.rb +4 -0
  22. data/lib/modesty/experiment/data.rb +75 -0
  23. data/lib/modesty/experiment/interface.rb +29 -0
  24. data/lib/modesty/experiment/significance.rb +376 -0
  25. data/lib/modesty/experiment/stats.rb +163 -0
  26. data/lib/modesty/frameworks/rails.rb +27 -0
  27. data/lib/modesty/identity.rb +32 -0
  28. data/lib/modesty/load.rb +80 -0
  29. data/lib/modesty/load/load_experiments.rb +14 -0
  30. data/lib/modesty/load/load_metrics.rb +17 -0
  31. data/lib/modesty/metric.rb +56 -0
  32. data/lib/modesty/metric/base.rb +38 -0
  33. data/lib/modesty/metric/builder.rb +23 -0
  34. data/lib/modesty/metric/data.rb +133 -0
  35. data/modesty.gemspec +192 -0
  36. data/spec/core_ext_spec.rb +17 -0
  37. data/spec/experiment_spec.rb +239 -0
  38. data/spec/identity_spec.rb +161 -0
  39. data/spec/load_spec.rb +87 -0
  40. data/spec/metric_spec.rb +176 -0
  41. data/spec/rails_spec.rb +48 -0
  42. data/spec/redis_spec.rb +29 -0
  43. data/spec/significance_spec.rb +147 -0
  44. data/spec/spec.opts +1 -0
  45. data/test/myapp/config/modesty.yml +9 -0
  46. data/test/myapp/modesty/experiments/cookbook.rb +4 -0
  47. data/test/myapp/modesty/metrics/kitchen_metrics.rb +9 -0
  48. data/test/myapp/modesty/metrics/stove/burner_metrics.rb +2 -0
  49. data/vendor/.piston.yml +8 -0
  50. data/vendor/mock_redis/.gitignore +2 -0
  51. data/vendor/mock_redis/README +8 -0
  52. data/vendor/mock_redis/lib/mock_redis.rb +10 -0
  53. data/vendor/mock_redis/lib/mock_redis/hash.rb +61 -0
  54. data/vendor/mock_redis/lib/mock_redis/list.rb +6 -0
  55. data/vendor/mock_redis/lib/mock_redis/misc.rb +69 -0
  56. data/vendor/mock_redis/lib/mock_redis/set.rb +108 -0
  57. data/vendor/mock_redis/lib/mock_redis/string.rb +32 -0
  58. data/vendor/redis-rb/.gitignore +8 -0
  59. data/vendor/redis-rb/LICENSE +20 -0
  60. data/vendor/redis-rb/README.markdown +129 -0
  61. data/vendor/redis-rb/Rakefile +155 -0
  62. data/vendor/redis-rb/benchmarking/logging.rb +62 -0
  63. data/vendor/redis-rb/benchmarking/pipeline.rb +51 -0
  64. data/vendor/redis-rb/benchmarking/speed.rb +21 -0
  65. data/vendor/redis-rb/benchmarking/suite.rb +24 -0
  66. data/vendor/redis-rb/benchmarking/thread_safety.rb +38 -0
  67. data/vendor/redis-rb/benchmarking/worker.rb +71 -0
  68. data/vendor/redis-rb/examples/basic.rb +15 -0
  69. data/vendor/redis-rb/examples/dist_redis.rb +43 -0
  70. data/vendor/redis-rb/examples/incr-decr.rb +17 -0
  71. data/vendor/redis-rb/examples/list.rb +26 -0
  72. data/vendor/redis-rb/examples/pubsub.rb +31 -0
  73. data/vendor/redis-rb/examples/sets.rb +36 -0
  74. data/vendor/redis-rb/examples/unicorn/config.ru +3 -0
  75. data/vendor/redis-rb/examples/unicorn/unicorn.rb +20 -0
  76. data/vendor/redis-rb/lib/redis.rb +676 -0
  77. data/vendor/redis-rb/lib/redis/client.rb +201 -0
  78. data/vendor/redis-rb/lib/redis/compat.rb +21 -0
  79. data/vendor/redis-rb/lib/redis/connection.rb +134 -0
  80. data/vendor/redis-rb/lib/redis/distributed.rb +526 -0
  81. data/vendor/redis-rb/lib/redis/hash_ring.rb +131 -0
  82. data/vendor/redis-rb/lib/redis/pipeline.rb +13 -0
  83. data/vendor/redis-rb/lib/redis/subscribe.rb +79 -0
  84. data/vendor/redis-rb/redis.gemspec +29 -0
  85. data/vendor/redis-rb/test/commands_on_hashes_test.rb +46 -0
  86. data/vendor/redis-rb/test/commands_on_lists_test.rb +50 -0
  87. data/vendor/redis-rb/test/commands_on_sets_test.rb +78 -0
  88. data/vendor/redis-rb/test/commands_on_sorted_sets_test.rb +109 -0
  89. data/vendor/redis-rb/test/commands_on_strings_test.rb +70 -0
  90. data/vendor/redis-rb/test/commands_on_value_types_test.rb +88 -0
  91. data/vendor/redis-rb/test/connection_handling_test.rb +87 -0
  92. data/vendor/redis-rb/test/db/.gitignore +1 -0
  93. data/vendor/redis-rb/test/distributd_key_tags_test.rb +53 -0
  94. data/vendor/redis-rb/test/distributed_blocking_commands_test.rb +54 -0
  95. data/vendor/redis-rb/test/distributed_commands_on_hashes_test.rb +12 -0
  96. data/vendor/redis-rb/test/distributed_commands_on_lists_test.rb +18 -0
  97. data/vendor/redis-rb/test/distributed_commands_on_sets_test.rb +85 -0
  98. data/vendor/redis-rb/test/distributed_commands_on_strings_test.rb +50 -0
  99. data/vendor/redis-rb/test/distributed_commands_on_value_types_test.rb +73 -0
  100. data/vendor/redis-rb/test/distributed_commands_requiring_clustering_test.rb +141 -0
  101. data/vendor/redis-rb/test/distributed_connection_handling_test.rb +25 -0
  102. data/vendor/redis-rb/test/distributed_internals_test.rb +18 -0
  103. data/vendor/redis-rb/test/distributed_persistence_control_commands_test.rb +24 -0
  104. data/vendor/redis-rb/test/distributed_publish_subscribe_test.rb +90 -0
  105. data/vendor/redis-rb/test/distributed_remote_server_control_commands_test.rb +31 -0
  106. data/vendor/redis-rb/test/distributed_sorting_test.rb +21 -0
  107. data/vendor/redis-rb/test/distributed_test.rb +60 -0
  108. data/vendor/redis-rb/test/distributed_transactions_test.rb +34 -0
  109. data/vendor/redis-rb/test/encoding_test.rb +16 -0
  110. data/vendor/redis-rb/test/helper.rb +86 -0
  111. data/vendor/redis-rb/test/internals_test.rb +27 -0
  112. data/vendor/redis-rb/test/lint/hashes.rb +90 -0
  113. data/vendor/redis-rb/test/lint/internals.rb +53 -0
  114. data/vendor/redis-rb/test/lint/lists.rb +93 -0
  115. data/vendor/redis-rb/test/lint/sets.rb +66 -0
  116. data/vendor/redis-rb/test/lint/sorted_sets.rb +132 -0
  117. data/vendor/redis-rb/test/lint/strings.rb +98 -0
  118. data/vendor/redis-rb/test/lint/value_types.rb +84 -0
  119. data/vendor/redis-rb/test/persistence_control_commands_test.rb +22 -0
  120. data/vendor/redis-rb/test/pipelining_commands_test.rb +78 -0
  121. data/vendor/redis-rb/test/publish_subscribe_test.rb +151 -0
  122. data/vendor/redis-rb/test/redis_mock.rb +64 -0
  123. data/vendor/redis-rb/test/remote_server_control_commands_test.rb +56 -0
  124. data/vendor/redis-rb/test/sorting_test.rb +44 -0
  125. data/vendor/redis-rb/test/test.conf +8 -0
  126. data/vendor/redis-rb/test/thread_safety_test.rb +34 -0
  127. data/vendor/redis-rb/test/transactions_test.rb +91 -0
  128. data/vendor/redis-rb/test/unknown_commands_test.rb +14 -0
  129. data/vendor/redis-rb/test/url_param_test.rb +52 -0
  130. metadata +277 -0
@@ -0,0 +1,161 @@
1
+ require 'modesty'
2
+
3
+ describe Modesty, "Working with identities" do
4
+ before :each do
5
+ @id = rand 10**10
6
+ end
7
+
8
+ it "can make an identity" do
9
+ Modesty.identify! @id
10
+ Modesty.identity.should == @id
11
+ end
12
+
13
+ it "can identify as nil" do
14
+ Modesty.identify! nil
15
+ Modesty.identity.should be_nil
16
+ end
17
+
18
+ it "can't identify as anything other than a Fixnum or nil." do
19
+ lambda do
20
+ Modesty.identify! "foo"
21
+ end.should raise_error(Modesty::IdentityError)
22
+ end
23
+
24
+ after :all do
25
+ Modesty.instance_variable_set("@identity", nil)
26
+ end
27
+ end
28
+
29
+ describe Modesty, "contextual identity" do
30
+ before :each do
31
+ Modesty.experiments.clear
32
+ Modesty.metrics.clear
33
+ Modesty.data.flushdb
34
+
35
+ Modesty.new_metric :donation_amount do |m|
36
+ m.submetric :birthday_wish
37
+ end
38
+ Modesty.new_metric :donation
39
+ Modesty.new_metric :creation
40
+
41
+ Modesty.new_experiment :creation_page do |e|
42
+ e.metric :creation
43
+ e.metric :donation, :as => :creator
44
+ e.metric :donation_amount, :as => :creator
45
+ end
46
+ @e = Modesty.experiments[:creation_page]
47
+ Modesty.identify! nil
48
+
49
+ @e.chooses :experiment, :for => 500
50
+ @e.chooses :control, :for => 600
51
+ @e.chooses :experiment, :for => 700
52
+ @group_exp = Modesty.metrics[:donation_amount/:creation_page/:experiment]
53
+ @group_ctrl = Modesty.metrics[:donation_amount/:creation_page/:control]
54
+ end
55
+
56
+ it "leaves the other metrics alone" do
57
+ Modesty.with_identity 700 do
58
+ @e.group.should == :experiment
59
+ Modesty.track! :creation
60
+ end
61
+
62
+ m = Modesty.metrics[:creation/:creation_page/:experiment]
63
+ m.distribution.should == {1 => 1}
64
+ end
65
+
66
+ it "expects a passed-in identity for the specified metrics" do
67
+ Modesty.identify! 700
68
+ lambda do
69
+ Modesty.track! :donation
70
+ end.should raise_error(Modesty::IdentityError)
71
+ end
72
+
73
+ it "aggregates counts by the contextual identity's experiment group" do
74
+ Modesty.with_identity 600 do
75
+ lambda do
76
+ #user 600 donated 10 bucks to user 700's birthday wish!
77
+ Modesty.track! :donation_amount, 10, :with => {:creator => 700}
78
+ end.should_not raise_error
79
+ end
80
+ @group_exp.distribution.should == {10 => 1}
81
+ @group_ctrl.distribution.should == {}
82
+
83
+ @e.chooses :experiment, :for => 500
84
+ #user 500 donated 2000 to 600's wish
85
+ Modesty.with_identity 500 do
86
+ Modesty.track! :donation_amount, 2000, :with => {:creator => 600}
87
+ end
88
+
89
+ @group_exp.distribution.should == {10 => 1}
90
+ @group_ctrl.distribution.should == {2000 => 1}
91
+ end
92
+
93
+ describe "with some data" do
94
+ before :each do
95
+ Modesty.data.flushdb
96
+
97
+ # users 500 and 700 hit the experiment
98
+ @e.chooses :experiment, :for => 700
99
+ @e.chooses :control, :for => 500
100
+
101
+ # user 600, who is in the control group, donates $45 to user 700's wish
102
+ Modesty.with_identity 600 do
103
+ Modesty.track! :donation_amount, 45, :with => {:creator => 700}
104
+ end
105
+
106
+ # user 500, who is in the experiment group, donates $30 to user 700's wish
107
+ Modesty.with_identity 500 do
108
+ Modesty.track! :donation_amount/:birthday_wish, 30, :with => {:creator => 700}
109
+ end
110
+
111
+ # a guest donates $15 to user 700's wish
112
+ Modesty.with_identity nil do
113
+ Modesty.track! :donation_amount, 15, :with => {:creator => 700}
114
+ end
115
+ end
116
+
117
+ it "knows its experiment" do
118
+ @group_exp.experiment.should == @e
119
+ end
120
+
121
+ it "aggregates work" do
122
+ @group_exp.aggregate_by(:creators).should == {700 => 90}
123
+ @group_ctrl.aggregate_by(:creators).should == {}
124
+ end
125
+
126
+ it "distributions work" do
127
+ @group_exp.distribution_by(:creator).should == {90 => 1}
128
+ @group_ctrl.distribution_by(:creator).should == {}
129
+ end
130
+
131
+ it "defaults to the given param as identity" do
132
+ @group_exp.aggregate.should == @group_exp.aggregate_by(:creator)
133
+ @group_exp.distribution.should == @group_exp.distribution_by(:creator)
134
+ end
135
+
136
+ it "all, unique, and unidentified_users work" do
137
+ @group_exp.all(:creators).should == [700]
138
+ @group_exp.all(:users).sort.should == [500, 600]
139
+ @group_exp.data.unidentified_users.should == 1
140
+ end
141
+
142
+ it "aggregates and distributes on the experiment" do
143
+ @e.aggregates(:donation_amount).should == {
144
+ :experiment => {
145
+ 700 => 90
146
+ },
147
+ :control => {
148
+ 500 => 0,
149
+ }
150
+ }
151
+ @e.distributions(:donation_amount).should == {
152
+ :experiment => {
153
+ 90 => 1,
154
+ },
155
+ :control => {
156
+ 0 => 1
157
+ }
158
+ }
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,87 @@
1
+ require 'modesty'
2
+
3
+ describe "the config file" do
4
+ before :all do
5
+ Modesty.root = File.join(
6
+ Modesty::TEST,
7
+ 'myapp',
8
+ 'modesty'
9
+ )
10
+ Modesty.environment = 'test'
11
+ Modesty.load_config!
12
+ end
13
+
14
+ it "can set the metrics directory" do
15
+ Modesty.metrics_dir.should ==
16
+ File.expand_path(
17
+ File.join(
18
+ File.dirname(__FILE__),
19
+ "../test/myapp/modesty/metrics"
20
+ )
21
+ )
22
+ end
23
+
24
+ after :all do
25
+ Modesty.root = nil
26
+ end
27
+ end
28
+
29
+ describe "loading metrics" do
30
+ before :all do
31
+ Modesty.root = File.join(
32
+ Modesty::TEST,
33
+ 'myapp'
34
+ )
35
+
36
+ Modesty.environment = 'test'
37
+ Modesty.metrics.clear
38
+ end
39
+
40
+ it "can load metrics" do
41
+ lambda do
42
+ Modesty.load_all_metrics!
43
+ end.should_not raise_error
44
+ end
45
+
46
+ it "doesn't try to load directories" do
47
+ lambda do
48
+ Modesty.load_all_metrics!
49
+ end.should_not raise_error(Errno::EISDIR)
50
+ end
51
+
52
+ it "actually loads the metrics" do
53
+ [
54
+ :baked_goods,
55
+ :baked_goods/:cookies,
56
+ :baked_goods/:brownies,
57
+ :baked_goods/:cake,
58
+ :baked_goods/:cake/:chocolate,
59
+ :baked_goods/:cake/:ice_cream,
60
+ ].each do |m|
61
+ Modesty.metrics.should include m
62
+ end
63
+ end
64
+
65
+ after :all do
66
+ Modesty.root = nil
67
+ end
68
+ end
69
+
70
+ describe "Loading experiments" do
71
+ before :all do
72
+ Modesty.environment = 'test'
73
+ Modesty.metrics.clear
74
+ Modesty.experiments.clear
75
+ Modesty.load_all_metrics!
76
+ end
77
+
78
+ it "can load experiments" do
79
+ lambda do
80
+ Modesty.load_all_experiments!
81
+ end.should_not raise_error
82
+ end
83
+
84
+ it "actually loads experiments" do
85
+ Modesty.experiments.should include :cookbook
86
+ end
87
+ end
@@ -0,0 +1,176 @@
1
+ require 'modesty'
2
+
3
+ describe Modesty::Metric, "Creating Metrics" do
4
+ before :each do
5
+ Modesty.set_store :redis, :mock => true
6
+ Modesty.metrics.clear
7
+ end
8
+
9
+ it "can create a metric without a block" do
10
+ m = Modesty.new_metric(:foo)
11
+ m.slug.should == :foo
12
+ Modesty.metrics[:foo].should == m
13
+ end
14
+
15
+ it "can create a metric with a block" do
16
+ m = Modesty.new_metric :foo do |m|
17
+ m.description "Foo"
18
+ end
19
+ m.slug.should == :foo
20
+ m.description.should == "Foo"
21
+ Modesty.metrics[:foo].should == m
22
+ end
23
+
24
+ it "can create submetrics" do
25
+ Modesty.new_metric :foo do |foo|
26
+ foo.description "Foo"
27
+
28
+ foo.submetric :bar do |bar|
29
+ bar.description "Bar"
30
+
31
+ bar.submetric :baz do |baz|
32
+ baz.description "Baz"
33
+ end
34
+ end
35
+ end
36
+
37
+ Modesty.metrics.should include :foo
38
+ Modesty.metrics.should include :foo/:bar
39
+ Modesty.metrics.should include :foo/:bar/:baz
40
+
41
+ Modesty.metrics[:foo].parent.should == nil
42
+ Modesty.metrics[:foo/:bar].parent.should_not == nil
43
+ Modesty.metrics[:foo/:bar].parent.slug.should == :foo
44
+ Modesty.metrics[:foo/:bar/:baz].parent.should_not == nil
45
+ Modesty.metrics[:foo/:bar/:baz].parent.slug.should == :foo/:bar
46
+ end
47
+ end
48
+
49
+ describe Modesty::Metric, "Tracking Metrics" do
50
+ before :each do
51
+ Modesty.set_store :redis, :mock => true
52
+ Modesty.data.flushdb
53
+ Modesty.metrics.clear
54
+ Modesty.new_metric :foo do |foo|
55
+ foo.description "Foo"
56
+
57
+ foo.submetric :bar do |bar|
58
+ bar.description "Bar"
59
+
60
+ bar.submetric :baz do |baz|
61
+ baz.description "Baz"
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ it "can track a metric" do
68
+ (1..100).each do |i|
69
+ lambda { Modesty.track! :foo }.should_not raise_error
70
+ Modesty.metrics[:foo].count.to_i.should == i
71
+ end
72
+ end
73
+
74
+ it "can track a metric with a count" do
75
+ (1..100).each do |i|
76
+ lambda { Modesty.track! :foo, 3 }.should_not raise_error
77
+ Modesty.metrics[:foo].count.to_i.should == i*3
78
+ end
79
+ end
80
+
81
+ it "can fetch a metric for a date" do
82
+ now = Time.now
83
+ Time.stub!(:now).and_return(now-1.day)
84
+ 25.times {|i| Modesty.track! :foo}
85
+ Modesty.metrics[:foo].count((now-1.day).to_date).should == 25
86
+ end
87
+
88
+ it "can fetch a metric over a date range" do
89
+ now = Time.now
90
+ Time.stub!(:now).and_return(now-1.day)
91
+ 25.times {|i| Modesty.track! :foo}
92
+ Time.stub!(:now).and_return(now)
93
+ 50.times {|i| Modesty.track! :foo}
94
+ Modesty.metrics[:foo].count((now-1.day).to_date..(now.to_date)).should == [25, 50]
95
+ end
96
+
97
+ it "can fetch a metric over a date range as array" do
98
+ now = Time.now
99
+ Time.stub!(:now).and_return(now-1.day)
100
+ 25.times {|i| Modesty.track! :foo}
101
+ Time.stub!(:now).and_return(now)
102
+ 50.times {|i| Modesty.track! :foo}
103
+ Modesty.metrics[:foo].count((now-1.day).to_date, now.to_date).should == [25, 50]
104
+ end
105
+
106
+ it "can track one submetric" do
107
+ (1..100).each do |i|
108
+ lambda { Modesty.track! :foo/:bar }.should_not raise_error
109
+ Modesty.metrics[:foo].count.to_i.should == i
110
+ Modesty.metrics[:foo/:bar].count.to_i.should == i
111
+ Modesty.metrics[:foo/:bar/:baz].count.to_i.should == 0
112
+ end
113
+ end
114
+
115
+ it "can track more than one submetric" do
116
+ (1..100).each do |i|
117
+ lambda { Modesty.track! :foo/:bar/:baz }.should_not raise_error
118
+ Modesty.metrics[:foo].count.to_i.should == i
119
+ Modesty.metrics[:foo/:bar].count.to_i.should == i
120
+ Modesty.metrics[:foo/:bar/:baz].count.to_i.should == i
121
+ end
122
+ end
123
+
124
+ describe "can track with custom data" do
125
+ before :each do
126
+ @m = Modesty.metrics[:foo/:bar]
127
+ lambda do
128
+ Modesty.track! :foo/:bar, :with => {:zing => 56, :user => 1}
129
+ end.should_not raise_error
130
+ @m.unique(:zings).should == 1
131
+ @m.all(:zings).should include 56
132
+
133
+ lambda do
134
+ Modesty.track! :foo/:bar, :with => {:zing => 97, :user => 2}, :count => 4
135
+ end.should_not raise_error
136
+ @m.unique(:zings).should == 2
137
+ @m.all(:zings).should include 97
138
+
139
+ lambda do
140
+ Modesty.track! :foo/:bar, 7, :with => {:zing => 97}
141
+ end.should_not raise_error
142
+ end
143
+
144
+ it "and count unique" do
145
+ @m.unique(:zings).should == 2
146
+ @m.unique(:zings, :all).should == 2
147
+ end
148
+
149
+ it "and bucket by dates" do
150
+ @m.unique(:zings, Date.parse('1/1/2002')).should == 0
151
+ end
152
+
153
+ it "and count all" do
154
+ @m.all(:zings).count.should == 2
155
+ end
156
+
157
+
158
+ it "and keep an aggregate by users" do
159
+ @m.aggregate.should == {1 => 1, 2 => 4}
160
+ end
161
+
162
+ it "and keep a distribution by users" do
163
+ @m.distribution.should == {1 => 1, 4 => 1}
164
+ @m.distribution(:all).should == {1 => 1, 4 => 1}
165
+ end
166
+
167
+ it "and keep an aggregate by custom data" do
168
+ @m.aggregate_by(:zings).should == {56 => 1, 97 => 11}
169
+ end
170
+
171
+ it "and keep a distribution by custom data" do
172
+ @m.distribution_by(:zings).should == {1 => 1, 11 => 1}
173
+ end
174
+
175
+ end
176
+ end
@@ -0,0 +1,48 @@
1
+ require 'modesty'
2
+
3
+ describe "bootstrap" do
4
+ before :all do
5
+ Modesty.data.flushdb
6
+ Modesty.metrics.clear
7
+ Modesty.experiments.clear
8
+
9
+ unless defined? Rails
10
+ class Rails
11
+ def self.root
12
+ File.join(
13
+ File.expand_path(File.dirname(__FILE__)),
14
+ '../test/myapp'
15
+ )
16
+ end
17
+
18
+ def self.configuration
19
+ self
20
+ end
21
+
22
+ def self.env
23
+ 'test'
24
+ end
25
+
26
+ def self.after_initialize
27
+ yield
28
+ end
29
+ end
30
+ end
31
+
32
+ require 'modesty/frameworks/rails'
33
+ end
34
+
35
+ it "bootstraps Redis" do
36
+ Modesty.data.store.should be_an_instance_of Redis
37
+ Modesty.data.store.client.port.should == 6379
38
+ Modesty.data.store.client.host.should == 'localhost'
39
+ end
40
+
41
+ it "loads metrics" do
42
+ Modesty.metrics.keys.should include :baked_goods
43
+ end
44
+
45
+ it "loads experiments" do
46
+ Modesty.experiments.keys.should include :cookbook
47
+ end
48
+ end