Skip to content

Commit ccb72da

Browse files
cataphractdmehala
andauthored
fix: bugs in Remote Configuration payload construction (#151)
* Fix bugs in remote config * update remote configuration - Add and rework remote configuration tests. - Rework when client state are updated. * fix test --------- Co-authored-by: Damien Mehala <[email protected]>
1 parent 3e0244f commit ccb72da

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

src/datadog/remote_config/remote_config.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,12 @@ nlohmann::json Manager::make_request_payload() {
154154
nlohmann::json cached_file = {
155155
{"path", config.path},
156156
{"length", config.content.size()},
157-
{"hashes", {{"algorithm", "sha256"}, {"hash", config.hash}}}};
157+
{"hashes", {{{"algorithm", "sha256"}, {"hash", config.hash}}}}};
158158

159159
cached_target_files.emplace_back(std::move(cached_file));
160160
}
161161

162-
j["cached_target"] = cached_target_files;
162+
j["cached_target_files"] = cached_target_files;
163163
j["client"]["state"]["config_states"] = config_states;
164164
}
165165

@@ -173,10 +173,6 @@ void Manager::process_response(const nlohmann::json& json) {
173173
const auto targets = nlohmann::json::parse(
174174
base64_decode(json.at("targets").get<StringView>()));
175175

176-
state_.targets_version = targets.at("/signed/version"_json_pointer);
177-
state_.opaque_backend_state =
178-
targets.at("/signed/custom/opaque_backend_state"_json_pointer);
179-
180176
const auto client_configs_it = json.find("client_configs");
181177

182178
// `client_configs` is absent => remove previously applied configuration if
@@ -196,6 +192,11 @@ void Manager::process_response(const nlohmann::json& json) {
196192
for (const auto& listener : listeners_) {
197193
listener->on_post_process();
198194
}
195+
196+
state_.targets_version =
197+
targets.at("/signed/version"_json_pointer).get<std::uint64_t>();
198+
state_.opaque_backend_state =
199+
targets.at("/signed/custom/opaque_backend_state"_json_pointer);
199200
return;
200201
}
201202

@@ -283,6 +284,10 @@ void Manager::process_response(const nlohmann::json& json) {
283284
for (const auto& listener : listeners_) {
284285
listener->on_post_process();
285286
}
287+
state_.targets_version =
288+
targets.at("/signed/version"_json_pointer).get<std::uint64_t>();
289+
state_.opaque_backend_state =
290+
targets.at("/signed/custom/opaque_backend_state"_json_pointer);
286291
} catch (const nlohmann::json::exception& json_exception) {
287292
std::string reason = "Failed to parse the response: ";
288293
reason += json_exception.what();

test/remote_config/test_remote_config.cpp

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <algorithm>
2+
13
#include "catch.hpp"
24
#include "datadog/json.hpp"
35
#include "datadog/remote_config/remote_config.h"
@@ -170,6 +172,12 @@ REMOTE_CONFIG_TEST("response processing") {
170172
"client_configs": ["employee/APM_TRACING/valid_conf_path/config"],
171173
"target_files": [{"path": "employee/APM_TRACING/valid_conf_path/config", "raw": "eyJmb28iOiAiYmFyIn0="}]
172174
})",
175+
/// invalid configuration path
176+
R"({
177+
"targets": "eyJzaWduZWQiOiB7InZlcnNpb24iOiAyLCAidGFyZ2V0cyI6IHsiZW1wbG95ZWUvQVBNX1RSQUNJTkcvdmFsaWRfY29uZl9wYXRoL2NvbmZpZyI6IHt9LCAiYmFyIjoge319LCJjdXN0b20iOiB7Im9wYXF1ZV9iYWNrZW5kX3N0YXRlIjogIjE1In19fQ==",
178+
"client_configs": ["foo"],
179+
"target_files": [{"path": "foo", "raw": "eyJmb28iOiAiYmFyIn0="}]
180+
})",
173181
}));
174182
// clang-format on
175183

