rollout 2.1.0 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc88ca14f2eb1ae5156873fce8e5f569e8e551d5
4
- data.tar.gz: 37e6306414e96c1dad888d68f4241bb339af5dd0
3
+ metadata.gz: c64885c4cf5254332da642dc02ee9b21aeaa62c8
4
+ data.tar.gz: 7847a0a450a0641f71b1f47926ce867dc00e40af
5
5
  SHA512:
6
- metadata.gz: 43b4ba29fd8bc735ec1646aa3386ebf409d7d19c3d459fdd649670cf773bcef5ed28583b653ad824b15dcb022ed0e49d55b256a1c477044d93fbd292451df88f
7
- data.tar.gz: 36031f802e6b61f2d4e8d5205da8bcc8103cc837ddf6fcff1b51db3c4f71e6a2deeb18286e691fdc5f2daa9ab82ee7717118739cd22d7b6bcd5f72de4075e0e4
6
+ metadata.gz: 8d673450a953468fbe6ebca47ee985af3499a37627dd1e086f5b018216d6bc2d3c12ffac1a33e2bbc369802d059faff2a69ef8f5899f7a7e10b6750a852ffad3
7
+ data.tar.gz: 594d9322387a7019ca0f0d34cf8d5c4133181ec960f7dd8749babc1353d978bd326505651f220dd3cf034b46113c7054a7c216f142605001cad43f0938860ffa
File without changes
data/.travis.yml CHANGED
@@ -1,7 +1,9 @@
1
1
  language: ruby
2
+ sudo: false
2
3
  services:
3
4
  - redis-server
4
5
  rvm:
6
+ - 2.2
5
7
  - 2.1
6
8
  - 2.0.0
7
9
  - 1.9.3
data/Gemfile.lock CHANGED
@@ -1,40 +1,52 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rollout (2.0.0)
4
+ rollout (2.2.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- bourne (1.0)
10
- mocha (= 0.9.8)
11
- diff-lcs (1.1.3)
12
- git (1.2.5)
9
+ codeclimate-test-reporter (0.4.8)
10
+ simplecov (>= 0.7.1, < 1.0.0)
11
+ diff-lcs (1.2.5)
12
+ docile (1.1.5)
13
+ git (1.2.9.1)
13
14
  jeweler (1.6.4)
14
15
  bundler (~> 1.0)
15
16
  git (>= 1.2.5)
16
17
  rake
17
- mocha (0.9.8)
18
- rake
19
- rake (0.9.2.2)
20
- redis (3.0.7)
21
- rspec (2.10.0)
22
- rspec-core (~> 2.10.0)
23
- rspec-expectations (~> 2.10.0)
24
- rspec-mocks (~> 2.10.0)
25
- rspec-core (2.10.1)
26
- rspec-expectations (2.10.0)
27
- diff-lcs (~> 1.1.3)
28
- rspec-mocks (2.10.1)
18
+ json (1.8.3)
19
+ rake (10.4.2)
20
+ redis (3.2.1)
21
+ rspec (3.4.0)
22
+ rspec-core (~> 3.4.0)
23
+ rspec-expectations (~> 3.4.0)
24
+ rspec-mocks (~> 3.4.0)
25
+ rspec-core (3.4.2)
26
+ rspec-support (~> 3.4.0)
27
+ rspec-expectations (3.4.0)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.4.0)
30
+ rspec-mocks (3.4.1)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.4.0)
33
+ rspec-support (3.4.1)
34
+ simplecov (0.11.1)
35
+ docile (~> 1.1.0)
36
+ json (~> 1.8)
37
+ simplecov-html (~> 0.10.0)
38
+ simplecov-html (0.10.0)
29
39
 
30
40
  PLATFORMS
31
41
  ruby
32
42
 
33
43
  DEPENDENCIES
34
- bourne (= 1.0)
35
44
  bundler (>= 1.0.0)
45
+ codeclimate-test-reporter
36
46
  jeweler (~> 1.6.4)
37
- mocha (= 0.9.8)
38
47
  redis
39
48
  rollout!
