master
cpp 169 lines 5.79 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WSLCCLIResourceLimitsParserUnitTests.cpp
8
9 Abstract:
10
11 This file contains unit tests for WSLC CLI resource-limit (--cpus, --memory, --ulimit) parsing and validation.
12
13 --*/
14
15 #include "precomp.h"
16 #include "windows/Common.h"
17 #include "WSLCCLITestHelpers.h"
18 #include "ArgumentValidation.h"
19
20 using namespace wsl::windows::wslc;
21
22 namespace WSLCCLIResourceLimitsParserUnitTests {
23
24 class WSLCCLIResourceLimitsParserUnitTests
25 {
26 WSLC_TEST_CLASS(WSLCCLIResourceLimitsParserUnitTests)
27
28 TEST_METHOD(NanoCpus_Valid)
29 {
30 // (input, expected nanoCpus)
31 std::vector<std::pair<std::wstring, int64_t>> valid = {
32 {L"1", 1'000'000'000LL},
33 {L"2", 2'000'000'000LL},
34 {L"0.5", 500'000'000LL},
35 {L"1.5", 1'500'000'000LL},
36 {L"2.5", 2'500'000'000LL},
37 {L"0.001", 1'000'000LL},
38 };
39
40 for (const auto& [input, expected] : valid)
41 {
42 const auto actual = validation::GetNanoCpusFromString(input, L"cpus");
43 VERIFY_ARE_EQUAL(expected, actual);
44 }
45 }
46
47 TEST_METHOD(NanoCpus_Invalid)
48 {
49 // Each value should be rejected as an invalid --cpus value.
50 const std::vector<std::wstring> invalid = {
51 L"",
52 L"0", // not positive
53 L"-1", // sign char rejected
54 L"-0.5", // sign char rejected
55 L"abc", // not numeric
56 L"1.5x", // trailing garbage
57 L" 1", // leading whitespace
58 L"1 ", // trailing whitespace
59 L"1e3", // exponent not allowed
60 L"+1", // sign char rejected
61 L"1.2.3", // multiple dots (rejected by strtod's strict end check)
62 L"99999999999" // overflow when multiplied by 1e9
63 };
64
65 for (const auto& input : invalid)
66 {
67 VERIFY_THROWS(validation::GetNanoCpusFromString(input, L"cpus"), ArgumentException);
68 }
69 }
70
71 TEST_METHOD(Ulimit_Valid)
72 {
73 // (input, expectedName, expectedSoft, expectedHard)
74 std::vector<std::tuple<std::wstring, std::string, int64_t, int64_t>> valid = {
75 {L"nofile=1024", "nofile", 1024, 1024},
76 {L"nofile=1024:2048", "nofile", 1024, 2048},
77 {L"nproc=512:512", "nproc", 512, 512},
78 {L"core=-1", "core", -1, -1},
79 {L"core=-1:-1", "core", -1, -1},
80 {L"memlock=0", "memlock", 0, 0},
81 {L"stack=8192:-1", "stack", 8192, -1},
82 };
83
84 for (const auto& [input, expectedName, expectedSoft, expectedHard] : valid)
85 {
86 const auto [name, soft, hard] = validation::ParseUlimit(input, L"ulimit");
87 VERIFY_ARE_EQUAL(expectedName, name);
88 VERIFY_ARE_EQUAL(expectedSoft, soft);
89 VERIFY_ARE_EQUAL(expectedHard, hard);
90 }
91 }
92
93 TEST_METHOD(Ulimit_Invalid)
94 {
95 const std::vector<std::wstring> invalid = {
96 L"",
97 L"=1024", // empty name
98 L"nofile=", // empty value
99 L"nofile", // missing '='
100 L"nofile=abc", // non-numeric soft
101 L"nofile=1024:", // empty hard
102 L"nofile=:1024", // empty soft
103 L"nofile=-2", // negative other than -1
104 L"nofile=1024:512", // hard < soft (and both positive)
105 L"nofile=-1:1024", // unlimited soft but limited hard
106 L"nofile=-1:9223372036854775807", // unlimited soft but finite (INT64_MAX) hard
107 L"nofile=1.5", // not integer
108 };
109
110 for (const auto& input : invalid)
111 {
112 VERIFY_THROWS(validation::ParseUlimit(input, L"ulimit"), ArgumentException);
113 }
114 }
115
116 TEST_METHOD(NanoCpus_Validator)
117 {
118 VERIFY_NO_THROW(validation::ValidateNanoCpus({L"0.5", L"1", L"2.5"}, L"cpus"));
119 VERIFY_THROWS(validation::ValidateNanoCpus({L"1", L"0"}, L"cpus"), ArgumentException);
120 }
121
122 TEST_METHOD(Ulimit_Validator)
123 {
124 VERIFY_NO_THROW(validation::ValidateUlimit({L"nofile=1024", L"core=-1"}, L"ulimit"));
125 VERIFY_THROWS(validation::ValidateUlimit({L"nofile=1024", L"bad"}, L"ulimit"), ArgumentException);
126 }
127
128 TEST_METHOD(Duration_Valid)
129 {
130 std::vector<std::pair<std::wstring, int64_t>> valid = {
131 {L"0", 0LL},
132 {L"0s", 0LL},
133 {L"1ns", 1LL},
134 {L"500ms", 500'000'000LL},
135 {L"30s", 30'000'000'000LL},
136 {L"1m", 60'000'000'000LL},
137 {L"1m30s", 90'000'000'000LL},
138 {L"1h", 3'600'000'000'000LL},
139 {L"1.5h", 5'400'000'000'000LL},
140 {L"2h45m", 9'900'000'000'000LL},
141 {L"100us", 100'000LL},
142 };
143
144 for (const auto& [input, expected] : valid)
145 {
146 const auto actual = validation::GetDurationNanosFromString(input, L"health-interval");
147 VERIFY_ARE_EQUAL(expected, actual);
148 }
149 }
150
151 TEST_METHOD(Duration_Invalid)
152 {
153 const std::vector<std::wstring> invalid = {
154 L"", L"-1", L"s", L"abc", L"30", L"30sec", L"30x", L"-30s", L"30 s", L"s", L"1.2.3s", L"9223372036854775808s"};
155
156 for (const auto& input : invalid)
157 {
158 VERIFY_THROWS(validation::GetDurationNanosFromString(input, L"health-interval"), ArgumentException);
159 }
160 }
161
162 TEST_METHOD(Duration_Validator)
163 {
164 VERIFY_NO_THROW(validation::ValidateDuration({L"30s", L"1m30s", L"0"}, L"health-interval"));
165 VERIFY_THROWS(validation::ValidateDuration({L"30s", L"bad"}, L"health-interval"), ArgumentException);
166 }
167 };
168
169 } // namespace WSLCCLIResourceLimitsParserUnitTests