415 lines · cpp
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-exception6//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#include <thread>22 23using namespace lldb;24using namespace lldb_private;25 26static std::chrono::milliseconds TIMEOUT(500);27 28class ProgressReportTest : public ::testing::Test {29public:30 ListenerSP CreateListenerFor(uint32_t bit) {31 // Set up the debugger, make sure that was done properly.32 ArchSpec arch("x86_64-apple-macosx-");33 Platform::SetHostPlatform(34 PlatformRemoteMacOSX::CreateInstance(true, &arch));35 36 m_debugger_sp = Debugger::CreateInstance();37 38 // Get the debugger's broadcaster.39 Broadcaster &broadcaster = m_debugger_sp->GetBroadcaster();40 41 // Create a listener, make sure it can receive events and that it's42 // listening to the correct broadcast bit.43 m_listener_sp = Listener::MakeListener("progress-listener");44 m_listener_sp->StartListeningForEvents(&broadcaster, bit);45 return m_listener_sp;46 }47 48protected:49 // The debugger's initialization function can't be called with no arguments50 // so calling it using SubsystemRAII will cause the test build to fail as51 // SubsystemRAII will call Initialize with no arguments. As such we set it up52 // here the usual way.53 void SetUp() override {54 std::call_once(TestUtilities::g_debugger_initialize_flag,55 []() { Debugger::Initialize(nullptr); });56 };57 58 DebuggerSP m_debugger_sp;59 ListenerSP m_listener_sp;60 SubsystemRAII<FileSystem, HostInfo, PlatformMacOSX> subsystems;61};62 63TEST_F(ProgressReportTest, TestReportCreation) {64 ListenerSP listener_sp = CreateListenerFor(lldb::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 having70 // 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 recevied78 // in this order:79 // Starting progress: 1, 2, 380 // Ending progress: 3, 2, 181 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 so109 // get each report from the queue and check that they've been110 // 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 136TEST_F(ProgressReportTest, TestReportDestructionWithPartialProgress) {137 ListenerSP listener_sp = CreateListenerFor(lldb::eBroadcastBitProgress);138 EventSP event_sp;139 const ProgressEventData *data;140 141 // Create a finite progress report and only increment to a non-completed142 // state before destruction.143 {144 Progress progress("Finite progress", "Report 1", 100);145 progress.Increment(3);146 }147 148 // Verify that the progress in the events are:149 // 1. At construction: 0 out of 100150 // 2. At increment: 3 out of 100151 // 3. At destruction: 100 out of 100152 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));153 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());154 EXPECT_EQ(data->GetDetails(), "Report 1");155 EXPECT_TRUE(data->IsFinite());156 EXPECT_EQ(data->GetCompleted(), (uint64_t)0);157 EXPECT_EQ(data->GetTotal(), (uint64_t)100);158 EXPECT_EQ(data->GetMessage(), "Finite progress: Report 1");159 160 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));161 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());162 EXPECT_EQ(data->GetDetails(), "Report 1");163 EXPECT_TRUE(data->IsFinite());164 EXPECT_EQ(data->GetCompleted(), (uint64_t)3);165 EXPECT_EQ(data->GetTotal(), (uint64_t)100);166 EXPECT_EQ(data->GetMessage(), "Finite progress: Report 1");167 168 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));169 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());170 EXPECT_EQ(data->GetDetails(), "Report 1");171 EXPECT_TRUE(data->IsFinite());172 EXPECT_EQ(data->GetCompleted(), (uint64_t)100);173 EXPECT_EQ(data->GetTotal(), (uint64_t)100);174 EXPECT_EQ(data->GetMessage(), "Finite progress: Report 1");175 176 // Create an infinite progress report and increment by some amount.177 {178 Progress progress("Infinite progress", "Report 2");179 progress.Increment(3);180 }181 182 // Verify that the progress in the events are:183 // 1. At construction: 0184 // 2. At increment: 3185 // 3. At destruction: Progress::kNonDeterministicTotal186 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));187 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());188 EXPECT_EQ(data->GetDetails(), "Report 2");189 EXPECT_FALSE(data->IsFinite());190 EXPECT_EQ(data->GetCompleted(), (uint64_t)0);191 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);192 EXPECT_EQ(data->GetMessage(), "Infinite progress: Report 2");193 194 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));195 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());196 EXPECT_EQ(data->GetDetails(), "Report 2");197 EXPECT_FALSE(data->IsFinite());198 EXPECT_EQ(data->GetCompleted(), (uint64_t)3);199 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);200 EXPECT_EQ(data->GetMessage(), "Infinite progress: Report 2");201 202 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));203 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());204 EXPECT_EQ(data->GetDetails(), "Report 2");205 EXPECT_FALSE(data->IsFinite());206 EXPECT_EQ(data->GetCompleted(), Progress::kNonDeterministicTotal);207 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);208 EXPECT_EQ(data->GetMessage(), "Infinite progress: Report 2");209}210 211TEST_F(ProgressReportTest, TestFiniteOverflow) {212 ListenerSP listener_sp = CreateListenerFor(lldb::eBroadcastBitProgress);213 EventSP event_sp;214 const ProgressEventData *data;215 216 // Increment the report beyond its limit and make sure we only get one217 // completed event.218 {219 Progress progress("Finite progress", "Report 1", 10);220 progress.Increment(11);221 progress.Increment(47);222 }223 224 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));225 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());226 EXPECT_TRUE(data->IsFinite());227 EXPECT_EQ(data->GetCompleted(), 0U);228 EXPECT_EQ(data->GetTotal(), 10U);229 230 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));231 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());232 EXPECT_TRUE(data->IsFinite());233 EXPECT_EQ(data->GetCompleted(), 10U);234 EXPECT_EQ(data->GetTotal(), 10U);235 236 ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT));237}238 239TEST_F(ProgressReportTest, TestNonDeterministicOverflow) {240 ListenerSP listener_sp = CreateListenerFor(lldb::eBroadcastBitProgress);241 EventSP event_sp;242 const ProgressEventData *data;243 constexpr uint64_t max_minus_1 = std::numeric_limits<uint64_t>::max() - 1;244 245 // Increment the report beyond its limit and make sure we only get one246 // completed event. The event which overflows the counter should be ignored.247 {248 Progress progress("Non deterministic progress", "Report 1");249 progress.Increment(max_minus_1);250 progress.Increment(max_minus_1);251 }252 253 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));254 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());255 EXPECT_FALSE(data->IsFinite());256 EXPECT_EQ(data->GetCompleted(), 0U);257 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);258 259 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));260 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());261 EXPECT_FALSE(data->IsFinite());262 EXPECT_EQ(data->GetCompleted(), max_minus_1);263 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);264 265 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));266 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());267 EXPECT_FALSE(data->IsFinite());268 EXPECT_EQ(data->GetCompleted(), Progress::kNonDeterministicTotal);269 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);270 271 ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT));272}273 274TEST_F(ProgressReportTest, TestMinimumReportTime) {275 ListenerSP listener_sp = CreateListenerFor(lldb::eBroadcastBitProgress);276 EventSP event_sp;277 const ProgressEventData *data;278 279 {280 Progress progress("Finite progress", "Report 1", /*total=*/20,281 m_debugger_sp.get(),282 /*minimum_report_time=*/std::chrono::seconds(1));283 // Send 10 events in quick succession. These should not generate any events.284 for (int i = 0; i < 10; ++i)285 progress.Increment();286 287 // Sleep, then send 10 more. This should generate one event for the first288 // increment, and then another for completion.289 std::this_thread::sleep_for(std::chrono::seconds(1));290 for (int i = 0; i < 10; ++i)291 progress.Increment();292 }293 294 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));295 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());296 EXPECT_TRUE(data->IsFinite());297 EXPECT_EQ(data->GetCompleted(), 0U);298 EXPECT_EQ(data->GetTotal(), 20U);299 300 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));301 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());302 EXPECT_TRUE(data->IsFinite());303 EXPECT_EQ(data->GetCompleted(), 11U);304 EXPECT_EQ(data->GetTotal(), 20U);305 306 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));307 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());308 EXPECT_TRUE(data->IsFinite());309 EXPECT_EQ(data->GetCompleted(), 20U);310 EXPECT_EQ(data->GetTotal(), 20U);311 312 ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT));313}314 315TEST_F(ProgressReportTest, TestExternalReportCreation) {316 ListenerSP listener_sp =317 CreateListenerFor(lldb::eBroadcastBitExternalProgress);318 EventSP event_sp;319 const ProgressEventData *data;320 321 // Scope this for RAII on the progress objects.322 // Create progress reports and check that their respective events for having323 // started and ended are broadcasted.324 {325 Progress progress1("Progress report 1", "Starting report 1",326 /*total=*/std::nullopt, /*debugger=*/nullptr,327 /*minimum_report_time=*/std::chrono::seconds(0),328 Progress::Origin::eExternal);329 Progress progress2("Progress report 2", "Starting report 2",330 /*total=*/std::nullopt, /*debugger=*/nullptr,331 /*minimum_report_time=*/std::chrono::seconds(0),332 Progress::Origin::eExternal);333 Progress progress3("Progress report 3", "Starting report 3",334 /*total=*/std::nullopt, /*debugger=*/nullptr,335 /*minimum_report_time=*/std::chrono::seconds(0),336 Progress::Origin::eExternal);337 }338 339 // Start popping events from the queue, they should have been recevied340 // in this order:341 // Starting progress: 1, 2, 3342 // Ending progress: 3, 2, 1343 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));344 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());345 346 EXPECT_EQ(data->GetDetails(), "Starting report 1");347 EXPECT_FALSE(data->IsFinite());348 EXPECT_FALSE(data->GetCompleted());349 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);350 EXPECT_EQ(data->GetMessage(), "Progress report 1: Starting report 1");351 352 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));353 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());354 355 EXPECT_EQ(data->GetDetails(), "Starting report 2");356 EXPECT_FALSE(data->IsFinite());357 EXPECT_FALSE(data->GetCompleted());358 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);359 EXPECT_EQ(data->GetMessage(), "Progress report 2: Starting report 2");360 361 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));362 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());363 364 EXPECT_EQ(data->GetDetails(), "Starting report 3");365 EXPECT_FALSE(data->IsFinite());366 EXPECT_FALSE(data->GetCompleted());367 EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);368 EXPECT_EQ(data->GetMessage(), "Progress report 3: Starting report 3");369 370 // Progress report objects should be destroyed at this point so371 // get each report from the queue and check that they've been372 // destroyed in reverse order.373 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));374 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());375 376 EXPECT_EQ(data->GetTitle(), "Progress report 3");377 EXPECT_TRUE(data->GetCompleted());378 EXPECT_FALSE(data->IsFinite());379 EXPECT_EQ(data->GetMessage(), "Progress report 3: Starting report 3");380 381 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));382 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());383 384 EXPECT_EQ(data->GetTitle(), "Progress report 2");385 EXPECT_TRUE(data->GetCompleted());386 EXPECT_FALSE(data->IsFinite());387 EXPECT_EQ(data->GetMessage(), "Progress report 2: Starting report 2");388 389 ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));390 data = ProgressEventData::GetEventDataFromEvent(event_sp.get());391 392 EXPECT_EQ(data->GetTitle(), "Progress report 1");393 EXPECT_TRUE(data->GetCompleted());394 EXPECT_FALSE(data->IsFinite());395 EXPECT_EQ(data->GetMessage(), "Progress report 1: Starting report 1");396}397 398TEST_F(ProgressReportTest, TestExternalReportNotReceived) {399 ListenerSP listener_sp = CreateListenerFor(lldb::eBroadcastBitProgress);400 EventSP event_sp;401 402 // Scope this for RAII on the progress objects.403 // Create progress reports and check that their respective events for having404 // started and ended are broadcasted.405 {406 Progress progress1("External Progress report 1",407 "Starting external report 1",408 /*total=*/std::nullopt, /*debugger=*/nullptr,409 /*minimum_report_time=*/std::chrono::seconds(0),410 Progress::Origin::eExternal);411 }412 413 ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT));414}415