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