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