Skip to content

Commit 610a390

Browse files
RahulHereRahulHere
authored andcommitted
Resolve three failing unit tests (#194)
Fixes FileConfigSourceEnhancedTest, test_logger_registry, and FilterChainEventHubTest that were failing due to various issues. Changes: - Fix LoggerRegistry constructor to use LogLevel::Info (was Warning) - Fix thread safety data race in FilterChainEventHubTest by adding mutex protection for shared vector access - Convert printf-style format strings (%s, %d, %zu) to fmt-style ({}) in file_config_source.cc to fix "invalid format string" exceptions
1 parent 250b20e commit 610a390

3 files changed

Lines changed: 67 additions & 62 deletions

File tree

src/config/file_config_source.cc

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ class FileConfigSource : public ConfigSource {
268268
int priority,
269269
const Options& opts = Options{})
270270
: name_(name), priority_(priority), options_(opts) {
271-
GOPHER_LOG(Info, "FileConfigSource created: name=%s priority=%d",
272-
name_.c_str(), static_cast<int>(priority_));
271+
GOPHER_LOG(Info, "FileConfigSource created: name={} priority={}",
272+
name_, priority_);
273273
}
274274

275275
std::string getName() const override { return name_; }
@@ -285,22 +285,22 @@ class FileConfigSource : public ConfigSource {
285285
mcp::json::JsonValue loadConfiguration() override {
286286
// Keep logs under config.file so tests that attach a sink to
287287
// "config.file" see discovery start/end messages.
288-
GOPHER_LOG(Info, "Starting configuration discovery for source: %s%s",
289-
name_.c_str(),
288+
GOPHER_LOG(Info, "Starting configuration discovery for source: {}{}",
289+
name_,
290290
(options_.trace_id.empty()
291291
? ""
292-
: (" trace_id=" + options_.trace_id).c_str()));
292+
: (" trace_id=" + options_.trace_id)));
293293

294294
// Determine the config file path using deterministic search order
295295
std::string config_path = findConfigFile();
296296

297297
if (config_path.empty()) {
298-
GOPHER_LOG(Warning, "No configuration file found for source: %s",
299-
name_.c_str());
298+
GOPHER_LOG(Warning, "No configuration file found for source: {}",
299+
name_);
300300
return mcp::json::JsonValue::object();
301301
}
302302

303-
GOPHER_LOG(Info, "Base configuration file chosen: %s", config_path.c_str());
303+
GOPHER_LOG(Info, "Base configuration file chosen: {}", config_path);
304304

305305
// Load and parse the main configuration file
306306
ParseContext context;
@@ -323,8 +323,8 @@ class FileConfigSource : public ConfigSource {
323323
// Emit a brief summary and also dump top-level keys/types to aid debugging
324324
GOPHER_LOG(
325325
Info,
326-
"Configuration discovery completed: files_parsed=%zu "
327-
"includes_processed=%zu env_vars_expanded=%zu overlays_applied=%zu",
326+
"Configuration discovery completed: files_parsed={} "
327+
"includes_processed={} env_vars_expanded={} overlays_applied={}",
328328
context.files_parsed_count, context.includes_processed_count,
329329
context.env_vars_expanded_count, context.overlays_applied.size());
330330

@@ -346,11 +346,11 @@ class FileConfigSource : public ConfigSource {
346346
t = "array";
347347
else if (v.isObject())
348348
t = "object";
349-
GOPHER_LOG(Debug, " key='%s' type=%s", key.c_str(), t);
349+
GOPHER_LOG(Debug, " key='{}' type={}", key, t);
350350
}
351351
// Emit compact JSON for quick inspection
352-
GOPHER_LOG(Info, "Top-level configuration JSON: %s",
353-
config.toString(false).c_str());
352+
GOPHER_LOG(Info, "Top-level configuration JSON: {}",
353+
config.toString(false));
354354
// Also print to stderr for test visibility when sinks are not attached
355355
fprintf(stderr, "[config.file] Top-level JSON: %s\n",
356356
config.toString(false).c_str());
@@ -364,7 +364,7 @@ class FileConfigSource : public ConfigSource {
364364
if (!context.overlays_applied.empty()) {
365365
GOPHER_LOG(Debug, "Overlays applied in order:");
366366
for (const auto& overlay : context.overlays_applied) {
367-
GOPHER_LOG(Debug, " - %s", overlay.c_str());
367+
GOPHER_LOG(Debug, " - {}", overlay);
368368
}
369369
}
370370

@@ -443,27 +443,27 @@ class FileConfigSource : public ConfigSource {
443443
search_paths.push_back("/etc/gopher-mcp/config.yaml");
444444
search_paths.push_back("/etc/gopher-mcp/config.json");
445445

446-
GOPHER_LOG(Debug, "Configuration search order: %zu paths to check",
446+
GOPHER_LOG(Debug, "Configuration search order: {} paths to check",
447447
search_paths.size());
448448

449449
for (size_t i = 0; i < search_paths.size(); ++i) {
450450
const auto& path = search_paths[i];
451451
if (exists(path)) {
452452
// Determine which source won
453453
if (i == 0 && !explicit_config_path_.empty()) {
454-
GOPHER_LOG(Info, "Configuration source won: CLI --config=%s",
455-
path.c_str());
454+
GOPHER_LOG(Info, "Configuration source won: CLI --config={}",
455+
path);
456456
} else if ((i == 0 || i == 1) && env_config) {
457457
GOPHER_LOG(
458458
Info,
459459
"Configuration source won: MCP_CONFIG environment variable");
460460
} else if (path.find("./config") != std::string::npos ||
461461
path.find("./config.") != std::string::npos) {
462-
GOPHER_LOG(Info, "Configuration source won: local directory at %s",
463-
path.c_str());
462+
GOPHER_LOG(Info, "Configuration source won: local directory at {}",
463+
path);
464464
} else {
465-
GOPHER_LOG(Info, "Configuration source won: system directory at %s",
466-
path.c_str());
465+
GOPHER_LOG(Info, "Configuration source won: system directory at {}",
466+
path);
467467
}
468468
return path;
469469
}
@@ -484,8 +484,8 @@ class FileConfigSource : public ConfigSource {
484484
size_t file_size = st.st_size;
485485
if (file_size > options_.max_file_size) {
486486
GOPHER_LOG(Error,
487-
"File exceeds maximum size limit: %s size=%zu limit=%zu",
488-
filepath.c_str(), file_size, options_.max_file_size);
487+
"File exceeds maximum size limit: {} size={} limit={}",
488+
filepath, file_size, options_.max_file_size);
489489
throw std::runtime_error("File too large: " + filepath + " (" +
490490
std::to_string(file_size) + " bytes)");
491491
}
@@ -500,13 +500,13 @@ class FileConfigSource : public ConfigSource {
500500
}
501501

502502
GOPHER_LOG(Debug,
503-
"Loading configuration file: %s size=%zu last_modified=%ld",
504-
filepath.c_str(), file_size, static_cast<long>(last_modified));
503+
"Loading configuration file: {} size={} last_modified={}",
504+
filepath, file_size, last_modified);
505505

506506
std::ifstream file(filepath);
507507
if (!file.is_open()) {
508-
GOPHER_LOG(Error, "Failed to open configuration file: %s",
509-
filepath.c_str());
508+
GOPHER_LOG(Error, "Failed to open configuration file: {}",
509+
filepath);
510510
throw std::runtime_error("Cannot open config file: " + filepath);
511511
}
512512

@@ -543,8 +543,8 @@ class FileConfigSource : public ConfigSource {
543543
}
544544
}
545545
} catch (const std::exception& e) {
546-
GOPHER_LOG(Error, "Failed to parse configuration file: %s reason=%s",
547-
filepath.c_str(), e.what());
546+
GOPHER_LOG(Error, "Failed to parse configuration file: {} reason={}",
547+
filepath, e.what());
548548
throw;
549549
}
550550

@@ -696,8 +696,8 @@ class FileConfigSource : public ConfigSource {
696696

697697
if (!env_value && !has_default) {
698698
GOPHER_LOG(Error,
699-
"Undefined environment variable without default: ${%s}",
700-
var_name.c_str());
699+
"Undefined environment variable without default: ${{{}}}",
700+
var_name);
701701
throw std::runtime_error("Undefined environment variable: " + var_name);
702702
}
703703

@@ -725,7 +725,7 @@ class FileConfigSource : public ConfigSource {
725725

726726
context.env_vars_expanded_count += vars_expanded;
727727
if (vars_expanded > 0) {
728-
GOPHER_LOG(Debug, "Expanded %zu environment variables", vars_expanded);
728+
GOPHER_LOG(Debug, "Expanded {} environment variables", vars_expanded);
729729
}
730730

731731
return result;
@@ -734,7 +734,7 @@ class FileConfigSource : public ConfigSource {
734734
mcp::json::JsonValue processIncludes(const mcp::json::JsonValue& config,
735735
ParseContext& context) {
736736
if (++context.include_depth > context.max_include_depth) {
737-
GOPHER_LOG(Error, "Maximum include depth exceeded: %d at depth %d",
737+
GOPHER_LOG(Error, "Maximum include depth exceeded: {} at depth {}",
738738
context.max_include_depth, context.include_depth);
739739
throw std::runtime_error("Maximum include depth (" +
740740
std::to_string(context.max_include_depth) +
@@ -756,22 +756,22 @@ class FileConfigSource : public ConfigSource {
756756
const auto& include = includes[i];
757757
if (include.isString()) {
758758
std::string include_path = include.getString();
759-
GOPHER_LOG(Debug, "Processing include: %s from base_dir=%s",
760-
include_path.c_str(), context.base_dir.string().c_str());
759+
GOPHER_LOG(Debug, "Processing include: {} from base_dir={}",
760+
include_path, context.base_dir.string());
761761

762762
path resolved_path = resolveIncludePath(include_path, context);
763763

764764
if (context.processed_files.count(resolved_path.string()) > 0) {
765-
GOPHER_LOG(Warning, "Circular include detected, skipping: %s",
766-
resolved_path.string().c_str());
765+
GOPHER_LOG(Warning, "Circular include detected, skipping: {}",
766+
resolved_path.string());
767767
continue;
768768
}
769769

770770
context.processed_files.insert(resolved_path.string());
771771
context.includes_processed_count++;
772772

773-
GOPHER_LOG(Info, "Including configuration from: %s",
774-
resolved_path.string().c_str());
773+
GOPHER_LOG(Info, "Including configuration from: {}",
774+
resolved_path.string());
775775

776776
ParseContext include_context = context;
777777
include_context.base_dir = resolved_path.parent_path();
@@ -809,8 +809,8 @@ class FileConfigSource : public ConfigSource {
809809
std::string dir_pattern = config["include_dir"].getString();
810810
path dir_path = resolveIncludePath(dir_pattern, context);
811811

812-
GOPHER_LOG(Info, "Scanning directory for configurations: %s",
813-
dir_path.string().c_str());
812+
GOPHER_LOG(Info, "Scanning directory for configurations: {}",
813+
dir_path.string());
814814

815815
if (exists(dir_path.string()) && is_directory(dir_path.string())) {
816816
std::vector<path> config_files;
@@ -830,7 +830,7 @@ class FileConfigSource : public ConfigSource {
830830
// Sort for deterministic order
831831
std::sort(config_files.begin(), config_files.end());
832832

833-
GOPHER_LOG(Debug, "Found %zu configuration files in directory",
833+
GOPHER_LOG(Debug, "Found {} configuration files in directory",
834834
config_files.size());
835835

836836
for (const auto& file : config_files) {
@@ -841,8 +841,8 @@ class FileConfigSource : public ConfigSource {
841841
context.processed_files.insert(canonical(file.string()));
842842
context.includes_processed_count++;
843843

844-
GOPHER_LOG(Info, "Including configuration from directory: %s",
845-
file.string().c_str());
844+
GOPHER_LOG(Info, "Including configuration from directory: {}",
845+
file.string());
846846

847847
ParseContext include_context = context;
848848
include_context.base_dir = file.parent_path();
@@ -860,8 +860,8 @@ class FileConfigSource : public ConfigSource {
860860
}
861861
} else {
862862
GOPHER_LOG(Warning,
863-
"Include directory does not exist or is not a directory: %s",
864-
dir_path.string().c_str());
863+
"Include directory does not exist or is not a directory: {}",
864+
dir_path.string());
865865
}
866866

867867
result.erase("include_dir");
@@ -886,8 +886,8 @@ class FileConfigSource : public ConfigSource {
886886
}
887887
}
888888
if (!allowed) {
889-
GOPHER_LOG(Error, "Absolute include path not under allowed roots: %s",
890-
filepath.c_str());
889+
GOPHER_LOG(Error, "Absolute include path not under allowed roots: {}",
890+
filepath);
891891
throw std::runtime_error("Include path not allowed: " + filepath);
892892
}
893893
}
@@ -932,8 +932,8 @@ class FileConfigSource : public ConfigSource {
932932
const mcp::json::JsonValue& base_config,
933933
const path& overlay_dir,
934934
ParseContext& context) {
935-
GOPHER_LOG(Info, "Scanning config.d directory: %s",
936-
overlay_dir.string().c_str());
935+
GOPHER_LOG(Info, "Scanning config.d directory: {}",
936+
overlay_dir.string());
937937

938938
mcp::json::JsonValue result = base_config;
939939
std::vector<path> overlay_files;
@@ -954,28 +954,28 @@ class FileConfigSource : public ConfigSource {
954954
std::sort(overlay_files.begin(), overlay_files.end());
955955

956956
GOPHER_LOG(Info,
957-
"Directory scan results: found %zu configuration overlay files",
957+
"Directory scan results: found {} configuration overlay files",
958958
overlay_files.size());
959959

960960
// Log overlay list in order
961961
if (!overlay_files.empty()) {
962962
GOPHER_LOG(Info, "Overlay files in lexicographic order:");
963963
for (const auto& file : overlay_files) {
964-
GOPHER_LOG(Info, " - %s", file.filename().string().c_str());
964+
GOPHER_LOG(Info, " - {}", file.filename().string());
965965
}
966966
}
967967

968968
for (const auto& overlay_file : overlay_files) {
969969
if (context.processed_files.count(canonical(overlay_file.string())) > 0) {
970-
GOPHER_LOG(Debug, "Skipping already processed overlay: %s",
971-
overlay_file.string().c_str());
970+
GOPHER_LOG(Debug, "Skipping already processed overlay: {}",
971+
overlay_file.string());
972972
continue;
973973
}
974974

975975
context.processed_files.insert(canonical(overlay_file.string()));
976976

977-
GOPHER_LOG(Debug, "Applying overlay: %s",
978-
overlay_file.filename().string().c_str());
977+
GOPHER_LOG(Debug, "Applying overlay: {}",
978+
overlay_file.filename().string());
979979

980980
ParseContext overlay_context = context;
981981
overlay_context.base_dir = overlay_file.parent_path();
@@ -995,8 +995,8 @@ class FileConfigSource : public ConfigSource {
995995
context.latest_mtime = overlay_context.latest_mtime;
996996
}
997997
} catch (const std::exception& e) {
998-
GOPHER_LOG(Error, "Failed to process overlay %s: %s",
999-
overlay_file.string().c_str(), e.what());
998+
GOPHER_LOG(Error, "Failed to process overlay {}: {}",
999+
overlay_file.string(), e.what());
10001000
// Continue with other overlays
10011001
}
10021002
}

src/logging/logger_registry.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ LoggerRegistry& LoggerRegistry::instance() {
1111
return instance;
1212
}
1313

14-
LoggerRegistry::LoggerRegistry() : global_level_(LogLevel::Warning) {
14+
LoggerRegistry::LoggerRegistry() : global_level_(LogLevel::Info) {
1515
initializeDefaults();
1616
}
1717

tests/filter/test_filter_chain_event_hub.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
#include <atomic>
7+
#include <mutex>
78
#include <thread>
89
#include <vector>
910

@@ -295,6 +296,7 @@ TEST_F(FilterChainEventHubTest, ThreadSafety) {
295296
callbacks_list;
296297
std::vector<FilterChainEventHub::ObserverHandle> handles;
297298
std::atomic<int> total_events_received{0};
299+
std::mutex list_mutex;
298300

299301
// Register observers from multiple threads
300302
std::vector<std::thread> registration_threads;
@@ -309,9 +311,12 @@ TEST_F(FilterChainEventHubTest, ThreadSafety) {
309311

310312
auto handle = hub_->registerObserver(callbacks);
311313

312-
// Store safely (in test main thread context after join)
313-
callbacks_list.push_back(callbacks);
314-
handles.push_back(std::move(handle));
314+
// Store safely with mutex protection
315+
{
316+
std::lock_guard<std::mutex> lock(list_mutex);
317+
callbacks_list.push_back(callbacks);
318+
handles.push_back(std::move(handle));
319+
}
315320
});
316321
}
317322

0 commit comments

Comments
 (0)