diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/test/llhttpnode_tut.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/test/llhttpnode_tut.cpp')
-rw-r--r-- | linden/indra/test/llhttpnode_tut.cpp | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/linden/indra/test/llhttpnode_tut.cpp b/linden/indra/test/llhttpnode_tut.cpp new file mode 100644 index 0000000..006ba09 --- /dev/null +++ b/linden/indra/test/llhttpnode_tut.cpp | |||
@@ -0,0 +1,428 @@ | |||
1 | /** | ||
2 | * @file lliohttpserver_tut.cpp | ||
3 | * @date May 2006 | ||
4 | * @brief HTTP server unit tests | ||
5 | * | ||
6 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #include <tut/tut.h> | ||
30 | #include "lltut.h" | ||
31 | |||
32 | #include "llhttpnode.h" | ||
33 | #include "llsdhttpserver.h" | ||
34 | |||
35 | namespace tut | ||
36 | { | ||
37 | struct HTTPNodeTestData | ||
38 | { | ||
39 | LLHTTPNode mRoot; | ||
40 | LLSD mContext; | ||
41 | |||
42 | const LLSD& context() { return mContext; } | ||
43 | |||
44 | std::string remainderPath() | ||
45 | { | ||
46 | std::ostringstream pathOutput; | ||
47 | bool addSlash = false; | ||
48 | |||
49 | LLSD& remainder = mContext["request"]["remainder"]; | ||
50 | for (LLSD::array_const_iterator i = remainder.beginArray(); | ||
51 | i != remainder.endArray(); | ||
52 | ++i) | ||
53 | { | ||
54 | if (addSlash) { pathOutput << '/'; } | ||
55 | pathOutput << i->asString(); | ||
56 | addSlash = true; | ||
57 | } | ||
58 | |||
59 | return pathOutput.str(); | ||
60 | } | ||
61 | |||
62 | void ensureRootTraversal(const std::string& path, | ||
63 | const LLHTTPNode* expectedNode, | ||
64 | const char* expectedRemainder) | ||
65 | { | ||
66 | mContext.clear(); | ||
67 | |||
68 | const LLHTTPNode* actualNode = mRoot.traverse(path, mContext); | ||
69 | |||
70 | ensure_equals("traverse " + path + " node", | ||
71 | actualNode, expectedNode); | ||
72 | ensure_equals("traverse " + path + " remainder", | ||
73 | remainderPath(), expectedRemainder); | ||
74 | } | ||
75 | |||
76 | class Response : public LLHTTPNode::Response | ||
77 | { | ||
78 | public: | ||
79 | static LLPointer<Response> create() {return new Response();} | ||
80 | |||
81 | LLSD mResult; | ||
82 | |||
83 | void result(const LLSD& result) { mResult = result; } | ||
84 | void status(S32 code, const std::string& message) { } | ||
85 | |||
86 | private: | ||
87 | Response() {;} // Must be accessed through LLPointer. | ||
88 | }; | ||
89 | |||
90 | typedef LLPointer<Response> ResponsePtr; | ||
91 | |||
92 | LLSD get(const std::string& path) | ||
93 | { | ||
94 | mContext.clear(); | ||
95 | const LLHTTPNode* node = mRoot.traverse(path, mContext); | ||
96 | ensure(path + " found", node != NULL); | ||
97 | |||
98 | ResponsePtr response = Response::create(); | ||
99 | node->get(LLHTTPNode::ResponsePtr(response), mContext); | ||
100 | return response->mResult; | ||
101 | } | ||
102 | |||
103 | LLSD post(const std::string& path, const LLSD& input) | ||
104 | { | ||
105 | mContext.clear(); | ||
106 | const LLHTTPNode* node = mRoot.traverse(path, mContext); | ||
107 | ensure(path + " found", node != NULL); | ||
108 | |||
109 | ResponsePtr response = Response::create(); | ||
110 | node->post(LLHTTPNode::ResponsePtr(response), mContext, input); | ||
111 | return response->mResult; | ||
112 | } | ||
113 | |||
114 | void ensureMemberString(const std::string& name, | ||
115 | const LLSD& actualMap, const std::string& member, | ||
116 | const std::string& expectedValue) | ||
117 | { | ||
118 | ensure_equals(name + " " + member, | ||
119 | actualMap[member].asString(), expectedValue); | ||
120 | } | ||
121 | |||
122 | |||
123 | void ensureInArray(const LLSD& actualArray, | ||
124 | const std::string& expectedValue) | ||
125 | { | ||
126 | LLSD::array_const_iterator i = actualArray.beginArray(); | ||
127 | LLSD::array_const_iterator end = actualArray.endArray(); | ||
128 | |||
129 | for (; i != end; ++i) | ||
130 | { | ||
131 | std::string path = i->asString(); | ||
132 | |||
133 | if (path == expectedValue) | ||
134 | { | ||
135 | return; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | fail("didn't find " + expectedValue); | ||
140 | } | ||
141 | |||
142 | }; | ||
143 | |||
144 | typedef test_group<HTTPNodeTestData> HTTPNodeTestGroup; | ||
145 | typedef HTTPNodeTestGroup::object HTTPNodeTestObject; | ||
146 | HTTPNodeTestGroup httpNodeTestGroup("http node"); | ||
147 | |||
148 | template<> template<> | ||
149 | void HTTPNodeTestObject::test<1>() | ||
150 | { | ||
151 | // traversal of the lone node | ||
152 | |||
153 | ensureRootTraversal("", &mRoot, ""); | ||
154 | ensureRootTraversal("/", &mRoot, ""); | ||
155 | ensureRootTraversal("foo", NULL, "foo"); | ||
156 | ensureRootTraversal("foo/bar", NULL, "foo/bar"); | ||
157 | |||
158 | ensure_equals("root of root", mRoot.rootNode(), &mRoot); | ||
159 | } | ||
160 | |||
161 | template<> template<> | ||
162 | void HTTPNodeTestObject::test<2>() | ||
163 | { | ||
164 | // simple traversal of a single node | ||
165 | |||
166 | LLHTTPNode* helloNode = new LLHTTPNode; | ||
167 | mRoot.addNode("hello", helloNode); | ||
168 | |||
169 | ensureRootTraversal("hello", helloNode, ""); | ||
170 | ensureRootTraversal("/hello", helloNode, ""); | ||
171 | ensureRootTraversal("hello/", helloNode, ""); | ||
172 | ensureRootTraversal("/hello/", helloNode, ""); | ||
173 | |||
174 | ensureRootTraversal("hello/there", NULL, "there"); | ||
175 | |||
176 | ensure_equals("root of hello", helloNode->rootNode(), &mRoot); | ||
177 | } | ||
178 | |||
179 | template<> template<> | ||
180 | void HTTPNodeTestObject::test<3>() | ||
181 | { | ||
182 | // traversal of mutli-branched tree | ||
183 | |||
184 | LLHTTPNode* greekNode = new LLHTTPNode; | ||
185 | LLHTTPNode* alphaNode = new LLHTTPNode; | ||
186 | LLHTTPNode* betaNode = new LLHTTPNode; | ||
187 | LLHTTPNode* gammaNode = new LLHTTPNode; | ||
188 | |||
189 | greekNode->addNode("alpha", alphaNode); | ||
190 | greekNode->addNode("beta", betaNode); | ||
191 | greekNode->addNode("gamma", gammaNode); | ||
192 | mRoot.addNode("greek", greekNode); | ||
193 | |||
194 | LLHTTPNode* hebrewNode = new LLHTTPNode; | ||
195 | LLHTTPNode* alephNode = new LLHTTPNode; | ||
196 | |||
197 | hebrewNode->addNode("aleph", alephNode); | ||
198 | mRoot.addNode("hebrew", hebrewNode); | ||
199 | |||
200 | ensureRootTraversal("greek/alpha", alphaNode, ""); | ||
201 | ensureRootTraversal("greek/beta", betaNode, ""); | ||
202 | ensureRootTraversal("greek/delta", NULL, "delta"); | ||
203 | ensureRootTraversal("greek/gamma", gammaNode, ""); | ||
204 | ensureRootTraversal("hebrew/aleph", alephNode, ""); | ||
205 | |||
206 | ensure_equals("root of greek", greekNode->rootNode(), &mRoot); | ||
207 | ensure_equals("root of alpha", alphaNode->rootNode(), &mRoot); | ||
208 | ensure_equals("root of beta", betaNode->rootNode(), &mRoot); | ||
209 | ensure_equals("root of gamma", gammaNode->rootNode(), &mRoot); | ||
210 | ensure_equals("root of hebrew", hebrewNode->rootNode(), &mRoot); | ||
211 | ensure_equals("root of aleph", alephNode->rootNode(), &mRoot); | ||
212 | } | ||
213 | |||
214 | template<> template<> | ||
215 | void HTTPNodeTestObject::test<4>() | ||
216 | { | ||
217 | // automatic creation of parent nodes and not overriding existing nodes | ||
218 | |||
219 | LLHTTPNode* alphaNode = new LLHTTPNode; | ||
220 | LLHTTPNode* betaNode = new LLHTTPNode; | ||
221 | LLHTTPNode* gammaNode = new LLHTTPNode; | ||
222 | LLHTTPNode* gamma2Node = new LLHTTPNode; | ||
223 | |||
224 | mRoot.addNode("greek/alpha", alphaNode); | ||
225 | mRoot.addNode("greek/beta", betaNode); | ||
226 | |||
227 | mRoot.addNode("greek/gamma", gammaNode); | ||
228 | mRoot.addNode("greek/gamma", gamma2Node); | ||
229 | |||
230 | LLHTTPNode* alephNode = new LLHTTPNode; | ||
231 | |||
232 | mRoot.addNode("hebrew/aleph", alephNode); | ||
233 | |||
234 | ensureRootTraversal("greek/alpha", alphaNode, ""); | ||
235 | ensureRootTraversal("greek/beta", betaNode, ""); | ||
236 | ensureRootTraversal("greek/delta", NULL, "delta"); | ||
237 | ensureRootTraversal("greek/gamma", gammaNode, ""); | ||
238 | ensureRootTraversal("hebrew/aleph", alephNode, ""); | ||
239 | |||
240 | ensure_equals("root of alpha", alphaNode->rootNode(), &mRoot); | ||
241 | ensure_equals("root of beta", betaNode->rootNode(), &mRoot); | ||
242 | ensure_equals("root of gamma", gammaNode->rootNode(), &mRoot); | ||
243 | ensure_equals("root of aleph", alephNode->rootNode(), &mRoot); | ||
244 | } | ||
245 | |||
246 | class IntegerNode : public LLHTTPNode | ||
247 | { | ||
248 | public: | ||
249 | virtual void get(ResponsePtr response, const LLSD& context) const | ||
250 | { | ||
251 | int n = context["extra"]["value"]; | ||
252 | |||
253 | LLSD info; | ||
254 | info["value"] = n; | ||
255 | info["positive"] = n > 0; | ||
256 | info["zero"] = n == 0; | ||
257 | info["negative"] = n < 0; | ||
258 | |||
259 | response->result(info); | ||
260 | } | ||
261 | |||
262 | virtual bool validate(const std::string& name, LLSD& context) const | ||
263 | { | ||
264 | int n; | ||
265 | std::istringstream i_stream(name); | ||
266 | i_stream >> n; | ||
267 | |||
268 | if (i_stream.fail() || i_stream.get() != EOF) | ||
269 | { | ||
270 | return false; | ||
271 | } | ||
272 | |||
273 | context["extra"]["value"] = n; | ||
274 | return true; | ||
275 | } | ||
276 | }; | ||
277 | |||
278 | class SquareNode : public LLHTTPNode | ||
279 | { | ||
280 | public: | ||
281 | virtual void get(ResponsePtr response, const LLSD& context) const | ||
282 | { | ||
283 | int n = context["extra"]["value"]; | ||
284 | response->result(n*n); | ||
285 | } | ||
286 | }; | ||
287 | |||
288 | template<> template<> | ||
289 | void HTTPNodeTestObject::test<5>() | ||
290 | { | ||
291 | // wildcard nodes | ||
292 | |||
293 | LLHTTPNode* miscNode = new LLHTTPNode; | ||
294 | LLHTTPNode* iNode = new IntegerNode; | ||
295 | LLHTTPNode* sqNode = new SquareNode; | ||
296 | |||
297 | mRoot.addNode("test/misc", miscNode); | ||
298 | mRoot.addNode("test/<int>", iNode); | ||
299 | mRoot.addNode("test/<int>/square", sqNode); | ||
300 | |||
301 | ensureRootTraversal("test/42", iNode, ""); | ||
302 | ensure_equals("stored integer", | ||
303 | context()["extra"]["value"].asInteger(), 42); | ||
304 | |||
305 | ensureRootTraversal("test/bob", NULL, "bob"); | ||
306 | ensure("nothing stored", | ||
307 | context()["extra"]["value"].isUndefined()); | ||
308 | |||
309 | ensureRootTraversal("test/3/square", sqNode, ""); | ||
310 | ResponsePtr response = Response::create(); | ||
311 | sqNode->get(LLHTTPNode::ResponsePtr(response), context()); | ||
312 | ensure_equals("square result", response->mResult.asInteger(), 9); | ||
313 | } | ||
314 | |||
315 | class AlphaNode : public LLHTTPNode | ||
316 | { | ||
317 | public: | ||
318 | virtual bool handles(const LLSD& remainder, LLSD& context) const | ||
319 | { | ||
320 | LLSD::array_const_iterator i = remainder.beginArray(); | ||
321 | LLSD::array_const_iterator end = remainder.endArray(); | ||
322 | |||
323 | for (; i != end; ++i) | ||
324 | { | ||
325 | std::string s = i->asString(); | ||
326 | if (s.empty() || s[0] != 'a') | ||
327 | { | ||
328 | return false; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | return true; | ||
333 | } | ||
334 | }; | ||
335 | |||
336 | template<> template<> | ||
337 | void HTTPNodeTestObject::test<6>() | ||
338 | { | ||
339 | // nodes that handle remainders | ||
340 | |||
341 | LLHTTPNode* miscNode = new LLHTTPNode; | ||
342 | LLHTTPNode* aNode = new AlphaNode; | ||
343 | LLHTTPNode* zNode = new LLHTTPNode; | ||
344 | |||
345 | mRoot.addNode("test/misc", miscNode); | ||
346 | mRoot.addNode("test/alpha", aNode); | ||
347 | mRoot.addNode("test/alpha/zebra", zNode); | ||
348 | |||
349 | ensureRootTraversal("test/alpha", aNode, ""); | ||
350 | ensureRootTraversal("test/alpha/abe", aNode, "abe"); | ||
351 | ensureRootTraversal("test/alpha/abe/amy", aNode, "abe/amy"); | ||
352 | ensureRootTraversal("test/alpha/abe/bea", NULL, "abe/bea"); | ||
353 | ensureRootTraversal("test/alpha/bob", NULL, "bob"); | ||
354 | ensureRootTraversal("test/alpha/zebra", zNode, ""); | ||
355 | } | ||
356 | |||
357 | template<> template<> | ||
358 | void HTTPNodeTestObject::test<7>() | ||
359 | { | ||
360 | // test auto registration | ||
361 | |||
362 | LLHTTPStandardServices::useServices(); | ||
363 | LLHTTPRegistrar::buildAllServices(mRoot); | ||
364 | |||
365 | { | ||
366 | LLSD result = get("web/hello"); | ||
367 | ensure_equals("hello result", result.asString(), "hello"); | ||
368 | } | ||
369 | { | ||
370 | LLSD stuff = 3.14159; | ||
371 | LLSD result = post("web/echo", stuff); | ||
372 | ensure_equals("echo result", result, stuff); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | template<> template<> | ||
377 | void HTTPNodeTestObject::test<8>() | ||
378 | { | ||
379 | // test introspection | ||
380 | |||
381 | LLHTTPRegistrar::buildAllServices(mRoot); | ||
382 | |||
383 | mRoot.addNode("test/misc", new LLHTTPNode); | ||
384 | mRoot.addNode("test/<int>", new IntegerNode); | ||
385 | mRoot.addNode("test/<int>/square", new SquareNode); | ||
386 | |||
387 | const LLSD result = get("web/server/api"); | ||
388 | |||
389 | ensure("result is array", result.isArray()); | ||
390 | ensure("result size", result.size() >= 2); | ||
391 | |||
392 | ensureInArray(result, "web/echo"); | ||
393 | ensureInArray(result, "web/hello"); | ||
394 | ensureInArray(result, "test/misc"); | ||
395 | ensureInArray(result, "test/<int>"); | ||
396 | ensureInArray(result, "test/<int>/square"); | ||
397 | } | ||
398 | |||
399 | template<> template<> | ||
400 | void HTTPNodeTestObject::test<9>() | ||
401 | { | ||
402 | // test introspection details | ||
403 | |||
404 | LLHTTPRegistrar::buildAllServices(mRoot); | ||
405 | |||
406 | const LLSD helloDetails = get("web/server/api/web/hello"); | ||
407 | |||
408 | ensure_contains("hello description", | ||
409 | helloDetails["description"].asString(), "hello"); | ||
410 | ensure_equals("method name", helloDetails["api"][0].asString(), std::string("GET")); | ||
411 | ensureMemberString("hello", helloDetails, "output", "\"hello\""); | ||
412 | ensure_contains("hello __file__", | ||
413 | helloDetails["__file__"].asString(), "llsdhttpserver.cpp"); | ||
414 | ensure("hello line", helloDetails["__line__"].isInteger()); | ||
415 | |||
416 | |||
417 | const LLSD echoDetails = get("web/server/api/web/echo"); | ||
418 | |||
419 | ensure_contains("echo description", | ||
420 | echoDetails["description"].asString(), "echo"); | ||
421 | ensure_equals("method name", echoDetails["api"][0].asString(), std::string("POST")); | ||
422 | ensureMemberString("echo", echoDetails, "input", "<any>"); | ||
423 | ensureMemberString("echo", echoDetails, "output", "<the input>"); | ||
424 | ensure_contains("echo __file__", | ||
425 | echoDetails["__file__"].asString(), "llsdhttpserver.cpp"); | ||
426 | ensure("echo", echoDetails["__line__"].isInteger()); | ||
427 | } | ||
428 | } | ||