| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 (window, undefined) { |
| |
| odatajs.oData.defaultHandler.accept = "application/json;q=0.9, */*;q=0.1"; |
| |
| var unexpectedErrorHandler = function (err) { |
| djstest.assert(false, "Unexpected call to error handler with error: " + djstest.toString(err)); |
| djstest.done(); |
| }; |
| |
| var determineExpected = function (batchRequests) { |
| var expected = 0; |
| $.each(batchRequests, function (_, batchRequest) { |
| // 2 assertions per request: response code and data |
| if (batchRequest.__changeRequests) { |
| expected += batchRequest.__changeRequests.length * 2; |
| } else { |
| expected += 2; |
| } |
| }); |
| |
| // 2 more assertions than the number of requests in batch: response code and batch response length |
| return expected + 2; |
| }; |
| |
| var verifyBatchRequest = function (serviceRoot, batchRequests, elementTypes, done) { |
| odatajs.oData.request({ requestUri: serviceRoot + "/$batch", method: "POST", data: { __batchRequests: batchRequests} }, |
| function (data, response) { |
| djstest.assertAreEqual(response.statusCode, httpStatusCode.accepted, "Verify response code"); |
| djstest.assertAreEqual(data.__batchResponses.length, batchRequests.length, "Verify batch response count"); |
| verifyBatchResponses(batchRequests, elementTypes, serviceRoot, data.__batchResponses, done); |
| }, |
| unexpectedErrorHandler, odatajs.oData.batch.batchHandler); |
| }; |
| |
| var verifyBatchResponses = function (batchRequests, elementTypes, serviceRoot, batchResponses, done) { |
| forEachAsync(batchRequests, function (index, batchRequest, doneOne) { |
| if (batchRequest.requestUri) { |
| var readFeedOrEntry = elementTypes[index] == "feed" ? ODataVerifyReader.readFeed : ODataVerifyReader.readEntry; |
| djstest.assertAreEqual(batchResponses[index].statusCode, httpStatusCode.ok, "Verify response code for: GET " + batchRequest.requestUri); |
| readFeedOrEntry(serviceRoot + "/" + batchRequest.requestUri, function (expectedData) { |
| djstest.assertAreEqualDeep(batchResponses[index].data, expectedData, "Verify data for: GET " + batchRequest.requestUri); |
| doneOne(); |
| }, batchRequests[index].headers.Accept); |
| } |
| else if (batchRequest.__changeRequests) { |
| verifyChangeResponses(batchRequest.__changeRequests, batchResponses[index].__changeResponses, function () { doneOne(); }); |
| } |
| }, done); |
| }; |
| |
| var verifyChangeResponses = function (changeRequests, changeResponses, done) { |
| forEachAsync(changeRequests, function (index, changeRequest, doneOne) { |
| var httpOperation = changeRequest.method + " " + changeRequest.requestUri; |
| var changeResponse = changeResponses[index]; |
| |
| if (changeRequest.method == "POST") { |
| djstest.assertAreEqual(changeResponse.statusCode, httpStatusCode.created, "Verify response code for: " + httpOperation); |
| ODataVerifyReader.readEntry(changeResponse.headers["Location"], function (expectedData) { |
| djstest.assertAreEqualDeep(changeResponse.data, expectedData, "Verify response data for: " + httpOperation); |
| doneOne(); |
| }, changeRequest.headers.Accept); |
| } |
| else if (changeRequest.method == "PUT") { |
| djstest.assertAreEqual(changeResponse.statusCode, httpStatusCode.noContent, "Verify response code for: " + httpOperation); |
| djstest.assertAreEqual(changeResponse.body, "", "Verify empty body for: " + httpOperation); |
| doneOne(); |
| } |
| else if (changeRequest.method == "DELETE") { |
| djstest.assertAreEqual(changeResponse.statusCode, httpStatusCode.noContent, "Verify response code for: " + httpOperation); |
| djstest.assertAreEqual(changeResponse.body, "", "Verify empty body for: " + httpOperation); |
| doneOne(); |
| } |
| }, done); |
| }; |
| |
| var forEachAsync = function (array, callback, done) { |
| var count = 0; |
| var doneOne = function () { |
| count++; |
| if (count == array.length) { |
| done(); |
| } |
| }; |
| |
| $.each(array, function (index, element) { callback(index, element, doneOne); }); |
| }; |
| |
| var cloneHeadersWithContentId = function (mimeHeaders, count) { |
| var headers = djstest.clone(mimeHeaders); |
| if (!headers) { headers = {} }; |
| headers["Content-ID"] = count; |
| return headers; |
| }; |
| |
| var service = "./endpoints/FoodStoreDataServiceV4.svc"; |
| var batchUri = service + "/$batch"; |
| |
| var httpStatusCode = { |
| ok: 200, |
| created: 201, |
| accepted: 202, |
| noContent: 204 |
| }; |
| |
| var mimeTypes = [undefined, "application/json;odata.metadata=minimal"]; |
| |
| module("Functional", { |
| setup: function () { |
| djstest.wait(function (done) { |
| $.post(service + "/ResetData", done); |
| }); |
| } |
| }); |
| |
| $.each(mimeTypes, function (_, mimeType) { |
| var acceptHeaders = mimeType ? { Accept: mimeType} : undefined; |
| var mimeHeaders = mimeType ? { "Content-Type": mimeType, Accept: mimeType} : undefined; |
| |
| djstest.addTest(function multipleRetrieves(acceptHeaders) { |
| var uriSegments = ["Foods(0)", "Foods?$filter=FoodID eq 1", "Foods?$top=2"]; |
| var elementTypes = ["entry", "feed", "feed"]; |
| |
| var batchRequests = $.map(uriSegments, function (uriSegment) { |
| return { requestUri: uriSegment, method: "GET", headers: acceptHeaders } |
| }); |
| |
| djstest.assertsExpected(determineExpected(batchRequests)); |
| verifyBatchRequest(service, batchRequests, elementTypes, function () { djstest.done(); }); |
| }, "Multiple retrieves: mimeType = " + mimeType, acceptHeaders); |
| |
| djstest.addTest(function multipleChangesets(params) { |
| var batchRequests = [ |
| { |
| __changeRequests: [ |
| { requestUri: "Categories", method: "POST", headers: cloneHeadersWithContentId(params.mimeHeaders, 1), data: |
| { CategoryID: 42, Name: "New Category" } |
| } |
| ] |
| }, |
| { |
| __changeRequests: [ |
| { requestUri: "Categories(1)", method: "PUT", headers: cloneHeadersWithContentId(params.mimeHeaders, 2), data: |
| { CategoryID: 1, Name: "Updated Category" } |
| }, |
| { requestUri: "Categories(0)", method: "DELETE", headers: cloneHeadersWithContentId(params.mimeHeaders, 3) } |
| ] |
| } |
| ]; |
| var elementTypes = [null, null]; |
| |
| djstest.assertsExpected(determineExpected(batchRequests)); |
| verifyBatchRequest(service, batchRequests, elementTypes, function () { djstest.done(); }); |
| }, "Multiple changesets: mimeType = " + mimeType, { acceptHeaders: acceptHeaders, mimeHeaders: mimeHeaders }); |
| |
| djstest.addTest(function multipleRetrievesAndChangesets(params) { |
| // Header needs to be cloned because it is mutable; this means that after processing one request in the batch |
| // the header object will be modified |
| var batchRequests = [ |
| { requestUri: "Foods(0)", method: "GET", headers: djstest.clone(params.acceptHeaders) }, |
| { requestUri: "Foods?$filter=FoodID eq 1", method: "GET", headers: djstest.clone(params.acceptHeaders) }, |
| { |
| __changeRequests: [ |
| { requestUri: "Categories", method: "POST", headers: cloneHeadersWithContentId(params.mimeHeaders, 1), data: |
| { CategoryID: 42, Name: "New Category" } |
| } |
| ] |
| }, |
| { requestUri: "Foods?$top=2", method: "GET", headers: djstest.clone(params.acceptHeaders) }, |
| { |
| __changeRequests: [ |
| { requestUri: "Categories(1)", method: "PUT", headers: cloneHeadersWithContentId(params.mimeHeaders, 2), data: |
| { CategoryID: 1, Name: "Updated Category" } |
| }, |
| { requestUri: "Categories(0)", method: "DELETE", headers: cloneHeadersWithContentId(params.mimeHeaders, 3) } |
| ] |
| } |
| ]; |
| var elementTypes = ["entry", "feed", null, "feed", null]; |
| |
| djstest.assertsExpected(determineExpected(batchRequests)); |
| verifyBatchRequest(service, batchRequests, elementTypes, function () { djstest.done(); }); |
| }, "Multiple retrieves and changesets: mimeType = " + mimeType, { acceptHeaders: acceptHeaders, mimeHeaders: mimeHeaders }); |
| |
| djstest.addTest(function singleRetrieve(acceptHeaders) { |
| var batchRequests = [{ requestUri: "Foods(2)", method: "GET", headers: acceptHeaders}]; |
| var elementTypes = ["entry"]; |
| |
| djstest.assertsExpected(determineExpected(batchRequests)); |
| verifyBatchRequest(service, batchRequests, elementTypes, function () { djstest.done(); }); |
| }, "Single retrieve: mimeType = " + mimeType, acceptHeaders); |
| |
| djstest.addTest(function singleChangeset(params) { |
| var batchRequests = [ |
| { |
| __changeRequests: [ |
| { requestUri: "Categories", method: "POST", headers: cloneHeadersWithContentId(params.mimeHeaders, 1), data: |
| { CategoryID: 42, Name: "New Category" } |
| }, |
| { requestUri: "Categories(1)", method: "PUT", headers: cloneHeadersWithContentId(params.mimeHeaders, 2), data: |
| { CategoryID: 1, Name: "Updated Category" } |
| } |
| ] |
| } |
| ]; |
| var elementTypes = [null]; |
| |
| djstest.assertsExpected(determineExpected(batchRequests)); |
| verifyBatchRequest(service, batchRequests, elementTypes, function () { djstest.done(); }); |
| }, "Single changeset: mimeType = " + mimeType, { acceptHeaders: acceptHeaders, mimeHeaders: mimeHeaders }); |
| |
| djstest.addTest(function singleRetrieveAndChangeset(params) { |
| var batchRequests = [ |
| { requestUri: "Foods(0)", method: "GET", headers: djstest.clone(params.acceptHeaders) }, |
| { |
| __changeRequests: [ |
| { requestUri: "Categories", method: "POST", headers: cloneHeadersWithContentId(params.mimeHeaders, 1), data: |
| { CategoryID: 42, Name: "New Category" } |
| }, |
| { requestUri: "Categories(1)", method: "PUT", headers: cloneHeadersWithContentId(params.mimeHeaders, 2), data: |
| { CategoryID: 1, Name: "Updated Category" } |
| } |
| ] |
| } |
| ]; |
| var elementTypes = ["entry", null]; |
| |
| djstest.assertsExpected(determineExpected(batchRequests)); |
| verifyBatchRequest(service, batchRequests, elementTypes, function () { djstest.done(); }); |
| }, "Single retrieve and changeset: mimeType = " + mimeType, { acceptHeaders: acceptHeaders, mimeHeaders: mimeHeaders }); |
| |
| djstest.addTest(function retrieveInsideChangeset(params) { |
| |
| var batchRequests = [ |
| { requestUri: "Foods(0)", method: "GET" }, |
| { __changeRequests: [ |
| { requestUri: "Categories", method: "POST", headers: cloneHeadersWithContentId(params.mimeHeaders, 1), data: { CategoryID: 42, Name: "New Category"} }, |
| { requestUri: "Categories(1)", method: "PUT", headers: cloneHeadersWithContentId(params.mimeHeaders, 2), data: { CategoryID: 1, Name: "Updated Category"} } |
| ] |
| }, |
| { requestUri: "Foods(1)", method: "GET" }, |
| { __changeRequests: [ |
| { requestUri: "Categories", method: "POST", headers: cloneHeadersWithContentId(params.mimeHeaders, 3), data: { CategoryID: 42, Name: "New Category"} }, |
| { requestUri: "Categories(1)", method: "PUT", headers: cloneHeadersWithContentId(params.mimeHeaders, 4), data: { CategoryID: 1, Name: "Updated Category"} }, |
| { requestUri: "Foods", method: "GET" } |
| ] |
| } |
| ]; |
| |
| odatajs.oData.request({ requestUri: batchUri, method: "POST", data: { __batchRequests: batchRequests} }, |
| function (data, response) { |
| var batchResponses = data.__batchResponses; |
| var error = batchResponses[3].__changeResponses[0]; |
| djstest.assert(error.response.body.indexOf("An error occurred while processing this request.") > -1, "Response contains expected message"); |
| // Verify that the responses prior to the error are the expected ones. |
| batchRequests.splice(3, 1); |
| batchResponses.splice(3, 1); |
| verifyBatchResponses(batchRequests, ["entry", null], service, batchResponses, function () { djstest.done(); }); |
| }, unexpectedErrorHandler, odatajs.oData.batch.batchHandler); |
| }, "Retrieve inside changeset: mimeType = " + mimeType, {mimeHeaders: mimeHeaders }); |
| }); |
| |
| /*On Odata V4 spec, the POST/PUT/Delete operations are allowed outside of changesets.*/ |
| djstest.addTest(function updateOutsideChangeset() { |
| var batchRequests = [{ requestUri: "Categories", method: "POST", data: { CategoryID: 42, Name: "New Category"}}]; |
| |
| djstest.assertsExpected(1); |
| odatajs.oData.request({ requestUri: batchUri, method: "POST", data: { __batchRequests: batchRequests} }, |
| function (data, response) { |
| djstest.assert(response.body.indexOf("An error occurred while processing this request.") == -1, "Verify that there is no error occurred."); |
| djstest.done(); |
| }, unexpectedErrorHandler, odatajs.oData.batch.batchHandler |
| ); |
| }, "Update outside changeset"); |
| })(this); |