// 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.etags_views = function(debug) { var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"true"}); db.deleteDb(); db.createDb(); if (debug) debugger; var designDoc = { _id: "_design/etags", language: "javascript", views : { fooView: { map: stringFun(function(doc) { if (doc.foo) { emit("bar", 1); } }), }, basicView : { map : stringFun(function(doc) { if(doc.integer && doc.string) { emit(doc.integer, doc.string); } }) }, withReduce : { map : stringFun(function(doc) { if(doc.integer && doc.string) { emit(doc.integer, doc.string); } }), reduce : stringFun(function(keys, values, rereduce) { if (rereduce) { return sum(values); } else { return values.length; } }) } } }; T(db.save(designDoc).ok); db.bulkSave(makeDocs(0, 10)); var xhr; // verify get w/Etag on map view xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView"); T(xhr.status == 200); var etag = xhr.getResponseHeader("etag"); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView", { headers: {"if-none-match": etag} }); T(xhr.status == 304); // verify ETag doesn't change when an update // doesn't change the view group's index T(db.save({"_id":"doc1", "foo":"bar"}).ok); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView"); var etag1 = xhr.getResponseHeader("etag"); T(etag1 == etag); // verify ETag always changes for include_docs=true on update xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView?include_docs=true"); var etag1 = xhr.getResponseHeader("etag"); T(db.save({"_id":"doc2", "foo":"bar"}).ok); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView?include_docs=true"); var etag2 = xhr.getResponseHeader("etag"); T(etag1 != etag2); // Verify that purges affect etags xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/fooView"); var foo_etag = xhr.getResponseHeader("etag"); var doc1 = db.open("doc1"); xhr = CouchDB.request("POST", "/test_suite_db/_purge", { body: JSON.stringify({"doc1":[doc1._rev]}) }); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/fooView"); var etag1 = xhr.getResponseHeader("etag"); T(etag1 != foo_etag); // Test that _purge didn't affect the other view etags. xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView"); var etag1 = xhr.getResponseHeader("etag"); T(etag1 == etag); // verify different views in the same view group may have different ETags xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/fooView"); var etag1 = xhr.getResponseHeader("etag"); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView"); var etag2 = xhr.getResponseHeader("etag"); T(etag1 != etag2); // verify ETag changes when an update changes the view group's index. db.bulkSave(makeDocs(10, 20)); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView"); var etag1 = xhr.getResponseHeader("etag"); T(etag1 != etag); // verify ETag is the same after a restart restartServer(); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView"); var etag2 = xhr.getResponseHeader("etag"); T(etag1 == etag2); // reduce view xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce"); T(xhr.status == 200); var etag = xhr.getResponseHeader("etag"); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce",{ headers: {"if-none-match": etag} }); T(xhr.status == 304); // verify ETag doesn't change when an update // doesn't change the view group's index T(db.save({"_id":"doc3", "foo":"bar"}).ok); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce"); var etag1 = xhr.getResponseHeader("etag"); T(etag1 == etag); // purge var doc3 = db.open("doc3"); xhr = CouchDB.request("POST", "/test_suite_db/_purge", { body: JSON.stringify({"doc3":[doc3._rev]}) }); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce"); var etag1 = xhr.getResponseHeader("etag"); T(etag1 == etag); // verify different views in the same view group may have different ETags xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/fooView"); var etag1 = xhr.getResponseHeader("etag"); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce"); var etag2 = xhr.getResponseHeader("etag"); T(etag1 != etag2); // verify ETag changes when an update changes the view group's index db.bulkSave(makeDocs(20, 30)); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce"); var etag1 = xhr.getResponseHeader("etag"); T(etag1 != etag); // verify ETag is the same after a restart restartServer(); xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce"); var etag2 = xhr.getResponseHeader("etag"); T(etag1 == etag2); // confirm ETag changes with different POST bodies xhr = CouchDB.request("POST", "/test_suite_db/_design/etags/_view/basicView", {body: JSON.stringify({keys:[1]})} ); var etag1 = xhr.getResponseHeader("etag"); xhr = CouchDB.request("POST", "/test_suite_db/_design/etags/_view/basicView", {body: JSON.stringify({keys:[2]})} ); var etag2 = xhr.getResponseHeader("etag"); T(etag1 != etag2, "POST to map view generates key-depdendent ETags"); xhr = CouchDB.request("POST", "/test_suite_db/_design/etags/_view/withReduce?group=true", {body: JSON.stringify({keys:[1]})} ); etag1 = xhr.getResponseHeader("etag"); xhr = CouchDB.request("POST", "/test_suite_db/_design/etags/_view/withReduce?group=true", {body: JSON.stringify({keys:[2]})} ); etag2 = xhr.getResponseHeader("etag"); T(etag1 != etag2, "POST to reduce view generates key-depdendent ETags"); // all docs xhr = CouchDB.request("GET", "/test_suite_db/_all_docs"); T(xhr.status == 200); var etag = xhr.getResponseHeader("etag"); xhr = CouchDB.request("GET", "/test_suite_db/_all_docs", { headers: {"if-none-match": etag} }); T(xhr.status == 304); // _changes xhr = CouchDB.request("GET", "/test_suite_db/_changes"); T(xhr.status == 200); var etag = xhr.getResponseHeader("etag"); xhr = CouchDB.request("GET", "/test_suite_db/_changes", { headers: {"if-none-match": etag} }); T(xhr.status == 304); // list etag // in the list test for now // A new database should have unique _all_docs etags. db.deleteDb(); db.createDb(); db.save({a: 1}); xhr = CouchDB.request("GET", "/test_suite_db/_all_docs"); var etag = xhr.getResponseHeader("etag"); db.deleteDb(); db.createDb(); db.save({a: 2}); xhr = CouchDB.request("GET", "/test_suite_db/_all_docs"); var new_etag = xhr.getResponseHeader("etag"); T(etag != new_etag); // but still be cacheable xhr = CouchDB.request("GET", "/test_suite_db/_all_docs"); T(new_etag == xhr.getResponseHeader("etag")); };