40
- rspec (~> 2.10.0)
49
+ rspec
50
+
51
+ BUNDLED WITH
52
+ 1.10.6
data/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # rollout
2
+
3
+ Feature flippers.
4
+
5
+ [![Build Status](https://travis-ci.org/FetLife/rollout.svg?branch=master)](https://travis-ci.org/FetLife/rollout)
6
+ [![Code Climate](https://codeclimate.com/github/FetLife/rollout/badges/gpa.svg)](https://codeclimate.com/github/FetLife/rollout)
7
+ [//]: # ([![Test Coverage](https://codeclimate.com/github/FetLife/rollout/badges/coverage.svg)](https://codeclimate.com/github/FetLife/rollout/coverage))
8
+
9
+ ## MAKE SURE TO READ THIS: 2.X Changes and Migration Path
10
+
11
+ As of rollout-2.x, only one key is used per feature for performance reasons.
12
+ The data format is `percentage|user_id,user_id,...|group,_group...`. This has
13
+ the effect of making concurrent feature modifications unsafe, but in practice,
14
+ I doubt this will actually be a problem.
15
+
16
+ This also has the effect of rollout no longer being dependent on redis. Just
17
+ give it something that responds to `set(key,value)`, `get(key)` and
18
+ `del(key)`.
19
+
20
+ If you have been using the 1.x format, you can initialize Rollout with
21
+ `migrate: true` and it'll do its best to automatically migrate your old
22
+ features to the new format. There will be some performance impact, but it
23
+ should be limited and short-lived since each feature only needs to get
24
+ migrated once.
25
+
26
+ ## Rollout::Legacy
27
+
28
+ If you'd prefer to continue to use the old layout in redis, `Rollout::Legacy`
29
+ is a copy and paste of the old code :-).
30
+
31
+ ## Install it
32
+
33
+ ```bash
34
+ gem install rollout
35
+ ```
36
+
37
+ ## How it works
38
+
39
+ Initialize a rollout object. I assign it to a global var.
40
+
41
+ ```ruby
42
+ require 'redis'
43
+
44
+ $redis = Redis.new
45
+ $rollout = Rollout.new($redis)
46
+ ```
47
+
48
+ Check whether a feature is active for a particular user:
49
+
50
+ ```ruby
51
+ $rollout.active?(:chat, User.first) # => true/false
52
+ ```
53
+
54
+ Check whether a feature is active globally:
55
+
56
+ ```ruby
57
+ $rollout.active?(:chat)
58
+ ```
59
+
60
+ You can activate features using a number of different mechanisms.
61
+
62
+ ## Groups
63
+
64
+ Rollout ships with one group by default: "all", which does exactly what it
65
+ sounds like.
66
+
67
+ You can activate the all group for the chat feature like this:
68
+
69
+ ```ruby
70
+ $rollout.activate_group(:chat, :all)
71
+ ```
72
+
73
+ You might also want to define your own groups. We have one for our caretakers:
74
+
75
+ ```ruby
76
+ $rollout.define_group(:caretakers) do |user|
77
+ user.caretaker?
78
+ end
79
+ ```
80
+
81
+ You can activate multiple groups per feature.
82
+
83
+ Deactivate groups like this:
84
+
85
+ ```ruby
86
+ $rollout.deactivate_group(:chat, :all)
87
+ ```
88
+
89
+ ## Specific Users
90
+
91
+ You might want to let a specific user into a beta test or something. If that
92
+ user isn't part of an existing group, you can let them in specifically:
93
+
94
+ ```ruby
95
+ $rollout.activate_user(:chat, @user)
96
+ ```
97
+
98
+ Deactivate them like this:
99
+
100
+ ```ruby
101
+ $rollout.deactivate_user(:chat, @user)
102
+ ```
103
+
104
+ ## User Percentages
105
+
106
+ If you're rolling out a new feature, you might want to test the waters by
107
+ slowly enabling it for a percentage of your users.
108
+
109
+ ```ruby
110
+ $rollout.activate_percentage(:chat, 20)
111
+ ```
112
+
113
+ The algorithm for determining which users get let in is this:
114
+
115
+ ```ruby
116
+ CRC32(user.id) % 100 < percentage
117
+ ```
118
+
119
+ So, for 20%, users 0, 1, 10, 11, 20, 21, etc would be allowed in. Those users
120
+ would remain in as the percentage increases.
121
+
122
+ Deactivate all percentages like this:
123
+
124
+ ```ruby
125
+ $rollout.deactivate_percentage(:chat)
126
+ ```
127
+
128
+ _Note that activating a feature for 100% of users will also make it active
129
+ "globally". That is when calling Rollout#active? without a user object._
130
+
131
+ In some cases you might want to have a feature activated for a random set of
132
+ users. It can come specially handy when using Rollout for split tests.
133
+
134
+ ```ruby
135
+ $rollout = Rollout.new($redis, randomize_percentage: true)
136
+ ```
137
+
138
+ When on `randomize_percentage` will make sure that 50% of users for feature A
139
+ are selected independently from users for feature B.
140
+
141
+ ## Feature is broken
142
+
143
+ Deactivate everybody at once:
144
+
145
+ ```ruby
146
+ $rollout.deactivate(:chat)
147
+ ```
148
+
149
+ For many of our features, we keep track of error rates using redis, and
150
+ deactivate them automatically when a threshold is reached to prevent service
151
+ failures from cascading. See http://github.com/jamesgolick/degrade for the
152
+ failure detection code.
153
+
154
+ ## Namespacing
155
+
156
+ Rollout separates its keys from other keys in the data store using the
157
+ "feature" keyspace.
158
+
159
+ If you're using redis, you can namespace keys further to support multiple
160
+ environments by using the
161
+ [redis-namespace](https://github.com/resque/redis-namespace) gem.
162
+
163
+ ```ruby
164
+ $ns = Redis::Namespace.new(Rails.env, redis: $redis)
165
+ $rollout = Rollout.new($ns)
166
+ $rollout.activate_group(:chat, :all)
167
+ ```
168
+
169
+ This example would use the "development:feature:chat:groups" key.
170
+
171
+ ## Implementations in other languages
172
+
173
+ * Python: http://github.com/asenchi/proclaim
174
+ * PHP: https://github.com/opensoft/rollout
175
+ * Clojure: https://github.com/tcrayford/shoutout
176
+
177
+
178
+ ## Contributors
179
+
180
+ * James Golick - Creator - https://github.com/jamesgolick
181
+ * Eric Rafaloff - Maintainer - https://github.com/EricR
182
+
183
+
184
+ ## Copyright
185
+
186
+ Copyright (c) 2010-InfinityAndBeyond BitLove, Inc. See LICENSE for details.
@@ -1,3 +1,3 @@
1
1
  class Rollout
2
- VERSION = "2.1.0"
2
+ VERSION = "2.2.1"
3
3
  end
data/lib/rollout.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "rollout/version"
2
2
  require "rollout/legacy"
3
3
  require "zlib"
4
+ require "set"
4
5
 
5
6
  class Rollout
6
7
  class Feature
@@ -14,15 +15,15 @@ class Rollout
14
15
  if string
15
16
  raw_percentage,raw_users,raw_groups = string.split("|")
16
17
  @percentage = raw_percentage.to_i
17
- @users = (raw_users || "").split(",").map(&:to_s)
18
- @groups = (raw_groups || "").split(",").map(&:to_sym)
18
+ @users = (raw_users || "").split(",").map(&:to_s).to_set
19
+ @groups = (raw_groups || "").split(",").map(&:to_sym).to_set
19
20
  else
20
21
  clear
21
22
  end
22
23
  end
23
24
 
24
25
  def serialize
25
- "#{@percentage}|#{@users.join(",")}|#{@groups.join(",")}"
26
+ "#{@percentage}|#{@users.to_a.join(",")}|#{@groups.to_a.join(",")}"
26
27
  end
27
28
 
28
29
  def add_user(user)
@@ -43,8 +44,8 @@ class Rollout
43
44
  end
44
45
 
45
46
  def clear
46
- @groups = []
47
- @users = []
47
+ @groups = Set.new
48
+ @users = Set.new
48
49
  @percentage = 0
49
50
  end
50
51
 
@@ -60,15 +61,16 @@ class Rollout
60
61
  end
61
62
 
62
63
  def to_hash
63
- {:percentage => @percentage,
64
- :groups => @groups,
65
- :users => @users}
64
+ {
65
+ percentage: @percentage,
66
+ groups: @groups,
67
+ users: @users
68
+ }
66
69
  end
67
70
 
68
71
  private
69
72
  def user_id(user)
70
- if user.is_a?(Fixnum) ||
71
- user.is_a?(String)
73
+ if user.is_a?(Fixnum) || user.is_a?(String)
72
74
  user.to_s
73
75
  else
74
76
  user.send(id_user_by).to_s
@@ -80,7 +82,15 @@ class Rollout
80
82
  end
81
83
 
82
84
  def user_in_percentage?(user)
83
- Zlib.crc32(user_id(user)) % 100 < @percentage
85
+ Zlib.crc32(user_id_for_percentage(user)) % 100 < @percentage
86
+ end
87
+
88
+ def user_id_for_percentage(user)
89
+ if @options[:randomize_percentage]
90
+ user_id(user).to_s + @name.to_s
91
+ else
92
+ user_id(user)
93
+ end
84
94
  end
85
95
 
86
96
  def user_in_active_users?(user)
@@ -97,7 +107,7 @@ class Rollout
97
107
  def initialize(storage, opts = {})
98
108
  @storage = storage
99
109
  @options = opts
100
- @groups = {:all => lambda { |user| true }}
110
+ @groups = { all: lambda { |user| true } }
101
111
  @legacy = Legacy.new(opts[:legacy_storage] || @storage) if opts[:migrate]
102
112
  end
103
113
 
@@ -113,6 +123,13 @@ class Rollout
113
123
  end
114
124
  end
115
125
 
126
+ def delete(feature)
127
+ features = (@storage.get(features_key) || "").split(",").map(&:to_sym)
128
+ features.delete(feature)
129
+ @storage.set(features_key, features.join(","))
130
+ @storage.del(key(feature))
131
+ end
132
+
116
133
  def set(feature, desired_state)
117
134
  with_feature(feature) do |f|
118
135
  if desired_state
@@ -147,6 +164,18 @@ class Rollout
147
164
  end
148
165
  end
149
166
 
167
+ def activate_users(feature, users)
168
+ with_feature(feature) do |f|
169
+ users.each{|user| f.add_user(user)}
170
+ end
171
+ end
172
+
173
+ def deactivate_users(feature, users)
174
+ with_feature(feature) do |f|
175
+ users.each{|user| f.remove_user(user)}
176
+ end
177
+ end
178
+
150
179
  def define_group(group, &block)
151
180
  @groups[group.to_sym] = block
152
181
  end
@@ -156,6 +185,10 @@ class Rollout
156
185
  feature.active?(self, user)
157
186
  end
158
187
 
188
+ def inactive?(feature, user = nil)
189
+ !active(feature, user)
190
+ end
191
+
159
192
  def activate_percentage(feature, percentage)
160
193
  with_feature(feature) do |f|
161
194
  f.percentage = percentage
@@ -193,6 +226,18 @@ class Rollout
193
226
  (@storage.get(features_key) || "").split(",").map(&:to_sym)
194
227
  end
195
228
 
229
+ def feature_states(user = nil)
230
+ features.each_with_object({}) do |f, hash|
231
+ hash[f] = active?(f, user)
232
+ end
233
+ end
234
+
235
+ def active_features(user = nil)
236
+ features.select do |f|
237
+ active?(f, user)
238
+ end
239
+ end
240
+
196
241
  def clear!
197
242
  features.each do |feature|
198
243
  with_feature(feature) { |f| f.clear }
data/rollout.gemspec CHANGED
@@ -11,17 +11,14 @@ Gem::Specification.new do |s|
11
11
  s.summary = "Feature flippers with redis."
12
12
  s.homepage = "https://github.com/jamesgolick/rollout"
13
13
 
14
- s.rubyforge_project = "rollout"
15
-
16
14
  s.files = `git ls-files`.split("\n")
17
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
17
  s.require_paths = ["lib"]
20
18
 
21
- s.add_development_dependency "rspec", "~> 2.10.0"
19
+ s.add_development_dependency "rspec"
22
20
  s.add_development_dependency "bundler", ">= 1.0.0"
23
21
  s.add_development_dependency "jeweler", "~> 1.6.4"
24
- s.add_development_dependency "bourne", "1.0"
25
- s.add_development_dependency "mocha", "0.9.8"
26
22
  s.add_development_dependency "redis"
23
+ s.add_development_dependency "codeclimate-test-reporter"
27
24
  end
data/spec/legacy_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require "spec_helper"
2
2
 
3
- describe "Rollout::Legacy" do
3
+ RSpec.describe "Rollout::Legacy" do
4
4
  before do
5
5
  @redis = Redis.new
6
6
  @rollout = Rollout::Legacy.new(@redis)
@@ -13,16 +13,16 @@ describe "Rollout::Legacy" do
13
13
  end
14
14
 
15
15
  it "the feature is active for users for which the block evaluates to true" do
16
- @rollout.should be_active(:chat, stub(:id => 5))
16
+ expect(@rollout).to be_active(:chat, double(id: 5))
17
17
  end
18
18
 
19
19
  it "is not active for users for which the block evaluates to false" do
20
- @rollout.should_not be_active(:chat, stub(:id => 1))
20
+ expect(@rollout).not_to be_active(:chat, double(id: 1))
21
21
  end
22
22
 
23
23
  it "is not active if a group is found in Redis but not defined in Rollout" do
24
24
  @rollout.activate_group(:chat, :fake)
25
- @rollout.should_not be_active(:chat, stub(:id => 1))
25
+ expect(@rollout).not_to be_active(:chat, double(id: 1))
26
26
  end
27
27
  end
28
28
 
@@ -32,7 +32,7 @@ describe "Rollout::Legacy" do
32
32
  end
33
33
 
34
34
  it "evaluates to true no matter what" do
35
- @rollout.should be_active(:chat, stub(:id => 0))
35
+ expect(@rollout).to be_active(:chat, double(id: 0))
36
36
  end
37
37
  end
38
38
 
@@ -45,11 +45,11 @@ describe "Rollout::Legacy" do
45
45
  end
46
46
 
47
47
  it "deactivates the rules for that group" do
48
- @rollout.should_not be_active(:chat, stub(:id => 10))
48
+ expect(@rollout).not_to be_active(:chat, double(id: 10))
49
49
  end
50
50
 
51
51
  it "leaves the other groups active" do
52
- @rollout.should be_active(:chat, stub(:id => 5))
52
+ expect(@rollout).to be_active(:chat, double(id: 5))
53
53
  end
54
54
  end
55
55
 
@@ -58,56 +58,56 @@ describe "Rollout::Legacy" do
58
58
  @rollout.define_group(:fivesonly) { |user| user.id == 5 }
59
59
  @rollout.activate_group(:chat, :all)
60
60
  @rollout.activate_group(:chat, :fivesonly)
61
- @rollout.activate_user(:chat, stub(:id => 51))
61
+ @rollout.activate_user(:chat, double(id: 51))
62
62
  @rollout.activate_percentage(:chat, 100)
63
63
  @rollout.activate_globally(:chat)
64
64
  @rollout.deactivate_all(:chat)
65
65
  end
66
66
 
67
67
  it "removes all of the groups" do
68
- @rollout.should_not be_active(:chat, stub(:id => 0))
68
+ expect(@rollout).not_to be_active(:chat, double(id: 0))
69
69
  end
70
70
 
71
71
  it "removes all of the users" do
72
- @rollout.should_not be_active(:chat, stub(:id => 51))
72
+ expect(@rollout).not_to be_active(:chat, double(id: 51))
73
73
  end
74
74
 
75
75
  it "removes the percentage" do
76
- @rollout.should_not be_active(:chat, stub(:id => 24))
76
+ expect(@rollout).not_to be_active(:chat, double(id: 24))
77
77
  end
78
78
 
79
79
  it "removes globally" do
80
- @rollout.should_not be_active(:chat)
80
+ expect(@rollout).not_to be_active(:chat)
81
81
  end
82
82
  end
83
83
 
84
84
  describe "activating a specific user" do
85
85
  before do
86
- @rollout.activate_user(:chat, stub(:id => 42))
86
+ @rollout.activate_user(:chat, double(id: 42))
87
87
  end
88
88
 
89
89
  it "is active for that user" do
90
- @rollout.should be_active(:chat, stub(:id => 42))
90
+ expect(@rollout).to be_active(:chat, double(id: 42))
91
91
  end
92
92
 
93
93
  it "remains inactive for other users" do
94
- @rollout.should_not be_active(:chat, stub(:id => 24))
94
+ expect(@rollout).not_to be_active(:chat, double(id: 24))
95
95
  end
96
96
  end
97
97
 
98
98
  describe "deactivating a specific user" do
99
99
  before do
100
- @rollout.activate_user(:chat, stub(:id => 42))
101
- @rollout.activate_user(:chat, stub(:id => 24))
102
- @rollout.deactivate_user(:chat, stub(:id => 42))
100
+ @rollout.activate_user(:chat, double(id: 42))
101
+ @rollout.activate_user(:chat, double(id: 24))
102
+ @rollout.deactivate_user(:chat, double(id: 42))
103
103
  end
104
104
 
105
105
  it "that user should no longer be active" do
106
- @rollout.should_not be_active(:chat, stub(:id => 42))
106
+ expect(@rollout).not_to be_active(:chat, double(id: 42))
107
107
  end
108
108
 
109
109
  it "remains active for other active users" do
110
- @rollout.should be_active(:chat, stub(:id => 24))
110
+ expect(@rollout).to be_active(:chat, double(id: 24))
111
111
  end
112
112
  end
113
113
 
@@ -117,7 +117,7 @@ describe "Rollout::Legacy" do
117
117
  end
118
118
 
119
119
  it "activates the feature" do
120
- @rollout.should be_active(:chat)
120
+ expect(@rollout).to be_active(:chat)
121
121
  end
122
122
  end
123
123
 
@@ -127,7 +127,7 @@ describe "Rollout::Legacy" do
127
127
  end
128
128
 
129
129
  it "activates the feature for that percentage of the users" do
130
- (1..120).select { |id| @rollout.active?(:chat, stub(:id => id)) }.length.should == 39
130
+ expect((1..120).select { |id| @rollout.active?(:chat, double(id: id)) }.length).to eq(39)
131
131
  end
132
132
  end
133
133
 
@@ -137,7 +137,7 @@ describe "Rollout::Legacy" do
137
137
  end
138
138
 
139
139
  it "activates the feature for that percentage of the users" do
140
- (1..200).select { |id| @rollout.active?(:chat, stub(:id => id)) }.length.should == 40
140
+ expect((1..200).select { |id| @rollout.active?(:chat, double(id: id)) }.length).to eq(40)
141
141
  end
142
142
  end
143
143
 
@@ -147,7 +147,7 @@ describe "Rollout::Legacy" do
147
147
  end
148
148
 
149
149
  it "activates the feature for that percentage of the users" do
150
- (1..100).select { |id| @rollout.active?(:chat, stub(:id => id)) }.length.should == 5
150
+ expect((1..100).select { |id| @rollout.active?(:chat, double(id: id)) }.length).to eq(5)
151
151
  end
152
152
  end
153
153
 
@@ -159,7 +159,7 @@ describe "Rollout::Legacy" do
159
159
  end
160
160
 
161
161
  it "becomes inactivate for all users" do
162
- @rollout.should_not be_active(:chat, stub(:id => 24))
162
+ expect(@rollout).not_to be_active(:chat, double(id: 24))
163
163
  end
164
164
  end
165
165
 
@@ -170,7 +170,7 @@ describe "Rollout::Legacy" do
170
170
  end
171
171
 
172
172
  it "becomes inactivate" do
173
- @rollout.should_not be_active(:chat)
173
+ expect(@rollout).not_to be_active(:chat)
174
174
  end
175
175
  end
176
176
 
@@ -185,7 +185,7 @@ describe "Rollout::Legacy" do
185
185
  end
186
186
 
187
187
  it "returns all global features" do
188
- @rollout.info[:global].should include(*features)
188
+ expect(@rollout.info[:global]).to include(*features)
189
189
  end
190
190
  end
191
191
 
@@ -195,26 +195,26 @@ describe "Rollout::Legacy" do
195
195
  @rollout.activate_group(:chat, :caretakers)
196
196
  @rollout.activate_group(:chat, :greeters)
197
197
  @rollout.activate_globally(:signup)
198
- @rollout.activate_user(:chat, stub(:id => 42))
198
+ @rollout.activate_user(:chat, double(id: 42))
199
199
  end
200
200
 
201
201
  it "returns info about all the activations" do
202
202
  info = @rollout.info(:chat)
203
- info[:percentage].should == 10
204
- info[:groups].should include(:caretakers, :greeters)
205
- info[:users].should include(42)
206
- info[:global].should include(:signup)
203
+ expect(info[:percentage]).to eq(10)
204
+ expect(info[:groups]).to include(:caretakers, :greeters)
205
+ expect(info[:users]).to include(42)
206
+ expect(info[:global]).to include(:signup)
207
207
  end
208
208
  end
209
209
 
210
210
  describe "without a percentage set" do
211
211
  it "defaults to 0" do
212
- @rollout.info(:chat).should == {
213
- :percentage => 0,
214
- :groups => [],
215
- :users => [],
216
- :global => []
217
- }
212
+ expect(@rollout.info(:chat)).to eq(
213
+ percentage: 0,
214
+ groups: [],
215
+ users: [],
216
+ global: [],
217
+ )
218
218
  end
219
219
  end
220
220
  end