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,131 @@
1
+ require 'zlib'
2
+
3
+ class Redis
4
+ class HashRing
5
+
6
+ POINTS_PER_SERVER = 160 # this is the default in libmemcached
7
+
8
+ attr_reader :ring, :sorted_keys, :replicas, :nodes
9
+
10
+ # nodes is a list of objects that have a proper to_s representation.
11
+ # replicas indicates how many virtual points should be used pr. node,
12
+ # replicas are required to improve the distribution.
13
+ def initialize(nodes=[], replicas=POINTS_PER_SERVER)
14
+ @replicas = replicas
15
+ @ring = {}
16
+ @nodes = []
17
+ @sorted_keys = []
18
+ nodes.each do |node|
19
+ add_node(node)
20
+ end
21
+ end
22
+
23
+ # Adds a `node` to the hash ring (including a number of replicas).
24
+ def add_node(node)
25
+ @nodes << node
26
+ @replicas.times do |i|
27
+ key = Zlib.crc32("#{node.id}:#{i}")
28
+ @ring[key] = node
29
+ @sorted_keys << key
30
+ end
31
+ @sorted_keys.sort!
32
+ end
33
+
34
+ def remove_node(node)
35
+ @nodes.reject!{|n| n.id == node.id}
36
+ @replicas.times do |i|
37
+ key = Zlib.crc32("#{node.id}:#{i}")
38
+ @ring.delete(key)
39
+ @sorted_keys.reject! {|k| k == key}
40
+ end
41
+ end
42
+
43
+ # get the node in the hash ring for this key
44
+ def get_node(key)
45
+ get_node_pos(key)[0]
46
+ end
47
+
48
+ def get_node_pos(key)
49
+ return [nil,nil] if @ring.size == 0
50
+ crc = Zlib.crc32(key)
51
+ idx = HashRing.binary_search(@sorted_keys, crc)
52
+ return [@ring[@sorted_keys[idx]], idx]
53
+ end
54
+
55
+ def iter_nodes(key)
56
+ return [nil,nil] if @ring.size == 0
57
+ node, pos = get_node_pos(key)
58
+ @sorted_keys[pos..-1].each do |k|
59
+ yield @ring[k]
60
+ end
61
+ end
62
+
63
+ class << self
64
+
65
+ # gem install RubyInline to use this code
66
+ # Native extension to perform the binary search within the hashring.
67
+ # There's a pure ruby version below so this is purely optional
68
+ # for performance. In testing 20k gets and sets, the native
69
+ # binary search shaved about 12% off the runtime (9sec -> 8sec).
70
+ begin
71
+ require 'inline'
72
+ inline do |builder|
73
+ builder.c <<-EOM
74
+ int binary_search(VALUE ary, unsigned int r) {
75
+ int upper = RARRAY_LEN(ary) - 1;
76
+ int lower = 0;
77
+ int idx = 0;
78
+
79
+ while (lower <= upper) {
80
+ idx = (lower + upper) / 2;
81
+
82
+ VALUE continuumValue = RARRAY_PTR(ary)[idx];
83
+ unsigned int l = NUM2UINT(continuumValue);
84
+ if (l == r) {
85
+ return idx;
86
+ }
87
+ else if (l > r) {
88
+ upper = idx - 1;
89
+ }
90
+ else {
91
+ lower = idx + 1;
92
+ }
93
+ }
94
+ if (upper < 0) {
95
+ upper = RARRAY_LEN(ary) - 1;
96
+ }
97
+ return upper;
98
+ }
99
+ EOM
100
+ end
101
+ rescue Exception => e
102
+ # Find the closest index in HashRing with value <= the given value
103
+ def binary_search(ary, value, &block)
104
+ upper = ary.size - 1
105
+ lower = 0
106
+ idx = 0
107
+
108
+ while(lower <= upper) do
109
+ idx = (lower + upper) / 2
110
+ comp = ary[idx] <=> value
111
+
112
+ if comp == 0
113
+ return idx
114
+ elsif comp > 0
115
+ upper = idx - 1
116
+ else
117
+ lower = idx + 1
118
+ end
119
+ end
120
+
121
+ if upper < 0
122
+ upper = ary.size - 1
123
+ end
124
+ return upper
125
+ end
126
+
127
+ end
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,13 @@
1
+ class Redis
2
+ class Pipeline
3
+ attr :commands
4
+
5
+ def initialize
6
+ @commands = []
7
+ end
8
+
9
+ def call(*args)
10
+ @commands << args
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,79 @@
1
+ class Redis
2
+ class SubscribedClient
3
+ def initialize(client)
4
+ @client = client
5
+ end
6
+
7
+ def call(*args)
8
+ @client.process(args)
9
+ end
10
+
11
+ def subscribe(*channels, &block)
12
+ subscription("subscribe", "unsubscribe", channels, block)
13
+ end
14
+
15
+ def psubscribe(*channels, &block)
16
+ subscription("psubscribe", "punsubscribe", channels, block)
17
+ end
18
+
19
+ def unsubscribe(*channels)
20
+ call(:unsubscribe, *channels)
21
+ end
22
+
23
+ def punsubscribe(*channels)
24
+ call(:punsubscribe, *channels)
25
+ end
26
+
27
+ protected
28
+
29
+ def subscription(start, stop, channels, block)
30
+ sub = Subscription.new(&block)
31
+
32
+ begin
33
+ @client.call_loop(start, *channels) do |line|
34
+ type, *rest = line
35
+ sub.callbacks[type].call(*rest)
36
+ break if type == stop && rest.last == 0
37
+ end
38
+ ensure
39
+ send(stop)
40
+ end
41
+ end
42
+ end
43
+
44
+ class Subscription
45
+ attr :callbacks
46
+
47
+ def initialize
48
+ @callbacks = Hash.new do |hash, key|
49
+ hash[key] = lambda { |*_| }
50
+ end
51
+
52
+ yield(self)
53
+ end
54
+
55
+ def subscribe(&block)
56
+ @callbacks["subscribe"] = block
57
+ end
58
+
59
+ def unsubscribe(&block)
60
+ @callbacks["unsubscribe"] = block
61
+ end
62
+
63
+ def message(&block)
64
+ @callbacks["message"] = block
65
+ end
66
+
67
+ def psubscribe(&block)
68
+ @callbacks["psubscribe"] = block
69
+ end
70
+
71
+ def punsubscribe(&block)
72
+ @callbacks["punsubscribe"] = block
73
+ end
74
+
75
+ def pmessage(&block)
76
+ @callbacks["pmessage"] = block
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{redis}
5
+ s.version = "2.1.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ezra Zygmuntowicz", "Taylor Weibley", "Matthew Clark", "Brian McKinney", "Salvatore Sanfilippo", "Luca Guidi", "Michel Martens", "Damian Janowski"]
9
+ s.autorequire = %q{redis}
10
+ s.date = %q{2010-11-05}
11
+ s.description = %q{Ruby client library for Redis, the key value storage server}
12
+ s.email = %q{ez@engineyard.com}
13
+ s.extra_rdoc_files = ["LICENSE"]
14
+ s.files = ["LICENSE", "README.markdown", "Rakefile", "lib/redis", "lib/redis/client.rb", "lib/redis/compat.rb", "lib/redis/connection.rb", "lib/redis/distributed.rb", "lib/redis/hash_ring.rb", "lib/redis/pipeline.rb", "lib/redis/subscribe.rb", "lib/redis.rb"]
15
+ s.homepage = %q{http://github.com/ezmobius/redis-rb}
16
+ s.require_paths = ["lib"]
17
+ s.rubygems_version = %q{1.3.7}
18
+ s.summary = %q{Ruby client library for Redis, the key value storage server}
19
+
20
+ if s.respond_to? :specification_version then
21
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
22
+ s.specification_version = 3
23
+
24
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ else
26
+ end
27
+ else
28
+ end
29
+ end
@@ -0,0 +1,46 @@
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
+ load './test/lint/hashes.rb'
10
+
11
+ test "HSETNX" do |r|
12
+ r.hset("foo", "f1", "s1")
13
+ r.hsetnx("foo", "f1", "s2")
14
+
15
+ assert "s1" == r.hget("foo", "f1")
16
+
17
+ r.del("foo")
18
+ r.hsetnx("foo", "f1", "s2")
19
+
20
+ assert "s2" == r.hget("foo", "f1")
21
+ end
22
+
23
+ test "HMGET" do |r|
24
+ r.hset("foo", "f1", "s1")
25
+ r.hset("foo", "f2", "s2")
26
+ r.hset("foo", "f3", "s3")
27
+
28
+ assert ["s2", "s3"] == r.hmget("foo", "f2", "f3")
29
+ end
30
+
31
+ test "HMGET mapped" do |r|
32
+ r.hset("foo", "f1", "s1")
33
+ r.hset("foo", "f2", "s2")
34
+ r.hset("foo", "f3", "s3")
35
+
36
+ assert({"f1" => "s1"} == r.mapped_hmget("foo", "f1"))
37
+ assert({"f1" => "s1", "f2" => "s2"} == r.mapped_hmget("foo", "f1", "f2"))
38
+ end
39
+
40
+ test "Mapped HMSET" do |r|
41
+ r.mapped_hmset("foo", :f1 => "s1", :f2 => "s2")
42
+
43
+ assert "s1" == r.hget("foo", "f1")
44
+ assert "s2" == r.hget("foo", "f2")
45
+ end
46
+
@@ -0,0 +1,50 @@
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
+ load './test/lint/lists.rb'
10
+
11
+ test "RPUSHX" do |r|
12
+ r.rpushx "foo", "s1"
13
+ r.rpush "foo", "s2"
14
+ r.rpushx "foo", "s3"
15
+
16
+ assert 2 == r.llen("foo")
17
+ assert ["s2", "s3"] == r.lrange("foo", 0, -1)
18
+ end
19
+
20
+ test "LPUSHX" do |r|
21
+ r.lpushx "foo", "s1"
22
+ r.lpush "foo", "s2"
23
+ r.lpushx "foo", "s3"
24
+
25
+ assert 2 == r.llen("foo")
26
+ assert ["s3", "s2"] == r.lrange("foo", 0, -1)
27
+ end
28
+
29
+ test "LINSERT" do |r|
30
+ r.rpush "foo", "s1"
31
+ r.rpush "foo", "s3"
32
+ r.linsert "foo", :before, "s3", "s2"
33
+
34
+ assert ["s1", "s2", "s3"] == r.lrange("foo", 0, -1)
35
+
36
+ assert_raise(RuntimeError) do
37
+ r.linsert "foo", :anywhere, "s3", "s2"
38
+ end
39
+ end
40
+
41
+ test "RPOPLPUSH" do |r|
42
+ r.rpush "foo", "s1"
43
+ r.rpush "foo", "s2"
44
+
45
+ assert "s2" == r.rpoplpush("foo", "bar")
46
+ assert ["s2"] == r.lrange("bar", 0, -1)
47
+ assert "s1" == r.rpoplpush("foo", "bar")
48
+ assert ["s1", "s2"] == r.lrange("bar", 0, -1)
49
+ end
50
+
@@ -0,0 +1,78 @@
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
+ load './test/lint/sets.rb'
10
+
11
+ test "SMOVE" do |r|
12
+ r.sadd "foo", "s1"
13
+ r.sadd "bar", "s2"
14
+
15
+ assert r.smove("foo", "bar", "s1")
16
+ assert r.sismember("bar", "s1")
17
+ end
18
+
19
+ test "SINTER" do |r|
20
+ r.sadd "foo", "s1"
21
+ r.sadd "foo", "s2"
22
+ r.sadd "bar", "s2"
23
+
24
+ assert ["s2"] == r.sinter("foo", "bar")
25
+ end
26
+
27
+ test "SINTERSTORE" do |r|
28
+ r.sadd "foo", "s1"
29
+ r.sadd "foo", "s2"
30
+ r.sadd "bar", "s2"
31
+
32
+ r.sinterstore("baz", "foo", "bar")
33
+
34
+ assert ["s2"] == r.smembers("baz")
35
+ end
36
+
37
+ test "SUNION" do |r|
38
+ r.sadd "foo", "s1"
39
+ r.sadd "foo", "s2"
40
+ r.sadd "bar", "s2"
41
+ r.sadd "bar", "s3"
42
+
43
+ assert ["s1", "s2", "s3"] == r.sunion("foo", "bar").sort
44
+ end
45
+
46
+ test "SUNIONSTORE" do |r|
47
+ r.sadd "foo", "s1"
48
+ r.sadd "foo", "s2"
49
+ r.sadd "bar", "s2"
50
+ r.sadd "bar", "s3"
51
+
52
+ r.sunionstore("baz", "foo", "bar")
53
+
54
+ assert ["s1", "s2", "s3"] == r.smembers("baz").sort
55
+ end
56
+
57
+ test "SDIFF" do |r|
58
+ r.sadd "foo", "s1"
59
+ r.sadd "foo", "s2"
60
+ r.sadd "bar", "s2"
61
+ r.sadd "bar", "s3"
62
+
63
+ assert ["s1"] == r.sdiff("foo", "bar")
64
+ assert ["s3"] == r.sdiff("bar", "foo")
65
+ end
66
+
67
+ test "SDIFFSTORE" do |r|
68
+ r.sadd "foo", "s1"
69
+ r.sadd "foo", "s2"
70
+ r.sadd "bar", "s2"
71
+ r.sadd "bar", "s3"
72
+
73
+ r.sdiffstore("baz", "foo", "bar")
74
+
75
+ assert ["s1"] == r.smembers("baz")
76
+ end
77
+
78
+
@@ -0,0 +1,109 @@
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
+ load './test/lint/sorted_sets.rb'
10
+
11
+ test "ZCOUNT" do |r|
12
+ r.zadd "foo", 1, "s1"
13
+ r.zadd "foo", 2, "s2"
14
+ r.zadd "foo", 3, "s3"
15
+
16
+ assert 2 == r.zcount("foo", 2, 3)
17
+ end
18
+
19
+ test "ZUNIONSTORE" do |r|
20
+ r.zadd "foo", 1, "s1"
21
+ r.zadd "bar", 2, "s2"
22
+ r.zadd "foo", 3, "s3"
23
+ r.zadd "bar", 4, "s4"
24
+
25
+ assert 4 == r.zunionstore("foobar", ["foo", "bar"])
26
+ assert ["s1", "s2", "s3", "s4"] == r.zrange("foobar", 0, -1)
27
+ end
28
+
29
+ test "ZUNIONSTORE with WEIGHTS" do |r|
30
+ r.zadd "foo", 1, "s1"
31
+ r.zadd "foo", 3, "s3"
32
+ r.zadd "bar", 20, "s2"
33
+ r.zadd "bar", 40, "s4"
34
+
35
+ assert 4 == r.zunionstore("foobar", ["foo", "bar"])
36
+ assert ["s1", "s3", "s2", "s4"] == r.zrange("foobar", 0, -1)
37
+
38
+ assert 4 == r.zunionstore("foobar", ["foo", "bar"], :weights => [10, 1])
39
+ assert ["s1", "s2", "s3", "s4"] == r.zrange("foobar", 0, -1)
40
+ end
41
+
42
+ test "ZUNIONSTORE with AGGREGATE" do |r|
43
+ r.zadd "foo", 1, "s1"
44
+ r.zadd "foo", 2, "s2"
45
+ r.zadd "bar", 4, "s2"
46
+ r.zadd "bar", 3, "s3"
47
+
48
+ assert 3 == r.zunionstore("foobar", ["foo", "bar"])
49
+ assert ["s1", "s3", "s2"] == r.zrange("foobar", 0, -1)
50
+
51
+ assert 3 == r.zunionstore("foobar", ["foo", "bar"], :aggregate => :min)
52
+ assert ["s1", "s2", "s3"] == r.zrange("foobar", 0, -1)
53
+
54
+ assert 3 == r.zunionstore("foobar", ["foo", "bar"], :aggregate => :max)
55
+ assert ["s1", "s3", "s2"] == r.zrange("foobar", 0, -1)
56
+ end
57
+
58
+ test "ZINTERSTORE" do |r|
59
+ r.zadd "foo", 1, "s1"
60
+ r.zadd "bar", 2, "s1"
61
+ r.zadd "foo", 3, "s3"
62
+ r.zadd "bar", 4, "s4"
63
+
64
+ assert 1 == r.zinterstore("foobar", ["foo", "bar"])
65
+ assert ["s1"] == r.zrange("foobar", 0, -1)
66
+ end
67
+
68
+ test "ZINTERSTORE with WEIGHTS" do |r|
69
+ r.zadd "foo", 1, "s1"
70
+ r.zadd "foo", 2, "s2"
71
+ r.zadd "foo", 3, "s3"
72
+ r.zadd "bar", 20, "s2"
73
+ r.zadd "bar", 30, "s3"
74
+ r.zadd "bar", 40, "s4"
75
+
76
+ assert 2 == r.zinterstore("foobar", ["foo", "bar"])
77
+ assert ["s2", "s3"] == r.zrange("foobar", 0, -1)
78
+
79
+ assert 2 == r.zinterstore("foobar", ["foo", "bar"], :weights => [10, 1])
80
+ assert ["s2", "s3"] == r.zrange("foobar", 0, -1)
81
+
82
+ assert "40" == r.zscore("foobar", "s2")
83
+ assert "60" == r.zscore("foobar", "s3")
84
+ end
85
+
86
+ test "ZINTERSTORE with AGGREGATE" do |r|
87
+ r.zadd "foo", 1, "s1"
88
+ r.zadd "foo", 2, "s2"
89
+ r.zadd "foo", 3, "s3"
90
+ r.zadd "bar", 20, "s2"
91
+ r.zadd "bar", 30, "s3"
92
+ r.zadd "bar", 40, "s4"
93
+
94
+ assert 2 == r.zinterstore("foobar", ["foo", "bar"])
95
+ assert ["s2", "s3"] == r.zrange("foobar", 0, -1)
96
+ assert "22" == r.zscore("foobar", "s2")
97
+ assert "33" == r.zscore("foobar", "s3")
98
+
99
+ assert 2 == r.zinterstore("foobar", ["foo", "bar"], :aggregate => :min)
100
+ assert ["s2", "s3"] == r.zrange("foobar", 0, -1)
101
+ assert "2" == r.zscore("foobar", "s2")
102
+ assert "3" == r.zscore("foobar", "s3")
103
+
104
+ assert 2 == r.zinterstore("foobar", ["foo", "bar"], :aggregate => :max)
105
+ assert ["s2", "s3"] == r.zrange("foobar", 0, -1)
106
+ assert "20" == r.zscore("foobar", "s2")
107
+ assert "30" == r.zscore("foobar", "s3")
108
+ end
109
+