11#include < gtest/gtest.h>
22
3+ #include < launchdarkly/server_side/bindings/c/integrations/redis/redis_big_segment_store.h>
34#include < launchdarkly/server_side/bindings/c/integrations/redis/redis_source.h>
45
56#include < launchdarkly/bindings/c/context_builder.h>
1011
1112#include " prefixed_redis_client.hpp"
1213
14+ #include < chrono>
15+ #include < condition_variable>
16+ #include < mutex>
17+
1318using namespace launchdarkly ::data_model;
1419
1520TEST (RedisBindings, SourcePointerIsStoredOnSuccessfulCreation) {
@@ -91,8 +96,8 @@ TEST(RedisBindings, CanUseInSDKLazyLoadDataSource) {
9196
9297 std::unordered_map<std::string, launchdarkly::Value> values;
9398 LDValue_ObjectIter iter;
94- for (iter = LDValue_ObjectIter_New (all);
95- ! LDValue_ObjectIter_End (iter); LDValue_ObjectIter_Next (iter)) {
99+ for (iter = LDValue_ObjectIter_New (all); ! LDValue_ObjectIter_End (iter);
100+ LDValue_ObjectIter_Next (iter)) {
96101 char const * key = LDValue_ObjectIter_Key (iter);
97102 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
98103 auto value_ref = reinterpret_cast <launchdarkly::Value const * const >(
@@ -112,3 +117,100 @@ TEST(RedisBindings, CanUseInSDKLazyLoadDataSource) {
112117 LDContext_Free (context);
113118 LDServerSDK_Free (sdk);
114119}
120+
121+ TEST (RedisBindings, BigSegmentsStorePointerIsStoredOnSuccessfulCreation) {
122+ LDServerBigSegmentsRedisResult result;
123+ ASSERT_TRUE (LDServerBigSegmentsRedisStore_New (" tcp://localhost:1234" , " foo" ,
124+ &result));
125+ ASSERT_NE (result.store , nullptr );
126+ LDServerBigSegmentsRedisStore_Free (result.store );
127+ }
128+
129+ TEST (RedisBindings, BigSegmentsErrorMessageIsPropagatedOnFailure) {
130+ LDServerBigSegmentsRedisResult result;
131+ ASSERT_FALSE (
132+ LDServerBigSegmentsRedisStore_New (" totally not a URI" , " foo" , &result));
133+ ASSERT_STRNE (result.error_message , " " );
134+ }
135+
136+ TEST (RedisBindings, BigSegmentsStorePointerIsNullptrOnFailure) {
137+ LDServerBigSegmentsRedisResult result;
138+ ASSERT_FALSE (
139+ LDServerBigSegmentsRedisStore_New (" totally not a URI" , " foo" , &result));
140+ ASSERT_EQ (result.store , nullptr );
141+ }
142+
143+ // This is an end-to-end test that uses an actual Redis instance with
144+ // provisioned Big Segments metadata. The store is passed into the SDK's Big
145+ // Segments configuration, and the SDK's Big Segment store status listener is
146+ // used to verify that the store is reachable and reports available.
147+ TEST (RedisBindings, CanUseInSDKBigSegmentsConfig) {
148+ sw::redis::Redis redis (" tcp://localhost:6379" );
149+ redis.flushdb ();
150+
151+ // Set the store's sync timestamp so the poll reports available.
152+ auto const now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
153+ std::chrono::system_clock::now ().time_since_epoch ())
154+ .count ();
155+ redis.set (" testprefix:big_segments_synchronized_on" ,
156+ std::to_string (now_ms));
157+
158+ LDServerBigSegmentsRedisResult result;
159+ ASSERT_TRUE (LDServerBigSegmentsRedisStore_New (" tcp://localhost:6379" ,
160+ " testprefix" , &result));
161+
162+ LDServerBigSegmentsBuilder bs_builder = LDServerBigSegmentsBuilder_New (
163+ reinterpret_cast <LDServerBigSegmentStorePtr>(result.store ));
164+ LDServerBigSegmentsBuilder_StatusPollIntervalMs (bs_builder, 50 );
165+
166+ LDServerConfigBuilder cfg_builder = LDServerConfigBuilder_New (" sdk-123" );
167+ LDServerConfigBuilder_BigSegments (cfg_builder, bs_builder);
168+ LDServerConfigBuilder_Offline (cfg_builder, true );
169+
170+ LDServerConfig config;
171+ LDStatus status = LDServerConfigBuilder_Build (cfg_builder, &config);
172+ ASSERT_TRUE (LDStatus_Ok (status));
173+
174+ LDServerSDK sdk = LDServerSDK_New (config);
175+
176+ std::mutex mu;
177+ std::condition_variable cv;
178+ bool available = false ;
179+
180+ struct ListenerCtx {
181+ std::mutex* mu;
182+ std::condition_variable* cv;
183+ bool * available;
184+ };
185+ ListenerCtx ctx{&mu, &cv, &available};
186+
187+ struct LDServerBigSegmentStoreStatusListener listener{};
188+ LDServerBigSegmentStoreStatusListener_Init (&listener);
189+ listener.UserData = &ctx;
190+ listener.StatusChanged =
191+ +[](LDServerBigSegmentStoreStatus s, void * user_data) {
192+ auto * c = static_cast <ListenerCtx*>(user_data);
193+ {
194+ std::lock_guard<std::mutex> lk (*c->mu );
195+ *c->available = LDServerBigSegmentStoreStatus_Available (s);
196+ }
197+ c->cv ->notify_all ();
198+ };
199+
200+ LDListenerConnection connection =
201+ LDServerSDK_BigSegmentStoreStatus_OnStatusChange (sdk, listener);
202+ ASSERT_NE (connection, nullptr );
203+
204+ LDServerSDK_Start (sdk, LD_NONBLOCKING , nullptr );
205+
206+ {
207+ std::unique_lock<std::mutex> lk (mu);
208+ cv.wait_for (lk, std::chrono::seconds (3 ), [&] { return available; });
209+ }
210+
211+ EXPECT_TRUE (available);
212+
213+ LDListenerConnection_Disconnect (connection);
214+ LDListenerConnection_Free (connection);
215+ LDServerSDK_Free (sdk);
216+ }
0 commit comments