1
+/*++
2
+
3
+Copyright (c) Microsoft. All rights reserved.
4
+
5
+Module Name:
6
+
7
+ WSLCE2EContainerPruneTests.cpp
8
+
9
+Abstract:
10
+
11
+ This file contains end-to-end tests for WSLC container prune command.
12
+--*/
13
+
14
+#include "precomp.h"
15
+#include "windows/Common.h"
16
+#include "WSLCExecutor.h"
17
+#include "WSLCE2EHelpers.h"
18
+
19
+namespace WSLCE2ETests {
20
+using namespace wsl::shared;
21
+
22
+class WSLCE2EContainerPruneTests
23
+{
24
+ WSLC_TEST_CLASS(WSLCE2EContainerPruneTests)
25
+
26
+ TEST_CLASS_SETUP(ClassSetup)
27
+ {
28
+ EnsureImageIsLoaded(DebianImage);
29
+
30
+ // Clean up any leftover containers from previous failed runs
31
+ EnsureContainerDoesNotExist(L"prune-test-container");
32
+ EnsureContainerDoesNotExist(L"prune-running-test");
33
+ EnsureContainerDoesNotExist(L"prune-multi-1");
34
+ EnsureContainerDoesNotExist(L"prune-multi-2");
35
+ return true;
36
+ }
37
+
38
+ TEST_CLASS_CLEANUP(ClassCleanup)
39
+ {
40
+ // Clean up any leftover containers
41
+ RunWslc(L"container prune");
42
+ return true;
43
+ }
44
+
45
+ WSLC_TEST_METHOD(WSLCE2E_Container_Prune_HelpCommand)
46
+ {
47
+ const auto result = RunWslc(L"container prune --help");
48
+ result.Verify({.Stdout = GetHelpMessage(), .Stderr = L"", .ExitCode = 0});
49
+ }
50
+
51
+ WSLC_TEST_METHOD(WSLCE2E_Container_Prune_NoStoppedContainers)
52
+ {
53
+ // Prune when no stopped containers exist should succeed with zero reclaimed space
54
+ const auto result = RunWslc(L"container prune");
55
+ result.Verify({.Stderr = L"", .ExitCode = 0});
56
+
57
+ VERIFY_IS_TRUE(result.StdoutContainsSubstring(Localization::WSLCCLI_ContainerPruneSpaceReclaimed(0.0)));
58
+ }
59
+
60
+ WSLC_TEST_METHOD(WSLCE2E_Container_Prune_StoppedContainer)
61
+ {
62
+ // Create and stop a container, then prune it
63
+ auto createResult = RunWslc(std::format(L"container create --name prune-test-container {}", DebianImage.NameAndTag()));
64
+ createResult.Verify({.Stderr = L"", .ExitCode = 0});
65
+ auto containerId = createResult.GetStdoutOneLine();
66
+
67
+ auto cleanup = wil::scope_exit([&]() { RunWslc(L"container prune"); });
68
+
69
+ // The created container is in stopped state, so prune should remove it
70
+ const auto result = RunWslc(L"container prune");
71
+ result.Verify({.Stderr = L"", .ExitCode = 0});
72
+
73
+ // Verify pruned container ID is in output
74
+ VERIFY_IS_TRUE(result.StdoutContainsSubstring(containerId));
75
+
76
+ // Verify the container is actually removed
77
+ VerifyContainerIsNotListed(L"prune-test-container");
78
+ }
79
+
80
+ WSLC_TEST_METHOD(WSLCE2E_Container_Prune_RunningContainerNotPruned)
81
+ {
82
+ // Start a running container, verify prune does NOT remove it
83
+ auto runResult = RunWslc(std::format(L"container run --detach --name prune-running-test {} sleep 300", DebianImage.NameAndTag()));
84
+ runResult.Verify({.Stderr = L"", .ExitCode = 0});
85
+
86
+ auto cleanup = wil::scope_exit([&]() {
87
+ RunWslc(L"container kill prune-running-test");
88
+ RunWslc(L"container remove --force prune-running-test");
89
+ });
90
+
91
+ // Prune should not remove a running container
92
+ const auto pruneResult = RunWslc(L"container prune");
93
+ pruneResult.Verify({.Stderr = L"", .ExitCode = 0});
94
+
95
+ // Verify the running container is still present
96
+ VerifyContainerIsListed(L"prune-running-test", L"running");
97
+ }
98
+
99
+ WSLC_TEST_METHOD(WSLCE2E_Container_Prune_MultipleStopped)
100
+ {
101
+ // Create multiple stopped containers and verify all are pruned
102
+ auto create1 = RunWslc(std::format(L"container create --name prune-multi-1 {}", DebianImage.NameAndTag()));
103
+ create1.Verify({.Stderr = L"", .ExitCode = 0});
104
+ auto containerId1 = create1.GetStdoutOneLine();
105
+
106
+ auto create2 = RunWslc(std::format(L"container create --name prune-multi-2 {}", DebianImage.NameAndTag()));
107
+ create2.Verify({.Stderr = L"", .ExitCode = 0});
108
+ auto containerId2 = create2.GetStdoutOneLine();
109
+
110
+ auto cleanup = wil::scope_exit([&]() { RunWslc(L"container prune"); });
111
+
112
+ const auto result = RunWslc(L"container prune");
113
+ result.Verify({.Stderr = L"", .ExitCode = 0});
114
+
115
+ // Verify pruned container IDs are in output
116
+ VERIFY_IS_TRUE(result.StdoutContainsSubstring(containerId1));
117
+ VERIFY_IS_TRUE(result.StdoutContainsSubstring(containerId2));
118
+
119
+ // Verify both containers are removed
120
+ VerifyContainerIsNotListed(L"prune-multi-1");
121
+ VerifyContainerIsNotListed(L"prune-multi-2");
122
+ }
123
+
124
+private:
125
+ const TestImage& DebianImage = DebianTestImage();
126
+
127
+ std::wstring GetHelpMessage() const
128
+ {
129
+ std::wstringstream output;
130
+ output << GetWslcHeader() //
131
+ << GetDescription() //
132
+ << GetUsage() //
133
+ << GetAvailableOptions();
134
+ return output.str();
135
+ }
136
+
137
+ std::wstring GetDescription() const
138
+ {
139
+ return Localization::WSLCCLI_ContainerPruneLongDesc() + L"\r\n\r\n";
140
+ }
141
+
142
+ std::wstring GetUsage() const
143
+ {
144
+ return L"Usage: wslc container prune [<options>]\r\n\r\n";
145
+ }
146
+
147
+ std::wstring GetAvailableOptions() const
148
+ {
149
+ std::wstringstream options;
150
+ options << L"The following options are available:\r\n"
151
+ << L" --session " << Localization::WSLCCLI_SessionIdArgDescription() << L"\r\n"
152
+ << L" -?,--help " << Localization::WSLCCLI_HelpArgDescription() << L"\r\n"
153
+ << L"\r\n";
154
+ return options.str();
155
+ }
156
+};
157
+} // namespace WSLCE2ETests