rollout 2.1.0 → 2.2.1

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.
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