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 +4 -4
- data/{spec/spec.opts → .rspec} +0 -0
- data/.travis.yml +2 -0
- data/Gemfile.lock +32 -20
- data/README.md +186 -0
- data/lib/rollout/version.rb +1 -1
- data/lib/rollout.rb +57 -12
- data/rollout.gemspec +2 -5
- data/spec/legacy_spec.rb +39 -39
- data/spec/rollout_spec.rb +263 -79
- data/spec/spec_helper.rb +11 -5
- metadata +16 -32
- data/README.rdoc +0 -130
- data/misc/check_rollout.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c64885c4cf5254332da642dc02ee9b21aeaa62c8
|
4
|
+
data.tar.gz: 7847a0a450a0641f71b1f47926ce867dc00e40af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d673450a953468fbe6ebca47ee985af3499a37627dd1e086f5b018216d6bc2d3c12ffac1a33e2bbc369802d059faff2a69ef8f5899f7a7e10b6750a852ffad3
|
7
|
+
data.tar.gz: 594d9322387a7019ca0f0d34cf8d5c4133181ec960f7dd8749babc1353d978bd326505651f220dd3cf034b46113c7054a7c216f142605001cad43f0938860ffa
|
data/{spec/spec.opts → .rspec}
RENAMED
File without changes
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,40 +1,52 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rollout (2.
|
4
|
+
rollout (2.2.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
|
10
|
-
|
11
|
-
diff-lcs (1.
|
12
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
rspec-
|
23
|
-
rspec-
|
24
|
-
|
25
|
-
|
26
|
-
rspec-expectations (
|
27
|
-
diff-lcs (
|
28
|
-
|
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
|
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.
|
data/lib/rollout/version.rb
CHANGED
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
|
-
{
|
64
|
-
|
65
|
-
|
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(
|
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 = {:
|
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"
|
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
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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,
|
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.
|
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.
|
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.
|
76
|
+
expect(@rollout).not_to be_active(:chat, double(id: 24))
|
77
77
|
end
|
78
78
|
|
79
79
|
it "removes globally" do
|
80
|
-
@rollout.
|
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,
|
86
|
+
@rollout.activate_user(:chat, double(id: 42))
|
87
87
|
end
|
88
88
|
|
89
89
|
it "is active for that user" do
|
90
|
-
@rollout.
|
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.
|
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,
|
101
|
-
@rollout.activate_user(:chat,
|
102
|
-
@rollout.deactivate_user(:chat,
|
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.
|
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.
|
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.
|
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,
|
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,
|
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,
|
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.
|
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.
|
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].
|
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,
|
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].
|
204
|
-
info[:groups].
|
205
|
-
info[:users].
|
206
|
-
info[:global].
|
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).
|
213
|
-
:
|
214
|
-
:
|
215
|
-
:
|
216
|
-
:
|
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
|