master
cpp 391 lines 13.2 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WSLCPortParserUnitTests.cpp
8
9 Abstract:
10
11 This file contains unit tests for WSLC port argument parsing and validation.
12 --*/
13
14 #include "precomp.h"
15 #include "windows/Common.h"
16 #include "WSLCCLITestHelpers.h"
17
18 #include <ContainerModel.h>
19
20 namespace WSLCPortParserUnitTests {
21
22 using namespace wsl::windows::wslc::models;
23
24 class WSLCPortParserUnitTests
25 {
26 WSLC_TEST_CLASS(WSLCPortParserUnitTests)
27
28 TEST_CLASS_SETUP(TestClassSetup)
29 {
30 return true;
31 }
32
33 TEST_CLASS_CLEANUP(TestClassCleanup)
34 {
35 return true;
36 }
37
38 TEST_METHOD(PortParserTest_HostAndContainerPort_Valid)
39 {
40 auto result = PublishPort::Parse("8080:80");
41
42 VerifyParseState(result, "8080:80", false, false);
43 VerifyNoHostIP(result);
44 VerifyHostPort(result, 8080, 8080);
45 VerifyContainerPort(result, 80, 80);
46 VerifyProtocol(result, PublishPort::Protocol::TCP);
47 }
48
49 TEST_METHOD(PortParserTest_ContainerPort_Only_Valid)
50 {
51 auto result = PublishPort::Parse("80");
52
53 VerifyParseState(result, "80", true, false);
54 VerifyNoHostIP(result);
55 VerifyEphemeralHostPort(result);
56 VerifyContainerPort(result, 80, 80);
57 VerifyProtocol(result, PublishPort::Protocol::TCP);
58 }
59
60 TEST_METHOD(PortParserTest_ContainerPort_WithProtocol_NoIP)
61 {
62 {
63 auto result = PublishPort::Parse("80/tcp");
64
65 VerifyParseState(result, "80/tcp", true, false);
66 VerifyNoHostIP(result);
67 VerifyEphemeralHostPort(result);
68 VerifyContainerPort(result, 80, 80);
69 VerifyProtocol(result, PublishPort::Protocol::TCP);
70 }
71
72 {
73 auto result = PublishPort::Parse("54/udp");
74
75 VerifyParseState(result, "54/udp", true, false);
76 VerifyNoHostIP(result);
77 VerifyEphemeralHostPort(result);
78 VerifyContainerPort(result, 54, 54);
79 VerifyProtocol(result, PublishPort::Protocol::UDP);
80 }
81 }
82
83 TEST_METHOD(PortParserTest_ContainerPortRange_Only_Valid)
84 {
85 auto result = PublishPort::Parse("8000-8005");
86
87 VerifyParseState(result, "8000-8005", true, true);
88 VerifyNoHostIP(result);
89 VerifyEphemeralHostPort(result);
90 VerifyContainerPort(result, 8000, 8005);
91 VerifyProtocol(result, PublishPort::Protocol::TCP);
92 }
93
94 TEST_METHOD(PortParserTest_ContainerPortRange_WithProtocol_NoIP)
95 {
96 auto result = PublishPort::Parse("8000-8005/udp");
97
98 VerifyParseState(result, "8000-8005/udp", true, true);
99 VerifyNoHostIP(result);
100 VerifyEphemeralHostPort(result);
101 VerifyContainerPort(result, 8000, 8005);
102 VerifyProtocol(result, PublishPort::Protocol::UDP);
103 }
104
105 TEST_METHOD(PortParserTest_IPv4Mappings_Valid)
106 {
107 {
108 auto result = PublishPort::Parse("127.0.0.1:8080:80");
109
110 VerifyParseState(result, "127.0.0.1:8080:80", false, false);
111 VerifyHostIPv4(result, "127.0.0.1");
112 VerifyHostPort(result, 8080, 8080);
113 VerifyContainerPort(result, 80, 80);
114 VerifyProtocol(result, PublishPort::Protocol::TCP);
115 }
116
117 {
118 auto result = PublishPort::Parse("0.0.0.0:8080:80");
119
120 VerifyParseState(result, "0.0.0.0:8080:80", false, false);
121 VerifyHostIPv4(result, "0.0.0.0");
122 VerifyHostPort(result, 8080, 8080);
123 VerifyContainerPort(result, 80, 80);
124 VerifyProtocol(result, PublishPort::Protocol::TCP);
125 }
126
127 {
128 auto result = PublishPort::Parse("192.168.1.50:8080:80");
129
130 VerifyParseState(result, "192.168.1.50:8080:80", false, false);
131 VerifyHostIPv4(result, "192.168.1.50");
132 VerifyHostPort(result, 8080, 8080);
133 VerifyContainerPort(result, 80, 80);
134 VerifyProtocol(result, PublishPort::Protocol::TCP);
135 }
136
137 {
138 auto result = PublishPort::Parse("127.0.0.1:5353:5353/udp");
139
140 VerifyParseState(result, "127.0.0.1:5353:5353/udp", false, false);
141 VerifyHostIPv4(result, "127.0.0.1");
142 VerifyHostPort(result, 5353, 5353);
143 VerifyContainerPort(result, 5353, 5353);
144 VerifyProtocol(result, PublishPort::Protocol::UDP);
145 }
146
147 {
148 auto result = PublishPort::Parse("127.0.0.1::80");
149
150 VerifyParseState(result, "127.0.0.1::80", true, false);
151 VerifyHostIPv4(result, "127.0.0.1");
152 VerifyEphemeralHostPort(result);
153 VerifyContainerPort(result, 80, 80);
154 VerifyProtocol(result, PublishPort::Protocol::TCP);
155 }
156
157 {
158 auto result = PublishPort::Parse("127.0.0.1::53/udp");
159
160 VerifyParseState(result, "127.0.0.1::53/udp", true, false);
161 VerifyHostIPv4(result, "127.0.0.1");
162 VerifyEphemeralHostPort(result);
163 VerifyContainerPort(result, 53, 53);
164 VerifyProtocol(result, PublishPort::Protocol::UDP);
165 }
166 }
167
168 TEST_METHOD(PortParserTest_IPv6Mappings_Valid)
169 {
170 {
171 auto result = PublishPort::Parse("[::1]:8080:80");
172
173 VerifyParseState(result, "[::1]:8080:80", false, false);
174 VerifyHostIPv6(result, "::1");
175 VerifyHostPort(result, 8080, 8080);
176 VerifyContainerPort(result, 80, 80);
177 VerifyProtocol(result, PublishPort::Protocol::TCP);
178 }
179
180 {
181 auto result = PublishPort::Parse("[::]:8080:80");
182
183 VerifyParseState(result, "[::]:8080:80", false, false);
184 VerifyHostIPv6(result, "::");
185 VerifyHostPort(result, 8080, 8080);
186 VerifyContainerPort(result, 80, 80);
187 VerifyProtocol(result, PublishPort::Protocol::TCP);
188 }
189
190 {
191 auto result = PublishPort::Parse("[2001:db8::10]:8080:80");
192
193 VerifyParseState(result, "[2001:db8::10]:8080:80", false, false);
194 VerifyHostIPv6(result, "2001:db8::10");
195 VerifyHostPort(result, 8080, 8080);
196 VerifyContainerPort(result, 80, 80);
197 VerifyProtocol(result, PublishPort::Protocol::TCP);
198 }
199
200 {
201 auto result = PublishPort::Parse("[::1]:5353:5353/udp");
202
203 VerifyParseState(result, "[::1]:5353:5353/udp", false, false);
204 VerifyHostIPv6(result, "::1");
205 VerifyHostPort(result, 5353, 5353);
206 VerifyContainerPort(result, 5353, 5353);
207 VerifyProtocol(result, PublishPort::Protocol::UDP);
208 }
209
210 {
211 auto result = PublishPort::Parse("[::1]::80");
212
213 VerifyParseState(result, "[::1]::80", true, false);
214 VerifyHostIPv6(result, "::1");
215 VerifyEphemeralHostPort(result);
216 VerifyContainerPort(result, 80, 80);
217 VerifyProtocol(result, PublishPort::Protocol::TCP);
218 }
219
220 {
221 auto result = PublishPort::Parse("[::]::53/udp");
222
223 VerifyParseState(result, "[::]::53/udp", true, false);
224 VerifyHostIPv6(result, "::");
225 VerifyEphemeralHostPort(result);
226 VerifyContainerPort(result, 53, 53);
227 VerifyProtocol(result, PublishPort::Protocol::UDP);
228 }
229 }
230
231 TEST_METHOD(PortParserTest_PortRangeMappings_Valid)
232 {
233 {
234 auto result = PublishPort::Parse("8000-8005:8000-8005");
235
236 VerifyParseState(result, "8000-8005:8000-8005", false, true);
237 VerifyNoHostIP(result);
238 VerifyHostPort(result, 8000, 8005);
239 VerifyContainerPort(result, 8000, 8005);
240 VerifyProtocol(result, PublishPort::Protocol::TCP);
241 }
242
243 {
244 auto result = PublishPort::Parse("127.0.0.1:9000-9003:9000-9003");
245
246 VerifyParseState(result, "127.0.0.1:9000-9003:9000-9003", false, true);
247 VerifyHostIPv4(result, "127.0.0.1");
248 VerifyHostPort(result, 9000, 9003);
249 VerifyContainerPort(result, 9000, 9003);
250 VerifyProtocol(result, PublishPort::Protocol::TCP);
251 }
252
253 {
254 auto result = PublishPort::Parse("[::1]:7000-7002:7000-7002");
255
256 VerifyParseState(result, "[::1]:7000-7002:7000-7002", false, true);
257 VerifyHostIPv6(result, "::1");
258 VerifyHostPort(result, 7000, 7002);
259 VerifyContainerPort(result, 7000, 7002);
260 VerifyProtocol(result, PublishPort::Protocol::TCP);
261 }
262
263 {
264 auto result = PublishPort::Parse("10000-10010:10000-10010/tcp");
265
266 VerifyParseState(result, "10000-10010:10000-10010/tcp", false, true);
267 VerifyNoHostIP(result);
268 VerifyHostPort(result, 10000, 10010);
269 VerifyContainerPort(result, 10000, 10010);
270 VerifyProtocol(result, PublishPort::Protocol::TCP);
271 }
272
273 {
274 auto result = PublishPort::Parse("20000-20002:20000-20002/udp");
275
276 VerifyParseState(result, "20000-20002:20000-20002/udp", false, true);
277 VerifyNoHostIP(result);
278 VerifyHostPort(result, 20000, 20002);
279 VerifyContainerPort(result, 20000, 20002);
280 VerifyProtocol(result, PublishPort::Protocol::UDP);
281 }
282 }
283
284 TEST_METHOD(PortParserTest_EphemeralHostPort_WithRange_AndIP_Valid)
285 {
286 {
287 auto result = PublishPort::Parse("127.0.0.1::8000-8005");
288
289 VerifyParseState(result, "127.0.0.1::8000-8005", true, true);
290 VerifyHostIPv4(result, "127.0.0.1");
291 VerifyEphemeralHostPort(result);
292 VerifyContainerPort(result, 8000, 8005);
293 VerifyProtocol(result, PublishPort::Protocol::TCP);
294 }
295
296 {
297 auto result = PublishPort::Parse("[::1]::8000-8005");
298
299 VerifyParseState(result, "[::1]::8000-8005", true, true);
300 VerifyHostIPv6(result, "::1");
301 VerifyEphemeralHostPort(result);
302 VerifyContainerPort(result, 8000, 8005);
303 VerifyProtocol(result, PublishPort::Protocol::TCP);
304 }
305 }
306
307 TEST_METHOD(PortParserTest_InvalidMappings)
308 {
309 static const std::vector<std::string> invalidCases = {
310 "", // Empty input
311 " ", // Whitespace only
312 "80 ", // Trailing whitespace
313 ":80", // Empty host port
314 "127.0.0.1:80", // Missing container port
315 "[::1]:8080", // Missing container port
316 "8000-8005:8000-8006", // Mismatched port ranges
317 "8000-8005:8000", // Mismatched port ranges
318 "8000:8000-8005", // Mismatched port ranges
319 "8080:80/icmp", // Invalid protocol
320 "8080:80/udpp", // Invalid protocol
321 "80/TCP", // Protocol is case sensitive
322 "80/tcp:90", // Protocol suffix must be final
323 "80-", // Malformed port range
324 "-80", // Malformed port range
325 "80--81", // Malformed port range
326 "8000-7000", // Invalid port range
327 "0", // Invalid port number
328 "65536", // Invalid port number
329 };
330
331 for (const auto& value : invalidCases)
332 {
333 VERIFY_THROWS(PublishPort::Parse(value), wil::ResultException);
334 }
335 }
336
337 private:
338 static void VerifyRange(const PublishPort::PortRange& range, int start, int end)
339 {
340 VERIFY_ARE_EQUAL(start, range.Start());
341 VERIFY_ARE_EQUAL(end, range.End());
342 VERIFY_ARE_EQUAL(start == end, range.IsSingle());
343 }
344
345 static void VerifyParseState(const PublishPort& result, const std::string& original, bool hasEphemeralHostPort, bool isRangeMapping)
346 {
347 VERIFY_ARE_EQUAL(original, result.Original());
348 VERIFY_ARE_EQUAL(hasEphemeralHostPort, result.HostPort().IsEphemeral());
349 VERIFY_ARE_EQUAL(isRangeMapping, result.IsRangeMapping());
350 }
351
352 static void VerifyProtocol(const PublishPort& result, PublishPort::Protocol protocol)
353 {
354 VERIFY_ARE_EQUAL(static_cast<int>(protocol), static_cast<int>(result.PortProtocol()));
355 }
356
357 static void VerifyNoHostIP(const PublishPort& result)
358 {
359 VERIFY_IS_FALSE(result.HostIP().has_value());
360 }
361
362 static void VerifyEphemeralHostPort(const PublishPort& result)
363 {
364 VERIFY_IS_TRUE(result.HostPort().IsEphemeral());
365 }
366
367 static void VerifyHostPort(const PublishPort& result, int start, int end)
368 {
369 VerifyRange(result.HostPort(), start, end);
370 }
371
372 static void VerifyContainerPort(const PublishPort& result, int start, int end)
373 {
374 VerifyRange(result.ContainerPort(), start, end);
375 }
376
377 static void VerifyHostIPv4(const PublishPort& result, const std::string& expectedString)
378 {
379 VERIFY_IS_TRUE(result.HostIP().has_value());
380 VERIFY_IS_FALSE(result.HostIP()->IsIPv6());
381 VERIFY_ARE_EQUAL(expectedString, result.HostIP()->IP());
382 }
383
384 static void VerifyHostIPv6(const PublishPort& result, const std::string& expectedString)
385 {
386 VERIFY_IS_TRUE(result.HostIP().has_value());
387 VERIFY_IS_TRUE(result.HostIP()->IsIPv6());
388 VERIFY_ARE_EQUAL(expectedString, result.HostIP()->IP());
389 }
390 };
391 } // namespace WSLCPortParserUnitTests