modesty 0.1.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/Gemfile +13 -0
- data/Gemfile.lock +18 -0
- data/LICENSE +21 -0
- data/README.md +121 -0
- data/Rakefile +29 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/modesty.rb +26 -0
- data/lib/modesty/api.rb +14 -0
- data/lib/modesty/core_ext.rb +5 -0
- data/lib/modesty/core_ext/array.rb +21 -0
- data/lib/modesty/core_ext/fixnum.rb +5 -0
- data/lib/modesty/core_ext/hash.rb +39 -0
- data/lib/modesty/core_ext/string.rb +9 -0
- data/lib/modesty/core_ext/symbol.rb +33 -0
- data/lib/modesty/datastore.rb +51 -0
- data/lib/modesty/datastore/redis.rb +180 -0
- data/lib/modesty/experiment.rb +87 -0
- data/lib/modesty/experiment/base.rb +47 -0
- data/lib/modesty/experiment/builder.rb +48 -0
- data/lib/modesty/experiment/console.rb +4 -0
- data/lib/modesty/experiment/data.rb +75 -0
- data/lib/modesty/experiment/interface.rb +29 -0
- data/lib/modesty/experiment/significance.rb +376 -0
- data/lib/modesty/experiment/stats.rb +163 -0
- data/lib/modesty/frameworks/rails.rb +27 -0
- data/lib/modesty/identity.rb +32 -0
- data/lib/modesty/load.rb +80 -0
- data/lib/modesty/load/load_experiments.rb +14 -0
- data/lib/modesty/load/load_metrics.rb +17 -0
- data/lib/modesty/metric.rb +56 -0
- data/lib/modesty/metric/base.rb +38 -0
- data/lib/modesty/metric/builder.rb +23 -0
- data/lib/modesty/metric/data.rb +133 -0
- data/modesty.gemspec +192 -0
- data/spec/core_ext_spec.rb +17 -0
- data/spec/experiment_spec.rb +239 -0
- data/spec/identity_spec.rb +161 -0
- data/spec/load_spec.rb +87 -0
- data/spec/metric_spec.rb +176 -0
- data/spec/rails_spec.rb +48 -0
- data/spec/redis_spec.rb +29 -0
- data/spec/significance_spec.rb +147 -0
- data/spec/spec.opts +1 -0
- data/test/myapp/config/modesty.yml +9 -0
- data/test/myapp/modesty/experiments/cookbook.rb +4 -0
- data/test/myapp/modesty/metrics/kitchen_metrics.rb +9 -0
- data/test/myapp/modesty/metrics/stove/burner_metrics.rb +2 -0
- data/vendor/.piston.yml +8 -0
- data/vendor/mock_redis/.gitignore +2 -0
- data/vendor/mock_redis/README +8 -0
- data/vendor/mock_redis/lib/mock_redis.rb +10 -0
- data/vendor/mock_redis/lib/mock_redis/hash.rb +61 -0
- data/vendor/mock_redis/lib/mock_redis/list.rb +6 -0
- data/vendor/mock_redis/lib/mock_redis/misc.rb +69 -0
- data/vendor/mock_redis/lib/mock_redis/set.rb +108 -0
- data/vendor/mock_redis/lib/mock_redis/string.rb +32 -0
- data/vendor/redis-rb/.gitignore +8 -0
- data/vendor/redis-rb/LICENSE +20 -0
- data/vendor/redis-rb/README.markdown +129 -0
- data/vendor/redis-rb/Rakefile +155 -0
- data/vendor/redis-rb/benchmarking/logging.rb +62 -0
- data/vendor/redis-rb/benchmarking/pipeline.rb +51 -0
- data/vendor/redis-rb/benchmarking/speed.rb +21 -0
- data/vendor/redis-rb/benchmarking/suite.rb +24 -0
- data/vendor/redis-rb/benchmarking/thread_safety.rb +38 -0
- data/vendor/redis-rb/benchmarking/worker.rb +71 -0
- data/vendor/redis-rb/examples/basic.rb +15 -0
- data/vendor/redis-rb/examples/dist_redis.rb +43 -0
- data/vendor/redis-rb/examples/incr-decr.rb +17 -0
- data/vendor/redis-rb/examples/list.rb +26 -0
- data/vendor/redis-rb/examples/pubsub.rb +31 -0
- data/vendor/redis-rb/examples/sets.rb +36 -0
- data/vendor/redis-rb/examples/unicorn/config.ru +3 -0
- data/vendor/redis-rb/examples/unicorn/unicorn.rb +20 -0
- data/vendor/redis-rb/lib/redis.rb +676 -0
- data/vendor/redis-rb/lib/redis/client.rb +201 -0
- data/vendor/redis-rb/lib/redis/compat.rb +21 -0
- data/vendor/redis-rb/lib/redis/connection.rb +134 -0
- data/vendor/redis-rb/lib/redis/distributed.rb +526 -0
- data/vendor/redis-rb/lib/redis/hash_ring.rb +131 -0
- data/vendor/redis-rb/lib/redis/pipeline.rb +13 -0
- data/vendor/redis-rb/lib/redis/subscribe.rb +79 -0
- data/vendor/redis-rb/redis.gemspec +29 -0
- data/vendor/redis-rb/test/commands_on_hashes_test.rb +46 -0
- data/vendor/redis-rb/test/commands_on_lists_test.rb +50 -0
- data/vendor/redis-rb/test/commands_on_sets_test.rb +78 -0
- data/vendor/redis-rb/test/commands_on_sorted_sets_test.rb +109 -0
- data/vendor/redis-rb/test/commands_on_strings_test.rb +70 -0
- data/vendor/redis-rb/test/commands_on_value_types_test.rb +88 -0
- data/vendor/redis-rb/test/connection_handling_test.rb +87 -0
- data/vendor/redis-rb/test/db/.gitignore +1 -0
- data/vendor/redis-rb/test/distributd_key_tags_test.rb +53 -0
- data/vendor/redis-rb/test/distributed_blocking_commands_test.rb +54 -0
- data/vendor/redis-rb/test/distributed_commands_on_hashes_test.rb +12 -0
- data/vendor/redis-rb/test/distributed_commands_on_lists_test.rb +18 -0
- data/vendor/redis-rb/test/distributed_commands_on_sets_test.rb +85 -0
- data/vendor/redis-rb/test/distributed_commands_on_strings_test.rb +50 -0
- data/vendor/redis-rb/test/distributed_commands_on_value_types_test.rb +73 -0
- data/vendor/redis-rb/test/distributed_commands_requiring_clustering_test.rb +141 -0
- data/vendor/redis-rb/test/distributed_connection_handling_test.rb +25 -0
- data/vendor/redis-rb/test/distributed_internals_test.rb +18 -0
- data/vendor/redis-rb/test/distributed_persistence_control_commands_test.rb +24 -0
- data/vendor/redis-rb/test/distributed_publish_subscribe_test.rb +90 -0
- data/vendor/redis-rb/test/distributed_remote_server_control_commands_test.rb +31 -0
- data/vendor/redis-rb/test/distributed_sorting_test.rb +21 -0
- data/vendor/redis-rb/test/distributed_test.rb +60 -0
- data/vendor/redis-rb/test/distributed_transactions_test.rb +34 -0
- data/vendor/redis-rb/test/encoding_test.rb +16 -0
- data/vendor/redis-rb/test/helper.rb +86 -0
- data/vendor/redis-rb/test/internals_test.rb +27 -0
- data/vendor/redis-rb/test/lint/hashes.rb +90 -0
- data/vendor/redis-rb/test/lint/internals.rb +53 -0
- data/vendor/redis-rb/test/lint/lists.rb +93 -0
- data/vendor/redis-rb/test/lint/sets.rb +66 -0
- data/vendor/redis-rb/test/lint/sorted_sets.rb +132 -0
- data/vendor/redis-rb/test/lint/strings.rb +98 -0
- data/vendor/redis-rb/test/lint/value_types.rb +84 -0
- data/vendor/redis-rb/test/persistence_control_commands_test.rb +22 -0
- data/vendor/redis-rb/test/pipelining_commands_test.rb +78 -0
- data/vendor/redis-rb/test/publish_subscribe_test.rb +151 -0
- data/vendor/redis-rb/test/redis_mock.rb +64 -0
- data/vendor/redis-rb/test/remote_server_control_commands_test.rb +56 -0
- data/vendor/redis-rb/test/sorting_test.rb +44 -0
- data/vendor/redis-rb/test/test.conf +8 -0
- data/vendor/redis-rb/test/thread_safety_test.rb +34 -0
- data/vendor/redis-rb/test/transactions_test.rb +91 -0
- data/vendor/redis-rb/test/unknown_commands_test.rb +14 -0
- data/vendor/redis-rb/test/url_param_test.rb +52 -0
- 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
|
data/spec/load_spec.rb
ADDED
|
@@ -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
|
data/spec/metric_spec.rb
ADDED
|
@@ -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
|
data/spec/rails_spec.rb
ADDED
|
@@ -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
|