Skip to content

Commit 4ebebf8

Browse files
committed
Add grpc_watcher unit tests
Signed-off-by: Konvalinka <[email protected]>
1 parent bee7cf8 commit 4ebebf8

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import threading
2+
import time
3+
import unittest
4+
from unittest.mock import MagicMock, Mock, patch
5+
6+
from google.protobuf.json_format import MessageToDict
7+
from google.protobuf.struct_pb2 import Struct
8+
from grpc import Channel
9+
10+
from openfeature.contrib.provider.flagd.config import Config
11+
from openfeature.contrib.provider.flagd.resolvers.process.connector.grpc_watcher import (
12+
GrpcWatcher,
13+
)
14+
from openfeature.contrib.provider.flagd.resolvers.process.flags import FlagStore
15+
from openfeature.event import ProviderEventDetails
16+
from openfeature.schemas.protobuf.flagd.sync.v1.sync_pb2 import (
17+
GetMetadataResponse,
18+
SyncFlagsResponse,
19+
)
20+
from openfeature.schemas.protobuf.flagd.sync.v1.sync_pb2_grpc import FlagSyncServiceStub
21+
22+
23+
class TestGrpcWatcher(unittest.TestCase):
24+
def setUp(self):
25+
config = Mock(spec=Config)
26+
config.retry_backoff_ms = 1000
27+
config.retry_backoff_max_ms = 5000
28+
config.retry_grace_period = 5
29+
config.stream_deadline_ms = 1000
30+
config.deadline_ms = 5000
31+
config.selector = None
32+
config.provider_id = None
33+
config.tls = False
34+
config.cert_path = None
35+
config.channel_credentials = None
36+
config.host = "localhost"
37+
config.port = 5000
38+
config.sync_metadata_disabled = False
39+
40+
flag_store = Mock(spec=FlagStore)
41+
flag_store.update.return_value = None
42+
self.emit_provider_ready = Mock()
43+
emit_provider_error = Mock()
44+
emit_provider_stale = Mock()
45+
channel = Mock(spec=Channel)
46+
47+
with patch(
48+
"openfeature.contrib.provider.flagd.resolvers.process.connector.grpc_watcher.GrpcWatcher._generate_channel",
49+
return_value=channel,
50+
):
51+
self.grpc_watcher = GrpcWatcher(
52+
config=config,
53+
flag_store=flag_store,
54+
emit_provider_ready=self.emit_provider_ready,
55+
emit_provider_error=emit_provider_error,
56+
emit_provider_stale=emit_provider_stale,
57+
)
58+
self.mock_stub = MagicMock(spec=FlagSyncServiceStub)
59+
self.mock_metadata = GetMetadataResponse(metadata={"attribute": "value1"})
60+
self.mock_stub.GetMetadata = Mock(return_value=self.mock_metadata)
61+
self.grpc_watcher.stub = self.mock_stub
62+
self.grpc_watcher.active = True
63+
self.shutdown_thread = lambda: threading.Thread(
64+
target=self.shutdown_after_x_seconds
65+
)
66+
67+
def shutdown_after_x_seconds(self, seconds=1):
68+
time.sleep(seconds)
69+
self.grpc_watcher.shutdown()
70+
71+
def test_listen_with_sync_metadata_and_sync_context(self):
72+
sync_context = Struct()
73+
sync_context.update({"attribute": "value"})
74+
mock_stream_with_sync_context = iter(
75+
[
76+
SyncFlagsResponse(
77+
flag_configuration='{"flag_key": "flag_value"}',
78+
sync_context=sync_context,
79+
),
80+
]
81+
)
82+
self.mock_stub.SyncFlags = Mock(return_value=mock_stream_with_sync_context)
83+
84+
self.shutdown_thread().start()
85+
86+
self.grpc_watcher.listen()
87+
88+
self.emit_provider_ready.assert_called_once_with(
89+
ProviderEventDetails(message="gRPC sync connection established"),
90+
MessageToDict(sync_context),
91+
)
92+
93+
def test_listen_with_sync_metadata_only(self):
94+
mock_stream_no_sync_context = iter(
95+
[
96+
SyncFlagsResponse(flag_configuration='{"flag_key": "flag_value"}'),
97+
]
98+
)
99+
self.mock_stub.SyncFlags = Mock(return_value=mock_stream_no_sync_context)
100+
101+
self.shutdown_thread().start()
102+
103+
self.grpc_watcher.listen()
104+
105+
self.emit_provider_ready.assert_called_once_with(
106+
ProviderEventDetails(message="gRPC sync connection established"),
107+
MessageToDict(self.mock_metadata.metadata),
108+
)
109+
110+
def test_listen_with_sync_metadata_disabled_in_config(self):
111+
self.grpc_watcher.config.sync_metadata_disabled = True
112+
mock_stream_no_sync_context = iter(
113+
[
114+
SyncFlagsResponse(flag_configuration='{"flag_key": "flag_value"}'),
115+
]
116+
)
117+
self.mock_stub.SyncFlags = Mock(return_value=mock_stream_no_sync_context)
118+
self.shutdown_thread().start()
119+
120+
self.grpc_watcher.listen()
121+
122+
self.mock_stub.GetMetadata.assert_not_called()
123+
124+
self.emit_provider_ready.assert_called_once_with(
125+
ProviderEventDetails(message="gRPC sync connection established"), {}
126+
)

0 commit comments

Comments
 (0)