| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <signal.h> |
| |
| #include "flutter/fml/build_config.h" |
| #include "flutter/fml/log_settings.h" |
| #include "flutter/fml/logging.h" |
| #include "gtest/gtest.h" |
| |
| #if defined(OS_FUCHSIA) |
| #include <lib/syslog/global.h> |
| #include <lib/syslog/logger.h> |
| #include <lib/syslog/wire_format.h> |
| #include <lib/zx/socket.h> |
| |
| #include "gmock/gmock.h" |
| #endif |
| |
| namespace fml { |
| namespace testing { |
| |
| #ifndef OS_FUCHSIA |
| class MakeSureFmlLogDoesNotSegfaultWhenStaticallyCalled { |
| public: |
| MakeSureFmlLogDoesNotSegfaultWhenStaticallyCalled() { |
| SegfaultCatcher catcher; |
| // If this line causes a segfault, FML is using a method of logging that is |
| // not safe from static initialization on your platform. |
| FML_LOG(INFO) |
| << "This log exists to verify that static logging from FML works."; |
| } |
| |
| private: |
| struct SegfaultCatcher { |
| typedef void (*sighandler_t)(int); |
| |
| SegfaultCatcher() { |
| handler = ::signal(SIGSEGV, SegfaultHandler); |
| FML_CHECK(handler != SIG_ERR); |
| } |
| |
| ~SegfaultCatcher() { FML_CHECK(::signal(SIGSEGV, handler) != SIG_ERR); } |
| |
| static void SegfaultHandler(int signal) { |
| fprintf(stderr, |
| "FML failed to handle logging from static initialization.\n"); |
| exit(signal); |
| } |
| |
| sighandler_t handler; |
| }; |
| }; |
| |
| static MakeSureFmlLogDoesNotSegfaultWhenStaticallyCalled fml_log_static_check_; |
| #endif // !defined(OS_FUCHSIA) |
| |
| int UnreachableScopeWithoutReturnDoesNotMakeCompilerMad() { |
| KillProcess(); |
| // return 0; <--- Missing but compiler is fine. |
| } |
| |
| int UnreachableScopeWithMacroWithoutReturnDoesNotMakeCompilerMad() { |
| FML_UNREACHABLE(); |
| // return 0; <--- Missing but compiler is fine. |
| } |
| |
| TEST(LoggingTest, UnreachableKillProcess) { |
| ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
| ASSERT_DEATH(KillProcess(), ""); |
| } |
| |
| TEST(LoggingTest, UnreachableKillProcessWithMacro) { |
| ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
| ASSERT_DEATH({ FML_UNREACHABLE(); }, ""); |
| } |
| |
| #if defined(OS_FUCHSIA) |
| |
| struct LogPacket { |
| fx_log_metadata_t metadata; |
| std::vector<std::string> tags; |
| std::string message; |
| }; |
| |
| class LoggingSocketTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| zx::socket local; |
| ASSERT_EQ(ZX_OK, zx::socket::create(ZX_SOCKET_DATAGRAM, &local, &socket_)); |
| |
| fx_logger_config_t config = { |
| .min_severity = FX_LOG_INFO, |
| .log_sink_socket = local.release(), |
| .tags = nullptr, |
| .num_tags = 0, |
| }; |
| |
| fx_log_reconfigure(&config); |
| } |
| |
| LogPacket ReadPacket() { |
| LogPacket result; |
| fx_log_packet_t packet; |
| zx_status_t res = socket_.read(0, &packet, sizeof(packet), nullptr); |
| EXPECT_EQ(ZX_OK, res); |
| result.metadata = packet.metadata; |
| int pos = 0; |
| while (packet.data[pos]) { |
| int tag_len = packet.data[pos++]; |
| result.tags.emplace_back(packet.data + pos, tag_len); |
| pos += tag_len; |
| } |
| result.message.append(packet.data + pos + 1); |
| return result; |
| } |
| |
| void ReadPacketAndCompare(fx_log_severity_t severity, |
| const std::string& message, |
| const std::vector<std::string>& tags = {}) { |
| LogPacket packet = ReadPacket(); |
| EXPECT_EQ(severity, packet.metadata.severity); |
| EXPECT_THAT(packet.message, ::testing::EndsWith(message)); |
| EXPECT_EQ(tags, packet.tags); |
| } |
| |
| void CheckSocketEmpty() { |
| zx_info_socket_t info = {}; |
| zx_status_t status = |
| socket_.get_info(ZX_INFO_SOCKET, &info, sizeof(info), nullptr, nullptr); |
| ASSERT_EQ(ZX_OK, status); |
| EXPECT_EQ(0u, info.rx_buf_available); |
| } |
| |
| zx::socket socket_; |
| }; |
| |
| TEST_F(LoggingSocketTest, UseSyslogOnFuchsia) { |
| const char* msg1 = "test message"; |
| const char* msg2 = "hello"; |
| const char* msg3 = "logging"; |
| const char* msg4 = "Another message"; |
| const char* msg5 = "Foo"; |
| |
| fml::SetLogSettings({.min_log_level = -1}); |
| |
| FML_LOG(INFO) << msg1; |
| ReadPacketAndCompare(FX_LOG_INFO, msg1); |
| CheckSocketEmpty(); |
| |
| FML_LOG(WARNING) << msg2; |
| ReadPacketAndCompare(FX_LOG_WARNING, msg2); |
| CheckSocketEmpty(); |
| |
| FML_LOG(ERROR) << msg3; |
| ReadPacketAndCompare(FX_LOG_ERROR, msg3); |
| CheckSocketEmpty(); |
| |
| FML_VLOG(1) << msg4; |
| ReadPacketAndCompare(fx_log_severity_from_verbosity(1), msg4); |
| CheckSocketEmpty(); |
| |
| // VLOG(2) is not enabled so the log gets dropped. |
| FML_VLOG(2) << msg5; |
| CheckSocketEmpty(); |
| } |
| |
| #endif |
| |
| } // namespace testing |
| } // namespace fml |