@@ -184,10 +192,15 @@ REMOTE_CONFIG_TEST("response processing") {
184192

185193
rc.process_response(response_json);
186194

187-
// Next payload should contains an error.
195+
// Next payload should contain an error.
188196
const auto payload = rc.make_request_payload();
189197
CHECK(payload.contains("/client/state/has_error"_json_pointer) == true);
190198
CHECK(payload.contains("/client/state/error"_json_pointer) == true);
199+
200+
// `targets_version` and `backend_client_state` should not have been
201+
// updated.
202+
CHECK(payload["client"]["state"]["targets_version"] == 0);
203+
CHECK(payload["client"]["state"]["backend_client_state"] == "");
191204
}
192205

193206
SECTION("update dispatch") {
@@ -247,8 +260,22 @@ REMOTE_CONFIG_TEST("response processing") {
247260
CHECK(agent_listener->count_on_revert == 0);
248261
CHECK(agent_listener->count_on_post_process == 1);
249262

250-
SECTION("config states are reported on next payload") {
263+
SECTION("next request payload is correctly populated") {
251264
const auto payload = rc.make_request_payload();
265+
266+
// Verify client state is reported
267+
REQUIRE(payload.contains("/client/state"_json_pointer) == true);
268+
const auto& client_state = payload.at("/client/state"_json_pointer);
269+
CHECK(client_state.at("targets_version") == 66204320);
270+
CHECK(
271+
client_state.at("backend_client_state") ==
272+
"eyJ2ZXJzaW9uIjoyLCJzdGF0ZSI6eyJmaWxlX2hhc2hlcyI6eyJkYXRhZG9nLzEwMDAx"
273+
"MjU4NDAvQVBNX1RSQUNJTkcvODI3ZWFjZjhkYmMzYWIxNDM0ZDMyMWNiODFkZmJmN2Fm"
274+
"ZTY1NGE0YjYxMTFjZjE2NjBiNzFjY2Y4OTc4MTkzOC8yOTA4NmJkYmU1MDZlNjhiNTBm"
275+
"MzA1NTgyM2EzZGE1Y2UwNTI4ZjE2NDBkNTJjZjg4NjE4MTZhYWE5ZmNlYWY0IjpbIm9Y"
276+
"ZDJpeUMzeC9oRWsxeXVhY1hGN1lqcXJpTk9BWUtuZzFtWE01NVZKTHc9Il19fX0=");
277+
278+
// Verify config states are reported
252279
REQUIRE(payload.contains("/client/state/config_states"_json_pointer) ==
253280
true);
254281

@@ -268,6 +295,31 @@ REMOTE_CONFIG_TEST("response processing") {
268295
CHECK(!config_state.contains("apply_error"));
269296
}
270297
}
298+
299+
// Verify `cached_target_files` is reported
300+
REQUIRE(payload.contains("/cached_target_files"_json_pointer) == true);
301+
auto cached_target_files = payload["cached_target_files"];
302+
REQUIRE(cached_target_files.is_array());
303+
REQUIRE(cached_target_files.size() == 3);
304+
305+
std::sort(cached_target_files.begin(), cached_target_files.end(),
306+
[](const auto& a, const auto& b) {
307+
return a.at("path").template get<std::string_view>() <
308+
b.at("path").template get<std::string_view>();
309+
});
310+
311+
const auto ctf = cached_target_files.at(0);
312+
CHECK(ctf.at("path").get<std::string_view>() ==
313+
"employee/AGENT_CONFIG/test_rc_update/flare_conf");
314+
CHECK(ctf.at("length").get<std::uint64_t>() == 381UL);
315+
316+
auto hashes = ctf.at("hashes");
317+
REQUIRE(hashes.is_array());
318+
REQUIRE(hashes.size() == 1);
319+
320+
const auto h = hashes.at(0);
321+
CHECK(h.at("algorithm").get<std::string_view>() == "sha256");
322+
CHECK(h.at("hash").get<std::string_view>().size() == 64U);
271323
}
272324

273325
SECTION("same config update should not trigger listeners") {

0 commit comments

Comments
 (0)