Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libs/client-sdk/src/bindings/c/sdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ LDClientSDK_TrackMetric(LDClientSDK sdk,

auto as_value = reinterpret_cast<Value*>(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);
}
Expand Down
37 changes: 37 additions & 0 deletions libs/client-sdk/tests/client_c_bindings_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
#include <launchdarkly/client_side/bindings/c/sdk.h>

#include <launchdarkly/bindings/c/context_builder.h>
#include <launchdarkly/bindings/c/value.h>

#include <launchdarkly/client_side/client.hpp>
#include <launchdarkly/client_side/data_source_status.hpp>
#include <launchdarkly/context_builder.hpp>

#include <chrono>

Expand All @@ -14,7 +17,7 @@
TEST(ClientBindings, MinimalInstantiation) {
LDClientConfigBuilder cfg_builder = LDClientConfigBuilder_New("sdk-123");

LDClientConfig config;

Check warning on line 20 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:20:20 [cppcoreguidelines-init-variables]

variable 'config' is not initialized
LDStatus status = LDClientConfigBuilder_Build(cfg_builder, &config);
ASSERT_TRUE(LDStatus_Ok(status));

Expand All @@ -33,7 +36,7 @@
}

void FlagListenerFunction(char const* flag_key,
LDValue new_value,

Check warning on line 39 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:39:27 [bugprone-easily-swappable-parameters]

2 adjacent parameters of 'FlagListenerFunction' of similar type ('LDValue') are easily swapped by mistake
LDValue old_value,
bool deleted,
void* user_data) {}
Expand All @@ -44,7 +47,7 @@
LDClientConfigBuilder cfg_builder = LDClientConfigBuilder_New("sdk-123");
LDClientConfigBuilder_Offline(cfg_builder, true);

LDClientConfig config;

Check warning on line 50 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:50:20 [cppcoreguidelines-init-variables]

variable 'config' is not initialized
LDStatus status = LDClientConfigBuilder_Build(cfg_builder, &config);
ASSERT_TRUE(LDStatus_Ok(status));

Expand All @@ -60,15 +63,15 @@
EXPECT_TRUE(success);

struct LDFlagListener listener {
reinterpret_cast<FlagChangedCallbackFn>(0x123),

Check warning on line 66 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:66:9 [cppcoreguidelines-pro-type-reinterpret-cast]

do not use reinterpret_cast
reinterpret_cast<void*>(0x456)

Check warning on line 67 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:67:13 [cppcoreguidelines-pro-type-reinterpret-cast]

do not use reinterpret_cast
};

LDFlagListener_Init(&listener);
ASSERT_EQ(listener.FlagChanged, nullptr);
ASSERT_EQ(listener.UserData, nullptr);

listener.UserData = const_cast<char*>("Potato");

Check warning on line 74 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:74:25 [cppcoreguidelines-pro-type-const-cast]

do not use const_cast
listener.FlagChanged = FlagListenerFunction;

LDListenerConnection connection =
Expand All @@ -90,7 +93,7 @@
LDClientConfigBuilder cfg_builder = LDClientConfigBuilder_New("sdk-123");
LDClientConfigBuilder_Offline(cfg_builder, true);

LDClientConfig config;

Check warning on line 96 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:96:20 [cppcoreguidelines-init-variables]

variable 'config' is not initialized
LDStatus status = LDClientConfigBuilder_Build(cfg_builder, &config);
ASSERT_TRUE(LDStatus_Ok(status));

Expand All @@ -102,15 +105,15 @@
LDClientSDK sdk = LDClientSDK_New(config, context);

struct LDDataSourceStatusListener listener {
reinterpret_cast<DataSourceStatusCallbackFn>(0x123),

Check warning on line 108 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:108:9 [cppcoreguidelines-pro-type-reinterpret-cast]

do not use reinterpret_cast
reinterpret_cast<void*>(0x456)

Check warning on line 109 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:109:13 [cppcoreguidelines-pro-type-reinterpret-cast]

do not use reinterpret_cast
};
LDDataSourceStatusListener_Init(&listener);

ASSERT_EQ(listener.StatusChanged, nullptr);
ASSERT_EQ(listener.UserData, nullptr);

listener.UserData = const_cast<char*>("Potato");

Check warning on line 116 in libs/client-sdk/tests/client_c_bindings_test.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

libs/client-sdk/tests/client_c_bindings_test.cpp:116:25 [cppcoreguidelines-pro-type-const-cast]

do not use const_cast
listener.StatusChanged = StatusListenerFunction;

LDListenerConnection connection =
Expand Down Expand Up @@ -219,3 +222,37 @@
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<LDClientSDK>(
static_cast<launchdarkly::client_side::Client*>(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);
}
4 changes: 2 additions & 2 deletions libs/server-sdk/src/bindings/c/sdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
51 changes: 51 additions & 0 deletions libs/server-sdk/tests/server_c_bindings_hooks_test.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#include "gtest/gtest.h"

#include <launchdarkly/server_side/bindings/c/config/builder.h>
Expand Down Expand Up @@ -263,6 +263,57 @@
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<HookCallTracker*>(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,
Expand Down
Loading