xref: /llvm-project/lldb/unittests/Core/ProgressReportTest.cpp (revision 4dcb1db44f9dbfa09c220703a1b097f51d20a2a5)
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