-
Notifications
You must be signed in to change notification settings - Fork 47
Description
Is your feature request related to a problem? Please describe.
We have very many feature flags in our codebase, many of which are permanent for partial availability reasons.
We'd like our devs' tests to be initialized with a known-good state of those feature flags that we'd store on disk and then use the TestData
API to override those values in their tests.
Describe the solution you'd like
It'd be really nice for Files
and TestData
to have a way to cross through them.
Something like:
feature_store: FeatureStore = Files.load_from_file('/path/to/flagdata.json');
td = TestData(feature_store)
td.update(td.flag(...))
Describe alternatives you've considered
Currently, we try to not know much of anything about the schema of the flag data on disk from a dump of https://app.launchdarkly.com/sdk/latest-all
We have a subclass of TestData
that takes a FeatureStore
argument, and overrides _make_init_data
to use the FeatureStore
's values as the initial values in _TestDataSource
's FeatureStore
(with some jiggering of version
). That could probably be made into how TestData
operates if created with a FeatureStore
.
However, getting the FeatureStore
to pass into TestData
filled with data is grody because there's no public way to turn file data into a FeatureStore directly without knowing details about the schema of the flag data.
One horrible hack imagined was creating a Config
with an InMemoryFeatureStore
as feature_store
and a Files.new_data_source()
as update_processor_class
, passing that Config
to an LDClient
, and waiting for the LDClient
to initialize. Then, using the contents of InMemoryFeatureStore
as the initial FeatureStore
our subclass uses and throwing away that Files
-y LDClient
.
Something like:
feature_store = InMemoryFeatureStore()
data_source_factory = Files.new_data_source(paths=["flagdata.json"], auto_update=False)
files_ldclient = LDClient(Config(sdk_key='sdk-fake', update_processor_class=data_source_factory, send_events=False, feature_store=feature_store)
td = OurTestData(feature_store) # See "Additional context"
Additional context
The subclass we wrote:
class OurTestData(TestData):
def __init__(self, initial_feature_store: Optional[FeatureStore]):
self.initial_feature_store = initial_feature_store
super().__init__()
def _make_init_data(self) -> dict:
features = {}
if self.initial_feature_store:
features = self.initial_feature_store.all(FEATURES, lambda x: x)
for k, v in self._current_flags.items():
initial_v = features.get(k, None)
if initial_v:
v['version'] = initial_v['version']
features[k] = v
return {FEATURES: features}