Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the possibility to fetch all features already released to a given resource #67

Merged
merged 18 commits into from
Jul 31, 2020

Conversation

nsoufr
Copy link
Contributor

@nsoufr nsoufr commented Jun 25, 2020

This PR introduces the ability to fetch which features were released to a given resource (account, user, etc).

acc = Account.find(2)
acc.release(:email_marketing, :whitelabel)

Account.all_released_ids(:email_marketing, :whitelabel) 
#=> [2]

# not available before it
acc.releases
#=> ["account:email_marketing:whitelabel"]

expect(storage.all_values(key).sort).to eq values.sort
it 'returns all resource_ids for the given feature_key' do
redis.sadd(feature_key, resource_ids)
expect(storage.all_values(feature_key).sort).to eq resource_ids.sort
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

match_array

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

it { expect(storage).to have_value(key, value) }
describe '#has_values?' do
context 'resource_id is stored for given feature_key' do
before { redis.sadd(feature_key, resource_id) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could use the storage.add method, what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense, done!

spec/feature_flagger/storage/redis_spec.rb Show resolved Hide resolved
it { expect(storage).not_to have_value(key, value) }
context 'when there is features under global structure' do
before do
storage.add(feature_key, resource_name, resource_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the test doesn't need this setup :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

storage.add(feature_key, resource_name, resource_id)

expect(redis.sismember(feature_key, resource_id)).to be_truthy
expect(redis.sismember(resource_key, feature_key)).to be_truthy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use the redis to make the assertion? And why there are two assertions and only one context?

storage.add_all(global_key, resource_id)
expect(redis.sismember(global_key, resource_id)).to be_truthy

expect(redis.sismember(feature_key, resource_id)).to be_falsey
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be discussed/done in another PR

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO it's fine as it is. The single expectation tip is not well accepted by the community and will probably be removed from the guide.

betterspecs/betterspecs#5
https://stackoverflow.com/questions/38437162/whats-the-difference-between-rspecs-subject-and-let-when-should-they-be-used/38459039#38459039

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides, the expects are co-dependent, we don't want to isolate then, in order the expect from line 71 be valid, it needs to expect from line 69 to pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I think this can be discussed in another issue, or PR. not related to this change, as long this is actually an opinionated style.

@@ -19,19 +20,19 @@ module FeatureFlagger
it { expect(result).to be_falsey }

context 'and a feature is release to all' do
before { storage.add(FeatureFlagger::Control::RELEASED_FEATURES, key) }
before { storage.add(FeatureFlagger::Control::RELEASED_FEATURES, resource_name, key) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be using control.release in all control tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense, done

it { expect(result).to be_falsey }
end

context 'when feature was released to all' do
before { storage.add(FeatureFlagger::Control::RELEASED_FEATURES, key) }
before { storage.add_all(FeatureFlagger::Control::RELEASED_FEATURES, key) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

control.release_to_all

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, tests are better now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you missed this one :) It still using storage, IMHO this spec we should not use the storage class at all only the public API of FeatureFlagger::Control does that make sense to you? I think we can do this refactor in another time anyways :D

lib/feature_flagger/storage/redis_keys.rb Outdated Show resolved Hide resolved
before { redis.sadd(key, value) }
it { expect(storage).to have_value(key, value) }
describe '#has_values?' do
context 'resource_id is stored for given feature_key' do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end

context 'when add_all is called right after add' do
it 'adds resource_id to redis global key, and clear both resource_id and feature_key' do
Copy link
Contributor

@henrich-m henrich-m Jul 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you think a and here means this is two separate contexts?

lib/feature_flagger/control.rb Outdated Show resolved Hide resolved
lib/feature_flagger/storage/redis.rb Show resolved Hide resolved
lib/feature_flagger/storage/redis.rb Outdated Show resolved Hide resolved
it { expect(result).to be_falsey }
end

context 'when feature was released to all' do
before { storage.add(FeatureFlagger::Control::RELEASED_FEATURES, key) }
before { storage.add_all(FeatureFlagger::Control::RELEASED_FEATURES, key) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you missed this one :) It still using storage, IMHO this spec we should not use the storage class at all only the public API of FeatureFlagger::Control does that make sense to you? I think we can do this refactor in another time anyways :D

@@ -2,7 +2,7 @@ module FeatureFlagger
class Manager

def self.detached_feature_keys
persisted_features = FeatureFlagger.control.search_keys("*").to_a
persisted_features = FeatureFlagger.control.feature_keys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

henrich-m
henrich-m previously approved these changes Jul 7, 2020
Copy link
Contributor

@henrich-m henrich-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nsoufr nsoufr requested a review from andrehjr July 27, 2020 13:35
@@ -13,15 +13,27 @@ def released?(feature_key, resource_id)
end

def release(feature_key, resource_id)
@storage.add(feature_key, resource_id)
resource_name = FeatureFlagger::Storage::RedisKeys.extract_resource_name_from_feature_key(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should calls made to RedisKeys only be made inside the Redis Storage adapter?

Or is it something we would be able to re-use to other types of storages? In that case, I think we should rename RedisKeys to something else.

Why? Keys class it's responsible for decomposing the feature_key
and this logic will be needed in others Storages as well.
So we are renaming it to make clear it doesn't depends on Redis.
@codeclimate
Copy link

codeclimate bot commented Jul 30, 2020

Code Climate has analyzed commit 1eb46df and detected 0 issues on this pull request.

The test coverage on the diff in this pull request is 100.0% (80% is the threshold).

This pull request will bring the total coverage in the repository to 99.0% (0.2% change).

View more on Code Climate.

@masisiliani masisiliani merged commit bb74c2b into master Jul 31, 2020
@henrich-m henrich-m deleted the ns-features-by-account branch August 3, 2020 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants