Align wslc volume inspect and prune output with docker (#41404)

volume inspect - Add Mountpoint and Scope ("local"). - Report Labels and Options as null rather than {} when absent, and omit Status when the driver reports nothing. - Rename DriverOpts to Options on the read path; DriverOpts remains the create-request name. volume prune - Print deleted volumes under a "Deleted Volumes:" header as bare names. - Emit the blank line before the total only when something was deleted. - Report reclaimed space with four significant digits (12.29kB). Also renames FormatDockerSize to FormatHumanReadableSize with a Precision parameter defaulting to 3, leaving image sizes unchanged. Tests updated, plus a new e2e test covering the full inspect field set. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

ggarzia-MSFT committed Aug 21, 2026 at 09:31 UTC 58c89ade0240f9a43f179d967863fb14920e66a8
17 files changed +161 -57
localization/strings/en-US/Resources.resw
+2 -3
@@ -3602,9 +3602,8 @@ On first run, creates the file with all settings commented out at their defaults
3602 <data name="WSLCCLI_VolumePruneAllArgDescription" xml:space="preserve">
3603 <value>Remove all unused volumes, not just anonymous ones.</value>
3604 </data>
3605 - <data name="WSLCCLI_VolumePruneDeleted" xml:space="preserve">
3606 - <value>Deleted: {}</value>
3607 - <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
3605 + <data name="WSLCCLI_VolumePruneDeletedHeader" xml:space="preserve">
3606 + <value>Deleted Volumes:</value>
3607 </data>
3608 <data name="WSLCCLI_VolumePruneSpaceReclaimed" xml:space="preserve">
3609 <value>Total reclaimed space: {}</value>
src/windows/common/string.cpp
+2 -2
@@ -401,7 +401,7 @@ std::wstring wsl::windows::common::string::FormatBytes(uint64_t Bytes)
401 return FormatStorageSize(Bytes, StorageSizeUnit::Decimal, 2, true);
402 }
403
404 -std::wstring wsl::windows::common::string::FormatDockerSize(uint64_t Bytes)
404 +std::wstring wsl::windows::common::string::FormatHumanReadableSize(uint64_t Bytes, uint32_t Precision)
405 {
406 constexpr std::wstring_view c_units[] = {L"B", L"kB", L"MB", L"GB", L"TB", L"PB", L"EB", L"ZB", L"YB"};
407
@@ -413,7 +413,7 @@ std::wstring wsl::windows::common::string::FormatDockerSize(uint64_t Bytes)
413 unitIndex++;
414 }
415
416 - return std::format(L"{:.3g}{}", value, c_units[unitIndex]);
416 + return std::format(L"{:.{}g}{}", value, Precision, c_units[unitIndex]);
417 }
418
419 std::wstring wsl::windows::common::string::TruncateId(_In_ std::wstring_view id, bool shortenLength)
src/windows/common/string.hpp
+3 -3
@@ -35,9 +35,9 @@ std::wstring FormatStorageSize(uint64_t Bytes, StorageSizeUnit Unit, uint32_t De
35
36 std::wstring FormatBytes(uint64_t Bytes);
37
38 -// Formats a size the way docker reports image sizes: base 1000, three significant digits and no
39 -// space (119856765 -> "120MB").
40 -std::wstring FormatDockerSize(uint64_t Bytes);
38 +// Formats a size as base 1000 with no space and the given number of significant digits
39 +// (119856765 -> "120MB" at precision 3, "119.9MB" at 4).
40 +std::wstring FormatHumanReadableSize(uint64_t Bytes, uint32_t Precision = 3);
41
42 std::vector<std::string> InitializeStringSet(_In_count_(BufferSize) LPCSTR Buffer, _In_ SIZE_T BufferSize);
43
src/windows/inc/wslc_schema.h
+29 -4
@@ -209,13 +209,38 @@ struct InspectVolume
209 std::string Name;
210 std::string Driver;
211 std::string CreatedAt;
212 - std::map<std::string, std::string> DriverOpts;
213 - std::map<std::string, std::string> Labels;
212 + std::string Mountpoint;
213 + std::string Scope;
214 + std::optional<std::map<std::string, std::string>> Options;
215 + std::optional<std::map<std::string, std::string>> Labels;
216 std::optional<std::map<std::string, std::string>> Status;
215 -
216 - NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(InspectVolume, Name, Driver, CreatedAt, DriverOpts, Labels, Status);
217 };
218
219 +// Labels and options are reported as null rather than as empty objects, and the driver-specific
220 +// status is omitted entirely when the driver reports nothing.
221 +inline void to_json(nlohmann::json& j, const InspectVolume& volume)
222 +{
223 + const auto mapOrNull = [](const std::optional<std::map<std::string, std::string>>& value) {
224 + return value.has_value() && !value->empty() ? nlohmann::json(*value) : nlohmann::json(nullptr);
225 + };
226 +
227 + j = nlohmann::json::object();
228 + j["CreatedAt"] = volume.CreatedAt;
229 + j["Driver"] = volume.Driver;
230 + j["Labels"] = mapOrNull(volume.Labels);
231 + j["Mountpoint"] = volume.Mountpoint;
232 + j["Name"] = volume.Name;
233 + j["Options"] = mapOrNull(volume.Options);
234 + j["Scope"] = volume.Scope;
235 +
236 + if (volume.Status.has_value() && !volume.Status->empty())
237 + {
238 + j["Status"] = *volume.Status;
239 + }
240 +}
241 +
242 +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_FROM_ONLY(InspectVolume, Name, Driver, CreatedAt, Mountpoint, Scope, Options, Labels, Status);
243 +
244 struct IPAMConfig
245 {
246 std::string Subnet;
src/windows/wslc/tasks/ImageTasks.cpp
+1 -1
@@ -89,7 +89,7 @@ namespace {
89 entry.ID = truncate ? TruncateId(image.Id, true) : image.Id;
90 entry.Repository = image.Repository.value_or(std::string{c_none});
91 entry.SharedSize = c_notAvailable;
92 - entry.Size = WideToMultiByte(FormatDockerSize(static_cast<uint64_t>(std::max<int64_t>(image.Size, 0))));
92 + entry.Size = WideToMultiByte(FormatHumanReadableSize(static_cast<uint64_t>(std::max<int64_t>(image.Size, 0))));
93 entry.Tag = image.Tag.value_or(std::string{c_none});
94 entry.UniqueSize = c_notAvailable;
95
src/windows/wslc/tasks/VolumeTasks.cpp
+13 -5
@@ -27,10 +27,12 @@ using namespace wsl::windows::common::wslutil;
27 using namespace wsl::windows::wslc::execution;
28 using namespace wsl::windows::wslc::models;
29 using namespace wsl::windows::wslc::services;
30 -using wsl::windows::common::string::FormatBytes;
30 +using wsl::windows::common::string::FormatHumanReadableSize;
31
32 namespace wsl::windows::wslc::task {
33
34 +constexpr uint32_t c_reclaimedSpacePrecision = 4;
35 +
36 static bool TryInspectVolume(Terminal& terminal, Session& session, const std::string& volumeName, std::optional<wslc_schema::InspectVolume>& inspectData)
37 {
38 try
@@ -211,12 +213,18 @@ void PruneVolumes(CLIExecutionContext& context)
213
214 auto result = VolumeService::Prune(context.Terminal, session, all, filters);
215
214 - for (const auto& volumeName : result.PrunedVolumes)
216 + if (!result.PrunedVolumes.empty())
217 {
216 - context.Terminal.Output(L"{}\n", Localization::WSLCCLI_VolumePruneDeleted(MultiByteToWide(volumeName)));
218 + context.Terminal.Output(L"{}\n", Localization::WSLCCLI_VolumePruneDeletedHeader());
219 + for (const auto& volumeName : result.PrunedVolumes)
220 + {
221 + context.Terminal.Output(L"{}\n", MultiByteToWide(volumeName));
222 + }
223 +
224 + context.Terminal.Output(L"\n");
225 }
226
219 - context.Terminal.Output(L"\n");
220 - context.Terminal.Output(L"{}\n", Localization::WSLCCLI_VolumePruneSpaceReclaimed(FormatBytes(result.SpaceReclaimed)));
227 + context.Terminal.Output(
228 + L"{}\n", Localization::WSLCCLI_VolumePruneSpaceReclaimed(FormatHumanReadableSize(result.SpaceReclaimed, c_reclaimedSpacePrecision)));
229 }
230 } // namespace wsl::windows::wslc::task
src/windows/wslcsession/WSLCGuestVolume.cpp
+17 -4
@@ -49,10 +49,16 @@ namespace {
49 WSLCGuestVolumeImpl::WSLCGuestVolumeImpl(
50 std::string&& Name,
51 std::string&& CreatedAt,
52 + std::string&& Mountpoint,
53 std::map<std::string, std::string>&& DriverOpts,
54 std::map<std::string, std::string>&& Labels,
55 DockerHTTPClient& DockerClient) :
55 - m_name(std::move(Name)), m_createdAt(std::move(CreatedAt)), m_driverOpts(std::move(DriverOpts)), m_labels(std::move(Labels)), m_dockerClient(DockerClient)
56 + m_name(std::move(Name)),
57 + m_createdAt(std::move(CreatedAt)),
58 + m_mountpoint(std::move(Mountpoint)),
59 + m_driverOpts(std::move(DriverOpts)),
60 + m_labels(std::move(Labels)),
61 + m_dockerClient(DockerClient)
62 {
63 }
64
@@ -80,7 +86,12 @@ std::unique_ptr<WSLCGuestVolumeImpl> WSLCGuestVolumeImpl::Create(
86 auto createdVolume = DockerClient.CreateVolume(request);
87
88 return std::make_unique<WSLCGuestVolumeImpl>(
83 - std::move(createdVolume.Name), std::move(createdVolume.CreatedAt), std::move(DriverOpts), std::move(Labels), DockerClient);
89 + std::move(createdVolume.Name),
90 + std::move(createdVolume.CreatedAt),
91 + std::move(createdVolume.Mountpoint),
92 + std::move(DriverOpts),
93 + std::move(Labels),
94 + DockerClient);
95 }
96 CATCH_AND_THROW_DOCKER_USER_ERROR("Failed to create volume '%hs'", Name != nullptr ? Name : "");
97 }
@@ -98,7 +109,7 @@ std::unique_ptr<WSLCGuestVolumeImpl> WSLCGuestVolumeImpl::Open(const wsl::window
109 std::map<std::string, std::string> labels = Volume.Labels.value_or(std::map<std::string, std::string>{});
110
111 return std::make_unique<WSLCGuestVolumeImpl>(
101 - std::string{Volume.Name}, std::string{Volume.CreatedAt}, std::move(driverOpts), std::move(labels), DockerClient);
112 + std::string{Volume.Name}, std::string{Volume.CreatedAt}, std::string{Volume.Mountpoint}, std::move(driverOpts), std::move(labels), DockerClient);
113 }
114
115 void WSLCGuestVolumeImpl::Delete()
@@ -122,7 +133,9 @@ std::string WSLCGuestVolumeImpl::Inspect() const
133 inspect.Name = m_name;
134 inspect.Driver = WSLCGuestVolumeDriver;
135 inspect.CreatedAt = m_createdAt;
125 - inspect.DriverOpts = m_driverOpts;
136 + inspect.Mountpoint = m_mountpoint;
137 + inspect.Scope = WSLCVolumeScope;
138 + inspect.Options = m_driverOpts;
139 inspect.Labels = m_labels;
140
141 return wsl::shared::ToJson(inspect);
src/windows/wslcsession/WSLCGuestVolume.h
+2
@@ -41,6 +41,7 @@ public:
41 WSLCGuestVolumeImpl(
42 std::string&& Name,
43 std::string&& CreatedAt,
44 + std::string&& Mountpoint,
45 std::map<std::string, std::string>&& DriverOpts,
46 std::map<std::string, std::string>&& Labels,
47 DockerHTTPClient& DockerClient);
@@ -76,6 +77,7 @@ public:
77 private:
78 std::string m_name;
79 std::string m_createdAt;
80 + std::string m_mountpoint;
81 std::map<std::string, std::string> m_driverOpts;
82 std::map<std::string, std::string> m_labels;
83 DockerHTTPClient& m_dockerClient;
src/windows/wslcsession/WSLCVhdVolume.cpp
+7 -1
@@ -118,6 +118,7 @@ WSLCVhdVolumeImpl::WSLCVhdVolumeImpl(
118 ULONG Lun,
119 std::string&& VirtualMachinePath,
120 std::string&& CreatedAt,
121 + std::string&& Mountpoint,
122 std::map<std::string, std::string>&& DriverOpts,
123 std::map<std::string, std::string>&& Labels,
124 WSLCVirtualMachine& VirtualMachine,
@@ -128,6 +129,7 @@ WSLCVhdVolumeImpl::WSLCVhdVolumeImpl(
129 m_hostPath(std::move(HostPath)),
130 m_virtualMachinePath(std::move(VirtualMachinePath)),
131 m_createdAt(std::move(CreatedAt)),
132 + m_mountpoint(std::move(Mountpoint)),
133 m_driverOpts(std::move(DriverOpts)),
134 m_labels(std::move(Labels)),
135 m_sizeBytes(SizeBytes),
@@ -217,6 +219,7 @@ std::unique_ptr<WSLCVhdVolumeImpl> WSLCVhdVolumeImpl::Create(
219 lun,
220 std::move(virtualMachinePath),
221 std::move(createdVolume.CreatedAt),
222 + std::move(createdVolume.Mountpoint),
223 std::move(DriverOpts),
224 std::move(Labels),
225 VirtualMachine,
@@ -303,6 +306,7 @@ std::unique_ptr<WSLCVhdVolumeImpl> WSLCVhdVolumeImpl::Open(
306 lun,
307 std::move(virtualMachinePath),
308 std::string{Volume.CreatedAt},
309 + std::string{Volume.Mountpoint},
310 std::move(driverOpts),
311 std::move(userLabels),
312 VirtualMachine,
@@ -334,7 +338,9 @@ std::string WSLCVhdVolumeImpl::Inspect() const
338 inspect.Name = m_name;
339 inspect.Driver = WSLCVhdVolumeDriver;
340 inspect.CreatedAt = m_createdAt;
337 - inspect.DriverOpts = m_driverOpts;
341 + inspect.Mountpoint = m_mountpoint;
342 + inspect.Scope = WSLCVolumeScope;
343 + inspect.Options = m_driverOpts;
344 inspect.Labels = m_labels;
345 inspect.Status = std::map<std::string, std::string>{
346 {"HostPath", m_hostPath.string()},
src/windows/wslcsession/WSLCVhdVolume.h
+2
@@ -43,6 +43,7 @@ public:
43 ULONG Lun,
44 std::string&& VirtualMachinePath,
45 std::string&& CreatedAt,
46 + std::string&& Mountpoint,
47 std::map<std::string, std::string>&& DriverOpts,
48 std::map<std::string, std::string>&& Labels,
49 WSLCVirtualMachine& VirtualMachine,
@@ -99,6 +100,7 @@ private:
100 std::filesystem::path m_hostPath;
101 std::string m_virtualMachinePath;
102 std::string m_createdAt;
103 + std::string m_mountpoint;
104 std::map<std::string, std::string> m_driverOpts;
105 std::map<std::string, std::string> m_labels;
106 ULONGLONG m_sizeBytes{};
src/windows/wslcsession/WSLCVolumeMetadata.h
+4
@@ -27,6 +27,10 @@ constexpr auto WSLCVhdVolumeDriver = "vhd";
27 // Volume driver name for guest-backed volumes (passthrough to docker's built-in "local" driver).
28 constexpr auto WSLCGuestVolumeDriver = "guest";
29
30 +// The level at which a volume exists: "local" (machine level) or "global" (cluster-wide).
31 +// Every WSLC volume is machine level.
32 +constexpr auto WSLCVolumeScope = "local";
33 +
34 struct WSLCVolumeMetadata
35 {
36 std::string Driver;
test/windows/StringUnitTests.cpp
+22 -6
@@ -5,7 +5,7 @@
5 #include "string.hpp"
6
7 using wsl::windows::common::string::FormatBytes;
8 -using wsl::windows::common::string::FormatDockerSize;
8 +using wsl::windows::common::string::FormatHumanReadableSize;
9 using wsl::windows::common::string::FormatStorageSize;
10 using wsl::windows::common::string::ParseStorageSize;
11 using wsl::windows::common::string::StorageSizeUnit;
@@ -228,9 +228,9 @@ class StringUnitTests
228 VERIFY_ARE_EQUAL(std::wstring{L"119.86 MB"}, FormatBytes(119'856'765));
229 }
230
231 - // Docker renders image sizes with units.HumanSizeWithPrecision(size, 3), which is base 1000 with
232 - // three significant digits, no space, and "kB" rather than "KB".
233 - TEST_METHOD(FormatDockerSize_MatchesDockerPrecision)
231 + // Image sizes are rendered with three significant digits, base 1000, no space, and "kB" rather
232 + // than "KB".
233 + TEST_METHOD(FormatHumanReadableSize_MatchesImageSizePrecision)
234 {
235 const std::vector<std::pair<uint64_t, std::wstring>> TestCases{
236 {0, L"0B"},
@@ -245,11 +245,27 @@ class StringUnitTests
245
246 for (const auto& [bytes, expected] : TestCases)
247 {
248 - VERIFY_ARE_EQUAL(expected, FormatDockerSize(bytes));
248 + VERIFY_ARE_EQUAL(expected, FormatHumanReadableSize(bytes));
249 }
250
251 // Three significant digits switch to exponent form just below the next unit, matching Go's %g.
252 - VERIFY_ARE_EQUAL(std::wstring{L"1e+03MB"}, FormatDockerSize(999'900'000));
252 + VERIFY_ARE_EQUAL(std::wstring{L"1e+03MB"}, FormatHumanReadableSize(999'900'000));
253 + }
254 +
255 + TEST_METHOD(FormatHumanReadableSize_SupportsReclaimedSpacePrecision)
256 + {
257 + const std::vector<std::pair<uint64_t, std::wstring>> TestCases{
258 + {0, L"0B"},
259 + {999, L"999B"},
260 + {12'288, L"12.29kB"},
261 + {119'856'765, L"119.9MB"},
262 + {1'090'000'000, L"1.09GB"},
263 + };
264 +
265 + for (const auto& [bytes, expected] : TestCases)
266 + {
267 + VERIFY_ARE_EQUAL(expected, FormatHumanReadableSize(bytes, 4));
268 + }
269 }
270
271 TEST_METHOD(StorageSize_BytesToTextRoundTrips)
test/windows/WSLCTests.cpp
+7 -2
@@ -5108,7 +5108,10 @@ class WSLCTests
5108 auto vhdInspect = wsl::shared::FromJson<wsl::windows::common::wslc_schema::InspectVolume>(output.get());
5109 VERIFY_ARE_EQUAL(vhdInspect.Name, vhdVolumeName);
5110 VERIFY_ARE_EQUAL(vhdInspect.Driver, std::string("vhd"));
5111 - VERIFY_IS_TRUE(vhdInspect.DriverOpts.contains("SizeBytes"));
5111 + VERIFY_ARE_EQUAL(vhdInspect.Scope, std::string("local"));
5112 + VERIFY_IS_FALSE(vhdInspect.Mountpoint.empty());
5113 + VERIFY_IS_TRUE(vhdInspect.Options.has_value());
5114 + VERIFY_IS_TRUE(vhdInspect.Options->contains("SizeBytes"));
5115
5116 // Verify InspectVolume returns correct details for the guest volume (no driver opts).
5117 output.reset();
@@ -5118,7 +5121,9 @@ class WSLCTests
5121 auto guestInspect = wsl::shared::FromJson<wsl::windows::common::wslc_schema::InspectVolume>(output.get());
5122 VERIFY_ARE_EQUAL(guestInspect.Name, guestVolumeName);
5123 VERIFY_ARE_EQUAL(guestInspect.Driver, std::string("guest"));
5121 - VERIFY_IS_TRUE(guestInspect.DriverOpts.empty());
5124 + VERIFY_ARE_EQUAL(guestInspect.Scope, std::string("local"));
5125 + VERIFY_IS_FALSE(guestInspect.Mountpoint.empty());
5126 + VERIFY_IS_FALSE(guestInspect.Options.has_value());
5127
5128 // Verify InspectVolume fails for a non-existent volume.
5129 output.reset();
test/windows/wslc/e2e/WSLCE2EContainerRemoveTests.cpp
+2 -1
@@ -254,8 +254,9 @@ private:
254 VERIFY_ARE_EQUAL(mount->Destination, "/data");
255
256 const auto volumeName = wsl::shared::string::MultiByteToWide(mount->Name);
257 + const auto volumeLabels = InspectVolume(volumeName).Labels;
258 VERIFY_IS_TRUE(
258 - InspectVolume(volumeName).Labels.contains("com.docker.volume.anonymous"),
259 + volumeLabels.has_value() && volumeLabels->contains("com.docker.volume.anonymous"),
260 L"The volume returned by container inspect is not anonymous");
261 return volumeName;
262 }
test/windows/wslc/e2e/WSLCE2EVolumeCreateTests.cpp
+3 -2
@@ -107,8 +107,9 @@ class WSLCE2EVolumeCreateTests
107
108 VerifyVolumeIsListed(TestVolumeName);
109 auto inspect = InspectVolume(TestVolumeName);
110 - VERIFY_ARE_EQUAL("1", inspect.Labels["A"]);
111 - VERIFY_ARE_EQUAL("2", inspect.Labels["B"]);
110 + VERIFY_IS_TRUE(inspect.Labels.has_value());
111 + VERIFY_ARE_EQUAL("1", inspect.Labels->at("A"));
112 + VERIFY_ARE_EQUAL("2", inspect.Labels->at("B"));
113 }
114
115 private:
test/windows/wslc/e2e/WSLCE2EVolumeInspectTests.cpp
+25
@@ -69,6 +69,31 @@ class WSLCE2EVolumeInspectTests
69 VERIFY_ARE_EQUAL("guest", inspect.Driver);
70 }
71
72 + // Every volume reports the same field set: Labels and Options are null rather than empty
73 + // objects, Scope is always "local", and Status is only present when the driver reports one.
74 + WSLC_TEST_METHOD(WSLCE2E_Volume_Inspect_ReportsFullFieldSet)
75 + {
76 + auto result = RunWslc(std::format(L"volume create {}", TestVolumeName1));
77 + result.Verify({.Stderr = L"", .ExitCode = 0});
78 +
79 + result = RunWslc(std::format(L"volume inspect --format json {}", TestVolumeName1));
80 + result.Verify({.Stderr = L"", .ExitCode = 0});
81 +
82 + const auto document = VerifyCompactJsonOutput(result);
83 + VERIFY_ARE_EQUAL(1u, document.size());
84 + const auto& volume = document[0];
85 +
86 + VERIFY_ARE_EQUAL(7u, volume.size());
87 + VERIFY_IS_TRUE(volume["CreatedAt"].is_string());
88 + VERIFY_ARE_EQUAL("guest", volume["Driver"].get<std::string>());
89 + VERIFY_IS_TRUE(volume["Labels"].is_null());
90 + VERIFY_IS_FALSE(volume["Mountpoint"].get<std::string>().empty());
91 + VERIFY_ARE_EQUAL(WideToMultiByte(TestVolumeName1), volume["Name"].get<std::string>());
92 + VERIFY_IS_TRUE(volume["Options"].is_null());
93 + VERIFY_ARE_EQUAL("local", volume["Scope"].get<std::string>());
94 + VERIFY_IS_FALSE(volume.contains("Status"));
95 + }
96 +
97 WSLC_TEST_METHOD(WSLCE2E_Volume_Inspect_FormatJson_IsSingleLine)
98 {
99 auto result = RunWslc(std::format(L"volume create {}", TestVolumeName1));
test/windows/wslc/e2e/WSLCE2EVolumePruneTests.cpp
+20 -23
@@ -56,7 +56,9 @@ class WSLCE2EVolumePruneTests
56 const auto result = RunWslc(L"volume prune");
57 result.Verify({.Stderr = L"", .ExitCode = 0});
58
59 - VERIFY_IS_TRUE(result.StdoutContainsSubstring(L"Total reclaimed space:"));
59 + // The deleted-volume block, and the blank line that follows it, are only written when
60 + // something was actually removed.
61 + result.Verify({.Stdout = L"Total reclaimed space: 0B\r\n"});
62 }
63
64 WSLC_TEST_METHOD(WSLCE2E_Volume_Prune_NoAllFlag_PreservesNamedVolumes)
@@ -70,9 +72,8 @@ class WSLCE2EVolumePruneTests
72 result.Verify({.Stderr = L"", .ExitCode = 0});
73
74 auto output = result.GetStdoutLines();
73 - VERIFY_ARE_EQUAL(2u, output.size());
74 - VERIFY_ARE_EQUAL(output[0], L"");
75 - VERIFY_ARE_NOT_EQUAL(std::wstring::npos, output[1].find(L"Total reclaimed space:"));
75 + VERIFY_ARE_EQUAL(1u, output.size());
76 + VERIFY_ARE_NOT_EQUAL(std::wstring::npos, output[0].find(L"Total reclaimed space:"));
77
78 VerifyVolumeIsListed(TestVolumeName);
79 }
@@ -88,10 +89,11 @@ class WSLCE2EVolumePruneTests
89 result.Verify({.Stderr = L"", .ExitCode = 0});
90
91 auto output = result.GetStdoutLines();
91 - VERIFY_ARE_EQUAL(3u, output.size());
92 - VERIFY_ARE_NOT_EQUAL(std::wstring::npos, output[0].find(std::format(L"Deleted: {}", TestVolumeName)));
93 - VERIFY_ARE_EQUAL(output[1], L"");
94 - VERIFY_ARE_NOT_EQUAL(std::wstring::npos, output[2].find(L"Total reclaimed space:"));
92 + VERIFY_ARE_EQUAL(4u, output.size());
93 + VERIFY_ARE_EQUAL(output[0], L"Deleted Volumes:");
94 + VERIFY_ARE_EQUAL(output[1], TestVolumeName);
95 + VERIFY_ARE_EQUAL(output[2], L"");
96 + VERIFY_ARE_NOT_EQUAL(std::wstring::npos, output[3].find(L"Total reclaimed space:"));
97
98 VerifyVolumeIsNotListed(TestVolumeName);
99 }
@@ -111,8 +113,9 @@ class WSLCE2EVolumePruneTests
113 const auto result = RunWslc(L"volume prune --all");
114 result.Verify({.Stderr = L"", .ExitCode = 0});
115
114 - VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)));
115 - VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName2)));
116 + VERIFY_IS_TRUE(result.StdoutContainsLine(L"Deleted Volumes:"));
117 + VERIFY_IS_TRUE(result.StdoutContainsLine(TestVolumeName));
118 + VERIFY_IS_TRUE(result.StdoutContainsLine(TestVolumeName2));
119
120 VerifyVolumeIsNotListed(TestVolumeName);
121 VerifyVolumeIsNotListed(TestVolumeName2);
@@ -136,9 +139,7 @@ class WSLCE2EVolumePruneTests
139 const auto result = RunWslc(L"volume prune --all");
140 result.Verify({.Stderr = L"", .ExitCode = 0});
141
139 - VERIFY_IS_FALSE(
140 - result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)),
141 - L"Volume in use by a running container must not be pruned");
142 + VERIFY_IS_FALSE(result.StdoutContainsLine(TestVolumeName), L"Volume in use by a running container must not be pruned");
143
144 VerifyVolumeIsListed(TestVolumeName);
145 }
@@ -154,15 +155,14 @@ class WSLCE2EVolumePruneTests
155 const auto filteredPrune = RunWslc(L"volume prune --all --filter label=wslc.test.never=present");
156 filteredPrune.Verify({.Stderr = L"", .ExitCode = 0});
157 VERIFY_IS_FALSE(
157 - filteredPrune.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)),
158 - L"Filtered prune should not have deleted the non-matching volume");
158 + filteredPrune.StdoutContainsLine(TestVolumeName), L"Filtered prune should not have deleted the non-matching volume");
159 VerifyVolumeIsListed(TestVolumeName);
160
161 // Subsequent unfiltered prune --all should still remove it, proving
162 // the filter was the reason it survived.
163 const auto unfilteredPrune = RunWslc(L"volume prune --all");
164 unfilteredPrune.Verify({.Stderr = L"", .ExitCode = 0});
165 - VERIFY_IS_TRUE(unfilteredPrune.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)));
165 + VERIFY_IS_TRUE(unfilteredPrune.StdoutContainsLine(TestVolumeName));
166 VerifyVolumeIsNotListed(TestVolumeName);
167 }
168
@@ -181,10 +181,8 @@ class WSLCE2EVolumePruneTests
181 const auto result = RunWslc(L"volume prune --all --filter label=wslc.test.prune=keep");
182 result.Verify({.Stderr = L"", .ExitCode = 0});
183
184 - VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)));
185 - VERIFY_IS_FALSE(
186 - result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName2)),
187 - L"Volume without the matching label must not be deleted");
184 + VERIFY_IS_TRUE(result.StdoutContainsLine(TestVolumeName));
185 + VERIFY_IS_FALSE(result.StdoutContainsLine(TestVolumeName2), L"Volume without the matching label must not be deleted");
186
187 VerifyVolumeIsNotListed(TestVolumeName);
188 VerifyVolumeIsListed(TestVolumeName2);
@@ -205,10 +203,9 @@ class WSLCE2EVolumePruneTests
203 const auto result = RunWslc(L"volume prune --all --filter label!=wslc.test.keep");
204 result.Verify({.Stderr = L"", .ExitCode = 0});
205
208 - VERIFY_IS_TRUE(result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName2)));
206 + VERIFY_IS_TRUE(result.StdoutContainsLine(TestVolumeName2));
207 VERIFY_IS_FALSE(
210 - result.StdoutContainsLine(std::format(L"Deleted: {}", TestVolumeName)),
211 - L"Labeled volume must be preserved when prune negates that label");
208 + result.StdoutContainsLine(TestVolumeName), L"Labeled volume must be preserved when prune negates that label");
209
210 VerifyVolumeIsListed(TestVolumeName);
211 VerifyVolumeIsNotListed(TestVolumeName2);