From 949f9da6a6548704786d809be76a3a2d47d6fabe Mon Sep 17 00:00:00 2001 From: Adam Kocoloski Date: Thu, 26 Aug 2010 12:21:37 -0400 Subject: move futon to share/www --- rel/overlay/share/www/script/test/changes.js | 402 +++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 rel/overlay/share/www/script/test/changes.js (limited to 'rel/overlay/share/www/script/test/changes.js') diff --git a/rel/overlay/share/www/script/test/changes.js b/rel/overlay/share/www/script/test/changes.js new file mode 100644 index 00000000..50649508 --- /dev/null +++ b/rel/overlay/share/www/script/test/changes.js @@ -0,0 +1,402 @@ +// 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. + +function jsonp(obj) { + T(jsonp_flag == 0); + T(obj.results.length == 1 && obj.last_seq==1, "jsonp") + jsonp_flag = 1; +} + +couchTests.changes = function(debug) { + var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"true"}); + db.deleteDb(); + db.createDb(); + if (debug) debugger; + + var req = CouchDB.request("GET", "/test_suite_db/_changes"); + var resp = JSON.parse(req.responseText); + + T(resp.results.length == 0 && resp.last_seq==0, "empty db") + var docFoo = {_id:"foo", bar:1}; + T(db.save(docFoo).ok); + T(db.ensureFullCommit().ok); + T(db.open(docFoo._id)._id == docFoo._id); + + req = CouchDB.request("GET", "/test_suite_db/_changes"); + var resp = JSON.parse(req.responseText); + + T(resp.last_seq == 1); + T(resp.results.length == 1, "one doc db") + T(resp.results[0].changes[0].rev == docFoo._rev) + + // test with callback + + run_on_modified_server( + [{section: "httpd", + key: "allow_jsonp", + value: "true"}], + function() { + var xhr = CouchDB.request("GET", "/test_suite_db/_changes?callback=jsonp"); + T(xhr.status == 200); + jsonp_flag = 0; + eval(xhr.responseText); + T(jsonp_flag == 1); + }); + + req = CouchDB.request("GET", "/test_suite_db/_changes?feed=continuous&timeout=10"); + var lines = req.responseText.split("\n"); + T(JSON.parse(lines[0]).changes[0].rev == docFoo._rev); + T(JSON.parse(lines[1]).last_seq == 1); + + var xhr; + + try { + xhr = CouchDB.newXhr(); + } catch (err) { + } + + // poor man's browser detection + var is_safari = false; + if(typeof(navigator) == "undefined") { + is_safari = true; // For CouchHTTP based runners + } else if(navigator.userAgent.match(/AppleWebKit/)) { + is_safari = true; + }; + if (!is_safari && xhr) { + // Only test the continuous stuff if we have a real XHR object + // with real async support. + + // WebKit (last checked on nightly #47686) does fail on processing + // the async-request properly while javascript is executed. + + xhr.open("GET", "/test_suite_db/_changes?feed=continuous&timeout=500", true); + xhr.send(""); + + var docBar = {_id:"bar", bar:1}; + db.save(docBar); + + var lines, change1, change2; + waitForSuccess(function() { + lines = xhr.responseText.split("\n"); + change1 = JSON.parse(lines[0]); + change2 = JSON.parse(lines[1]); + if (change2.seq != 2) { + throw "bad seq, try again" + } + }, "bar-only"); + + T(change1.seq == 1) + T(change1.id == "foo") + + T(change2.seq == 2) + T(change2.id == "bar") + T(change2.changes[0].rev == docBar._rev) + + + var docBaz = {_id:"baz", baz:1}; + db.save(docBaz); + + var change3; + waitForSuccess(function() { + lines = xhr.responseText.split("\n"); + change3 = JSON.parse(lines[2]); + if (change3.seq != 3) { + throw "bad seq, try again" + } + }); + + T(change3.seq == 3); + T(change3.id == "baz"); + T(change3.changes[0].rev == docBaz._rev); + + + xhr = CouchDB.newXhr(); + + //verify the hearbeat newlines are sent + xhr.open("GET", "/test_suite_db/_changes?feed=continuous&heartbeat=10&timeout=500", true); + xhr.send(""); + + var str; + waitForSuccess(function() { + str = xhr.responseText; + if (str.charAt(str.length - 1) != "\n" || str.charAt(str.length - 2) != "\n") { + throw("keep waiting"); + } + }, "heartbeat"); + + T(str.charAt(str.length - 1) == "\n") + T(str.charAt(str.length - 2) == "\n") + + // otherwise we'll continue to receive heartbeats forever + xhr.abort(); + + // test longpolling + xhr = CouchDB.newXhr(); + + xhr.open("GET", "/test_suite_db/_changes?feed=longpoll", true); + xhr.send(""); + + waitForSuccess(function() { + lines = xhr.responseText.split("\n"); + if (lines[5] != '"last_seq":3}') { + throw("still waiting"); + } + }, "last_seq"); + + xhr = CouchDB.newXhr(); + + xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&since=3", true); + xhr.send(""); + + var docBarz = {_id:"barz", bar:1}; + db.save(docBarz); + + var parse_changes_line = function(line) { + if (line.charAt(line.length-1) == ",") { + var linetrimmed = line.substring(0, line.length-1); + } else { + var linetrimmed = line + } + return JSON.parse(linetrimmed); + } + + waitForSuccess(function() { + lines = xhr.responseText.split("\n"); + if (lines[3] != '"last_seq":4}') { + throw("still waiting"); + } + }, "change_lines"); + + var change = parse_changes_line(lines[1]); + T(change.seq == 4); + T(change.id == "barz"); + T(change.changes[0].rev == docBarz._rev); + T(lines[3]=='"last_seq":4}'); + } + + // test the filtered changes + var ddoc = { + _id : "_design/changes_filter", + "filters" : { + "bop" : "function(doc, req) { return (doc.bop);}", + "dynamic" : stringFun(function(doc, req) { + var field = req.query.field; + return doc[field]; + }), + "userCtx" : stringFun(function(doc, req) { + return doc.user && (doc.user == req.userCtx.name); + }), + "conflicted" : "function(doc, req) { return (doc._conflicts);}", + }, + options : { + local_seq : true + }, + views : { + local_seq : { + map : "function(doc) {emit(doc._local_seq, null)}" + } + } + } + + db.save(ddoc); + + var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/bop"); + var resp = JSON.parse(req.responseText); + T(resp.results.length == 0); + + db.save({"bop" : "foom"}); + db.save({"bop" : false}); + + var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/bop"); + var resp = JSON.parse(req.responseText); + T(resp.results.length == 1, "filtered/bop"); + + req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/dynamic&field=woox"); + resp = JSON.parse(req.responseText); + T(resp.results.length == 0); + + req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/dynamic&field=bop"); + resp = JSON.parse(req.responseText); + T(resp.results.length == 1, "changes_filter/dynamic&field=bop"); + + if (!is_safari && xhr) { // full test requires parallel connections + // filter with longpoll + // longpoll filters full history when run without a since seq + xhr = CouchDB.newXhr(); + xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&filter=changes_filter/bop", false); + xhr.send(""); + var resp = JSON.parse(xhr.responseText); + T(resp.last_seq == 7); + // longpoll waits until a matching change before returning + xhr = CouchDB.newXhr(); + xhr.open("GET", "/test_suite_db/_changes?feed=longpoll&since=7&filter=changes_filter/bop", true); + xhr.send(""); + db.save({"_id":"falsy", "bop" : ""}); // empty string is falsy + db.save({"_id":"bingo","bop" : "bingo"}); + + waitForSuccess(function() { + resp = JSON.parse(xhr.responseText); + }, "longpoll-since"); + + T(resp.last_seq == 9); + T(resp.results && resp.results.length > 0 && resp.results[0]["id"] == "bingo", "filter the correct update"); + xhr.abort(); + + timeout = 500; + last_seq = 10 + while (true) { + + // filter with continuous + xhr = CouchDB.newXhr(); + xhr.open("GET", "/test_suite_db/_changes?feed=continuous&filter=changes_filter/bop&timeout="+timeout, true); + xhr.send(""); + + db.save({"_id":"rusty", "bop" : "plankton"}); + T(xhr.readyState != 4, "test client too slow"); + var rusty = db.open("rusty", {cache_bust : new Date()}); + T(rusty._id == "rusty"); + + waitForSuccess(function() { // throws an error after 5 seconds + if (xhr.readyState != 4) { + throw("still waiting") + } + }, "continuous-rusty"); + lines = xhr.responseText.split("\n"); + try { + JSON.parse(lines[3]) + good = true; + } catch(e) { + good = false; + } + if (good) { + T(JSON.parse(lines[1]).id == "bingo", lines[1]); + T(JSON.parse(lines[2]).id == "rusty", lines[2]); + T(JSON.parse(lines[3]).last_seq == last_seq, lines[3]); + break; + } else { + xhr.abort(); + db.deleteDoc(rusty); + timeout = timeout * 2; + last_seq = last_seq + 2; + } + } + } + // error conditions + + // non-existing design doc + var req = CouchDB.request("GET", + "/test_suite_db/_changes?filter=nothingtosee/bop"); + TEquals(404, req.status, "should return 404 for non existant design doc"); + + // non-existing filter + var req = CouchDB.request("GET", + "/test_suite_db/_changes?filter=changes_filter/movealong"); + TEquals(404, req.status, "should return 404 for non existant filter fun"); + + // both + var req = CouchDB.request("GET", + "/test_suite_db/_changes?filter=nothingtosee/movealong"); + TEquals(404, req.status, + "should return 404 for non existant design doc and filter fun"); + + // changes get all_docs style with deleted docs + var doc = {a:1}; + db.save(doc); + db.deleteDoc(doc); + var req = CouchDB.request("GET", + "/test_suite_db/_changes?filter=changes_filter/bop&style=all_docs"); + var resp = JSON.parse(req.responseText); + var expect = (!is_safari && xhr) ? 3: 1; + TEquals(expect, resp.results.length, "should return matching rows"); + + // test for userCtx + run_on_modified_server( + [{section: "httpd", + key: "authentication_handlers", + value: "{couch_httpd_auth, special_test_authentication_handler}"}, + {section:"httpd", + key: "WWW-Authenticate", + value: "X-Couch-Test-Auth"}], + + function() { + var authOpts = {"headers":{"WWW-Authenticate": "X-Couch-Test-Auth Chris Anderson:mp3"}}; + + var req = CouchDB.request("GET", "/_session", authOpts); + var resp = JSON.parse(req.responseText); + + T(db.save({"user" : "Noah Slater"}).ok); + var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/userCtx", authOpts); + var resp = JSON.parse(req.responseText); + T(resp.results.length == 0); + + var docResp = db.save({"user" : "Chris Anderson"}); + T(docResp.ok); + T(db.ensureFullCommit().ok); + req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/userCtx", authOpts); + resp = JSON.parse(req.responseText); + T(resp.results.length == 1, "userCtx"); + T(resp.results[0].id == docResp.id); + } + ); + + req = CouchDB.request("GET", "/test_suite_db/_changes?limit=1"); + resp = JSON.parse(req.responseText); + TEquals(1, resp.results.length) + + //filter includes _conflicts + var id = db.save({'food' : 'pizza'}).id; + db.bulkSave([{_id: id, 'food' : 'pasta'}], {all_or_nothing:true}); + + req = CouchDB.request("GET", "/test_suite_db/_changes?filter=changes_filter/conflicted"); + resp = JSON.parse(req.responseText); + T(resp.results.length == 1, "filter=changes_filter/conflicted"); + + // test with erlang filter function + run_on_modified_server([{ + section: "native_query_servers", + key: "erlang", + value: "{couch_native_process, start_link, []}" + }], function() { + var erl_ddoc = { + _id: "_design/erlang", + language: "erlang", + filters: { + foo: + 'fun({Doc}, Req) -> ' + + ' Value = couch_util:get_value(<<"value">>, Doc),' + + ' (Value rem 2) =:= 0' + + 'end.' + } + }; + + db.deleteDb(); + db.createDb(); + T(db.save(erl_ddoc).ok); + + var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=erlang/foo"); + var resp = JSON.parse(req.responseText); + T(resp.results.length === 0); + + T(db.save({_id: "doc1", value : 1}).ok); + T(db.save({_id: "doc2", value : 2}).ok); + T(db.save({_id: "doc3", value : 3}).ok); + T(db.save({_id: "doc4", value : 4}).ok); + + var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=erlang/foo"); + var resp = JSON.parse(req.responseText); + T(resp.results.length === 2); + T(resp.results[0].id === "doc2"); + T(resp.results[1].id === "doc4"); + }); + +}; + -- cgit v1.2.3