Skip to content

Commit d1b47e6

Browse files
committed
fixup: adding gherkin tests for in-process via file
Signed-off-by: Simon Schrottner <[email protected]>
1 parent 1e78ebe commit d1b47e6

14 files changed

+113
-444
lines changed
Lines changed: 17 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,33 @@
11
import typing
22

33
import pytest
4-
from pytest_bdd import given, parsers, then, when
5-
from tests.e2e.parsers import to_bool
4+
from testcontainers.core.container import DockerContainer
5+
from tests.e2e.flagd_container import FlagDContainer
6+
from tests.e2e.steps import * # noqa: F403
67

78
from openfeature import api
8-
from openfeature.client import OpenFeatureClient
99
from openfeature.contrib.provider.flagd import FlagdProvider
10-
from openfeature.contrib.provider.flagd.config import ResolverType
11-
from openfeature.evaluation_context import EvaluationContext
1210

1311
JsonPrimitive = typing.Union[str, bool, float, int]
1412

1513

16-
@pytest.fixture
17-
def evaluation_context() -> EvaluationContext:
18-
return EvaluationContext()
19-
20-
21-
@given("a flagd provider is set", target_fixture="client")
22-
def setup_provider(flag_file) -> OpenFeatureClient:
14+
@pytest.fixture(autouse=True, scope="package")
15+
def setup(request, port, image, resolver_type):
16+
container: DockerContainer = FlagDContainer(
17+
image=image,
18+
port=port,
19+
)
20+
# Setup code
21+
c = container.start()
2322
api.set_provider(
2423
FlagdProvider(
25-
resolver_type=ResolverType.IN_PROCESS,
26-
offline_flag_source_path=flag_file,
27-
offline_poll_interval_seconds=0.1,
24+
resolver_type=resolver_type,
25+
port=int(container.get_exposed_port(port)),
2826
)
2927
)
30-
return api.get_client()
31-
32-
33-
@when(
34-
parsers.cfparse(
35-
'a zero-value boolean flag with key "{key}" is evaluated with default value "{default:bool}"',
36-
extra_types={"bool": to_bool},
37-
),
38-
target_fixture="key_and_default",
39-
)
40-
@when(
41-
parsers.cfparse(
42-
'a zero-value string flag with key "{key}" is evaluated with default value "{default}"',
43-
),
44-
target_fixture="key_and_default",
45-
)
46-
@when(
47-
parsers.cfparse(
48-
'a string flag with key "{key}" is evaluated with default value "{default}"'
49-
),
50-
target_fixture="key_and_default",
51-
)
52-
@when(
53-
parsers.cfparse(
54-
'a zero-value integer flag with key "{key}" is evaluated with default value {default:d}',
55-
),
56-
target_fixture="key_and_default",
57-
)
58-
@when(
59-
parsers.cfparse(
60-
'an integer flag with key "{key}" is evaluated with default value {default:d}',
61-
),
62-
target_fixture="key_and_default",
63-
)
64-
@when(
65-
parsers.cfparse(
66-
'a zero-value float flag with key "{key}" is evaluated with default value {default:f}',
67-
),
68-
target_fixture="key_and_default",
69-
)
70-
def setup_key_and_default(
71-
key: str, default: JsonPrimitive
72-
) -> typing.Tuple[str, JsonPrimitive]:
73-
return (key, default)
74-
75-
76-
@when(
77-
parsers.cfparse(
78-
'a context containing a targeting key with value "{targeting_key}"'
79-
),
80-
)
81-
def assign_targeting_context(evaluation_context: EvaluationContext, targeting_key: str):
82-
"""a context containing a targeting key with value <targeting key>."""
83-
evaluation_context.targeting_key = targeting_key
84-
85-
86-
@when(
87-
parsers.cfparse('a context containing a key "{key}", with value "{value}"'),
88-
)
89-
@when(
90-
parsers.cfparse('a context containing a key "{key}", with value {value:d}'),
91-
)
92-
def update_context(
93-
evaluation_context: EvaluationContext, key: str, value: JsonPrimitive
94-
):
95-
"""a context containing a key and value."""
96-
evaluation_context.attributes[key] = value
97-
98-
99-
@when(
100-
parsers.cfparse(
101-
'a context containing a nested property with outer key "{outer}" and inner key "{inner}", with value "{value}"'
102-
),
103-
)
104-
@when(
105-
parsers.cfparse(
106-
'a context containing a nested property with outer key "{outer}" and inner key "{inner}", with value {value:d}'
107-
),
108-
)
109-
def update_context_nested(
110-
evaluation_context: EvaluationContext,
111-
outer: str,
112-
inner: str,
113-
value: typing.Union[str, int],
114-
):
115-
"""a context containing a nested property with outer key, and inner key, and value."""
116-
if outer not in evaluation_context.attributes:
117-
evaluation_context.attributes[outer] = {}
118-
evaluation_context.attributes[outer][inner] = value
119-
120-
121-
@then(
122-
parsers.cfparse(
123-
'the resolved boolean zero-value should be "{expected_value:bool}"',
124-
extra_types={"bool": to_bool},
125-
)
126-
)
127-
def assert_boolean_value(
128-
client: OpenFeatureClient,
129-
key_and_default: tuple,
130-
expected_value: bool,
131-
evaluation_context: EvaluationContext,
132-
):
133-
key, default = key_and_default
134-
evaluation_result = client.get_boolean_value(key, default, evaluation_context)
135-
assert evaluation_result == expected_value
136-
137-
138-
@then(
139-
parsers.cfparse(
140-
"the resolved integer zero-value should be {expected_value:d}",
141-
)
142-
)
143-
@then(parsers.cfparse("the returned value should be {expected_value:d}"))
144-
def assert_integer_value(
145-
client: OpenFeatureClient,
146-
key_and_default: tuple,
147-
expected_value: bool,
148-
evaluation_context: EvaluationContext,
149-
):
150-
key, default = key_and_default
151-
evaluation_result = client.get_integer_value(key, default, evaluation_context)
152-
assert evaluation_result == expected_value
153-
154-
155-
@then(
156-
parsers.cfparse(
157-
"the resolved float zero-value should be {expected_value:f}",
158-
)
159-
)
160-
def assert_float_value(
161-
client: OpenFeatureClient,
162-
key_and_default: tuple,
163-
expected_value: bool,
164-
evaluation_context: EvaluationContext,
165-
):
166-
key, default = key_and_default
167-
evaluation_result = client.get_float_value(key, default, evaluation_context)
168-
assert evaluation_result == expected_value
169-
170-
171-
@then(parsers.cfparse('the returned value should be "{expected_value}"'))
172-
def assert_string_value(
173-
client: OpenFeatureClient,
174-
key_and_default: tuple,
175-
expected_value: bool,
176-
evaluation_context: EvaluationContext,
177-
):
178-
key, default = key_and_default
179-
evaluation_result = client.get_string_value(key, default, evaluation_context)
180-
assert evaluation_result == expected_value
181-
182-
183-
@then(
184-
parsers.cfparse(
185-
'the resolved string zero-value should be ""',
186-
)
187-
)
188-
def assert_empty_string(
189-
client: OpenFeatureClient,
190-
key_and_default: tuple,
191-
evaluation_context: EvaluationContext,
192-
):
193-
key, default = key_and_default
194-
evaluation_result = client.get_string_value(key, default, evaluation_context)
195-
assert evaluation_result == ""
19628

