PageRenderTime 48ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/rel/overlay/share/www/script/test/show_documents.js

http://github.com/cloudant/bigcouch
JavaScript | 462 lines | 348 code | 54 blank | 60 comment | 44 complexity | 1fa968097878abff7e8afbc6000ae8c8 MD5 | raw file
Possible License(s): Apache-2.0
  1. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  2. // use this file except in compliance with the License. You may obtain a copy of
  3. // the License at
  4. //
  5. // http://www.apache.org/licenses/LICENSE-2.0
  6. //
  7. // Unless required by applicable law or agreed to in writing, software
  8. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  9. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  10. // License for the specific language governing permissions and limitations under
  11. // the License.
  12. couchTests.show_documents = function(debug) {
  13. var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  14. db.deleteDb();
  15. db.createDb();
  16. if (debug) debugger;
  17. var designDoc = {
  18. _id:"_design/template",
  19. language: "javascript",
  20. shows: {
  21. "hello" : stringFun(function(doc, req) {
  22. log("hello fun");
  23. if (doc) {
  24. return "Hello World";
  25. } else {
  26. if(req.id) {
  27. return "New World";
  28. } else {
  29. return "Empty World";
  30. }
  31. }
  32. }),
  33. "just-name" : stringFun(function(doc, req) {
  34. if (doc) {
  35. return {
  36. body : "Just " + doc.name
  37. };
  38. } else {
  39. return {
  40. body : "No such doc",
  41. code : 404
  42. };
  43. }
  44. }),
  45. "json" : stringFun(function(doc, req) {
  46. return {
  47. json : doc
  48. }
  49. }),
  50. "req-info" : stringFun(function(doc, req) {
  51. return {
  52. json : req
  53. }
  54. }),
  55. "show-deleted" : stringFun(function(doc, req) {
  56. if(doc) {
  57. return doc._id;
  58. } else {
  59. return "No doc " + req.id;
  60. }
  61. }),
  62. "render-error" : stringFun(function(doc, req) {
  63. return noSuchVariable;
  64. }),
  65. "empty" : stringFun(function(doc, req) {
  66. return "";
  67. }),
  68. "fail" : stringFun(function(doc, req) {
  69. return doc._id;
  70. }),
  71. "xml-type" : stringFun(function(doc, req) {
  72. return {
  73. "headers" : {
  74. "Content-Type" : "application/xml"
  75. },
  76. "body" : new XML('<xml><node foo="bar"/></xml>').toXMLString()
  77. }
  78. }),
  79. "no-set-etag" : stringFun(function(doc, req) {
  80. return {
  81. headers : {
  82. "Etag" : "skipped"
  83. },
  84. "body" : "something"
  85. }
  86. }),
  87. "list-api" : stringFun(function(doc, req) {
  88. start({"X-Couch-Test-Header": "Yeah"});
  89. send("Hey");
  90. }),
  91. "list-api-provides" : stringFun(function(doc, req) {
  92. provides("text", function(){
  93. send("foo, ");
  94. send("bar, ");
  95. send("baz!");
  96. })
  97. }),
  98. "list-api-provides-and-return" : stringFun(function(doc, req) {
  99. provides("text", function(){
  100. send("4, ");
  101. send("5, ");
  102. send("6, ");
  103. return "7!";
  104. })
  105. send("1, ");
  106. send("2, ");
  107. return "3, ";
  108. }),
  109. "list-api-mix" : stringFun(function(doc, req) {
  110. start({"X-Couch-Test-Header": "Yeah"});
  111. send("Hey ");
  112. return "Dude";
  113. }),
  114. "list-api-mix-with-header" : stringFun(function(doc, req) {
  115. start({"X-Couch-Test-Header": "Yeah"});
  116. send("Hey ");
  117. return {
  118. headers: {
  119. "X-Couch-Test-Header-Awesome": "Oh Yeah!"
  120. },
  121. body: "Dude"
  122. };
  123. }),
  124. "accept-switch" : stringFun(function(doc, req) {
  125. if (req.headers["Accept"].match(/image/)) {
  126. return {
  127. // a 16x16 px version of the CouchDB logo
  128. "base64" :
  129. ["iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAsV",
  130. "BMVEUAAAD////////////////////////5ur3rEBn////////////////wDBL/",
  131. "AADuBAe9EB3IEBz/7+//X1/qBQn2AgP/f3/ilpzsDxfpChDtDhXeCA76AQH/v7",
  132. "/84eLyWV/uc3bJPEf/Dw/uw8bRWmP1h4zxSlD6YGHuQ0f6g4XyQkXvCA36MDH6",
  133. "wMH/z8/yAwX64ODeh47BHiv/Ly/20dLQLTj98PDXWmP/Pz//39/wGyJ7Iy9JAA",
  134. "AADHRSTlMAbw8vf08/bz+Pv19jK/W3AAAAg0lEQVR4Xp3LRQ4DQRBD0QqTm4Y5",
  135. "zMxw/4OleiJlHeUtv2X6RbNO1Uqj9g0RMCuQO0vBIg4vMFeOpCWIWmDOw82fZx",
  136. "vaND1c8OG4vrdOqD8YwgpDYDxRgkSm5rwu0nQVBJuMg++pLXZyr5jnc1BaH4GT",
  137. "LvEliY253nA3pVhQqdPt0f/erJkMGMB8xucAAAAASUVORK5CYII="].join(''),
  138. headers : {
  139. "Content-Type" : "image/png",
  140. "Vary" : "Accept" // we set this for proxy caches
  141. }
  142. };
  143. } else {
  144. return {
  145. "body" : "accepting text requests",
  146. headers : {
  147. "Content-Type" : "text/html",
  148. "Vary" : "Accept"
  149. }
  150. };
  151. }
  152. }),
  153. "provides" : stringFun(function(doc, req) {
  154. registerType("foo", "application/foo","application/x-foo");
  155. provides("html", function() {
  156. return "Ha ha, you said \"" + doc.word + "\".";
  157. });
  158. provides("xml", function() {
  159. var xml = new XML('<xml><node/></xml>');
  160. // Becase Safari can't stand to see that dastardly
  161. // E4X outside of a string. Outside of tests you
  162. // can just use E4X literals.
  163. eval('xml.node.@foo = doc.word');
  164. log('xml: '+xml.toSource());
  165. return xml.toXMLString();
  166. });
  167. provides("foo", function() {
  168. return "foofoo";
  169. });
  170. }),
  171. "withSlash": stringFun(function(doc, req) {
  172. return { json: doc }
  173. }),
  174. "secObj": stringFun(function(doc, req) {
  175. return { json: req.secObj };
  176. })
  177. }
  178. };
  179. T(db.save(designDoc).ok);
  180. var doc = {"word":"plankton", "name":"Rusty"}
  181. var resp = db.save(doc);
  182. T(resp.ok);
  183. var docid = resp.id;
  184. // show error
  185. var xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/");
  186. T(xhr.status == 404, 'Should be missing');
  187. T(JSON.parse(xhr.responseText).reason == "Invalid path.");
  188. // hello template world
  189. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello/"+docid);
  190. T(xhr.responseText == "Hello World", "hello");
  191. T(/charset=utf-8/.test(xhr.getResponseHeader("Content-Type")));
  192. // Fix for COUCHDB-379
  193. T(equals(xhr.getResponseHeader("Server").substr(0,7), "CouchDB"));
  194. // // error stacktraces
  195. // xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/render-error/"+docid);
  196. // T(JSON.parse(xhr.responseText).error == "render_error");
  197. // hello template world (no docid)
  198. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello");
  199. T(xhr.responseText == "Empty World");
  200. // hello template world (no docid)
  201. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/empty");
  202. T(xhr.responseText == "");
  203. // // hello template world (non-existing docid)
  204. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/fail/nonExistingDoc");
  205. T(xhr.status == 404);
  206. var resp = JSON.parse(xhr.responseText);
  207. T(resp.error == "not_found");
  208. // show with doc
  209. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid);
  210. T(xhr.responseText == "Just Rusty");
  211. // show with missing doc
  212. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/missingdoc");
  213. T(xhr.status == 404);
  214. TEquals("No such doc", xhr.responseText);
  215. // show with missing func
  216. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/missing/"+docid);
  217. T(xhr.status == 404, "function is missing");
  218. // missing design doc
  219. xhr = CouchDB.request("GET", "/test_suite_db/_design/missingddoc/_show/just-name/"+docid);
  220. T(xhr.status == 404);
  221. var resp = JSON.parse(xhr.responseText);
  222. T(resp.error == "not_found");
  223. // query parameters
  224. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/req-info/"+docid+"?foo=bar", {
  225. headers: {
  226. "Accept": "text/html;text/plain;*/*",
  227. "X-Foo" : "bar"
  228. }
  229. });
  230. var resp = JSON.parse(xhr.responseText);
  231. T(equals(resp.headers["X-Foo"], "bar"));
  232. T(equals(resp.query, {foo:"bar"}));
  233. T(equals(resp.method, "GET"));
  234. T(equals(resp.path[5], docid));
  235. T(equals(resp.info.db_name, "test_suite_db"));
  236. // returning a content-type
  237. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/xml-type/"+docid);
  238. T("application/xml" == xhr.getResponseHeader("Content-Type"));
  239. T("Accept" == xhr.getResponseHeader("Vary"));
  240. // accept header switching
  241. // different mime has different etag
  242. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/accept-switch/"+docid, {
  243. headers: {"Accept": "text/html;text/plain;*/*"}
  244. });
  245. var ct = xhr.getResponseHeader("Content-Type");
  246. T(/text\/html/.test(ct))
  247. T("Accept" == xhr.getResponseHeader("Vary"));
  248. var etag = xhr.getResponseHeader("etag");
  249. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/accept-switch/"+docid, {
  250. headers: {"Accept": "image/png;*/*"}
  251. });
  252. T(xhr.responseText.match(/PNG/))
  253. T("image/png" == xhr.getResponseHeader("Content-Type"));
  254. var etag2 = xhr.getResponseHeader("etag");
  255. T(etag2 != etag);
  256. // proper etags
  257. // show with doc
  258. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid);
  259. // extract the ETag header values
  260. etag = xhr.getResponseHeader("etag");
  261. // get again with etag in request
  262. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
  263. headers: {"if-none-match": etag}
  264. });
  265. // should be 304
  266. T(xhr.status == 304);
  267. // update the doc
  268. doc.name = "Crusty";
  269. resp = db.save(doc);
  270. T(resp.ok);
  271. // req with same etag
  272. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
  273. headers: {"if-none-match": etag}
  274. });
  275. // status is 200
  276. T(xhr.status == 200);
  277. // get new etag and request again
  278. etag = xhr.getResponseHeader("etag");
  279. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
  280. headers: {"if-none-match": etag}
  281. });
  282. // should be 304
  283. T(xhr.status == 304);
  284. // update design doc (but not function)
  285. designDoc.isChanged = true;
  286. T(db.save(designDoc).ok);
  287. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
  288. headers: {"if-none-match": etag}
  289. });
  290. // should not be 304 if we change the doc
  291. T(xhr.status != 304, "changed ddoc");
  292. // update design doc function
  293. designDoc.shows["just-name"] = (function(doc, req) {
  294. return {
  295. body : "Just old " + doc.name
  296. };
  297. }).toString();
  298. T(db.save(designDoc).ok);
  299. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, {
  300. headers: {"if-none-match": etag}
  301. });
  302. // status is 200
  303. T(xhr.status == 200);
  304. // JS can't set etag
  305. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/no-set-etag/"+docid);
  306. // extract the ETag header values
  307. etag = xhr.getResponseHeader("etag");
  308. T(etag != "skipped")
  309. // test the provides mime matcher
  310. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/provides/"+docid, {
  311. headers: {
  312. "Accept": 'text/html,application/atom+xml; q=0.9'
  313. }
  314. });
  315. var ct = xhr.getResponseHeader("Content-Type");
  316. T(/charset=utf-8/.test(ct))
  317. T(/text\/html/.test(ct))
  318. T(xhr.responseText == "Ha ha, you said \"plankton\".");
  319. // now with xml
  320. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/provides/"+docid, {
  321. headers: {
  322. "Accept": 'application/xml'
  323. }
  324. });
  325. T(xhr.getResponseHeader("Content-Type") == "application/xml");
  326. T(xhr.responseText.match(/node/));
  327. T(xhr.responseText.match(/plankton/));
  328. // registering types works
  329. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/provides/"+docid, {
  330. headers: {
  331. "Accept": "application/x-foo"
  332. }
  333. });
  334. T(xhr.getResponseHeader("Content-Type") == "application/x-foo");
  335. T(xhr.responseText.match(/foofoo/));
  336. // test the provides mime matcher without a match
  337. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/provides/"+docid, {
  338. headers: {
  339. "Accept": 'text/monkeys'
  340. }
  341. });
  342. var rs = JSON.parse(xhr.responseText);
  343. T(rs.error == "not_acceptable")
  344. // should fallback on the first one
  345. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/provides/"+docid, {
  346. headers: {
  347. "Accept": 'application/x-foo, application/xml'
  348. }
  349. });
  350. var ct = xhr.getResponseHeader("Content-Type");
  351. T(/application\/xml/.test(ct));
  352. // test inclusion of conflict state
  353. var doc1 = {_id:"foo", a:1};
  354. var doc2 = {_id:"foo", a:2};
  355. db.save(doc1);
  356. // create the conflict with an all_or_nothing bulk docs request
  357. var docs = [doc2];
  358. db.bulkSave(docs, {all_or_nothing:true});
  359. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/json/foo");
  360. TEquals(1, JSON.parse(xhr.responseText)._conflicts.length);
  361. var doc3 = {_id:"a/b/c", a:1};
  362. db.save(doc3);
  363. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/withSlash/a/b/c");
  364. T(xhr.status == 200);
  365. // hello template world (non-existing docid)
  366. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello/nonExistingDoc");
  367. T(xhr.responseText == "New World");
  368. // test list() compatible API
  369. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/list-api/foo");
  370. T(xhr.responseText == "Hey");
  371. TEquals("Yeah", xhr.getResponseHeader("X-Couch-Test-Header"), "header should be cool");
  372. // test list() compatible API with provides function
  373. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/list-api-provides/foo?format=text");
  374. TEquals(xhr.responseText, "foo, bar, baz!", "should join chunks to response body");
  375. // should keep next result order: chunks + return value + provided chunks + provided return value
  376. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/list-api-provides-and-return/foo?format=text");
  377. TEquals(xhr.responseText, "1, 2, 3, 4, 5, 6, 7!", "should not break 1..7 range");
  378. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/list-api-mix/foo");
  379. T(xhr.responseText == "Hey Dude");
  380. TEquals("Yeah", xhr.getResponseHeader("X-Couch-Test-Header"), "header should be cool");
  381. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/list-api-mix-with-header/foo");
  382. T(xhr.responseText == "Hey Dude");
  383. TEquals("Yeah", xhr.getResponseHeader("X-Couch-Test-Header"), "header should be cool");
  384. TEquals("Oh Yeah!", xhr.getResponseHeader("X-Couch-Test-Header-Awesome"), "header should be cool");
  385. // test deleted docs
  386. var doc = {_id:"testdoc",foo:1};
  387. db.save(doc);
  388. var xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/show-deleted/testdoc");
  389. TEquals("testdoc", xhr.responseText, "should return 'testdoc'");
  390. db.deleteDoc(doc);
  391. var xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/show-deleted/testdoc");
  392. TEquals("No doc testdoc", xhr.responseText, "should return 'no doc testdoc'");
  393. run_on_modified_server(
  394. [{section: "httpd",
  395. key: "authentication_handlers",
  396. value: "{couch_httpd_auth, special_test_authentication_handler}"},
  397. {section:"httpd",
  398. key: "WWW-Authenticate",
  399. value: "X-Couch-Test-Auth"}],
  400. function() {
  401. T(db.setDbProperty("_security", {foo: true}).ok);
  402. T(db.save(doc).ok);
  403. xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/secObj");
  404. var resp = JSON.parse(xhr.responseText);
  405. T(resp.foo == true);
  406. }
  407. );
  408. };