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