You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by bi...@apache.org on 2014/05/15 03:09:44 UTC
[10/10] git commit: [OLINGO-276] Check in the missing test source
codes.
[OLINGO-276] Check in the missing test source codes.
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/commit/48761e07
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/tree/48761e07
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/diff/48761e07
Branch: refs/heads/master
Commit: 48761e07fed897bc68496b8b526dc9ab6c71088c
Parents: 1b51dcb
Author: Bing Li <bi...@apache.org>
Authored: Thu May 15 09:07:47 2014 +0800
Committer: Bing Li <bi...@apache.org>
Committed: Thu May 15 09:07:47 2014 +0800
----------------------------------------------------------------------
JSLib/packages.config | 8 +
JSLib/tests/cache-tests.js | 1191 +++++++++
JSLib/tests/common/CacheOracle.js | 228 ++
JSLib/tests/common/Instrument.js | 48 +
JSLib/tests/common/Instrument.svc | 71 +
JSLib/tests/common/ObservableHttpClient.js | 78 +
JSLib/tests/common/gpo-ie8-tour-disable.reg | Bin 0 -> 384 bytes
JSLib/tests/common/mockHttpClient.js | 107 +
JSLib/tests/common/mockXMLHttpRequest.js | 192 ++
JSLib/tests/common/rx.js | 6 +
...cache-large-collection-functional-tests.html | 53 +
...s-cache-large-collection-functional-tests.js | 170 ++
JSLib/tests/datajs-cache-long-haul-tests.html | 192 ++
JSLib/tests/datajs-startup-perf-test.html | 89 +
JSLib/tests/endpoints/BasicAuthDataService.svc | 108 +
JSLib/tests/endpoints/CustomAnnotations.xml | 102 +
JSLib/tests/endpoints/CustomDataService.svc | 76 +
JSLib/tests/endpoints/EpmDataService.svc | 315 +++
JSLib/tests/endpoints/ErrorDataService.svc | 56 +
.../tests/endpoints/LargeCollectionService.svc | 93 +
JSLib/tests/odata-batch-functional-tests.html | 43 +
JSLib/tests/odata-batch-functional-tests.js | 270 ++
JSLib/tests/odata-batch-tests.js | 551 ++++
.../odata-cache-filter-functional-tests.html | 56 +
.../odata-cache-filter-functional-tests.js | 416 +++
JSLib/tests/odata-cache-fperf-tests.html | 54 +
JSLib/tests/odata-cache-fperf-tests.js | 103 +
JSLib/tests/odata-cache-functional-tests.html | 56 +
JSLib/tests/odata-cache-functional-tests.js | 611 +++++
.../tests/odata-cache-rx-functional-tests.html | 54 +
JSLib/tests/odata-cache-rx-functional-tests.js | 74 +
JSLib/tests/odata-fuzz.html | 561 ++++
JSLib/tests/odata-handler-tests.js | 319 +++
JSLib/tests/odata-json-light-tests.js | 2479 ++++++++++++++++++
JSLib/tests/odata-json-tests.js | 888 +++++++
JSLib/tests/odata-links-functional-tests.html | 44 +
JSLib/tests/odata-links-functional-tests.js | 232 ++
...ata-metadata-awareness-functional-tests.html | 43 +
...odata-metadata-awareness-functional-tests.js | 227 ++
JSLib/tests/odata-metadata-tests.js | 486 ++++
JSLib/tests/odata-net-tests.js | 286 ++
JSLib/tests/odata-perf-tests.html | 45 +
JSLib/tests/odata-perf-tests.js | 229 ++
...odata-read-crossdomain-functional-tests.html | 53 +
.../odata-read-crossdomain-functional-tests.js | 137 +
JSLib/tests/odata-read-functional-tests.html | 45 +
JSLib/tests/odata-read-functional-tests.js | 583 ++++
JSLib/tests/odata-request-functional-tests.html | 44 +
JSLib/tests/odata-request-functional-tests.js | 386 +++
JSLib/tests/odata-roundtrip-functional-tests.js | 374 +++
JSLib/tests/odata-tests.js | 306 +++
JSLib/tests/odata-xml-tests.js | 259 ++
JSLib/tests/store-indexeddb-tests.js | 246 ++
JSLib/tests/store-tests.js | 684 +++++
JSLib/tests/test-manager.html | 88 +
55 files changed, 14515 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/48761e07/JSLib/packages.config
----------------------------------------------------------------------
diff --git a/JSLib/packages.config b/JSLib/packages.config
new file mode 100644
index 0000000..d2b5a9b
--- /dev/null
+++ b/JSLib/packages.config
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Microsoft.OData.Client" version="6.0.0-beta1" targetFramework="net40" />
+ <package id="Microsoft.OData.Core" version="6.0.0-beta1" targetFramework="net40" />
+ <package id="Microsoft.OData.Edm" version="6.0.0-beta1" targetFramework="net40" />
+ <package id="Microsoft.OData.Service" version="6.0.0-beta1" targetFramework="net40" />
+ <package id="Microsoft.Spatial" version="6.0.0-beta1" targetFramework="net40" />
+</packages>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/48761e07/JSLib/tests/cache-tests.js
----------------------------------------------------------------------
diff --git a/JSLib/tests/cache-tests.js b/JSLib/tests/cache-tests.js
new file mode 100644
index 0000000..13fd4b9
--- /dev/null
+++ b/JSLib/tests/cache-tests.js
@@ -0,0 +1,1191 @@
+/// <reference path="../src/datajs.js" />
+/// <reference path="../src/odata-utils.js" />
+/// <reference path="../src/cache.js" />
+/// <reference path="common/djstest.js" />
+
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// cache-tests.js
+
+(function (window, undefined) {
+
+ module("Unit");
+ var foodsFeed = "./endpoints/FoodStoreDataServiceV4.svc/Foods";
+ var collectionSize = 16;
+
+ var thenFailTest = function (err) {
+ if (err && err.message) {
+ djstest.fail(err.message);
+ } else {
+ djstest.fail("unexepected promise failure");
+ }
+
+ djstest.done();
+ };
+
+ djstest.addTest(function dataCacheCountTest() {
+ var cache = datajs.createDataCache({ name: "cache", source: foodsFeed });
+ cache.count().then(function (count) {
+ djstest.assertAreEqual(count, collectionSize, "expected count for Foods");
+ djstest.destroyCacheAndDone(cache);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheCountOnLocalTest() {
+ var cache = datajs.createDataCache({ name: "cache", source: foodsFeed, pageSize: collectionSize + 10, mechanism: "memory" });
+ cache.readRange(0, collectionSize + 10).then(function (data) {
+ var expectedCount = data.value ? data.value.length : 0;
+ cache.count().then(function (count) {
+ djstest.assertAreEqual(count, expectedCount, "expected count for expectedCount");
+ djstest.destroyCacheAndDone(cache);
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheCountAbortTest() {
+ // Abort before completion.
+ var cache = datajs.createDataCache({ name: "cache", source: foodsFeed });
+ var item = cache.count().then(thenFailTest, function (err) {
+ djstest.assertAreEqual(true, err.canceled, "err.aborted is true");
+ djstest.destroyCacheAndDone(cache);
+ }).cancel();
+ });
+
+ var createNewCache = function (options) {
+
+ var thenSuccess = null;
+
+ var resolved = false;
+ var rejected = false;
+
+ var args = null;
+
+ this.then = function (success) {
+ if (resolved) {
+ success.apply(null, args);
+ } else if (!rejected) {
+ thenSuccess = success;
+ }
+ };
+
+ var resolve = function (/*args*/) {
+ resolved = true;
+ args = arguments;
+ if (thenSuccess) {
+ thenSuccess.apply(null, arguments);
+ }
+ };
+
+ var cache = datajs.createDataCache(options);
+ cache.clear().then(function () {
+ var newCache = datajs.createDataCache(options);
+ resolve(newCache);
+ }, function (err) {
+ rejected = true;
+ thenFailTest(err);
+ });
+
+ return this;
+ };
+
+ djstest.addTest(function dataCacheReadRangeSingleTest() {
+ // Read a new range.
+ var options = { name: "cache", source: foodsFeed, pageSize: 2 };
+ createNewCache(options).
+ then(function (cache) {
+ cache.readRange(0, 1).
+ then(function (data) {
+ djstest.assertAreEqual(data.value.length, 1, "single item was read.");
+ djstest.assertAreEqual(data.value[0].FoodID, 0, "food id is 0.");
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheReadRangeExactPageTest() {
+ // Read exactly one page.
+ var options = { name: "cache", source: foodsFeed, pageSize: 2 };
+ createNewCache(options).
+ then(function (cache) {
+ cache.readRange(0, 2).
+ then(function (data) {
+ djstest.assertAreEqual(data.value.length, 2, "single item was read.");
+ djstest.assertAreEqual(data.value[0].FoodID, 0, "first food id is 0.");
+ djstest.assertAreEqual(data.value[1].FoodID, 1, "second food id is 1.");
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheReadRangeMultiplePageTest() {
+ // Read multiple pages.
+ var options = { name: "cache", source: foodsFeed, pageSize: 2 };
+ createNewCache(options).
+ then(function (cache) {
+ cache.readRange(0, 3).
+ then(function (data) {
+ djstest.assertAreEqual(data.value.length, 3, "single item was read.");
+ djstest.assertAreEqual(data.value[0].FoodID, 0, "first food id is 0.");
+ djstest.assertAreEqual(data.value[1].FoodID, 1, "second food id is 1.");
+ djstest.assertAreEqual(data.value[2].FoodID, 2, "third food id is 2.");
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheReadRangeSyncDelaysTest() {
+ var options = { name: "cache", source: foodsFeed, pageSize: 2 };
+ var counter = 0;
+ createNewCache(options).
+ then(function (cache) {
+ cache.readRange(0, 1).
+ then(function (data) {
+ djstest.assertAreEqual(counter, 0, "counter is zero for first set of results");
+ djstest.assertAreEqual(cache.stats.netReads, 1, "one request made to fulfill the readRange");
+ counter++;
+ cache.readRange(0, 1).
+ then(function (data) {
+ djstest.assertAreEqual(counter, 2, "counter is two because even sync results are delayed)");
+ djstest.assertAreEqual(cache.stats.netReads, 1, "no additional requests since requested data is in cache");
+ djstest.done();
+ }, thenFailTest);
+ djstest.assertAreEqual(counter, 1, "counter is one because readRange hasn't run (even if results are cached)");
+ counter++;
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheReadRangesWithDestroyTest() {
+ var options = { name: "cache", source: foodsFeed, pageSize: 2, prefetchSize: 0 };
+ var counter = 0;
+ createNewCache(options).then(function (cache) {
+ cache.readRange(0, 1).then(function (data) {
+ djstest.assertAreEqual(cache.stats.netReads, 1, "one request made to fulfill the readRange");
+ cache.clear().then(function () {
+ djstest.assertAreEqual(cache.stats.netReads, 0, "stats cleared in destroy");
+ cache.readRange(0, 1).then(function (data) {
+ djstest.assertAreEqual(cache.stats.netReads, 1, "request made after destroy to fulfill the readRange");
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheReadSimultaneousTest() {
+ var options = { name: "cache", source: foodsFeed, pageSize: 2 };
+ var counter = 0;
+ var theCache;
+ var checkDataAndCount = function (data) {
+ djstest.assertAreEqual(data.value.length, 1, "Single item returned");
+ djstest.assertAreEqual(data.value[0].FoodID, 0, "FoodId is set to zero for first item");
+ djstest.assertAreEqual(theCache.stats.netReads, 1, "single theCache.stats.netReads");
+ djstest.assert(theCache.stats.prefetches <= 1, "theCache.stats.prefetches <= 1 - no repetitions");
+ counter++;
+ if (counter === 3) {
+ djstest.done();
+ }
+ };
+
+ createNewCache(options).
+ then(function (cache) {
+ theCache = cache;
+ cache.readRange(0, 1).then(checkDataAndCount, thenFailTest);
+ cache.readRange(0, 1).then(checkDataAndCount, thenFailTest);
+ cache.readRange(0, 1).then(checkDataAndCount, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheMultipleClearTest() {
+ var options = { name: "cache", source: foodsFeed, pageSize: 2 };
+ var counter = 0;
+ var checkCount = function (data) {
+ djstest.assert(true, "clear then was called");
+ counter++;
+ if (counter === 3) {
+ djstest.done();
+ }
+ };
+
+ createNewCache(options).
+ then(function (cache) {
+ cache.readRange(0, 1).then(function () {
+ cache.clear().then(checkCount, thenFailTest);
+ cache.clear().then(checkCount, thenFailTest);
+ cache.clear().then(checkCount, thenFailTest);
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheOnIdleIsFired() {
+ var options = { name: "cache", source: foodsFeed, pageSize: 2, prefetchSize: 0 };
+
+ createNewCache(options).
+ then(function (cache) {
+ var counter = 0;
+ var clearSucceeded = false;
+
+ var thenFailThisTest = function (err) {
+ if (err && err.message) {
+ djstest.fail(err.message);
+ } else {
+ djstest.fail("unexepected promise failure");
+ }
+ };
+
+ cache.onidle = function () {
+ counter++;
+ djstest.assertAreEqual(counter, 1, "onidle was called 1 times");
+ djstest.assert(clearSucceeded, "onidle was called after destroy");
+ djstest.done();
+ };
+
+ cache.readRange(0, 1).then(null, thenFailThisTest);
+ cache.readRange(0, 1).then(null, thenFailThisTest);
+ cache.readRange(3, 4).then(function () {
+ cache.readRange(5, 6).then(function () {
+ cache.clear().then(function () {
+ clearSucceeded = true;
+ }, thenFailThisTest);
+ }, thenFailThisTest);
+ }, thenFailThisTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheOnIdleFiresOnErrorTest() {
+
+ var errorResponse = false;
+ var httpClient = {
+ request: function (request, success, error) {
+ var response = { statusCode: 200, headers: { "Content-Type": "application/json", "OData-Version": "4.0" }, body: JSON.stringify({ d: [1, 2] }) };
+ if (!errorResponse) {
+ errorResponse = true;
+ setTimeout(function () {
+ success(response);
+ }, 0);
+ } else {
+ response.statusCode = 500;
+ response.body = "bad response";
+ setTimeout(function () {
+ error({ message: "HTTP request failed", request: request, response: response });
+ }, 0);
+ }
+ }
+ };
+
+ var options = { name: "cache", source: foodsFeed, pageSize: 2, prefetchSize: 0, httpClient: httpClient };
+
+ createNewCache(options).
+ then(function (cache) {
+ var counter = 0;
+ var errorHandlerCalled = false;
+
+ var thenFailThisTest = function (err) {
+ if (err && err.message) {
+ if (errorResponse) {
+ djstest.assertAreEqual(err.message, "HTTP request failed", "Error is the expected one");
+ errorHandlerCalled = true;
+ } else {
+ djstest.fail(err.message);
+ }
+ } else {
+ djstest.fail("unexepected promise failure");
+ }
+ };
+
+ cache.onidle = function () {
+ counter++;
+ djstest.assertAreEqual(counter, 1, "onidle was called");
+ djstest.assert(errorHandlerCalled, "error handler was called before onidle");
+ cache.onidle = null;
+ cache.clear().then(function () {
+ djstest.done();
+ }, thenFailTest);
+ };
+ cache.readRange(0, 2).then(function () {
+ cache.readRange(2, 4).then(function () {
+ djstest.fail("unexpected readRange success");
+ }, thenFailThisTest);
+ }, thenFailThisTest);
+ }, thenFailTest);
+ });
+
+
+ djstest.addTest(function dataCacheOdataSourceNormalizedURITest() {
+ var requestsMade = 0;
+ var httpClient = {
+ request: function (request, success, error) {
+ var response = { statusCode: 200, headers: { "Content-Type": "application/json", "OData-Version": "4.0" }, body: JSON.stringify({ value: [1, 2] }) };
+ if (requestsMade === 0) {
+ djstest.pass("Cache made first request for data from the source");
+ requestsMade++;
+ } else {
+ // In memory storage will make a second request from the new cache since two caches with the same name will coexist
+ if (window.mozIndexedDB || window.localStorage || requestsMade > 1) {
+ djstest.fail("Unexpected request to the source");
+ } else {
+ djstest.pass("In memory cache requested the data from the source");
+ }
+ }
+ setTimeout(function () {
+ success(response);
+ }, 0);
+ }
+ };
+
+ var options = { name: "cache", source: "http://exampleuri.com/my service.svc", pageSize: 2, prefetchSize: 0, httpClient: httpClient };
+
+ createNewCache(options).
+ then(function (cache) {
+ cache.readRange(0, 2).then(function () {
+ options.source = "HtTp://ExampleURI.cOm/my%20service.svc";
+ var newCache = datajs.createDataCache(options);
+ newCache.readRange(0, 2).then(function (data) {
+ djstest.assertAreEqualDeep(data.value, [1, 2], "Got the expected data from the new cache instance");
+ newCache.clear().then(function () {
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+
+ djstest.addTest(function dataCachePrefetchAllTest() {
+ var options = { name: "cache", source: foodsFeed, pageSize: 2, prefetchSize: -1 };
+ var counter = 0;
+ var theCache;
+
+ var callback = function () {
+ counter++;
+ if (counter === 2) {
+ djstest.assertAreEqual(1, theCache.stats.netReads, "single page to satisfy read (" + theCache.stats.netReads + ")");
+ djstest.assert(theCache.stats.prefetches > 1, "theCache.stats.prefetches(" + theCache.stats.prefetches + ") > 1 - multiple prefetches");
+ djstest.done();
+ }
+ };
+
+ var checkDataAndCount = function (data) {
+ djstest.assertAreEqual(data.value.length, 1, "Single item returned");
+ djstest.assertAreEqual(data.value[0].FoodID, 0, "FoodId is set to zero for first item");
+ djstest.assertAreEqual(1, theCache.stats.netReads, "single theCache.stats.netReads");
+ djstest.assert(theCache.stats.prefetches <= 1, "theCache.stats.prefetches <= 1 - no repetitions");
+ callback();
+ };
+
+ createNewCache(options).
+ then(function (cache) {
+ theCache = cache;
+ cache.readRange(0, 1).then(checkDataAndCount, thenFailTest);
+ cache.onidle = function () {
+ djstest.log("onidle fired");
+ callback();
+ };
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheReadRangeTakeMoreThanCollectionCountTest() {
+ // Read multiple pages.
+ var options = { name: "cache", source: foodsFeed, pageSize: 2 };
+ createNewCache(options).
+ then(function (cache) {
+ cache.count().then(function (count) {
+ cache.readRange(0, count + 1).
+ then(function (data) {
+ djstest.assertAreEqual(data.value.length, count, "all items in the collection were read.");
+ cache.readRange(2, count + 1).
+ then(function (data) {
+ djstest.assertAreEqual(data.value.length, count - 2, "all requested in the collection were read.");
+ djstest.assertAreEqual(data.value[0].FoodID, 2, "first read food id is 2.");
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheReadRangeSkipMoreThanCollectionCountTest() {
+ // Read multiple pages.
+ var options = { name: "cache", source: foodsFeed, pageSize: 2 };
+ createNewCache(options).
+ then(function (cache) {
+ cache.count().then(function (count) {
+ cache.readRange(count + 1, 5).
+ then(function (data) {
+ djstest.assertAreEqual(data.value.length, 0, "no items were read.");
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheReadRangeTakeMoreThanPrefetchSizeTest() {
+ // Read multiple pages.
+ var options = { name: "cache", source: foodsFeed, pageSize: 2, prefetchSize: 1 };
+ createNewCache(options).
+ then(function (cache) {
+ cache.readRange(0, 4).
+ then(function (data) {
+ djstest.assertAreEqual(data.value.length, 4, "all requested in the collection were read.");
+ djstest.assertAreEqual(data.value[0].FoodID, 0, "first food id is 0.");
+ djstest.assertAreEqual(data.value[1].FoodID, 1, "second food id is 1.");
+ djstest.assertAreEqual(data.value[2].FoodID, 2, "third food id is 2.");
+ djstest.assertAreEqual(data.value[3].FoodID, 3, "third food id is 3.");
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function dataCacheRangeInvalidIndexAndCount() {
+ var options = { name: "cache", source: foodsFeed, pageSize: 2, prefetchSize: 1 };
+ var counter = 0;
+
+ var thenFailSuccess = function () {
+ djstest.fail("Call to success was unexpected");
+ counter++;
+ if (counter === tests.length) {
+ djstest.done();
+ }
+ };
+
+ var thenFailError = function () {
+ djstest.fail("Call to error was unexpected");
+ counter++;
+ if (counter === tests.length) {
+ djstest.done();
+ }
+ };
+
+ var invalidValues = [-5, -1, null, undefined, NaN, Infinity, "5", "this is not a number"];
+ var tests = [];
+ $.each(invalidValues, function (_, value) {
+ tests.push({ i: value, c: 0 });
+ tests.push({ i: 0, c: value });
+ tests.push({ i: value, c: value });
+ });
+
+ createNewCache(options).
+ then(function (cache) {
+ var i, len;
+ for (i = 0, len = tests.length; i < len; i++) {
+ var test = tests[i];
+ try {
+ cache.readRange(test.i, test.c).then(thenFailSuccess, thenFailTest);
+ } catch (err) {
+ djstest.pass("Expected exception was thrown: " + err.message);
+ counter++;
+ }
+ }
+ if (counter === tests.length) {
+ djstest.done();
+ }
+ });
+ });
+
+
+ djstest.addTest(function cacheOptionsForCountTest() {
+ var httpClient = {
+ request: function (r, success, error) {
+ window.setTimeout(function () {
+ success({ data: "10" });
+ }, 1);
+ return null;
+ }
+ };
+ var cache = datajs.createDataCache({
+ name: "mem", mechanism: "memory", source: "http://www.example.org/service/",
+ httpClient: httpClient
+ });
+ cache.count().then(function (count) {
+ djstest.assertAreEqual(count, 10, "count value");
+ djstest.done();
+ }, djstest.failAndDoneCallback("failed to get count"));
+ });
+
+ djstest.addTest(function dataCacheDestoryStopsThePrefetcherTest() {
+ var oldHttpClientRequest = OData.defaultHttpClient.request;
+ var prefetchCount = 0;
+ var theCache;
+
+ OData.defaultHttpClient.request = function (request, success, error) {
+ prefetchCount++;
+ djstest.assert(prefetchCount <= 3, "Expected prefetch request");
+ if (prefetchCount === 3) {
+ theCache.clear().then(function () {
+ djstest.assertAreEqual(prefetchCount, 3, "cache.clear() stopped the prefetcher");
+ djstest.done();
+ OData.defaultHttpClient.request = oldHttpClientRequest;
+ }, thenFailTest);
+ return {
+ abort: function () { }
+ };
+ }
+ return oldHttpClientRequest(request, success, error);
+ };
+
+ try {
+ var options = { name: "cache", source: foodsFeed, pageSize: 1, prefetchSize: -1 };
+ createNewCache(options).then(function (cache) {
+ theCache = cache;
+ cache.readRange(0, 0).then(null, thenFailTest);
+ });
+ } catch (e) {
+ OData.defaultHttpClient.request = oldHttpClientRequest;
+ djstest.fail("Exception thrown, prefetchSize: " + tests[count] + " error: " + e.message);
+ djstest.done();
+ }
+ });
+
+ djstest.addTest(function dataCacheFilterTest() {
+ var options = { name: "cache", source: foodsFeed, pageSize: 3, prefetchSize: -1 };
+ var counter = 0;
+
+ var singleItemPredicate = function (data) {
+ return data.FoodID === 2;
+ };
+
+ var multipleItemPredicate = function (data) {
+ return data.FoodID % 2 === 1;
+ };
+
+ var noItemPredicate = function (data) {
+ return data.Name === "something i would never eat";
+ };
+
+ var allItemPredicate = function (data) {
+ return data.FoodID >= 0;
+ };
+
+ var doneAfterAllTests = function () {
+ counter++;
+ if (counter === tests.length) {
+ djstest.done();
+ }
+ };
+
+ var last = collectionSize - 1;
+ var tests = [
+ { index: 0, count: -5, predicate: singleItemPredicate }, // Single match in entire collection
+ {index: 2, count: 1, predicate: singleItemPredicate }, // Single match, single count
+ {index: 3, count: 1, predicate: singleItemPredicate }, // Single match skipped, i.e. no matches
+ {index: 0, count: -1, predicate: multipleItemPredicate }, // Multiple matches in entire collection
+ {index: 0, count: 5, predicate: multipleItemPredicate }, // Multiple matches, take partial
+ {index: 3, count: 5, predicate: multipleItemPredicate }, // Multiple matches, skip/take partial
+ {index: 7, count: 10, predicate: multipleItemPredicate }, // Multiple matches, skip partial, take past end of collection
+ {index: 13, count: 4, predicate: allItemPredicate }, // All items match, skip/take partial
+ {index: 0, count: 20, predicate: noItemPredicate }, // No matches
+ {index: 0, count: 0, predicate: allItemPredicate }, // Zero count
+ {index: -5, count: 1, predicate: allItemPredicate }, // Negative index
+ {index: last + 1, count: 1, predicate: allItemPredicate }, // Index past end of collection
+
+ {index: last, count: -5, predicate: singleItemPredicate, backwards: true }, // Single match in entire collection
+ {index: 2, count: 1, predicate: singleItemPredicate, backwards: true }, // Single match, single count
+ {index: 1, count: 1, predicate: singleItemPredicate, backwards: true }, // Single match skipped, i.e. no matches
+ {index: last, count: -1, predicate: multipleItemPredicate, backwards: true }, // Multiple matches in entire collection
+ {index: last, count: 6, predicate: multipleItemPredicate, backwards: true }, // Multiple matches, take partial
+ {index: last - 3, count: 5, predicate: multipleItemPredicate, backwards: true }, // Multiple matches, skip/take partial
+ {index: 13, count: 10, predicate: multipleItemPredicate, backwards: true }, // Multiple matches, skip partial, take past end of collection
+ {index: 4, count: 13, predicate: allItemPredicate, backwards: true }, // All items match, skip/take partial
+ {index: last, count: 20, predicate: noItemPredicate, backwards: true }, // No matches
+ {index: 0, count: 0, predicate: allItemPredicate, backwards: true }, // Zero count
+ {index: -5, count: 1, predicate: allItemPredicate, backwards: true }, // Negative index
+ {index: last + 1, count: 1, predicate: allItemPredicate, backwards: true }, // Index past end of collection
+
+ {index: "foo", count: 1, predicate: singleItemPredicate, exception: { message: "'index' must be a valid number.", index: NaN} },
+ { index: 0, count: "foo", predicate: multipleItemPredicate, exception: { message: "'count' must be a valid number.", count: NaN} }
+ ];
+
+ var testDescription = function(test) {
+ return "filter [" + test.index + ", " + test.count + " " + (test.backwards ? "back" : "forward") + "] for predicate " + test.predicate;
+ };
+
+ var filterErrorCallback = function (err) {
+ if (err && err.message) {
+ djstest.fail(err.message);
+ } else {
+ djstest.fail("unexpected promise failure");
+ }
+ doneAfterAllTests();
+ };
+
+ var removeSafariExceptionProperties = function (err) {
+ /// <summary>Removes Safari-specific properties from an exception object</summary>
+ /// <params name="err" type="Exception">The exception object to operate on</param>
+ /// <returns type="Exception">The original exception object with the Safari-specific properties removed</returns>
+ var safariProperties = ["line", "expressionBeginOffset", "expressionEndOffset", "sourceId", "sourceURL"];
+
+ var result = {};
+ $.each(err, function (property, value) {
+ if ($.inArray(property, safariProperties) === -1) {
+ result[property] = value;
+ }
+ });
+
+ return result;
+ };
+
+ ODataReadOracle.readJsonAcrossServerPages(foodsFeed, function (expectData) {
+ $.each(tests, function (_, test) {
+ createNewCache(options).then(function (cache) {
+ try {
+ var expectedResults = {};
+ if (test.backwards) {
+ cache.filterBack(test.index, test.count, test.predicate).then(function (results) {
+ expectedResults = CacheOracle.getExpectedFilterResults(expectData, test.index, test.count, test.predicate, test.backwards);
+ djstest.assertAreEqualDeep(results, expectedResults, "results for " + testDescription(test));
+ doneAfterAllTests();
+ }, filterErrorCallback);
+ } else {
+ cache.filterForward(test.index, test.count, test.predicate).then(function (results) {
+ expectedResults = CacheOracle.getExpectedFilterResults(expectData, test.index, test.count, test.predicate, test.backwards);
+ djstest.assertAreEqualDeep(results, expectedResults, "results for " + testDescription(test));
+ doneAfterAllTests();
+ }, filterErrorCallback);
+ }
+
+ if (test.exception) {
+ djstest.fail("expected exception for " + testDescription(test));
+ doneAfterAllTests();
+ }
+ } catch (err) {
+ if (test.exception) {
+ djstest.assertAreEqualDeep(removeSafariExceptionProperties(err), test.exception, "exception for " + testDescription(test));
+ } else {
+ djstest.fail("unexpected exception for " + testDescription(test) + ": " + djstest.toString(err));
+ }
+ doneAfterAllTests();
+ }
+ }, thenFailTest);
+ });
+ });
+ });
+
+ djstest.addTest(function createDataCacheTest() {
+ var cache;
+
+ // Verify the defaults.
+ cache = datajs.createDataCache({ name: "name", source: "src" });
+
+ djstest.assertAreEqual(cache.onidle, undefined, "onidle is undefined");
+
+ // Verify specific values.
+ cache = datajs.createDataCache({ name: "name", source: "src", cacheSize: 1, pageSize: 2, prefetchSize: 3, idle: 123 });
+
+ djstest.assertAreEqual(cache.onidle, 123, "onidle is as specified");
+
+ // Verify 0 pageSize
+ djstest.expectException(function () {
+ datajs.createDataCache({ name: "name", source: "src", cacheSize: 1, pageSize: 0, prefetchSize: 3, idle: 123 });
+ }, "zero pageSize");
+
+ // Verify negative pageSize
+ djstest.expectException(function () {
+ datajs.createDataCache({ name: "name", source: "src", cacheSize: 1, pageSize: -2, prefetchSize: 3, idle: 123 });
+ }, "negative pageSize");
+
+ // Verify NaN pageSize
+ djstest.expectException(function () {
+ cache = datajs.createDataCache({ name: "name", source: "src", cacheSize: 1, pageSize: "2", prefetchSize: 3, idle: 123 });
+ }, "NaN pageSize");
+
+ // Verify NaN cacheSize
+ djstest.expectException(function () {
+ cache = datajs.createDataCache({ name: "name", source: "src", cacheSize: "1", pageSize: 2, prefetchSize: 3, idle: 123 });
+ }, "NaN cacheSize");
+
+ // Verify NaN prefetchSize
+ djstest.expectException(function () {
+ cache = datajs.createDataCache({ name: "name", source: "src", cacheSize: 1, pageSize: 2, prefetchSize: "3", idle: 123 });
+ }, "NaN prefetchSize");
+
+ // Verify undefined name
+ djstest.expectException(function () {
+ datajs.createDataCache({ source: "src", cacheSize: 1, pageSize: 1, prefetchSize: 3, idle: 123 });
+ }, "undefined name");
+
+ // Verify null name
+ djstest.expectException(function () {
+ datajs.createDataCache({ name: null, source: "src", cacheSize: 1, pageSize: 1, prefetchSize: 3, idle: 123 });
+ }, "null name");
+
+ // Verify undefined source
+ djstest.expectException(function () {
+ datajs.createDataCache({ name: "name", cacheSize: 1, pageSize: 1, prefetchSize: 3, idle: 123 });
+ }, "undefined source");
+
+ djstest.done();
+ });
+
+ djstest.addTest(function createDataCacheWithSourceTest() {
+ var cacheSource = {
+ count: function (success) {
+ djstest.pass("cacheSource.count was called");
+ success(0);
+ },
+
+ read: function (index, count, success, error) {
+ djstest.assertAreEqual(index, 0, "index is the expected one");
+ djstest.assertAreEqual(count, 10, "test is the expected one");
+ djstest.assert(success, "success is defined");
+ djstest.assert(error, "error is defined");
+ djstest.pass("cacheSource.read was called");
+
+ setTimeout(function () {
+ success([]);
+ }, 0);
+ }
+ };
+
+ var cache = datajs.createDataCache({ name: "name", source: cacheSource, mechanism: "memory", pageSize: 10 });
+ cache.count().then(function () {
+ cache.readRange(0, 5).then(function () {
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ djstest.addTest(function cacheInitializationFailTest() {
+ // Tests various failure modes for cache initialization.
+ var failures = ["read-settings", "write-settings", "v2"];
+ var failureIndex = 0;
+
+ var originalStore = datajs.createStore;
+ var restoreStore = function () {
+ datajs.createStore = originalStore;
+ };
+
+ var storeError = { message: "cacheInitializationFailTest error" };
+ datajs.createStore = function (name, mechanism) {
+ return {
+ addOrUpdate: function (key, value, successCallback, errorCallback) {
+ if (failures[failureIndex] === "write-settings") {
+ window.setTimeout(function () { errorCallback(storeError); }, 2);
+ } else {
+ djstest.fail("Error unaccounted for in addOrUpdate for " + failures[failureIndex]);
+ window.setTimeout(function () { errorCallback(storeError); }, 2);
+ }
+ },
+ read: function (key, successCallback, errorCallback) {
+ if (failures[failureIndex] === "read-settings") {
+ window.setTimeout(function () { errorCallback(storeError); }, 2);
+ } else if (failures[failureIndex] === "v2") {
+ window.setTimeout(function () {
+ successCallback("K", { version: "2.0" });
+ }, 2);
+ } else if (failures[failureIndex] === "write-settings") {
+ window.setTimeout(function () { successCallback(null, null); }, 2);
+ } else {
+ djstest.fail("Error unaccounted for read in " + failures[failureIndex]);
+ window.setTimeout(function () { errorCallback(storeError); }, 2);
+ }
+ }
+ };
+ };
+
+ var nextFailure = function () {
+ djstest.log("Failure mode: " + failures[failureIndex]);
+ var cache = datajs.createDataCache({ name: "name", source: "foo", mechanism: "memory", pageSize: 10 });
+ try {
+ // The first readRange should succeed, because the data cache isn't really initialized at this time.
+ cache.readRange(1, 2).then(djstest.failAndDoneCallback("No function should succeed"), function (err) {
+ djstest.expectException(function () {
+ cache.readRange(1, 2);
+ }, "readRange after store is invalidated");
+
+ djstest.expectException(function () {
+ cache.count();
+ }, "count after store is invalidated");
+
+ djstest.expectException(function () {
+ cache.clear();
+ }, "clear after store is invalidated");
+
+ djstest.expectException(function () {
+ cache.filterForward(1, 2);
+ }, "filterForward after store is invalidated");
+
+ djstest.expectException(function () {
+ cache.filterBack(1, 2);
+ }, "filterBack after store is invalidated");
+
+ djstest.expectException(function () {
+ cache.toObservable();
+ }, "toObservable after store is invalidated");
+
+ failureIndex++;
+ if (failureIndex === failures.length) {
+ restoreStore();
+ djstest.done();
+ } else {
+ nextFailure();
+ }
+ });
+ } catch (outerError) {
+ djstest.fail("Unexpected failure for first .readRange: " + window.JSON.stringify(outerError));
+ restoreStore();
+ djstest.done();
+ }
+ };
+
+ nextFailure();
+ });
+
+ djstest.addTest(function createDataCacheWithSourceCallsErrorTest() {
+ var cacheSource = {
+ count: function () {
+ djstest.fail("cacheSource.count was called");
+ },
+
+ read: function (index, count, success, error) {
+ setTimeout(function () {
+ error({ message: "source error" });
+ }, 0);
+ }
+ };
+
+ var cache = datajs.createDataCache({ name: "name", source: cacheSource, mechanism: "memory", pageSize: 10 });
+ cache.readRange(0, 5).then(function () {
+ djstest.fail("unexpected call to then success");
+ djstest.done();
+ }, function (err) {
+ djstest.assertAreEqual(err.message, "source error", "got the expected error");
+ djstest.done();
+ });
+ });
+
+ djstest.addTest(function toObservableMissingTest() {
+ createNewCache({ name: "cache", source: "http://temp.org" }).then(function (cache) {
+ var hiddenRx = window.Rx;
+ try {
+ window.Rx = null;
+ var error = null;
+ try {
+ cache.ToObservable();
+ } catch (err) {
+ error = err;
+ }
+
+ djstest.assert(error !== null, "error !== null");
+ } finally {
+ window.Rx = hiddenRx;
+ }
+
+ djstest.assert(error !== null, "error !== null");
+ djstest.destroyCacheAndDone(cache);
+ });
+ });
+
+ djstest.addTest(function toObservableSinglePageTest() {
+ createNewCache({ name: "cache", source: foodsFeed }).then(function (cache) {
+ var lastId = -1;
+ cache.ToObservable().Subscribe(function (item) {
+ djstest.assert(lastId < item.FoodID, "lastId < item.FoodID");
+ lastId = item.FoodID;
+ }, thenFailTest, function () {
+ djstest.assert(lastId !== -1, "lastId !== -1");
+ djstest.done();
+ });
+ });
+ });
+
+ djstest.addTest(function toObservableCaseSinglePageTest() {
+ createNewCache({ name: "cache", source: foodsFeed }).then(function (cache) {
+ var lastId = -1;
+ cache.toObservable().Subscribe(function (item) {
+ djstest.assert(lastId < item.FoodID, "lastId < item.FoodID");
+ lastId = item.FoodID;
+ }, thenFailTest, function () {
+ djstest.assert(lastId !== -1, "lastId !== -1");
+ djstest.done();
+ });
+ });
+ });
+
+ djstest.addTest(function toObservableMultiplePageTest() {
+ createNewCache({ name: "cache", source: foodsFeed, pageSize: 2 }).then(function (cache) {
+ var lastId = -1;
+ var callCount = 0;
+ cache.toObservable().Subscribe(function (item) {
+ djstest.assert(lastId < item.FoodID, "lastId < item.FoodID");
+ lastId = item.FoodID;
+ callCount += 1;
+ }, thenFailTest, function () {
+ djstest.assert(lastId !== -1, "lastId !== -1");
+ djstest.assert(callCount > 1, "callCount > 1");
+ djstest.done();
+ });
+ });
+ });
+
+ djstest.addTest(function toObservableEarlyDisposeTest() {
+ createNewCache({ name: "cache", source: foodsFeed, pageSize: 2 }).then(function (cache) {
+ var lastId = -1;
+ var callCount = 0;
+ var complete = false;
+ var observer = cache.toObservable().Subscribe(function (item) {
+ djstest.assert(complete === false, "complete === false");
+ djstest.assert(lastId < item.FoodID, "lastId < item.FoodID");
+ lastId = item.FoodID;
+ callCount += 1;
+ complete = true;
+ observer.Dispose();
+ djstest.done();
+ }, thenFailTest);
+ });
+ });
+
+ djstest.addTest(function toObservableFailureTest() {
+ createNewCache({ name: "cache", source: foodsFeed, pageSize: 2 }).then(function (cache) {
+ var lastId = -1;
+ var complete = false;
+ window.MockHttpClient.clear().addResponse("*", { statusCode: 500, body: "server error" });
+ window.MockHttpClient.async = true;
+ var savedClient = OData.defaultHttpClient;
+ OData.defaultHttpClient = window.MockHttpClient;
+ cache.toObservable().Subscribe(function (item) {
+ OData.defaultHttpClient = savedClient;
+ djstest.fail("Unexpected call to OnNext");
+ }, function (err) {
+ djstest.assert(complete === false, "complete === false");
+ djstest.assert(err, "err defined");
+ OData.defaultHttpClient = savedClient;
+ complete = true;
+ djstest.done();
+ }, function (complete) {
+ djstest.fail("Unexpected call to complete. Error handler should be called.");
+ OData.defaultHttpClient = savedClient;
+ complete = true;
+ djstest.done();
+ });
+ });
+ });
+
+ // DATAJS INTERNAL START
+
+ djstest.addTest(function createDeferredTest() {
+ // Verify basic use of deferred object.
+ var deferred = datajs.createDeferred();
+ deferred.then(function (val1, val2) {
+ djstest.assertAreEqual(val1, 1, "val1 is as specified");
+ djstest.assertAreEqual(val2, 2, "val2 is as specified");
+ djstest.done();
+ });
+ deferred.resolve(1, 2);
+ });
+
+ djstest.addTest(function deferredThenTest() {
+ // Verify then registration and chaining.
+ var deferred = datajs.createDeferred();
+ deferred.then(function (val1, val2) {
+ djstest.assertAreEqual(val1, 1, "val1 is as specified");
+ djstest.assertAreEqual(val2, 2, "val2 is as specified");
+ return "foo";
+ }).then(function (foo) {
+ // See Compatibility Note B in DjsDeferred remarks.
+ djstest.assert(foo !== "foo", "argument for chained 'then' is *not* result of previous call");
+ djstest.assert(foo === 1, "argument for chained 'then' is same as for previous call");
+
+ var other = datajs.createDeferred();
+ other.then(null, function (err, msg) {
+ djstest.assertAreEqual("error", err, "err is as specified");
+ djstest.assertAreEqual("message", msg, "msg is as specified");
+
+ }).then(null, function (err, msg) {
+ djstest.log("chained errors are called");
+
+ djstest.assertAreEqual("error", err, "err is as specified");
+ djstest.assertAreEqual("message", msg, "msg is as specified");
+
+ var multiple = datajs.createDeferred();
+ var count = 0;
+
+ // See Compatibility Note A in DjsDeferred remarks.
+ multiple.then(function () {
+ djstest.assertAreEqual(count, 0, "first base registration fires as #0");
+ count++;
+ }).then(function () {
+ djstest.assertAreEqual(count, 1, "first chained registration fires as #1");
+ count++;
+ });
+
+ multiple.then(function () {
+ djstest.assertAreEqual(count, 2, "second base registration fires as #2");
+ count++;
+ }).then(function () {
+ djstest.assertAreEqual(count, 3, "second chained registration fires as #3");
+ djstest.done();
+ });
+
+ multiple.resolve();
+ });
+ other.reject("error", "message");
+ });
+
+ deferred.resolve(1, 2);
+ });
+
+ djstest.addTest(function deferredResolveTest() {
+ // Resolve with no arguments.
+ var deferred = datajs.createDeferred();
+ deferred.then(function (arg) {
+ djstest.assertAreEqual(arg, undefined, "resolve with no args shows up as undefined");
+
+ // Resolve with no callbacks.
+ var other = datajs.createDeferred();
+ other.resolve();
+ djstest.done();
+ });
+
+ deferred.resolve();
+ });
+
+ djstest.addTest(function deferredRejectTest() {
+ // Resolve with no arguments.
+ var deferred = datajs.createDeferred();
+ deferred.then(null, function (arg) {
+ djstest.assertAreEqual(arg, undefined, "reject with no args shows up as undefined");
+
+ // Resolve with no callbacks.
+ var other = datajs.createDeferred();
+ other.reject();
+ djstest.done();
+ });
+
+ deferred.reject();
+ });
+
+ djstest.addTest(function estimateSizeTest() {
+ var tests = [
+ { i: null, e: 8 },
+ { i: undefined, e: 8 },
+ { i: 0, e: 8 },
+ { i: "abc", e: 6 },
+ { i: [1, 2, 3], e: 30 },
+ { i: { a1: null, a2: undefined, a3: 5, a4: "ab", a5: { b1: 5, b2: 6} }, e: 72 },
+ { i: {}, e: 0 }
+ ];
+
+ var i, len;
+ for (i = 0, len = tests.length; i < len; i++) {
+ var test = tests[i];
+ djstest.assertAreEqual(datajs.estimateSize(test.i), test.e);
+ }
+ djstest.done();
+ });
+
+ djstest.addTest(function cacheOptionsTunnelTest() {
+ var mockClient = window.MockHttpClient;
+ var doneCalled = false;
+
+ mockClient.clear().setAsync(true).addRequestVerifier("*", function (theRequest) {
+ if (!doneCalled) {
+ doneCalled = true;
+ djstest.assertAreEqual(theRequest.user, "the-user", "theRequest.user");
+ djstest.assertAreEqual(theRequest.password, "the-password", "theRequest.password");
+ djstest.assertAreEqual(theRequest.enableJsonpCallback, false, "theRequest.enableJsonpCallback");
+ djstest.assertAreEqual(theRequest.callbackParameterName, "p", "callbackParameterName");
+ djstest.done();
+ }
+ });
+
+ var cache = datajs.createDataCache({
+ name: "cacheOptionsTunnel",
+ source: "http://foo-bar/",
+ user: "the-user",
+ password: "the-password",
+ enableJsonpCallback: false,
+ callbackParameterName: "p",
+ httpClient: mockClient
+ });
+
+ cache.readRange(0, 10).then(function (arr) {
+ djstest.fail("unexpected callback into readRange in test cacheOptionsTunnelTest");
+ if (!doneCalled) {
+ doneCalled = true;
+ djstest.done();
+ }
+ });
+ });
+
+ djstest.addTest(function dataCacheHandlesFullStoreTest() {
+
+ var TestStore = function (name) {
+ var that = new window.datajs.MemoryStore(name);
+ that.addOrUpdate = function (key, value, success, error) {
+ if (key === "__settings") {
+ window.setTimeout(function () {
+ success(key, value);
+ }, 0);
+ } else {
+ window.setTimeout(function () {
+ error({ name: "QUOTA_EXCEEDED_ERR" });
+ }, 0);
+ }
+ };
+ return that;
+ };
+
+ TestStore.create = function (name) {
+ return new TestStore(name);
+ };
+
+ TestStore.isSupported = function () {
+ return true;
+ };
+
+ var cacheSource = {
+ identifier: "testSource",
+ count: function (success) {
+ djstest.fail("cacheSource.count was called");
+ success(5);
+ },
+ read: function (index, count, success, error) {
+ djstest.assertAreEqual(index, 0, "index is the expected one");
+ djstest.assertAreEqual(count, 5, "test is the expected one");
+
+ setTimeout(function () {
+ success({ value: [1, 2, 3, 4, 5] });
+ }, 0);
+ }
+ };
+
+ var originalCreateStore = window.datajs.createStore;
+
+ window.datajs.createStore = function (name, mechanism) {
+ return TestStore(name);
+ };
+
+ try {
+ var cache = datajs.createDataCache({
+ name: "cache",
+ pageSize: 5,
+ prefetchSize: 0,
+ source: cacheSource,
+ mechanism: "teststore"
+ });
+ } finally {
+ window.datajs.createStore = originalCreateStore;
+ }
+
+ cache.readRange(0, 5).then(function (data) {
+ djstest.assertAreEqual(data.value.length, 5, "5 items were read.");
+ cache.readRange(0, 5).then(function (data) {
+ djstest.assertAreEqual(data.value.length, 5, "5 items were read.");
+ djstest.done();
+ }, thenFailTest);
+ }, thenFailTest);
+ });
+
+ // DATAJS INTERNAL END
+})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/48761e07/JSLib/tests/common/CacheOracle.js
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/CacheOracle.js b/JSLib/tests/common/CacheOracle.js
new file mode 100644
index 0000000..2130f82
--- /dev/null
+++ b/JSLib/tests/common/CacheOracle.js
@@ -0,0 +1,228 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// CacheOracle.js
+// This object verifies the operation of the cache.
+// Internally it maintains a simple model of the cache implemented using a lookup array of the expected cached pages.
+
+(function (window, undefined) {
+
+ var CacheOracle = function (baseUri, pageSize, total, cacheSize) {
+ /// <summary>Creates a new CacheOracle</summary>
+ /// <param name="baseUri" type="String">The base URI of the collection</param>
+ /// <param name="pageSize" type="Integer">The page size used in the cache</param>
+ /// <param name="total" type="Integer">The total number of items in the collection</param>
+ /// <param name="cacheSize" type="Integer">Cache size in bytes</param>
+ this.baseUri = baseUri;
+ this.pageSize = pageSize;
+ this.total = total;
+ this.cacheSize = (cacheSize !== undefined) ? cacheSize : 1024 * 1024;
+ this.actualSize = 0;
+ this.actualCount = 0;
+ this.cachedPages = [];
+ this.exactPageCount = (total % pageSize === 0);
+ this.maxPage = Math.floor(total / pageSize);
+ this.overflowed = this.cacheSize === 0;
+ };
+
+ CacheOracle.mechanisms = {
+ memory: "memory",
+ indexeddb: "indexeddb",
+ dom: "dom",
+ best: "best"
+ };
+
+ CacheOracle.isMechanismAvailable = function (mechanism) {
+ /// <summary>Determines if the specified local storage mechanism is available</summary>
+ /// <param name="mechanism">The name of the mechanism</param>
+ /// <returns>Whether the mechanism is available</returns>
+ switch (mechanism) {
+ case CacheOracle.mechanisms.indexeddb:
+ if (window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.indexedDB) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ break;
+ case CacheOracle.mechanisms.dom:
+ if (window.localStorage) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ break;
+ case CacheOracle.mechanisms.memory:
+ case CacheOracle.mechanisms.best:
+ case undefined:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ CacheOracle.prototype.clear = function () {
+ /// <summary>Clears the cache in the oracle</summary>
+ this.cachedPages = [];
+ this.actualSize = 0;
+ this.actualCount = 0;
+ this.overflowed = this.cacheSize === 0;
+ }
+
+ CacheOracle.prototype.verifyRequests = function (requests, responses, index, count, description, backwards, isPrefetch) {
+ /// <summary>Verifies the HTTP requests for a single data request, and updates the oracle with cached pages</summary>
+ /// <param name="requests" type="Array">The sequence of request objects (from OData.defaultHttpClient)</param>
+ /// <param name="responses" type="Array">The sequence of response objects (from OData.defaultHttpClient)</param>
+ /// <param name="index" type="Integer">The starting index of the read</param>
+ /// <param name="count" type="Integer">The count of items in the read</param>
+ /// <param name="description" type="String">The description of the requests being verified</param>
+ /// <param name="backwards" type="Boolean">Whether or not filterBack is being verified</param>
+ /// <param name="isPrefetch" type="Boolean">Whether the requests being verified come from the prefetcher</param>
+ var that = this;
+
+ index = (index < 0 ? 0 : index);
+ var pageIndex = function (index) {
+ /// <summary>Returns the page index that the given item index belongs to</summary>
+ /// <param name="index" type="Integer">The item index</param>
+ /// <returns>The page index</returns>
+ return Math.floor(index / that.pageSize);
+ };
+
+ var estimateSize = function (obj) {
+ /// <summary>Estimates the size of an object in bytes.</summary>
+ /// <param name="obj" type="Object">Object to determine the size of.</param>
+ /// <returns type="Number">Estimated size of the object in bytes.</returns>
+
+ var size = 0;
+ var type = typeof obj;
+
+ if (type === "object" && obj) {
+ for (var name in obj) {
+ size += name.length * 2 + estimateSize(obj[name]);
+ }
+ } else if (type === "string") {
+ size = obj.length * 2;
+ } else {
+ size = 8;
+ }
+ return size;
+ };
+
+ var expectedUris = [];
+ var responseIndex = 0;
+ if (count >= 0) {
+ var minPage = pageIndex(index);
+ var maxPage = Math.min(pageIndex(index + count - 1), pageIndex(this.total));
+
+ // In the case that the index is outside the range of the collection the minPage will be greater than the maxPage
+ maxPage = Math.max(minPage, maxPage);
+
+ if (!(isPrefetch && !this.exactPageCount && minPage > this.maxPage)) {
+ for (var page = minPage; page <= maxPage && this.actualCount <= this.total && !(isPrefetch && this.overflowed); page++) {
+ if (!this.cachedPages[page]) {
+
+ expectedUris.push(that.baseUri + "?$skip=" + page * this.pageSize + "&$top=" + (this.pageSize));
+
+ var actualPageSize = 0;
+ var actualPageCount = 0;
+ if (responses[responseIndex] && responses[responseIndex].data) {
+ actualPageSize += estimateSize(responses[responseIndex].data);
+ actualPageCount += responses[responseIndex].data.value.length;
+ // Handle server paging skipToken requests
+ while (responses[responseIndex].data["@odata.nextLink"]) {
+ var nextLink = responses[responseIndex].data["@odata.nextLink"];
+ if (nextLink) {
+ var index = that.baseUri.indexOf(".svc/", 0);
+ if (index != -1) {
+ nextLink = that.baseUri.substring(0, index + 5) + nextLink;
+ }
+ }
+
+ expectedUris.push(nextLink);
+ responseIndex++;
+ actualPageSize += estimateSize(responses[responseIndex].data);
+ actualPageCount += responses[responseIndex].data.value.length;
+ }
+
+ actualPageSize += 24; // 24 byte overhead for the pages (i)ndex, and (c)ount fields
+ }
+
+ responseIndex++;
+
+ this.overflowed = this.cacheSize >= 0 && this.actualSize + actualPageSize > this.cacheSize;
+ if (!this.overflowed) {
+ this.cachedPages[page] = true;
+ this.actualSize += actualPageSize;
+ this.actualCount += actualPageCount;
+ }
+ }
+ }
+ }
+ }
+
+ if (backwards) {
+ expectedUris.reverse();
+ }
+
+ var actualUris = $.map(requests, function (r) { return r.requestUri; });
+ djstest.assertAreEqualDeep(actualUris, expectedUris, description);
+ };
+
+ CacheOracle.getExpectedFilterResults = function (data, filterIndex, filterCount, predicate, backwards) {
+ /// <summary>Verifies the cache filter returns the correct data</summary>
+ /// <param name="collection" type="Array">Array of items in the collection</param>
+ /// <param name="filterIndex" type="Integer">The index value</param>
+ /// <param name="filterCount" type="Integer">The count value</param>
+ /// <param name="predicate" type="Function">Predicate to be applied in filter, takes an item</param>
+ /// <param name="backwards" type="Boolean">Whether or not filterBackwards is being verified</param>
+ if (!data || !data.value) {
+ return data;
+ }
+
+ var value = [];
+ if (filterCount !== 0) {
+ // Convert [item0, item1, ...] into [{ index: 0, item: item0 }, { index: 1, item: item1 }, ...]
+ var indexedCollection = $.map(data.value, function (item, index) {
+ return { index: index, item: item };
+ });
+
+ var grepPredicate = function (element, index) {
+ return predicate(element.item);
+ };
+
+ var index = filterIndex < 0 ? 0 : filterIndex;
+ var count = filterCount < 0 ? indexedCollection.length : filterCount;
+
+ value = backwards ?
+ // Slice up to 'index', filter, then slice 'count' number of items from the end
+ $.grep(indexedCollection.slice(0, index + 1), grepPredicate).slice(-count) :
+ // Slice from 'index' to the end, filter, then slice 'count' number of items from the beginning
+ $.grep(indexedCollection.slice(index), grepPredicate).slice(0, count);
+ }
+
+ var expectedResults = {};
+ for (var property in data) {
+ if (property == "value") {
+ expectedResults[property] = value;
+ } else {
+ expectedResults[property] = data[property];
+ }
+ }
+
+ return expectedResults;
+ };
+
+ window.CacheOracle = CacheOracle;
+
+})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/48761e07/JSLib/tests/common/Instrument.js
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/Instrument.js b/JSLib/tests/common/Instrument.js
new file mode 100644
index 0000000..acbb2b0
--- /dev/null
+++ b/JSLib/tests/common/Instrument.js
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Instrument.js
+// Instrumentation utilities
+
+(function (window, undefined) {
+
+ var warmedUp = false;
+ var getBrowserMemorySize = function (success) {
+ /// <summary>Gets the memory size (in bytes) of the browser process</summary>
+ /// <param name="success" type="Function">The success callback</param>
+ var makeRequest = function (success) {
+ $.get("./common/Instrument.svc/GetBrowserMemorySize", function (data) {
+ success(parseInt(data));
+ }, "text");
+ };
+
+ if (window.CollectGarbage) {
+ window.CollectGarbage();
+ }
+
+ if (!warmedUp) {
+ // Make a dummy request to warm it up
+ makeRequest(function () {
+ warmedUp = true;
+ makeRequest(success);
+ });
+ } else {
+ makeRequest(success);
+ }
+ }
+
+ window.Instrument = {
+ getBrowserMemorySize: getBrowserMemorySize
+ };
+
+})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/48761e07/JSLib/tests/common/Instrument.svc
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/Instrument.svc b/JSLib/tests/common/Instrument.svc
new file mode 100644
index 0000000..3d14b16
--- /dev/null
+++ b/JSLib/tests/common/Instrument.svc
@@ -0,0 +1,71 @@
+<%@ ServiceHost Language="C#" Debug="true" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"
+ Service="DataJS.Tests.Instrument" %>
+
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+namespace DataJS.Tests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Linq;
+ using System.Runtime.Serialization;
+ using System.ServiceModel;
+ using System.ServiceModel.Activation;
+ using System.ServiceModel.Syndication;
+ using System.ServiceModel.Web;
+ using System.Text;
+
+ /// <summary>
+ /// Instrumentation utilities
+ /// </summary>
+ [ServiceContract]
+ [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
+ [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
+ public class Instrument
+ {
+ static readonly Dictionary<string, string> userAgents = new Dictionary<string,string>
+ {
+ { "MSIE", "iexplore" },
+ { "Firefox", "firefox" },
+ { "Chrome", "chrome" },
+ { "Safari", "safari" }
+ };
+
+ /// <summary>
+ /// Gets the memory size used by the browser
+ /// </summary>
+ /// <returns>The memory size used by the browser (in bytes), or zero if browser is not supported</returns>
+ [OperationContract]
+ [WebGet]
+ public Stream GetBrowserMemorySize()
+ {
+ string userAgentString = WebOperationContext.Current.IncomingRequest.UserAgent;
+ string userAgentKey = Instrument.userAgents.Keys.FirstOrDefault(ua => userAgentString.Contains(ua));
+
+ if (userAgentKey != null)
+ {
+ string processName = userAgents[userAgentKey];
+ long totalMemory = Process.GetProcessesByName(processName).Select(p => p.WorkingSet64).Sum();
+
+ return new MemoryStream(Encoding.UTF8.GetBytes(totalMemory.ToString()));
+ }
+ else
+ {
+ return new MemoryStream(Encoding.UTF8.GetBytes("0"));
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/48761e07/JSLib/tests/common/ObservableHttpClient.js
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/ObservableHttpClient.js b/JSLib/tests/common/ObservableHttpClient.js
new file mode 100644
index 0000000..2b7fe98
--- /dev/null
+++ b/JSLib/tests/common/ObservableHttpClient.js
@@ -0,0 +1,78 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// ObservableHttpClient.js
+// This object extends OData's default httpClient by supporting request and response recording sessions, and firing a custom
+// JQuery event for each request/response.
+//
+// The events fired by this object are:
+// request: Before a request is made
+// success: Before the primary success handler is called
+//
+// To bind to an event, JQuery event attachers can be used on the object, e.g.
+// $(observableHttpClient).bind("request", function (request) { ... });
+//
+// To begin a new recording session, use:
+// var session = observableHttpClient.newSession();
+//
+// Requests and responses are then recorded in session.requests and session.responses. Session can be ended by session.end().
+// Multiple simultaneous sessions are supported.
+
+(function (window, undefined) {
+
+ var ObservableHttpClient = function (provider) {
+ this.provider = provider ? provider : OData.defaultHttpClient;
+ };
+
+ ObservableHttpClient.prototype.newSession = function () {
+ return new Session(this);
+ };
+
+ ObservableHttpClient.prototype.request = function (request, success, error) {
+ var that = this;
+
+ $(this).triggerHandler("request", request);
+ return this.provider.request(request, function (response) {
+ $(that).triggerHandler("success", response);
+ success(response);
+ }, error);
+ };
+
+
+ var Session = function (client) {
+ var that = this;
+
+ this.client = client;
+ this.clear();
+
+ this.requestHandler = function (event, request) { that.requests.push(request); };
+ $(client).bind("request", this.requestHandler);
+
+ this.successHandler = function (event, response) { that.responses.push(response); };
+ $(client).bind("success", this.successHandler);
+ };
+
+ Session.prototype.clear = function () {
+ this.requests = [];
+ this.responses = [];
+ }
+
+ Session.prototype.end = function () {
+ $(this.client).unbind("request", this.requestHandler);
+ $(this.client).unbind("success", this.successHandler);
+ };
+
+ window.ObservableHttpClient = ObservableHttpClient;
+ window.Session = Session;
+
+})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/48761e07/JSLib/tests/common/gpo-ie8-tour-disable.reg
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/gpo-ie8-tour-disable.reg b/JSLib/tests/common/gpo-ie8-tour-disable.reg
new file mode 100644
index 0000000..52dfd99
Binary files /dev/null and b/JSLib/tests/common/gpo-ie8-tour-disable.reg differ
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/48761e07/JSLib/tests/common/mockHttpClient.js
----------------------------------------------------------------------
diff --git a/JSLib/tests/common/mockHttpClient.js b/JSLib/tests/common/mockHttpClient.js
new file mode 100644
index 0000000..de2a69c
--- /dev/null
+++ b/JSLib/tests/common/mockHttpClient.js
@@ -0,0 +1,107 @@
+//mockHttpClient.js
+//this object allows for associating a uri with a requestVerfier and mock responses that will be sent back to the client of the httpStack.
+//It can be used to replace OData's httpClient for testing purposes.
+//
+//RequestVerifiers
+//
+// A request verifier is a function associated to a particular URI that will be executed by the mockHttpClient when it receives a request with the matching URI.
+// the callback receives as its only parameter the request object passed to the mockHttpClient.
+//
+// To register a request verifier, simply do
+//
+// MockHttpClient.addRequestVerifier("http://someUri", function(request) {
+// djstest.assertAreEqual(request.requestUri,"http://someUri");
+// }
+//
+//Responses
+// Mock responses can be associated with a particular URI. When the MockHttpClient receives a request with a URI mapped to a response, then it will,
+// depending on the response status code invoke either the success or the error callbacks.
+//
+// To register a response,
+//
+// MockHttpClient.addResponse("http://someUri", {status: 200, body:"some body"});
+//
+//Exceptions
+// MockHttpClient will throw an exception if it receives a request to a URI that is not mapped to either a request verifier or a response.
+//
+
+(function (window, undefined) {
+ if (!window.MockHttpClient) {
+ window.MockHttpClient = {};
+ }
+
+ var httpClient = window.MockHttpClient;
+
+ var responses = {};
+ var requestVerifiers = {};
+
+ httpClient.addRequestVerifier = function (uri, verifier) {
+ requestVerifiers[uri] = verifier;
+ return this;
+ };
+
+ httpClient.addResponse = function (uri, response) {
+ responses[uri] = response;
+ return this;
+ };
+
+ httpClient.async = false;
+
+ httpClient.clear = function () {
+ /// <summary>Clears all registered responses and verifiers.</summary>
+ /// <returns>this client.</returns>
+ responses = {};
+ requestVerifiers = {};
+ this.async = false;
+ return this;
+ };
+
+ httpClient.request = function (request, success, error) {
+ var uri = request.requestUri;
+ var verifier = requestVerifiers[uri];
+ var response = responses[uri];
+
+ if (verifier === undefined) {
+ verifier = requestVerifiers["*"];
+ }
+
+ if (response === undefined) {
+ response = responses["*"];
+ }
+
+ if (!verifier && !response) {
+ throw { message: "neither verifier or response defined for uri: " + uri };
+ }
+
+ if (verifier) {
+ verifier(request);
+ }
+
+ if (response) {
+ response.requestUri = uri;
+ if (response.statusCode >= 200 && response.statusCode <= 299) {
+ if (this.async) {
+ setTimeout(function () {
+ success(response);
+ });
+ } else {
+ success(response);
+ }
+ } else {
+ if (this.async) {
+ setTimeout(function () {
+ error({ message: "failed test response", request: request, response: response });
+ });
+ }
+ else {
+ error({ message: "failed test response", request: request, response: response });
+ }
+ }
+ }
+ };
+
+ httpClient.setAsync = function (value) {
+ this.async = value;
+ return this;
+ };
+})(this);