1 //===-- ProgressReportTest.cpp --------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Plugins/Platform/MacOSX/PlatformMacOSX.h" 10 #include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h" 11 #include "TestingSupport/SubsystemRAII.h" 12 #include "TestingSupport/TestUtilities.h" 13 #include "lldb/Core/Debugger.h" 14 #include "lldb/Core/Progress.h" 15 #include "lldb/Host/FileSystem.h" 16 #include "lldb/Host/HostInfo.h" 17 #include "lldb/Utility/Listener.h" 18 #include "gtest/gtest.h" 19 #include <memory> 20 #include <mutex> 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 static std::chrono::milliseconds TIMEOUT(100); 26 27 class ProgressReportTest : public ::testing::Test { 28 public: 29 ListenerSP CreateListenerFor(uint32_t bit) { 30 // Set up the debugger, make sure that was done properly. 31 ArchSpec arch("x86_64-apple-macosx-"); 32 Platform::SetHostPlatform( 33 PlatformRemoteMacOSX::CreateInstance(true, &arch)); 34 35 m_debugger_sp = Debugger::CreateInstance(); 36 37 // Get the debugger's broadcaster. 38 Broadcaster &broadcaster = m_debugger_sp->GetBroadcaster(); 39 40 // Create a listener, make sure it can receive events and that it's 41 // listening to the correct broadcast bit. 42 m_listener_sp = Listener::MakeListener("progress-listener"); 43 m_listener_sp->StartListeningForEvents(&broadcaster, bit); 44 return m_listener_sp; 45 } 46 47 protected: 48 // The debugger's initialization function can't be called with no arguments 49 // so calling it using SubsystemRAII will cause the test build to fail as 50 // SubsystemRAII will call Initialize with no arguments. As such we set it up 51 // here the usual way. 52 void SetUp() override { 53 std::call_once(TestUtilities::g_debugger_initialize_flag, 54 []() { Debugger::Initialize(nullptr); }); 55 }; 56 57 DebuggerSP m_debugger_sp; 58 ListenerSP m_listener_sp; 59 SubsystemRAII<FileSystem, HostInfo, PlatformMacOSX> subsystems; 60 }; 61 62 TEST_F(ProgressReportTest, TestReportCreation) { 63 ListenerSP listener_sp = CreateListenerFor(Debugger::eBroadcastBitProgress); 64 EventSP event_sp; 65 const ProgressEventData *data; 66 67 // Scope this for RAII on the progress objects. 68 // Create progress reports and check that their respective events for having 69 // started and ended are broadcasted. 70 { 71 Progress progress1("Progress report 1", "Starting report 1"); 72 Progress progress2("Progress report 2", "Starting report 2"); 73 Progress progress3("Progress report 3", "Starting report 3"); 74 } 75 76 // Start popping events from the queue, they should have been recevied 77 // in this order: 78 // Starting progress: 1, 2, 3 79 // Ending progress: 3, 2, 1 80 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 81 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 82 83 EXPECT_EQ(data->GetDetails(), "Starting report 1"); 84 EXPECT_FALSE(data->IsFinite()); 85 EXPECT_FALSE(data->GetCompleted()); 86 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 87 EXPECT_EQ(data->GetMessage(), "Progress report 1: Starting report 1"); 88 89 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 90 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 91 92 EXPECT_EQ(data->GetDetails(), "Starting report 2"); 93 EXPECT_FALSE(data->IsFinite()); 94 EXPECT_FALSE(data->GetCompleted()); 95 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 96 EXPECT_EQ(data->GetMessage(), "Progress report 2: Starting report 2"); 97 98 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 99 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 100 101 EXPECT_EQ(data->GetDetails(), "Starting report 3"); 102 EXPECT_FALSE(data->IsFinite()); 103 EXPECT_FALSE(data->GetCompleted()); 104 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 105 EXPECT_EQ(data->GetMessage(), "Progress report 3: Starting report 3"); 106 107 // Progress report objects should be destroyed at this point so 108 // get each report from the queue and check that they've been 109 // destroyed in reverse order. 110 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 111 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 112 113 EXPECT_EQ(data->GetTitle(), "Progress report 3"); 114 EXPECT_TRUE(data->GetCompleted()); 115 EXPECT_FALSE(data->IsFinite()); 116 EXPECT_EQ(data->GetMessage(), "Progress report 3: Starting report 3"); 117 118 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 119 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 120 121 EXPECT_EQ(data->GetTitle(), "Progress report 2"); 122 EXPECT_TRUE(data->GetCompleted()); 123 EXPECT_FALSE(data->IsFinite()); 124 EXPECT_EQ(data->GetMessage(), "Progress report 2: Starting report 2"); 125 126 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 127 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 128 129 EXPECT_EQ(data->GetTitle(), "Progress report 1"); 130 EXPECT_TRUE(data->GetCompleted()); 131 EXPECT_FALSE(data->IsFinite()); 132 EXPECT_EQ(data->GetMessage(), "Progress report 1: Starting report 1"); 133 } 134 135 TEST_F(ProgressReportTest, TestProgressManager) { 136 ListenerSP listener_sp = 137 CreateListenerFor(Debugger::eBroadcastBitProgressCategory); 138 EventSP event_sp; 139 const ProgressEventData *data; 140 141 // Create three progress events with the same category then try to pop 2 142 // events from the queue in a row before the progress reports are destroyed. 143 // Since only 1 event should've been broadcast for this category, the second 144 // GetEvent() call should return false. 145 { 146 Progress progress1("Progress report 1", "Starting report 1"); 147 Progress progress2("Progress report 1", "Starting report 2"); 148 Progress progress3("Progress report 1", "Starting report 3"); 149 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 150 ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT)); 151 } 152 153 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 154 155 EXPECT_EQ(data->GetDetails(), ""); 156 EXPECT_FALSE(data->IsFinite()); 157 EXPECT_FALSE(data->GetCompleted()); 158 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 159 EXPECT_EQ(data->GetMessage(), "Progress report 1"); 160 161 // Pop another event from the queue, this should be the event for the final 162 // report for this category. 163 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 164 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 165 166 EXPECT_EQ(data->GetDetails(), ""); 167 EXPECT_FALSE(data->IsFinite()); 168 EXPECT_TRUE(data->GetCompleted()); 169 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 170 EXPECT_EQ(data->GetMessage(), "Progress report 1"); 171 } 172 173 TEST_F(ProgressReportTest, TestOverlappingEvents) { 174 ListenerSP listener_sp = 175 CreateListenerFor(Debugger::eBroadcastBitProgressCategory); 176 EventSP event_sp; 177 const ProgressEventData *data; 178 179 // Create two progress reports of the same category that overlap with each 180 // other. Here we want to ensure that the ID broadcasted for the initial and 181 // final reports for this category are the same. 182 std::unique_ptr<Progress> overlap_progress1 = 183 std::make_unique<Progress>("Overlapping report 1", "Starting report 1"); 184 std::unique_ptr<Progress> overlap_progress2 = 185 std::make_unique<Progress>("Overlapping report 1", "Starting report 2"); 186 overlap_progress1.reset(); 187 188 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 189 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 190 // Get the ID used in the first report for this category. 191 uint64_t expected_progress_id = data->GetID(); 192 193 EXPECT_EQ(data->GetDetails(), ""); 194 EXPECT_FALSE(data->IsFinite()); 195 EXPECT_FALSE(data->GetCompleted()); 196 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 197 EXPECT_EQ(data->GetMessage(), "Overlapping report 1"); 198 199 overlap_progress2.reset(); 200 201 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 202 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 203 204 EXPECT_EQ(data->GetDetails(), ""); 205 EXPECT_FALSE(data->IsFinite()); 206 EXPECT_TRUE(data->GetCompleted()); 207 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 208 EXPECT_EQ(data->GetMessage(), "Overlapping report 1"); 209 // The progress ID for the final report should be the same as that for the 210 // initial report. 211 EXPECT_EQ(data->GetID(), expected_progress_id); 212 } 213