1+ #include " openfeature/global_context_manager.h"
2+
3+ #include < gtest/gtest.h>
4+
5+ #include < atomic>
6+ #include < thread>
7+ #include < vector>
8+
9+ #include " openfeature/evaluation_context.h"
10+
11+ using namespace openfeature ;
12+
13+ class GlobalContextManagerTest : public ::testing::Test {
14+ protected:
15+ // Reset to a clean state before every test.
16+ void SetUp () override {
17+ GlobalContextManager::GetInstance ().SetGlobalEvaluationContext (
18+ EvaluationContext{});
19+ }
20+ };
21+
22+ TEST_F (GlobalContextManagerTest, ReturnsSameInstance) {
23+ GlobalContextManager& instance1 = GlobalContextManager::GetInstance ();
24+ GlobalContextManager& instance2 = GlobalContextManager::GetInstance ();
25+
26+ EXPECT_EQ (&instance1, &instance2);
27+ }
28+
29+ TEST_F (GlobalContextManagerTest, SetAndGetContext) {
30+ GlobalContextManager& manager = GlobalContextManager::GetInstance ();
31+ EvaluationContext input_ctx;
32+
33+ EXPECT_NO_THROW (manager.SetGlobalEvaluationContext (input_ctx));
34+
35+ EvaluationContext output_ctx = manager.GetGlobalEvaluationContext ();
36+ EXPECT_NO_THROW (output_ctx = manager.GetGlobalEvaluationContext ());
37+
38+ // NOTE: Since EvaluationContext is currently an empty class,
39+ // we cannot assert EQ or check member values.
40+ // Currently, the test simply proves the API calls succeed and copy semantics
41+ // work.
42+
43+ // TODO: Add assertions.
44+ }
45+
46+ TEST_F (GlobalContextManagerTest, ThreadSafetyStressTest) {
47+ GlobalContextManager& manager = GlobalContextManager::GetInstance ();
48+ std::atomic<bool > stop{false };
49+
50+ // Writer Thread: Continuously updates the context.
51+ std::thread writer ([&]() {
52+ while (!stop) {
53+ EvaluationContext ctx;
54+ // In a real scenario, we would populate ctx with different data here.
55+ manager.SetGlobalEvaluationContext (ctx);
56+ std::this_thread::sleep_for (std::chrono::milliseconds (1 ));
57+ }
58+ });
59+
60+ // Reader Threads: Continuously read the context.
61+ std::vector<std::thread> readers;
62+ for (int i = 0 ; i < 10 ; ++i) {
63+ readers.emplace_back ([&]() {
64+ while (!stop) {
65+ // Just calling the getter to ensure locks work and no race conditions
66+ // occur resulting in a crash (segfault).
67+ EvaluationContext ctx = manager.GetGlobalEvaluationContext ();
68+
69+ // Prevent optimization from removing the call.
70+ volatile size_t size = sizeof (ctx);
71+ (void )size;
72+ }
73+ });
74+ }
75+
76+ // Let the chaos run for a short duration.
77+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
78+
79+ stop = true ;
80+ writer.join ();
81+ for (auto & t : readers) {
82+ t.join ();
83+ }
84+ }
85+
86+ int main (int argc, char ** argv) {
87+ testing::InitGoogleTest (&argc, argv);
88+ return RUN_ALL_TESTS ();
89+ }
0 commit comments