diff options
Diffstat (limited to '1.1.x/share/www/script/test/design_docs.js')
-rw-r--r-- | 1.1.x/share/www/script/test/design_docs.js | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/1.1.x/share/www/script/test/design_docs.js b/1.1.x/share/www/script/test/design_docs.js new file mode 100644 index 00000000..702f0441 --- /dev/null +++ b/1.1.x/share/www/script/test/design_docs.js @@ -0,0 +1,427 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +couchTests.design_docs = function(debug) { + var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"}); + var db2 = new CouchDB("test_suite_db_a", {"X-Couch-Full-Commit":"false"}); + + if (debug) debugger; + + db.deleteDb(); + db.createDb(); + db2.deleteDb(); + db2.createDb(); + + var server_config = [ + { + section: "query_server_config", + key: "reduce_limit", + value: "false" + } + ]; + + var testFun = function() { + var numDocs = 500; + + function makebigstring(power) { + var str = "a"; + while(power-- > 0) { + str = str + str; + } + return str; + } + + var designDoc = { + _id: "_design/test", + language: "javascript", + whatever : { + stringzone : "exports.string = 'plankton';", + commonjs : { + whynot : "exports.test = require('../stringzone'); " + + "exports.foo = require('whatever/stringzone');", + upper : "exports.testing = require('./whynot').test.string.toUpperCase()+" + + "module.id+require('./whynot').foo.string", + circular_one: "require('./circular_two'); exports.name = 'One';", + circular_two: "require('./circular_one'); exports.name = 'Two';" + }, + // paths relative to parent + idtest1: { + a: { + b: {d: "module.exports = require('../c/e').id;"}, + c: {e: "exports.id = module.id;"} + } + }, + // multiple paths relative to parent + idtest2: { + a: { + b: {d: "module.exports = require('../../a/c/e').id;"}, + c: {e: "exports.id = module.id;"} + } + }, + // paths relative to module + idtest3: { + a: { + b: "module.exports = require('./c/d').id;", + c: { + d: "module.exports = require('./e');", + e: "exports.id = module.id;" + } + } + }, + // paths relative to module and parent + idtest4: { + a: { + b: "module.exports = require('../a/./c/d').id;", + c: { + d: "module.exports = require('./e');", + e: "exports.id = module.id;" + } + } + }, + // paths relative to root + idtest5: { + a: "module.exports = require('whatever/idtest5/b').id;", + b: "exports.id = module.id;" + } + }, + views: { + all_docs_twice: { + map: + (function(doc) { + emit(doc.integer, null); + emit(doc.integer, null); + }).toString() + }, + no_docs: { + map: + (function(doc) { + }).toString() + }, + single_doc: { + map: + (function(doc) { + if (doc._id === "1") { + emit(1, null); + } + }).toString() + }, + summate: { + map: + (function(doc) { + emit(doc.integer, doc.integer); + }).toString(), + reduce: + (function(keys, values) { + return sum(values); + }).toString() + }, + summate2: { + map: + (function(doc) { + emit(doc.integer, doc.integer); + }).toString(), + reduce: + (function(keys, values) { + return sum(values); + }).toString() + }, + huge_src_and_results: { + map: + (function(doc) { + if (doc._id === "1") { + emit(makebigstring(16), null); + } + }).toString(), + reduce: + (function(keys, values) { + return makebigstring(16); + }).toString() + }, + lib : { + baz : "exports.baz = 'bam';", + foo : { + foo : "exports.foo = 'bar';", + boom : "exports.boom = 'ok';", + zoom : "exports.zoom = 'yeah';" + } + }, + commonjs : { + map : + (function(doc) { + emit(null, require('views/lib/foo/boom').boom); + }).toString() + } + }, + shows: { + simple: + (function() { + return 'ok'; + }).toString(), + requirey: + (function() { + var lib = require('whatever/commonjs/upper'); + return lib.testing; + }).toString(), + circular: + (function() { + var lib = require('whatever/commonjs/upper'); + return JSON.stringify(this); + }).toString(), + circular_require: + (function() { + return require('whatever/commonjs/circular_one').name; + }).toString(), + idtest1: (function() { + return require('whatever/idtest1/a/b/d'); + }).toString(), + idtest2: (function() { + return require('whatever/idtest2/a/b/d'); + }).toString(), + idtest3: (function() { + return require('whatever/idtest3/a/b'); + }).toString(), + idtest4: (function() { + return require('whatever/idtest4/a/b'); + }).toString(), + idtest5: (function() { + return require('whatever/idtest5/a'); + }).toString() + } + }; // designDoc + + var xhr = CouchDB.request( + "PUT", "/test_suite_db_a/_design/test", {body: JSON.stringify(designDoc)} + ); + var resp = JSON.parse(xhr.responseText); + + TEquals(resp.rev, db.save(designDoc).rev); + + // test that editing a show fun on the ddoc results in a change in output + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/simple"); + T(xhr.status == 200); + TEquals(xhr.responseText, "ok"); + + designDoc.shows.simple = (function() { + return 'ko'; + }).toString(); + T(db.save(designDoc).ok); + + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/simple"); + T(xhr.status == 200); + TEquals(xhr.responseText, "ko"); + + xhr = CouchDB.request( + "GET", "/test_suite_db_a/_design/test/_show/simple?cache=buster" + ); + T(xhr.status == 200); + TEquals("ok", xhr.responseText, 'query server used wrong ddoc'); + + // test commonjs require + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/requirey"); + T(xhr.status == 200); + TEquals("PLANKTONwhatever/commonjs/upperplankton", xhr.responseText); + + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/circular"); + T(xhr.status == 200); + TEquals("javascript", JSON.parse(xhr.responseText).language); + + // test circular commonjs dependencies + xhr = CouchDB.request( + "GET", + "/test_suite_db/_design/test/_show/circular_require" + ); + TEquals(200, xhr.status); + TEquals("One", xhr.responseText); + + // Test that changes to the design doc properly invalidate cached modules: + + // update the designDoc and replace + designDoc.whatever.commonjs.circular_one = "exports.name = 'Updated';" + T(db.save(designDoc).ok); + + // request circular_require show function again and check the response has + // changed + xhr = CouchDB.request( + "GET", + "/test_suite_db/_design/test/_show/circular_require" + ); + TEquals(200, xhr.status); + TEquals("Updated", xhr.responseText); + + + // test module id values are as expected: + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest1"); + TEquals(200, xhr.status); + TEquals("whatever/idtest1/a/c/e", xhr.responseText); + + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest2"); + TEquals(200, xhr.status); + TEquals("whatever/idtest2/a/c/e", xhr.responseText); + + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest3"); + TEquals(200, xhr.status); + TEquals("whatever/idtest3/a/c/e", xhr.responseText); + + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest4"); + TEquals(200, xhr.status); + TEquals("whatever/idtest4/a/c/e", xhr.responseText); + + xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_show/idtest5"); + TEquals(200, xhr.status); + TEquals("whatever/idtest5/b", xhr.responseText); + + + var prev_view_sig = db.designInfo("_design/test").view_index.signature; + var prev_view_size = db.designInfo("_design/test").view_index.disk_size; + + db.bulkSave(makeDocs(1, numDocs + 1)); + T(db.ensureFullCommit().ok); + + // test that we get correct design doc info back, + // and also that GET /db/_design/test/_info + // hasn't triggered an update of the views + db.view("test/summate", {stale: "ok"}); // make sure view group's open + for (var i = 0; i < 2; i++) { + var dinfo = db.designInfo("_design/test"); + TEquals("test", dinfo.name); + var vinfo = dinfo.view_index; + TEquals(prev_view_size, vinfo.disk_size, "view group disk size didn't change"); + TEquals(false, vinfo.compact_running); + TEquals(prev_view_sig, vinfo.signature, 'ddoc sig'); + // wait some time (there were issues where an update + // of the views had been triggered in the background) + var start = new Date().getTime(); + while (new Date().getTime() < start + 2000); + TEquals(0, db.view("test/all_docs_twice", {stale: "ok"}).total_rows, 'view info'); + TEquals(0, db.view("test/single_doc", {stale: "ok"}).total_rows, 'view info'); + TEquals(0, db.view("test/summate", {stale: "ok"}).rows.length, 'view info'); + T(db.ensureFullCommit().ok); + restartServer(); + }; + + db.bulkSave(makeDocs(numDocs + 1, numDocs * 2 + 1)); + T(db.ensureFullCommit().ok); + + // open view group + db.view("test/summate", {stale: "ok"}); + // wait so the views can get initialized + var start = new Date().getTime(); + while (new Date().getTime() < start + 2000); + + // test that POST /db/_view_cleanup + // doesn't trigger an update of the views + var len1 = db.view("test/all_docs_twice", {stale: "ok"}).total_rows; + var len2 = db.view("test/single_doc", {stale: "ok"}).total_rows; + var len3 = db.view("test/summate", {stale: "ok"}).rows.length; + for (i = 0; i < 2; i++) { + T(db.viewCleanup().ok); + // wait some time (there were issues where an update + // of the views had been triggered in the background) + start = new Date().getTime(); + while (new Date().getTime() < start + 2000); + TEquals(len1, db.view("test/all_docs_twice", {stale: "ok"}).total_rows, 'view cleanup'); + TEquals(len2, db.view("test/single_doc", {stale: "ok"}).total_rows, 'view cleanup'); + TEquals(len3, db.view("test/summate", {stale: "ok"}).rows.length, 'view cleanup'); + T(db.ensureFullCommit().ok); + restartServer(); + // we'll test whether the view group stays closed + // and the views stay uninitialized (they should!) + len1 = len2 = len3 = 0; + }; + + // test commonjs in map functions + resp = db.view("test/commonjs", {limit:1}); + T(resp.rows[0].value == 'ok'); + + // test that the _all_docs view returns correctly with keys + var results = db.allDocs({startkey:"_design", endkey:"_design0"}); + T(results.rows.length == 1); + + for (i = 0; i < 2; i++) { + var rows = db.view("test/all_docs_twice").rows; + for (var j = 0; j < numDocs; j++) { + T(rows[2 * j].key == (j + 1)); + T(rows[(2 * j) + 1].key == (j + 1)); + }; + T(db.view("test/no_docs").total_rows == 0); + T(db.view("test/single_doc").total_rows == 1); + T(db.ensureFullCommit().ok); + restartServer(); + }; + + // test when language not specified, Javascript is implied + var designDoc2 = { + _id: "_design/test2", + // language: "javascript", + views: { + single_doc: { + map: + (function(doc) { + if (doc._id === "1") { + emit(1, null); + } + }).toString() + } + } + }; + + T(db.save(designDoc2).ok); + T(db.view("test2/single_doc").total_rows == 1); + + var summate = function(N) { + return (N + 1) * (N / 2); + }; + var result = db.view("test/summate"); + T(result.rows[0].value == summate(numDocs * 2)); + + result = db.view("test/summate", {startkey: 4, endkey: 4}); + T(result.rows[0].value == 4); + + result = db.view("test/summate", {startkey: 4, endkey: 5}); + T(result.rows[0].value == 9); + + result = db.view("test/summate", {startkey: 4, endkey: 6}); + T(result.rows[0].value == 15); + + // test start_key and end_key aliases + result = db.view("test/summate", {start_key: 4, end_key: 6}); + T(result.rows[0].value == 15); + + // Verify that a shared index (view def is an exact copy of "summate") + // does not confuse the reduce stage + result = db.view("test/summate2", {startkey: 4, endkey: 6}); + T(result.rows[0].value == 15); + + for(i = 1; i < (numDocs / 2); i += 30) { + result = db.view("test/summate", {startkey: i, endkey: (numDocs - i)}); + T(result.rows[0].value == summate(numDocs - i) - summate(i - 1)); + } + + T(db.deleteDoc(designDoc).ok); + T(db.open(designDoc._id) == null); + T(db.view("test/no_docs") == null); + + T(db.ensureFullCommit().ok); + restartServer(); + T(db.open(designDoc._id) == null); + T(db.view("test/no_docs") == null); + + // trigger ddoc cleanup + T(db.viewCleanup().ok); + }; // enf of testFun + + run_on_modified_server(server_config, testFun); + + // cleanup + db.deleteDb(); + db2.deleteDb(); +}; |