00001
00033 #include "linden_common.h"
00034 #include "lltut.h"
00035 #include "llhttpnode.h"
00036 #include "llsdhttpserver.h"
00037
00038 namespace tut
00039 {
00040 struct HTTPNodeTestData
00041 {
00042 LLHTTPNode mRoot;
00043 LLSD mContext;
00044
00045 const LLSD& context() { return mContext; }
00046
00047 std::string remainderPath()
00048 {
00049 std::ostringstream pathOutput;
00050 bool addSlash = false;
00051
00052 LLSD& remainder = mContext["request"]["remainder"];
00053 for (LLSD::array_const_iterator i = remainder.beginArray();
00054 i != remainder.endArray();
00055 ++i)
00056 {
00057 if (addSlash) { pathOutput << '/'; }
00058 pathOutput << i->asString();
00059 addSlash = true;
00060 }
00061
00062 return pathOutput.str();
00063 }
00064
00065 void ensureRootTraversal(const std::string& path,
00066 const LLHTTPNode* expectedNode,
00067 const char* expectedRemainder)
00068 {
00069 mContext.clear();
00070
00071 const LLHTTPNode* actualNode = mRoot.traverse(path, mContext);
00072
00073 ensure_equals("traverse " + path + " node",
00074 actualNode, expectedNode);
00075 ensure_equals("traverse " + path + " remainder",
00076 remainderPath(), expectedRemainder);
00077 }
00078
00079 class Response : public LLHTTPNode::Response
00080 {
00081 public:
00082 static LLPointer<Response> create() {return new Response();}
00083
00084 LLSD mResult;
00085
00086 void result(const LLSD& result) { mResult = result; }
00087 void status(S32 code, const std::string& message) { }
00088
00089 private:
00090 Response() {;}
00091 };
00092
00093 typedef LLPointer<Response> ResponsePtr;
00094
00095 LLSD get(const std::string& path)
00096 {
00097 mContext.clear();
00098 const LLHTTPNode* node = mRoot.traverse(path, mContext);
00099 ensure(path + " found", node != NULL);
00100
00101 ResponsePtr response = Response::create();
00102 node->get(LLHTTPNode::ResponsePtr(response), mContext);
00103 return response->mResult;
00104 }
00105
00106 LLSD post(const std::string& path, const LLSD& input)
00107 {
00108 mContext.clear();
00109 const LLHTTPNode* node = mRoot.traverse(path, mContext);
00110 ensure(path + " found", node != NULL);
00111
00112 ResponsePtr response = Response::create();
00113 node->post(LLHTTPNode::ResponsePtr(response), mContext, input);
00114 return response->mResult;
00115 }
00116
00117 void ensureMemberString(const std::string& name,
00118 const LLSD& actualMap, const std::string& member,
00119 const std::string& expectedValue)
00120 {
00121 ensure_equals(name + " " + member,
00122 actualMap[member].asString(), expectedValue);
00123 }
00124
00125
00126 void ensureInArray(const LLSD& actualArray,
00127 const std::string& expectedValue)
00128 {
00129 LLSD::array_const_iterator i = actualArray.beginArray();
00130 LLSD::array_const_iterator end = actualArray.endArray();
00131
00132 for (; i != end; ++i)
00133 {
00134 std::string path = i->asString();
00135
00136 if (path == expectedValue)
00137 {
00138 return;
00139 }
00140 }
00141
00142 fail("didn't find " + expectedValue);
00143 }
00144
00145 };
00146
00147 typedef test_group<HTTPNodeTestData> HTTPNodeTestGroup;
00148 typedef HTTPNodeTestGroup::object HTTPNodeTestObject;
00149 HTTPNodeTestGroup httpNodeTestGroup("http node");
00150
00151 template<> template<>
00152 void HTTPNodeTestObject::test<1>()
00153 {
00154
00155
00156 ensureRootTraversal("", &mRoot, "");
00157 ensureRootTraversal("/", &mRoot, "");
00158 ensureRootTraversal("foo", NULL, "foo");
00159 ensureRootTraversal("foo/bar", NULL, "foo/bar");
00160
00161 ensure_equals("root of root", mRoot.rootNode(), &mRoot);
00162 }
00163
00164 template<> template<>
00165 void HTTPNodeTestObject::test<2>()
00166 {
00167
00168
00169 LLHTTPNode* helloNode = new LLHTTPNode;
00170 mRoot.addNode("hello", helloNode);
00171
00172 ensureRootTraversal("hello", helloNode, "");
00173 ensureRootTraversal("/hello", helloNode, "");
00174 ensureRootTraversal("hello/", helloNode, "");
00175 ensureRootTraversal("/hello/", helloNode, "");
00176
00177 ensureRootTraversal("hello/there", NULL, "there");
00178
00179 ensure_equals("root of hello", helloNode->rootNode(), &mRoot);
00180 }
00181
00182 template<> template<>
00183 void HTTPNodeTestObject::test<3>()
00184 {
00185
00186
00187 LLHTTPNode* greekNode = new LLHTTPNode;
00188 LLHTTPNode* alphaNode = new LLHTTPNode;
00189 LLHTTPNode* betaNode = new LLHTTPNode;
00190 LLHTTPNode* gammaNode = new LLHTTPNode;
00191
00192 greekNode->addNode("alpha", alphaNode);
00193 greekNode->addNode("beta", betaNode);
00194 greekNode->addNode("gamma", gammaNode);
00195 mRoot.addNode("greek", greekNode);
00196
00197 LLHTTPNode* hebrewNode = new LLHTTPNode;
00198 LLHTTPNode* alephNode = new LLHTTPNode;
00199
00200 hebrewNode->addNode("aleph", alephNode);
00201 mRoot.addNode("hebrew", hebrewNode);
00202
00203 ensureRootTraversal("greek/alpha", alphaNode, "");
00204 ensureRootTraversal("greek/beta", betaNode, "");
00205 ensureRootTraversal("greek/delta", NULL, "delta");
00206 ensureRootTraversal("greek/gamma", gammaNode, "");
00207 ensureRootTraversal("hebrew/aleph", alephNode, "");
00208
00209 ensure_equals("root of greek", greekNode->rootNode(), &mRoot);
00210 ensure_equals("root of alpha", alphaNode->rootNode(), &mRoot);
00211 ensure_equals("root of beta", betaNode->rootNode(), &mRoot);
00212 ensure_equals("root of gamma", gammaNode->rootNode(), &mRoot);
00213 ensure_equals("root of hebrew", hebrewNode->rootNode(), &mRoot);
00214 ensure_equals("root of aleph", alephNode->rootNode(), &mRoot);
00215 }
00216
00217 template<> template<>
00218 void HTTPNodeTestObject::test<4>()
00219 {
00220
00221
00222 LLHTTPNode* alphaNode = new LLHTTPNode;
00223 LLHTTPNode* betaNode = new LLHTTPNode;
00224 LLHTTPNode* gammaNode = new LLHTTPNode;
00225 LLHTTPNode* gamma2Node = new LLHTTPNode;
00226
00227 mRoot.addNode("greek/alpha", alphaNode);
00228 mRoot.addNode("greek/beta", betaNode);
00229
00230 mRoot.addNode("greek/gamma", gammaNode);
00231 mRoot.addNode("greek/gamma", gamma2Node);
00232
00233 LLHTTPNode* alephNode = new LLHTTPNode;
00234
00235 mRoot.addNode("hebrew/aleph", alephNode);
00236
00237 ensureRootTraversal("greek/alpha", alphaNode, "");
00238 ensureRootTraversal("greek/beta", betaNode, "");
00239 ensureRootTraversal("greek/delta", NULL, "delta");
00240 ensureRootTraversal("greek/gamma", gammaNode, "");
00241 ensureRootTraversal("hebrew/aleph", alephNode, "");
00242
00243 ensure_equals("root of alpha", alphaNode->rootNode(), &mRoot);
00244 ensure_equals("root of beta", betaNode->rootNode(), &mRoot);
00245 ensure_equals("root of gamma", gammaNode->rootNode(), &mRoot);
00246 ensure_equals("root of aleph", alephNode->rootNode(), &mRoot);
00247 }
00248
00249 class IntegerNode : public LLHTTPNode
00250 {
00251 public:
00252 virtual void get(ResponsePtr response, const LLSD& context) const
00253 {
00254 int n = context["extra"]["value"];
00255
00256 LLSD info;
00257 info["value"] = n;
00258 info["positive"] = n > 0;
00259 info["zero"] = n == 0;
00260 info["negative"] = n < 0;
00261
00262 response->result(info);
00263 }
00264
00265 virtual bool validate(const std::string& name, LLSD& context) const
00266 {
00267 int n;
00268 std::istringstream i_stream(name);
00269 i_stream >> n;
00270
00271 if (i_stream.fail() || i_stream.get() != EOF)
00272 {
00273 return false;
00274 }
00275
00276 context["extra"]["value"] = n;
00277 return true;
00278 }
00279 };
00280
00281 class SquareNode : public LLHTTPNode
00282 {
00283 public:
00284 virtual void get(ResponsePtr response, const LLSD& context) const
00285 {
00286 int n = context["extra"]["value"];
00287 response->result(n*n);
00288 }
00289 };
00290
00291 template<> template<>
00292 void HTTPNodeTestObject::test<5>()
00293 {
00294
00295
00296 LLHTTPNode* miscNode = new LLHTTPNode;
00297 LLHTTPNode* iNode = new IntegerNode;
00298 LLHTTPNode* sqNode = new SquareNode;
00299
00300 mRoot.addNode("test/misc", miscNode);
00301 mRoot.addNode("test/<int>", iNode);
00302 mRoot.addNode("test/<int>/square", sqNode);
00303
00304 ensureRootTraversal("test/42", iNode, "");
00305 ensure_equals("stored integer",
00306 context()["extra"]["value"].asInteger(), 42);
00307
00308 ensureRootTraversal("test/bob", NULL, "bob");
00309 ensure("nothing stored",
00310 context()["extra"]["value"].isUndefined());
00311
00312 ensureRootTraversal("test/3/square", sqNode, "");
00313 ResponsePtr response = Response::create();
00314 sqNode->get(LLHTTPNode::ResponsePtr(response), context());
00315 ensure_equals("square result", response->mResult.asInteger(), 9);
00316 }
00317
00318 class AlphaNode : public LLHTTPNode
00319 {
00320 public:
00321 virtual bool handles(const LLSD& remainder, LLSD& context) const
00322 {
00323 LLSD::array_const_iterator i = remainder.beginArray();
00324 LLSD::array_const_iterator end = remainder.endArray();
00325
00326 for (; i != end; ++i)
00327 {
00328 std::string s = i->asString();
00329 if (s.empty() || s[0] != 'a')
00330 {
00331 return false;
00332 }
00333 }
00334
00335 return true;
00336 }
00337 };
00338
00339 template<> template<>
00340 void HTTPNodeTestObject::test<6>()
00341 {
00342
00343
00344 LLHTTPNode* miscNode = new LLHTTPNode;
00345 LLHTTPNode* aNode = new AlphaNode;
00346 LLHTTPNode* zNode = new LLHTTPNode;
00347
00348 mRoot.addNode("test/misc", miscNode);
00349 mRoot.addNode("test/alpha", aNode);
00350 mRoot.addNode("test/alpha/zebra", zNode);
00351
00352 ensureRootTraversal("test/alpha", aNode, "");
00353 ensureRootTraversal("test/alpha/abe", aNode, "abe");
00354 ensureRootTraversal("test/alpha/abe/amy", aNode, "abe/amy");
00355 ensureRootTraversal("test/alpha/abe/bea", NULL, "abe/bea");
00356 ensureRootTraversal("test/alpha/bob", NULL, "bob");
00357 ensureRootTraversal("test/alpha/zebra", zNode, "");
00358 }
00359
00360 template<> template<>
00361 void HTTPNodeTestObject::test<7>()
00362 {
00363
00364
00365 LLHTTPStandardServices::useServices();
00366 LLHTTPRegistrar::buildAllServices(mRoot);
00367
00368 {
00369 LLSD result = get("web/hello");
00370 ensure_equals("hello result", result.asString(), "hello");
00371 }
00372 {
00373 LLSD stuff = 3.14159;
00374 LLSD result = post("web/echo", stuff);
00375 ensure_equals("echo result", result, stuff);
00376 }
00377 }
00378
00379 template<> template<>
00380 void HTTPNodeTestObject::test<8>()
00381 {
00382
00383
00384 LLHTTPRegistrar::buildAllServices(mRoot);
00385
00386 mRoot.addNode("test/misc", new LLHTTPNode);
00387 mRoot.addNode("test/<int>", new IntegerNode);
00388 mRoot.addNode("test/<int>/square", new SquareNode);
00389
00390 const LLSD result = get("web/server/api");
00391
00392 ensure("result is array", result.isArray());
00393 ensure("result size", result.size() >= 2);
00394
00395 ensureInArray(result, "web/echo");
00396 ensureInArray(result, "web/hello");
00397 ensureInArray(result, "test/misc");
00398 ensureInArray(result, "test/<int>");
00399 ensureInArray(result, "test/<int>/square");
00400 }
00401
00402 template<> template<>
00403 void HTTPNodeTestObject::test<9>()
00404 {
00405
00406
00407 LLHTTPRegistrar::buildAllServices(mRoot);
00408
00409 const LLSD helloDetails = get("web/server/api/web/hello");
00410
00411 ensure_contains("hello description",
00412 helloDetails["description"].asString(), "hello");
00413 ensure_equals("method name", helloDetails["api"][0].asString(), std::string("GET"));
00414 ensureMemberString("hello", helloDetails, "output", "\"hello\"");
00415 ensure_contains("hello __file__",
00416 helloDetails["__file__"].asString(), "llsdhttpserver.cpp");
00417 ensure("hello line", helloDetails["__line__"].isInteger());
00418
00419
00420 const LLSD echoDetails = get("web/server/api/web/echo");
00421
00422 ensure_contains("echo description",
00423 echoDetails["description"].asString(), "echo");
00424 ensure_equals("method name", echoDetails["api"][0].asString(), std::string("POST"));
00425 ensureMemberString("echo", echoDetails, "input", "<any>");
00426 ensureMemberString("echo", echoDetails, "output", "<the input>");
00427 ensure_contains("echo __file__",
00428 echoDetails["__file__"].asString(), "llsdhttpserver.cpp");
00429 ensure("echo", echoDetails["__line__"].isInteger());
00430 }
00431 }