spec/flipper/feature_spec.rb in flipper-0.3.0 vs spec/flipper/feature_spec.rb in flipper-0.4.0

- old
+ new

@@ -1,36 +1,198 @@ require 'helper' require 'flipper/feature' require 'flipper/adapters/memory' +require 'flipper/instrumenters/memory' describe Flipper::Feature do - subject { described_class.new(:search, adapter) } + subject { described_class.new(:search, adapter) } - let(:source) { {} } - let(:adapter) { Flipper::Adapters::Memory.new(source) } + let(:source) { {} } + let(:adapter) { Flipper::Adapters::Memory.new(source) } - it "initializes with name and adapter" do - feature = described_class.new(:search, adapter) - feature.name.should eq(:search) - feature.adapter.should eq(Flipper::Adapter.wrap(adapter)) + describe "#initialize" do + it "sets name" do + feature = described_class.new(:search, adapter) + feature.name.should eq(:search) + end + + it "sets adapter" do + feature = described_class.new(:search, adapter) + feature.adapter.should eq(Flipper::Adapter.wrap(adapter)) + end + + it "defaults instrumenter" do + feature = described_class.new(:search, adapter) + feature.instrumenter.should be(Flipper::Instrumenters::Noop) + end + + context "with overriden instrumenter" do + let(:instrumenter) { double('Instrumentor', :instrument => nil) } + + it "overrides default instrumenter" do + feature = described_class.new(:search, adapter, { + :instrumenter => instrumenter, + }) + feature.instrumenter.should be(instrumenter) + end + + it "passes overridden instrumenter to adapter wrapping" do + feature = described_class.new(:search, adapter, { + :instrumenter => instrumenter, + }) + feature.adapter.instrumenter.should be(instrumenter) + end + end end + describe "#gate_for" do + context "with percentage of actors" do + it "returns percentage of actors gate" do + percentage = Flipper::Types::PercentageOfActors.new(10) + gate = subject.gate_for(percentage) + gate.should be_instance_of(Flipper::Gates::PercentageOfActors) + end + end + end + describe "#gates" do - it "returns array of gates" do - subject.gates.should be_instance_of(Array) - subject.gates.each do |gate| + it "returns array of gates with each gate's instrumenter set" do + instrumenter = double('Instrumenter') + instance = described_class.new(:search, adapter, :instrumenter => instrumenter) + instance.gates.should be_instance_of(Array) + instance.gates.each do |gate| gate.should be_a(Flipper::Gate) + gate.instrumenter.should be(instrumenter) end - subject.gates.size.should be(5) + instance.gates.size.should be(5) end end - context "#disabled?" do - it "returns the opposite of enabled" do - subject.stub(:enabled? => true) - subject.disabled?.should be_false + describe "#inspect" do + it "returns easy to read string representation" do + string = subject.inspect + string.should include('Flipper::Feature') + string.should include('name=:search') + string.should include('state=:off') + string.should include("adapter=#{subject.adapter.name.inspect}") + end + end - subject.stub(:enabled? => false) - subject.disabled?.should be_true + describe "instrumentation" do + let(:instrumenter) { Flipper::Instrumenters::Memory.new } + + subject { + described_class.new(:search, adapter, :instrumenter => instrumenter) + } + + it "is recorded for enable" do + thing = Flipper::Types::Boolean.new + gate = subject.gate_for(thing) + + subject.enable(thing) + + event = instrumenter.events.last + event.should_not be_nil + event.name.should eq('feature_operation.flipper') + event.payload[:feature_name].should eq(:search) + event.payload[:operation].should eq(:enable) + event.payload[:thing].should eq(thing) + event.payload[:result].should_not be_nil + end + + it "is recorded for disable" do + thing = Flipper::Types::Boolean.new + gate = subject.gate_for(thing) + + subject.disable(thing) + + event = instrumenter.events.last + event.should_not be_nil + event.name.should eq('feature_operation.flipper') + event.payload[:feature_name].should eq(:search) + event.payload[:operation].should eq(:disable) + event.payload[:thing].should eq(thing) + event.payload[:result].should_not be_nil + end + + it "is recorded for enabled?" do + thing = Flipper::Types::Boolean.new + gate = subject.gate_for(thing) + + subject.enabled?(thing) + + event = instrumenter.events.last + event.should_not be_nil + event.name.should eq('feature_operation.flipper') + event.payload[:feature_name].should eq(:search) + event.payload[:operation].should eq(:enabled?) + event.payload[:thing].should eq(thing) + event.payload[:result].should be_false + end + end + + describe "#state" do + context "fully on" do + before do + subject.enable + end + + it "returns :on" do + subject.state.should be(:on) + end + end + + context "fully off" do + before do + subject.disable + end + + it "returns :off" do + subject.state.should be(:off) + end + end + + context "partially on" do + before do + subject.enable Flipper::Types::PercentageOfRandom.new(5) + end + + it "returns :conditional" do + subject.state.should be(:conditional) + end + end + end + + describe "#description" do + context "fully on" do + before do + subject.enable + end + + it "returns enabled" do + subject.description.should eq('Enabled') + end + end + + context "fully off" do + before do + subject.disable + end + + it "returns disabled" do + subject.description.should eq('Disabled') + end + end + + context "partially on" do + before do + actor = Struct.new(:flipper_id).new(5) + subject.enable Flipper::Types::PercentageOfRandom.new(5) + subject.enable actor + end + + it "returns text" do + subject.description.should eq('Enabled for actors (5), 5% of the time') + end end end end