diff --git a/libs/client-sdk/src/bindings/c/sdk.cpp b/libs/client-sdk/src/bindings/c/sdk.cpp index 078a4ba55..5f733dab1 100644 --- a/libs/client-sdk/src/bindings/c/sdk.cpp +++ b/libs/client-sdk/src/bindings/c/sdk.cpp @@ -119,7 +119,7 @@ LDClientSDK_TrackMetric(LDClientSDK sdk, auto as_value = reinterpret_cast(value); - TO_SDK(sdk)->Track(event_name, metric_value, std::move(*as_value)); + TO_SDK(sdk)->Track(event_name, std::move(*as_value), metric_value); LDValue_Free(value); } diff --git a/libs/client-sdk/tests/client_c_bindings_test.cpp b/libs/client-sdk/tests/client_c_bindings_test.cpp index ac8f9ec73..117154d41 100644 --- a/libs/client-sdk/tests/client_c_bindings_test.cpp +++ b/libs/client-sdk/tests/client_c_bindings_test.cpp @@ -4,8 +4,11 @@ #include #include +#include +#include #include +#include #include @@ -219,3 +222,37 @@ TEST(ClientBindings, TestDataSourceStatusStateName) { LD_DATASOURCESTATUS_STATE_UNUSED_MAXVALUE, "unknown"), "unknown"); } + +// Records the data and the metric value of a track call. The C API handle is +// a pointer to a Client, so the C API calls this override. +class TrackRecordingClient : public launchdarkly::client_side::Client { + public: + using Client::Client; + using Client::Track; + + void Track(std::string event_name, + launchdarkly::Value data, + double metric_value) override { + data_ = std::move(data); + metric_value_ = metric_value; + } + + launchdarkly::Value data_; + double metric_value_ = 0.0; +}; + +TEST(ClientBindings, TrackMetricPassesDataAndMetricValue) { + auto* client = new TrackRecordingClient( + launchdarkly::client_side::ConfigBuilder("sdk-123").Build().value(), + launchdarkly::ContextBuilder().Kind("cat", "shadow").Build()); + auto sdk = reinterpret_cast( + static_cast(client)); + + LDClientSDK_TrackMetric(sdk, "test-event", 42.5, + LDValue_NewString("my-data")); + + EXPECT_EQ(client->data_, launchdarkly::Value("my-data")); + EXPECT_EQ(client->metric_value_, 42.5); + + LDClientSDK_Free(sdk); +} diff --git a/libs/server-sdk/src/bindings/c/sdk.cpp b/libs/server-sdk/src/bindings/c/sdk.cpp index 5290aa42f..14aa469e8 100644 --- a/libs/server-sdk/src/bindings/c/sdk.cpp +++ b/libs/server-sdk/src/bindings/c/sdk.cpp @@ -136,8 +136,8 @@ LDServerSDK_TrackMetric(LDServerSDK sdk, Value* as_value = TO_VALUE(value); - TO_SDK(sdk)->Track(*TO_CONTEXT(context), event_name, metric_value, - std::move(*as_value)); + TO_SDK(sdk)->Track(*TO_CONTEXT(context), event_name, std::move(*as_value), + metric_value); LDValue_Free(value); } diff --git a/libs/server-sdk/tests/server_c_bindings_hooks_test.cpp b/libs/server-sdk/tests/server_c_bindings_hooks_test.cpp index c53dc2ee5..52becb403 100644 --- a/libs/server-sdk/tests/server_c_bindings_hooks_test.cpp +++ b/libs/server-sdk/tests/server_c_bindings_hooks_test.cpp @@ -263,6 +263,57 @@ TEST(ServerCBindingsHooksTest, TrackSeriesContextAccessors) { LDServerSDK_Free(client); } +// Hook that records the string data and the metric value of a track call +static void TrackValues_AfterTrack(LDServerSDKTrackSeriesContext track_context, + void* user_data) { + auto* tracker = static_cast(user_data); + + LDValue data_value = nullptr; + if (LDTrackSeriesContext_Data(track_context, &data_value) && + LDValue_Type(data_value) == LDValueType_String) { + tracker->calls.push_back(std::string("data:") + + LDValue_GetString(data_value)); + } + + double metric_value = 0.0; + if (LDTrackSeriesContext_MetricValue(track_context, &metric_value)) { + tracker->calls.push_back("metric:" + std::to_string(metric_value)); + } +} + +TEST(ServerCBindingsHooksTest, TrackMetricPassesDataAndMetricValue) { + HookCallTracker tracker; + + struct LDServerSDKHook hook; + LDServerSDKHook_Init(&hook); + hook.Name = "TrackValuesHook"; + hook.AfterTrack = TrackValues_AfterTrack; + hook.UserData = &tracker; + + auto config_builder = LDServerConfigBuilder_New("sdk-key"); + LDServerConfigBuilder_Hooks(config_builder, hook); + LDServerConfigBuilder_Events_Enabled(config_builder, false); + + LDServerConfig config = nullptr; + LDServerConfigBuilder_Build(config_builder, &config); + auto client = LDServerSDK_New(config); + + auto context_builder = LDContextBuilder_New(); + LDContextBuilder_AddKind(context_builder, "user", "user-key"); + auto context = LDContextBuilder_Build(context_builder); + + LDServerSDK_TrackMetric(client, context, "test-event", 42.5, + LDValue_NewString("my-data")); + + // The hook sees the data as the data, and the metric as the metric + ASSERT_EQ(tracker.calls.size(), 2); + EXPECT_EQ(tracker.calls[0], "data:my-data"); + EXPECT_EQ(tracker.calls[1], "metric:42.500000"); + + LDContext_Free(context); + LDServerSDK_Free(client); +} + // Hook that passes data between stages using EvaluationSeriesData static LDServerSDKEvaluationSeriesData DataPassing_BeforeEvaluation( LDServerSDKEvaluationSeriesContext series_context,