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(500); 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, ProgressManager> 60 subsystems; 61 }; 62 63 TEST_F(ProgressReportTest, TestReportCreation) { 64 ListenerSP listener_sp = CreateListenerFor(Debugger::eBroadcastBitProgress); 65 EventSP event_sp; 66 const ProgressEventData *data; 67 68 // Scope this for RAII on the progress objects. 69 // Create progress reports and check that their respective events for having 70 // started and ended are broadcasted. 71 { 72 Progress progress1("Progress report 1", "Starting report 1"); 73 Progress progress2("Progress report 2", "Starting report 2"); 74 Progress progress3("Progress report 3", "Starting report 3"); 75 } 76 77 // Start popping events from the queue, they should have been recevied 78 // in this order: 79 // Starting progress: 1, 2, 3 80 // Ending progress: 3, 2, 1 81 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 82 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 83 84 EXPECT_EQ(data->GetDetails(), "Starting report 1"); 85 EXPECT_FALSE(data->IsFinite()); 86 EXPECT_FALSE(data->GetCompleted()); 87 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 88 EXPECT_EQ(data->GetMessage(), "Progress report 1: Starting report 1"); 89 90 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 91 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 92 93 EXPECT_EQ(data->GetDetails(), "Starting report 2"); 94 EXPECT_FALSE(data->IsFinite()); 95 EXPECT_FALSE(data->GetCompleted()); 96 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 97 EXPECT_EQ(data->GetMessage(), "Progress report 2: Starting report 2"); 98 99 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 100 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 101 102 EXPECT_EQ(data->GetDetails(), "Starting report 3"); 103 EXPECT_FALSE(data->IsFinite()); 104 EXPECT_FALSE(data->GetCompleted()); 105 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 106 EXPECT_EQ(data->GetMessage(), "Progress report 3: Starting report 3"); 107 108 // Progress report objects should be destroyed at this point so 109 // get each report from the queue and check that they've been 110 // destroyed in reverse order. 111 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 112 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 113 114 EXPECT_EQ(data->GetTitle(), "Progress report 3"); 115 EXPECT_TRUE(data->GetCompleted()); 116 EXPECT_FALSE(data->IsFinite()); 117 EXPECT_EQ(data->GetMessage(), "Progress report 3: Starting report 3"); 118 119 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 120 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 121 122 EXPECT_EQ(data->GetTitle(), "Progress report 2"); 123 EXPECT_TRUE(data->GetCompleted()); 124 EXPECT_FALSE(data->IsFinite()); 125 EXPECT_EQ(data->GetMessage(), "Progress report 2: Starting report 2"); 126 127 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 128 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 129 130 EXPECT_EQ(data->GetTitle(), "Progress report 1"); 131 EXPECT_TRUE(data->GetCompleted()); 132 EXPECT_FALSE(data->IsFinite()); 133 EXPECT_EQ(data->GetMessage(), "Progress report 1: Starting report 1"); 134 } 135 136 TEST_F(ProgressReportTest, TestProgressManager) { 137 ListenerSP listener_sp = 138 CreateListenerFor(Debugger::eBroadcastBitProgressCategory); 139 EventSP event_sp; 140 const ProgressEventData *data; 141 142 // Create three progress events with the same category then try to pop 2 143 // events from the queue in a row before the progress reports are destroyed. 144 // Since only 1 event should've been broadcast for this category, the second 145 // GetEvent() call should return false. 146 { 147 Progress progress1("Progress report 1", "Starting report 1"); 148 Progress progress2("Progress report 1", "Starting report 2"); 149 Progress progress3("Progress report 1", "Starting report 3"); 150 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 151 ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT)); 152 } 153 154 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 155 156 EXPECT_EQ(data->GetDetails(), ""); 157 EXPECT_FALSE(data->IsFinite()); 158 EXPECT_FALSE(data->GetCompleted()); 159 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 160 EXPECT_EQ(data->GetMessage(), "Progress report 1"); 161 162 // Pop another event from the queue, this should be the event for the final 163 // report for this category. 164 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 165 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 166 167 EXPECT_EQ(data->GetDetails(), ""); 168 EXPECT_FALSE(data->IsFinite()); 169 EXPECT_TRUE(data->GetCompleted()); 170 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 171 EXPECT_EQ(data->GetMessage(), "Progress report 1"); 172 } 173 174 TEST_F(ProgressReportTest, TestOverlappingEvents) { 175 ListenerSP listener_sp = 176 CreateListenerFor(Debugger::eBroadcastBitProgressCategory); 177 EventSP event_sp; 178 const ProgressEventData *data; 179 180 // Create two progress reports of the same category that overlap with each 181 // other. Here we want to ensure that the ID broadcasted for the initial and 182 // final reports for this category are the same. 183 std::unique_ptr<Progress> overlap_progress1 = 184 std::make_unique<Progress>("Overlapping report 1", "Starting report 1"); 185 std::unique_ptr<Progress> overlap_progress2 = 186 std::make_unique<Progress>("Overlapping report 1", "Starting report 2"); 187 overlap_progress1.reset(); 188 189 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 190 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 191 // Get the ID used in the first report for this category. 192 uint64_t expected_progress_id = data->GetID(); 193 194 EXPECT_EQ(data->GetDetails(), ""); 195 EXPECT_FALSE(data->IsFinite()); 196 EXPECT_FALSE(data->GetCompleted()); 197 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 198 EXPECT_EQ(data->GetMessage(), "Overlapping report 1"); 199 200 overlap_progress2.reset(); 201 202 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 203 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 204 205 EXPECT_EQ(data->GetDetails(), ""); 206 EXPECT_FALSE(data->IsFinite()); 207 EXPECT_TRUE(data->GetCompleted()); 208 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 209 EXPECT_EQ(data->GetMessage(), "Overlapping report 1"); 210 // The progress ID for the final report should be the same as that for the 211 // initial report. 212 EXPECT_EQ(data->GetID(), expected_progress_id); 213 } 214 215 TEST_F(ProgressReportTest, TestProgressManagerDisjointReports) { 216 ListenerSP listener_sp = 217 CreateListenerFor(Debugger::eBroadcastBitProgressCategory); 218 EventSP event_sp; 219 const ProgressEventData *data; 220 uint64_t expected_progress_id; 221 222 { Progress progress("Coalesced report 1", "Starting report 1"); } 223 { Progress progress("Coalesced report 1", "Starting report 2"); } 224 { Progress progress("Coalesced report 1", "Starting report 3"); } 225 226 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 227 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 228 expected_progress_id = data->GetID(); 229 230 EXPECT_EQ(data->GetDetails(), ""); 231 EXPECT_FALSE(data->IsFinite()); 232 EXPECT_FALSE(data->GetCompleted()); 233 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 234 EXPECT_EQ(data->GetMessage(), "Coalesced report 1"); 235 236 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT)); 237 data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); 238 239 EXPECT_EQ(data->GetID(), expected_progress_id); 240 EXPECT_EQ(data->GetDetails(), ""); 241 EXPECT_FALSE(data->IsFinite()); 242 EXPECT_TRUE(data->GetCompleted()); 243 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal); 244 EXPECT_EQ(data->GetMessage(), "Coalesced report 1"); 245 246 ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT)); 247 } 248