Class: LaunchDarkly::Integrations::TestData

Inherits:
Object
  • Object
show all
Defined in:
lib/ldclient-rb/integrations/test_data.rb,
lib/ldclient-rb/integrations/test_data/flag_builder.rb

Overview

A mechanism for providing dynamically updatable feature flag state in a simplified form to an SDK client in test scenarios.

Unlike FileData, this mechanism does not use any external resources. It provides only the data that the application has put into it using the #update method.

The above example uses a simple boolean flag, but more complex configurations are possible using the methods of the FlagBuilder that is returned by #flag. FlagBuilder supports many of the ways a flag can be configured on the LaunchDarkly dashboard, but does not currently support 1. rule operators other than “in” and “not in”, or 2. percentage rollouts.

If the same ‘TestData` instance is used to configure multiple `LDClient` instances, any changes made to the data will propagate to all of the `LDClient`s.

Examples:

td = LaunchDarkly::Integrations::TestData.data_source
td.update(td.flag("flag-key-1").variation_for_all(true))
config = LaunchDarkly::Config.new(data_source: td)
client = LaunchDarkly::LDClient.new('sdkKey', config)
# flags can be updated at any time:
td.update(td.flag("flag-key-2")
            .variation_for_key("user", some-user-key", true)
            .fallthrough_variation(false))

Since:

  • 6.3.0

Defined Under Namespace

Classes: FlagBuilder

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeTestData

Returns a new instance of TestData.

Since:

  • 6.3.0



46
47
48
49
50
51
52
53
# File 'lib/ldclient-rb/integrations/test_data.rb', line 46

def initialize
  @flag_builders = Hash.new
  @current_flags = Hash.new
  @current_segments = Hash.new
  @instances = Array.new
  @instances_lock = Concurrent::ReadWriteLock.new
  @lock = Concurrent::ReadWriteLock.new
end

Class Method Details

.data_sourceTestData

Creates a new instance of the test data source.

Returns:

  • (TestData)

    a new configurable test data source

Since:

  • 6.3.0



41
42
43
# File 'lib/ldclient-rb/integrations/test_data.rb', line 41

def self.data_source
  self.new
end

Instance Method Details

#arityObject

Called internally by the SDK to determine what arguments to pass to call You do not need to call this method.

Since:

  • 6.3.0



60
61
62
# File 'lib/ldclient-rb/integrations/test_data.rb', line 60

def arity
  2
end

#call(_, config) ⇒ Object

Called internally by the SDK to associate this test data source with an LDClient instance. You do not need to call this method.

Since:

  • 6.3.0



69
70
71
72
73
# File 'lib/ldclient-rb/integrations/test_data.rb', line 69

def call(_, config)
  impl = LaunchDarkly::Impl::Integrations::TestData::TestDataSource.new(config.feature_store, self)
  @instances_lock.with_write_lock { @instances.push(impl) }
  impl
end

#closed_instance(instance) ⇒ Object

Since:

  • 6.3.0



208
209
210
# File 'lib/ldclient-rb/integrations/test_data.rb', line 208

def closed_instance(instance)
  @instances_lock.with_write_lock { @instances.delete(instance) }
end

#flag(key) ⇒ FlagBuilder

Creates or copies a FlagBuilder for building a test flag configuration.

If this flag key has already been defined in this ‘TestData` instance, then the builder starts with the same configuration that was last provided for this flag.

Otherwise, it starts with a new default configuration in which the flag has ‘true` and `false` variations, is `true` for all contexts when targeting is turned on and `false` otherwise, and currently has targeting turned on. You can change any of those properties, and provide more complex behavior, using the FlagBuilder methods.

Once you have set the desired configuration, pass the builder to #update.

Parameters:

  • key (String)

    the flag key

Returns:

Since:

  • 6.3.0



91
92
93
94
95
96
97
98
# File 'lib/ldclient-rb/integrations/test_data.rb', line 91

def flag(key)
  existing_builder = @lock.with_read_lock { @flag_builders[key] }
  if existing_builder.nil?
    FlagBuilder.new(key).boolean_flag
  else
    existing_builder.clone
  end
end

#make_init_dataObject

Since:

  • 6.3.0



198
199
200
201
202
203
204
205
# File 'lib/ldclient-rb/integrations/test_data.rb', line 198

def make_init_data
  @lock.with_read_lock do
    {
      FEATURES => @current_flags.clone,
      SEGMENTS => @current_segments.clone,
    }
  end
end

#update(flag_builder) ⇒ TestData

Updates the test data with the specified flag configuration.

This has the same effect as if a flag were added or modified on the LaunchDarkly dashboard. It immediately propagates the flag change to any ‘LDClient` instance(s) that you have already configured to use this `TestData`. If no `LDClient` has been started yet, it simply adds this flag to the test data which will be provided to any `LDClient` that you subsequently configure.

Any subsequent changes to this FlagBuilder instance do not affect the test data, unless you call #update again.

Parameters:

  • flag_builder (FlagBuilder)

    a flag configuration builder

Returns:

Since:

  • 6.3.0



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/ldclient-rb/integrations/test_data.rb', line 115

def update(flag_builder)
  new_flag = nil
  @lock.with_write_lock do
    @flag_builders[flag_builder.key] = flag_builder
    version = 0
    flag_key = flag_builder.key.to_sym
    if @current_flags[flag_key]
      version = @current_flags[flag_key][:version]
    end
    new_flag = Impl::Model.deserialize(FEATURES, flag_builder.build(version+1))
    @current_flags[flag_key] = new_flag
  end
  update_item(FEATURES, new_flag)
  self
end

#use_preconfigured_flag(flag) ⇒ TestData

Copies a full feature flag data model object into the test data.

It immediately propagates the flag change to any ‘LDClient` instance(s) that you have already configured to use this `TestData`. If no `LDClient` has been started yet, it simply adds this flag to the test data which will be provided to any LDClient that you subsequently configure.

Use this method if you need to use advanced flag configuration properties that are not supported by the simplified FlagBuilder API. Otherwise it is recommended to use the regular #flag/#update mechanism to avoid dependencies on details of the data model.

You cannot make incremental changes with #flag/#update to a flag that has been added in this way; you can only replace it with an entirely new flag configuration.

Parameters:

  • flag (Hash)

    the flag configuration

Returns:

Since:

  • 6.3.0



149
150
151
# File 'lib/ldclient-rb/integrations/test_data.rb', line 149

def use_preconfigured_flag(flag)
  use_preconfigured_item(FEATURES, flag, @current_flags)
end

#use_preconfigured_segment(segment) ⇒ TestData

Copies a full segment data model object into the test data.

It immediately propagates the change to any ‘LDClient` instance(s) that you have already configured to use this `TestData`. If no `LDClient` has been started yet, it simply adds this segment to the test data which will be provided to any LDClient that you subsequently configure.

This method is currently the only way to inject segment data, since there is no builder API for segments. It is mainly intended for the SDK’s own tests of segment functionality, since application tests that need to produce a desired evaluation state could do so more easily by just setting flag values.

Parameters:

  • segment (Hash)

    the segment configuration

Returns:

Since:

  • 6.3.0



169
170
171
# File 'lib/ldclient-rb/integrations/test_data.rb', line 169

def use_preconfigured_segment(segment)
  use_preconfigured_item(SEGMENTS, segment, @current_segments)
end