]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2025 The Squid Software Foundation and contributors | |
3 | * | |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
9 | #include "squid.h" | |
10 | #include "anyp/Uri.h" | |
11 | #include "CacheManager.h" | |
12 | #include "compat/cppunit.h" | |
13 | #include "mgr/Action.h" | |
14 | #include "mgr/Registration.h" | |
15 | #include "Store.h" | |
16 | #include "unitTestMain.h" | |
17 | ||
18 | #include <cppunit/TestAssert.h> | |
19 | /* | |
20 | * test the CacheManager implementation | |
21 | */ | |
22 | ||
23 | class TestCacheManager : public CPPUNIT_NS::TestFixture | |
24 | { | |
25 | CPPUNIT_TEST_SUITE(TestCacheManager); | |
26 | CPPUNIT_TEST(testCreate); | |
27 | CPPUNIT_TEST(testRegister); | |
28 | CPPUNIT_TEST(testParseUrl); | |
29 | CPPUNIT_TEST_SUITE_END(); | |
30 | ||
31 | protected: | |
32 | void testCreate(); | |
33 | void testRegister(); | |
34 | void testParseUrl(); | |
35 | }; | |
36 | ||
37 | CPPUNIT_TEST_SUITE_REGISTRATION( TestCacheManager ); | |
38 | ||
39 | /// Provides test code access to CacheManager internal symbols | |
40 | class CacheManagerInternals : public CacheManager | |
41 | { | |
42 | public: | |
43 | /// checks CacheManager parsing of the given valid URL | |
44 | void testValidUrl(const AnyP::Uri &); | |
45 | ||
46 | /// checks CacheManager parsing of the given invalid URL | |
47 | /// \param problem a bad part of the URL or its description | |
48 | void testInvalidUrl(const AnyP::Uri &, const char *problem); | |
49 | }; | |
50 | ||
51 | void | |
52 | CacheManagerInternals::testValidUrl(const AnyP::Uri &url) | |
53 | { | |
54 | CPPUNIT_ASSERT_NO_THROW(ParseUrl(url)); | |
55 | } | |
56 | ||
57 | void | |
58 | CacheManagerInternals::testInvalidUrl(const AnyP::Uri &url, const char *const problem) | |
59 | { | |
60 | CPPUNIT_ASSERT_THROW_MESSAGE(problem, ParseUrl(url), TextException); | |
61 | } | |
62 | ||
63 | /// customizes our test setup | |
64 | class MyTestProgram: public TestProgram | |
65 | { | |
66 | public: | |
67 | /* TestProgram API */ | |
68 | void startup() override; | |
69 | }; | |
70 | ||
71 | void | |
72 | MyTestProgram::startup() | |
73 | { | |
74 | Mem::Init(); | |
75 | AnyP::UriScheme::Init(); | |
76 | } | |
77 | ||
78 | /* | |
79 | * Test creating a CacheManager | |
80 | */ | |
81 | void | |
82 | TestCacheManager::testCreate() | |
83 | { | |
84 | CacheManager::GetInstance(); //it's a singleton.. | |
85 | } | |
86 | ||
87 | /* an action to register */ | |
88 | static void | |
89 | dummy_action(StoreEntry * sentry) | |
90 | { | |
91 | sentry->flags=1; | |
92 | } | |
93 | ||
94 | /* | |
95 | * registering an action makes it findable. | |
96 | */ | |
97 | void | |
98 | TestCacheManager::testRegister() | |
99 | { | |
100 | CacheManager *manager=CacheManager::GetInstance(); | |
101 | CPPUNIT_ASSERT(manager != nullptr); | |
102 | ||
103 | Mgr::RegisterAction("sample", "my sample", &dummy_action, Mgr::Protected::no, Mgr::Atomic::no, Mgr::Format::informal); | |
104 | Mgr::Action::Pointer action = manager->createNamedAction("sample"); | |
105 | CPPUNIT_ASSERT(action != nullptr); | |
106 | ||
107 | const Mgr::ActionProfile::Pointer profile = action->command().profile; | |
108 | CPPUNIT_ASSERT(profile != nullptr); | |
109 | CPPUNIT_ASSERT(profile->creator != nullptr); | |
110 | CPPUNIT_ASSERT_EQUAL(false, profile->isPwReq); | |
111 | CPPUNIT_ASSERT_EQUAL(false, profile->isAtomic); | |
112 | CPPUNIT_ASSERT_EQUAL(Mgr::Format::informal, profile->format); | |
113 | CPPUNIT_ASSERT_EQUAL(Mgr::Format::informal, action->format()); | |
114 | CPPUNIT_ASSERT_EQUAL(String("sample"), String(action->name())); | |
115 | ||
116 | StoreEntry *sentry=new StoreEntry(); | |
117 | sentry->createMemObject(); | |
118 | sentry->flags=0x25; //arbitrary test value | |
119 | action->run(sentry, false); | |
120 | CPPUNIT_ASSERT_EQUAL(1,(int)sentry->flags); | |
121 | } | |
122 | ||
123 | void | |
124 | TestCacheManager::testParseUrl() | |
125 | { | |
126 | auto *mgr = static_cast<CacheManagerInternals *>(CacheManager::GetInstance()); | |
127 | CPPUNIT_ASSERT(mgr != nullptr); | |
128 | ||
129 | std::vector<AnyP::ProtocolType> validSchemes = { | |
130 | AnyP::PROTO_HTTP, | |
131 | AnyP::PROTO_HTTPS, | |
132 | AnyP::PROTO_FTP | |
133 | }; | |
134 | ||
135 | AnyP::Uri mgrUrl; | |
136 | mgrUrl.host("localhost"); | |
137 | mgrUrl.port(3128); | |
138 | ||
139 | const std::vector<const char *> validActions = { | |
140 | "", | |
141 | "menu" | |
142 | }; | |
143 | ||
144 | const std::vector<const char *> invalidActions = { | |
145 | "INVALID" // any unregistered name | |
146 | }; | |
147 | ||
148 | const std::vector<const char *> validParams = { | |
149 | "", | |
150 | "?", | |
151 | "?&", | |
152 | "?&&&&&&&&&&&&", | |
153 | "?foo=bar", | |
154 | "?0123456789=bar", | |
155 | "?foo=bar&", | |
156 | "?foo=bar&&&&", | |
157 | "?&foo=bar", | |
158 | "?&&&&foo=bar", | |
159 | "?&foo=bar&", | |
160 | "?&&&&foo=bar&&&&", | |
161 | "?foo=?_weird?~`:[]stuff&bar=okay&&&&&&", | |
162 | "?intlist=1", | |
163 | "?intlist=1,2,3,4,5", | |
164 | "?string=1a", | |
165 | "?string=1,2,3,4,z", | |
166 | "?string=1,2,3,4,[0]", | |
167 | "?intlist=1,2,3,4,5&string=1,2,3,4,y" | |
168 | }; | |
169 | ||
170 | const std::vector<const char *> invalidParams = { | |
171 | "?/", | |
172 | "?foo", | |
173 | "?/foo", | |
174 | "?foo/", | |
175 | "?foo=", | |
176 | "?foo=&", | |
177 | "?=foo", | |
178 | "? foo=bar", | |
179 | "? &", | |
180 | "?& ", | |
181 | "?=&", | |
182 | "?&=", | |
183 | "? &&&", | |
184 | "?& &&", | |
185 | "?&& &", | |
186 | "?=&&&", | |
187 | "?&=&&", | |
188 | "?&&=&" | |
189 | }; | |
190 | ||
191 | const std::vector<const char *> validFragments = { | |
192 | "", | |
193 | "#", | |
194 | "##", | |
195 | "#?a=b", | |
196 | "#fragment" | |
197 | }; | |
198 | ||
199 | const auto &prefix = CacheManager::WellKnownUrlPathPrefix(); | |
200 | ||
201 | assert(prefix.length()); | |
202 | const auto insufficientPrefix = prefix.substr(0, prefix.length()-1); | |
203 | ||
204 | for (const auto &scheme : validSchemes) { | |
205 | mgrUrl.setScheme(scheme); | |
206 | ||
207 | // Check that the parser rejects URLs that lack the full prefix prefix. | |
208 | // These negative tests log "Squid BUG: assurance failed" ERRORs because | |
209 | // they violate CacheManager::ParseUrl()'s ForSomeCacheManager() | |
210 | // precondition. | |
211 | for (const auto *action : validActions) { | |
212 | for (const auto *param : validParams) { | |
213 | for (const auto *frag : validFragments) { | |
214 | SBuf bits; | |
215 | bits.append(insufficientPrefix); | |
216 | bits.append(action); | |
217 | bits.append(param); | |
218 | bits.append(frag); | |
219 | mgrUrl.path(bits); | |
220 | mgr->testInvalidUrl(mgrUrl, "insufficient prefix"); | |
221 | } | |
222 | } | |
223 | } | |
224 | ||
225 | // Check that the parser accepts valid URLs. | |
226 | for (const auto action: validActions) { | |
227 | for (const auto param: validParams) { | |
228 | for (const auto frag: validFragments) { | |
229 | SBuf bits; | |
230 | bits.append(prefix); | |
231 | bits.append(action); | |
232 | bits.append(param); | |
233 | bits.append(frag); | |
234 | mgrUrl.path(bits); | |
235 | mgr->testValidUrl(mgrUrl); | |
236 | } | |
237 | } | |
238 | } | |
239 | ||
240 | // Check that the parser rejects URLs with invalid parameters. | |
241 | for (const auto action: validActions) { | |
242 | for (const auto invalidParam: invalidParams) { | |
243 | for (const auto frag: validFragments) { | |
244 | SBuf bits; | |
245 | bits.append(prefix); | |
246 | bits.append(action); | |
247 | bits.append(invalidParam); | |
248 | bits.append(frag); | |
249 | mgrUrl.path(bits); | |
250 | mgr->testInvalidUrl(mgrUrl, invalidParam); | |
251 | } | |
252 | } | |
253 | } | |
254 | } | |
255 | } | |
256 | ||
257 | int | |
258 | main(int argc, char *argv[]) | |
259 | { | |
260 | return MyTestProgram().run(argc, argv); | |
261 | } | |
262 |