29+
def fin():
30+
c.stop()
19731

198-
@then(parsers.cfparse('the returned reason should be "{reason}"'))
199-
def assert_reason(
200-
client: OpenFeatureClient,
201-
key_and_default: tuple,
202-
evaluation_context: EvaluationContext,
203-
reason: str,
204-
):
205-
"""the returned reason should be <reason>."""
206-
key, default = key_and_default
207-
evaluation_result = client.get_string_details(key, default, evaluation_context)
208-
assert evaluation_result.reason.value == reason
32+
# Teardown code
33+
request.addfinalizer(fin)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
def to_bool(s: str) -> bool:
22
return s.lower() == "true"
3+
4+
5+
def to_list(s: str) -> list:
6+
values = s.replace('"', "").split(",")
7+
return [s.strip() for s in values]

providers/openfeature-provider-flagd/tests/e2eGherkin/steps.py renamed to providers/openfeature-provider-flagd/tests/e2e/steps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import pytest
55
from asserts import assert_equal, assert_in, assert_not_equal, assert_true
66
from pytest_bdd import given, parsers, then, when
7-
from tests.e2eGherkin.parsers import to_bool, to_list
7+
from tests.e2e.parsers import to_bool, to_list
88

99
from openfeature import api
1010
from openfeature.client import OpenFeatureClient
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import json
2+
import os
3+
import tempfile
4+
from os import listdir
5+
6+
import pytest
7+
import yaml
8+
from asserts import assert_true
9+
from pytest_bdd import parsers, scenarios, then
10+
11+
from openfeature import api
12+
from openfeature.contrib.provider.flagd import FlagdProvider
13+
from openfeature.contrib.provider.flagd.config import ResolverType
14+
15+
KEY_EVALUATORS = "$evaluators"
16+
17+
KEY_FLAGS = "flags"
18+
19+
MERGED_FILE = "merged_file"
20+
21+
22+
@pytest.fixture(params=["json", "yaml"], scope="package")
23+
def file_name(request):
24+
extension = request.param
25+
result = {KEY_FLAGS: {}, KEY_EVALUATORS: {}}
26+
27+
path = "../../test-harness/flags/"
28+
if not os.path.isabs(path):
29+
path = os.path.abspath(os.path.join(os.path.dirname(__file__), path))
30+
31+
for f in listdir(path):
32+
with open(path + "/" + f, "rb") as infile:
33+
loaded_json = json.load(infile)
34+
result[KEY_FLAGS] = {**result[KEY_FLAGS], **loaded_json[KEY_FLAGS]}
35+
if loaded_json.get(KEY_EVALUATORS):
36+
result[KEY_EVALUATORS] = {
37+
**result[KEY_EVALUATORS],
38+
**loaded_json[KEY_EVALUATORS],
39+
}
40+
41+
# TODO: improve file generation with default test utilities
42+
with tempfile.NamedTemporaryFile(
43+
"w", delete=False, suffix="." + extension
44+
) as outfile:
45+
if extension == "json":
46+
json.dump(result, outfile)
47+
else:
48+
yaml.dump(result, outfile)
49+
50+
return outfile
51+
52+
53+
@pytest.fixture(autouse=True, scope="package")
54+
def setup(request, file_name):
55+
"""`file_name` tests"""
56+
api.set_provider(
57+
FlagdProvider(
58+
resolver_type=ResolverType.IN_PROCESS,
59+
offline_flag_source_path=file_name.name,
60+
)
61+
)
62+
63+
64+
@then(
65+
parsers.cfparse("the PROVIDER_CONFIGURATION_CHANGED handler must run"),
66+
)
67+
def provider_changed_was_executed():
68+
assert_true(True)
69+
# TODO: DELETE AFTER IMPLEMENTATION OF EVENTS FOR RPC
70+
71+
72+
@then(parsers.cfparse('the event details must indicate "{flag_name}" was altered'))
73+
def flag_was_changed():
74+
assert_true(True)
75+
# TODO: DELETE AFTER IMPLEMENTATION OF EVENTS FOR RPC
76+
77+
78+
scenarios(
79+
"../../test-harness/gherkin/flagd.feature",
80+
"../../test-harness/gherkin/flagd-json-evaluator.feature",
81+
"../../spec/specification/assets/gherkin/evaluation.feature",
82+
)

providers/openfeature-provider-flagd/tests/e2e/test_inprocess_custom_ops.py

Lines changed: 0 additions & 38 deletions
This file was deleted.

providers/openfeature-provider-flagd/tests/e2e/test_inprocess_edge_cases.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

providers/openfeature-provider-flagd/tests/e2e/test_inprocess_evaluator_reuse.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)