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.
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,151 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+
5
+ setup do
6
+ init Redis.new(OPTIONS)
7
+ end
8
+
9
+ test "SUBSCRIBE and UNSUBSCRIBE" do |r|
10
+ thread = Thread.new do
11
+ r.subscribe("foo") do |on|
12
+ on.subscribe do |channel, total|
13
+ @subscribed = true
14
+ @t1 = total
15
+ end
16
+
17
+ on.message do |channel, message|
18
+ if message == "s1"
19
+ r.unsubscribe
20
+ @message = message
21
+ end
22
+ end
23
+
24
+ on.unsubscribe do |channel, total|
25
+ @unsubscribed = true
26
+ @t2 = total
27
+ end
28
+ end
29
+ end
30
+
31
+ Redis.new(OPTIONS).publish("foo", "s1")
32
+
33
+ thread.join
34
+
35
+ assert @subscribed
36
+ assert 1 == @t1
37
+ assert @unsubscribed
38
+ assert 0 == @t2
39
+ assert "s1" == @message
40
+ end
41
+
42
+ test "PSUBSCRIBE and PUNSUBSCRIBE" do |r|
43
+ listening = false
44
+
45
+ thread = Thread.new do
46
+ r.psubscribe("f*") do |on|
47
+ on.psubscribe do |pattern, total|
48
+ @subscribed = true
49
+ @t1 = total
50
+ end
51
+
52
+ on.pmessage do |pattern, channel, message|
53
+ if message == "s1"
54
+ r.punsubscribe
55
+ @message = message
56
+ end
57
+ end
58
+
59
+ on.punsubscribe do |pattern, total|
60
+ @unsubscribed = true
61
+ @t2 = total
62
+ end
63
+
64
+ listening = true
65
+ end
66
+ end
67
+
68
+ while !listening; end
69
+
70
+ Redis.new(OPTIONS).publish("foo", "s1")
71
+
72
+ thread.join
73
+
74
+ assert @subscribed
75
+ assert 1 == @t1
76
+ assert @unsubscribed
77
+ assert 0 == @t2
78
+ assert "s1" == @message
79
+ end
80
+
81
+ test "SUBSCRIBE within SUBSCRIBE" do |r|
82
+ listening = false
83
+
84
+ @channels = []
85
+
86
+ thread = Thread.new do
87
+ r.subscribe("foo") do |on|
88
+ on.subscribe do |channel, total|
89
+ @channels << channel
90
+
91
+ r.subscribe("bar") if channel == "foo"
92
+ r.unsubscribe if channel == "bar"
93
+ end
94
+
95
+ listening = true
96
+ end
97
+ end
98
+
99
+ while !listening; end
100
+
101
+ Redis.new(OPTIONS).publish("foo", "s1")
102
+
103
+ thread.join
104
+
105
+ assert ["foo", "bar"] == @channels
106
+ end
107
+
108
+ test "other commands within a SUBSCRIBE" do |r|
109
+ assert_raise RuntimeError do
110
+ r.subscribe("foo") do |on|
111
+ on.subscribe do |channel, total|
112
+ r.set("bar", "s2")
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ test "SUBSCRIBE without a block" do |r|
119
+ assert_raise LocalJumpError do
120
+ r.subscribe("foo")
121
+ end
122
+ end
123
+
124
+ test "UNSUBSCRIBE without a SUBSCRIBE" do |r|
125
+ assert_raise RuntimeError do
126
+ r.unsubscribe
127
+ end
128
+
129
+ assert_raise RuntimeError do
130
+ r.punsubscribe
131
+ end
132
+ end
133
+
134
+ test "SUBSCRIBE past a timeout" do |r|
135
+ # For some reason, a thread here doesn't reproduce the issue.
136
+ fork do
137
+ sleep OPTIONS[:timeout] + 1
138
+ Redis.new(OPTIONS).publish "foo", "bar"
139
+ end
140
+
141
+ received = false
142
+
143
+ r.subscribe "foo" do |on|
144
+ on.message do |channel, message|
145
+ received = true
146
+ r.unsubscribe
147
+ end
148
+ end
149
+
150
+ assert received
151
+ end
@@ -0,0 +1,64 @@
1
+ require "socket"
2
+
3
+ module RedisMock
4
+ def self.start(port = 6380)
5
+ server = TCPServer.new("127.0.0.1", port)
6
+
7
+ loop do
8
+ session = server.accept
9
+
10
+ while line = session.gets
11
+ parts = Array.new(line[1..-3].to_i) do
12
+ bytes = session.gets[1..-3].to_i
13
+ argument = session.read(bytes)
14
+ session.read(2) # Discard \r\n
15
+ argument
16
+ end
17
+
18
+ response = yield(*parts)
19
+
20
+ if response.nil?
21
+ session.shutdown(Socket::SHUT_RDWR)
22
+ break
23
+ else
24
+ session.write(response)
25
+ session.write("\r\n")
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ module Helper
32
+ # Forks the current process and starts a new mock Redis server on
33
+ # port 6380.
34
+ #
35
+ # The server will reply with a `+OK` to all commands, but you can
36
+ # customize it by providing a hash. For example:
37
+ #
38
+ # redis_mock(:ping => lambda { "+PONG" }) do
39
+ # assert_equal "PONG", Redis.new(:port => 6380).ping
40
+ # end
41
+ #
42
+ def redis_mock(replies = {})
43
+ begin
44
+ pid = fork do
45
+ trap("TERM") { exit }
46
+
47
+ RedisMock.start do |command, *args|
48
+ (replies[command.to_sym] || lambda { |*_| "+OK" }).call(*args)
49
+ end
50
+ end
51
+
52
+ sleep 1 # Give time for the socket to start listening.
53
+
54
+ yield
55
+
56
+ ensure
57
+ if pid
58
+ Process.kill("TERM", pid)
59
+ Process.wait(pid)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+ require File.expand_path("./redis_mock", File.dirname(__FILE__))
5
+
6
+ include RedisMock::Helper
7
+
8
+ setup do
9
+ init Redis.new(OPTIONS)
10
+ end
11
+
12
+ test "INFO" do |r|
13
+ %w(last_save_time redis_version total_connections_received connected_clients total_commands_processed connected_slaves uptime_in_seconds used_memory uptime_in_days changes_since_last_save).each do |x|
14
+ assert r.info.keys.include?(x)
15
+ end
16
+ end
17
+
18
+ test "MONITOR" do |r|
19
+ log = []
20
+
21
+ t1 = Thread.new do
22
+ Redis.new(OPTIONS).monitor do |line|
23
+ log << line
24
+ break if log.size == 3
25
+ end
26
+ end
27
+
28
+ while log.empty?; end # Faster than sleep
29
+
30
+ r.set "foo", "s1"
31
+
32
+ t1.join
33
+
34
+ assert log[-1][%q{(db 15) "set" "foo" "s1"}]
35
+ end
36
+
37
+ test "ECHO" do |r|
38
+ assert "foo bar baz\n" == r.echo("foo bar baz\n")
39
+ end
40
+
41
+ test "DEBUG" do |r|
42
+ r.set "foo", "s1"
43
+
44
+ assert r.debug(:object, "foo").kind_of?(String)
45
+ end
46
+
47
+ test "SYNC" do |r|
48
+ replies = {:sync => lambda { "+OK" }}
49
+
50
+ redis_mock(replies) do
51
+ redis = Redis.new(OPTIONS.merge(:port => 6380))
52
+
53
+ assert "OK" == redis.sync
54
+ end
55
+ end
56
+
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+
5
+ setup do
6
+ init Redis.new(OPTIONS)
7
+ end
8
+
9
+ test "SORT" do |r|
10
+ r.set("foo:1", "s1")
11
+ r.set("foo:2", "s2")
12
+
13
+ r.rpush("bar", "1")
14
+ r.rpush("bar", "2")
15
+
16
+ assert ["s1"] == r.sort("bar", :get => "foo:*", :limit => [0, 1])
17
+ assert ["s2"] == r.sort("bar", :get => "foo:*", :limit => [0, 1], :order => "desc alpha")
18
+ end
19
+
20
+ test "SORT with an array of GETs" do |r|
21
+ r.set("foo:1:a", "s1a")
22
+ r.set("foo:1:b", "s1b")
23
+
24
+ r.set("foo:2:a", "s2a")
25
+ r.set("foo:2:b", "s2b")
26
+
27
+ r.rpush("bar", "1")
28
+ r.rpush("bar", "2")
29
+
30
+ assert ["s1a", "s1b"] == r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1])
31
+ assert ["s2a", "s2b"] == r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1], :order => "desc alpha")
32
+ end
33
+
34
+ test "SORT with STORE" do |r|
35
+ r.set("foo:1", "s1")
36
+ r.set("foo:2", "s2")
37
+
38
+ r.rpush("bar", "1")
39
+ r.rpush("bar", "2")
40
+
41
+ r.sort("bar", :get => "foo:*", :store => "baz")
42
+ assert ["s1", "s2"] == r.lrange("baz", 0, -1)
43
+ end
44
+
@@ -0,0 +1,8 @@
1
+ dir ./test/db
2
+ pidfile ./redis.pid
3
+ port 6379
4
+ timeout 300
5
+ loglevel debug
6
+ logfile stdout
7
+ databases 16
8
+ daemonize yes
@@ -0,0 +1,34 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+
5
+ setup do
6
+ init Redis.new(OPTIONS)
7
+ end
8
+
9
+ test "thread safety" do |r|
10
+ r = init Redis.new(OPTIONS.merge(:thread_safe => true))
11
+ r.client.disconnect
12
+
13
+ r1, r2 = nil
14
+
15
+ t1 = Thread.new do
16
+ r1 = r.client.process([:set, "foo", 1]) do
17
+ sleep 1
18
+ r.client.send(:read)
19
+ end
20
+ end
21
+
22
+ t2 = Thread.new do
23
+ r2 = r.client.process([:get, "foo"]) do
24
+ r.client.send(:read)
25
+ end
26
+ end
27
+
28
+ t1.join
29
+ t2.join
30
+
31
+ assert "OK" == r1
32
+ assert "1" == r2
33
+ end
34
+
@@ -0,0 +1,91 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("./helper", File.dirname(__FILE__))
4
+
5
+ setup do
6
+ init Redis.new(OPTIONS)
7
+ end
8
+
9
+ test "MULTI/DISCARD" do |r|
10
+ r.multi
11
+
12
+ assert "QUEUED" == r.set("foo", "1")
13
+ assert "QUEUED" == r.get("foo")
14
+
15
+ r.discard
16
+
17
+ assert nil == r.get("foo")
18
+ end
19
+
20
+ test "MULTI/EXEC with a block" do |r|
21
+ r.multi do |r|
22
+ r.set "foo", "s1"
23
+ end
24
+
25
+ assert "s1" == r.get("foo")
26
+
27
+ begin
28
+ r.multi do
29
+ r.set "bar", "s2"
30
+ raise "Some error"
31
+ r.set "baz", "s3"
32
+ end
33
+ rescue
34
+ end
35
+
36
+ assert nil == r.get("bar")
37
+ assert nil == r.get("baz")
38
+ end
39
+
40
+ test "MULTI/EXEC with a block operating on a wrong kind of key" do |r|
41
+ begin
42
+ r.multi do |r|
43
+ r.set "foo", "s1"
44
+ r.lpush "foo", "s2"
45
+ r.get "foo"
46
+ end
47
+ rescue RuntimeError
48
+ end
49
+
50
+ assert "s1" == r.get("foo")
51
+ end
52
+
53
+ test "MULTI with a block yielding the client" do |r|
54
+ r.multi do |multi|
55
+ multi.set "foo", "s1"
56
+ end
57
+
58
+ assert "s1" == r.get("foo")
59
+ end
60
+
61
+ test "WATCH with an unmodified key" do |r|
62
+ r.watch "foo"
63
+ r.multi do |multi|
64
+ multi.set "foo", "s1"
65
+ end
66
+
67
+ assert "s1" == r.get("foo")
68
+ end
69
+
70
+ test "WATCH with a modified key" do |r|
71
+ r.watch "foo"
72
+ r.set "foo", "s1"
73
+ res = r.multi do |multi|
74
+ multi.set "foo", "s2"
75
+ end
76
+
77
+ assert nil == res
78
+ assert "s1" == r.get("foo")
79
+ end
80
+
81
+ test "UNWATCH with a modified key" do |r|
82
+ r.watch "foo"
83
+ r.set "foo", "s1"
84
+ r.unwatch
85
+ r.multi do |multi|
86
+ multi.set "foo", "s2"
87
+ end
88
+
89
+ assert "s2" == r.get("foo")
90
+ end
91
+