Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <atomic> | |
|
viettrungluu
2015/12/17 18:34:39
Apparently, you don't need any atomics, according
vardhan
2015/12/17 23:35:42
Done.
| |
| 6 #include <set> | |
| 7 #include <thread> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "mojo/public/cpp/application/application_test_base.h" | |
| 11 #include "mojo/public/cpp/bindings/strong_binding.h" | |
| 12 #include "mojo/public/cpp/system/macros.h" | |
| 13 #include "mojo/public/cpp/utility/run_loop.h" | |
| 14 #include "mojo/services/log/cpp/log_client.h" | |
| 15 #include "mojo/services/log/interfaces/entry.mojom.h" | |
| 16 #include "mojo/services/log/interfaces/log.mojom.h" | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 | |
| 19 using LogClientTest = mojo::test::ApplicationTestBase; | |
| 20 using mojo::Environment; | |
| 21 using mojo::internal::ValidationError; | |
| 22 | |
| 23 namespace mojo { | |
| 24 namespace { | |
| 25 | |
| 26 // A Log implementation that remembers the set of all incoming messages. | |
| 27 class TestLogServiceImpl : public log::Log { | |
| 28 public: | |
| 29 explicit TestLogServiceImpl(InterfaceRequest<log::Log> log_req) | |
| 30 : binding_(this, std::move(log_req)) { | |
| 31 EXPECT_TRUE(binding_.is_bound()); | |
| 32 binding_.set_connection_error_handler([this]() { | |
| 33 FAIL() << "Log service lost connection to the log client."; | |
| 34 }); | |
| 35 validation_observer_.set_last_error(ValidationError::NONE); | |
| 36 } | |
| 37 void AddEntry(mojo::log::EntryPtr entry) override { | |
| 38 entry_msgs_.insert(entry->message.To<std::string>()); | |
| 39 } | |
| 40 const std::set<std::string>& entries() { return entry_msgs_; } | |
| 41 mojo::internal::ValidationError previous_validation_error() { | |
| 42 return validation_observer_.last_error(); | |
| 43 } | |
| 44 | |
| 45 private: | |
| 46 mojo::StrongBinding<log::Log> binding_; | |
| 47 std::set<std::string> entry_msgs_; | |
| 48 mojo::internal::ValidationErrorObserverForTesting validation_observer_; | |
| 49 }; | |
| 50 | |
| 51 std::atomic<MojoLogLevel> g_fallback_logger_level(MOJO_LOG_LEVEL_INFO); | |
| 52 bool g_fallback_logger_invoked = false; | |
| 53 // This tests that multiple threads can use the MojoLogger that | |
| 54 // mojo::log::LogClient produces, by spawning off |kNumLogEntries| threads, each | |
| 55 // issuing one unique log message. | |
| 56 TEST_F(LogClientTest, ConcurrentAddEntry) { | |
| 57 log::LogPtr log_ptr; | |
| 58 std::unique_ptr<mojo::TestLogServiceImpl> log_impl( | |
| 59 new mojo::TestLogServiceImpl(mojo::GetProxy(&log_ptr))); | |
| 60 | |
| 61 // This is our test fallback logger + state. We simply records whether it's | |
| 62 // been called. | |
| 63 MojoLogger fallback_logger = { | |
| 64 // LogMessage | |
| 65 [](MojoLogLevel log_level, const char* source_file, uint32_t source_line, | |
| 66 const char* message) { g_fallback_logger_invoked = true; }, | |
| 67 // SetMinimumLogLevel | |
| 68 []() -> MojoLogLevel { | |
| 69 return g_fallback_logger_level.load(std::memory_order_relaxed); | |
| 70 }, | |
| 71 // GetMinimumLogLevel | |
| 72 [](MojoLogLevel lvl) { | |
| 73 g_fallback_logger_level.store(lvl, std::memory_order_relaxed); | |
| 74 }}; | |
| 75 log::InitializeLogger(std::move(log_ptr), &fallback_logger); | |
| 76 Environment::SetDefaultLogger(log::GetLogger()); | |
| 77 | |
| 78 // Spawn off numerous threads, each of them issuing a unique log message. | |
| 79 std::vector<std::thread> threads; | |
| 80 std::set<std::string> expected_entries; | |
| 81 | |
| 82 // The number of log entries to issue. | |
| 83 const int kNumLogEntries = 1000; | |
| 84 for (int i = 0; i < kNumLogEntries; i++) { | |
| 85 std::stringstream msg; | |
| 86 msg << "Test message: " << i; | |
| 87 EXPECT_TRUE(expected_entries.insert(msg.str()).second); | |
| 88 | |
| 89 std::thread t([](std::string msg) { MOJO_LOG(INFO) << msg; }, msg.str()); | |
| 90 | |
| 91 threads.push_back(std::move(t)); | |
| 92 } | |
| 93 for (auto& t : threads) { | |
| 94 t.join(); | |
| 95 } | |
| 96 | |
| 97 // The log message calls should now be processed by TestLogServiceImpl. | |
| 98 mojo::RunLoop::current()->RunUntilIdle(); | |
| 99 | |
| 100 EXPECT_EQ(expected_entries, log_impl->entries()); | |
| 101 EXPECT_EQ(ValidationError::NONE, log_impl->previous_validation_error()); | |
| 102 | |
| 103 // We kill our binding, closing the connection to the log client and | |
| 104 // causing the log client to revert to using its fallback logger. | |
| 105 log_impl.reset(); | |
| 106 | |
| 107 EXPECT_FALSE(mojo::g_fallback_logger_invoked); | |
| 108 MOJO_LOG(INFO) << "Ignore this log message."; | |
| 109 EXPECT_TRUE(mojo::g_fallback_logger_invoked); | |
| 110 | |
| 111 // Check that this logger propogates get/set min level calls to the fallback | |
| 112 // logger. | |
| 113 auto* logger = log::GetLogger(); | |
| 114 EXPECT_EQ(MOJO_LOG_LEVEL_INFO, logger->GetMinimumLogLevel()); | |
| 115 logger->SetMinimumLogLevel(MOJO_LOG_LEVEL_FATAL); | |
| 116 EXPECT_EQ(MOJO_LOG_LEVEL_FATAL, logger->GetMinimumLogLevel()); | |
| 117 EXPECT_EQ(MOJO_LOG_LEVEL_FATAL, fallback_logger.GetMinimumLogLevel()); | |
| 118 | |
| 119 log::DestroyLogger(); | |
| 120 } | |
| 121 | |
| 122 } // namespace | |
| 123 } // namespace mojo | |
| OLD | NEW |