blob: 0f55594f7f6be675853bb9508177ea4ff7d0b60f [file] [log] [blame]
/// <reference path="common/djstest.js" />
/// <reference path="../src/odata.js" />
/// <reference path="../src/odata-batch.js" />
/// <reference path="common/ODataReadOracle.js" />
(function (window, undefined) {
OData.defaultHandler.accept = "application/atomsvc+xml;q=0.9, application/json;odata=verbose;q=0.8, application/json;odata=fullmetadata;q=0.7, application/json;q=0.5, */*;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) {
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, OData.batchHandler);
}
var verifyBatchResponses = function (batchRequests, elementTypes, serviceRoot, batchResponses, done) {
forEachAsync(batchRequests, function (index, batchRequest, doneOne) {
if (batchRequest.requestUri) {
var readFeedOrEntry = elementTypes[index] == "feed" ? ODataReadOracle.readFeed : ODataReadOracle.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);
ODataReadOracle.readEntry(changeResponse.data.__metadata.uri, 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 service = "./endpoints/FoodStoreDataServiceV3.svc";
var batchUri = service + "/$batch";
var foodsFeedUri = service + "/Foods";
var httpStatusCode = {
ok: 200,
created: 201,
accepted: 202,
noContent: 204
};
var mimeTypes = [undefined, "application/atom+xml", "application/json;odata=verbose"];
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: djstest.clone(params.mimeHeaders), data:
{ CategoryID: 42, Name: "New Category" }
}
]
},
{
__changeRequests: [
{ requestUri: "Categories(1)", method: "PUT", headers: djstest.clone(params.mimeHeaders), data:
{ CategoryID: 1, Name: "Updated Category" }
},
{ requestUri: "Categories(0)", method: "DELETE", headers: djstest.clone(params.acceptHeaders) }
]
}
];
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: djstest.clone(params.mimeHeaders), data:
{ CategoryID: 42, Name: "New Category" }
}
]
},
{ requestUri: "Foods?$top=2", method: "GET", headers: djstest.clone(params.acceptHeaders) },
{
__changeRequests: [
{ requestUri: "Categories(1)", method: "PUT", headers: djstest.clone(params.mimeHeaders), data:
{ CategoryID: 1, Name: "Updated Category" }
},
{ requestUri: "Categories(0)", method: "DELETE", headers: djstest.clone(params.acceptHeaders) }
]
}
];
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: djstest.clone(params.mimeHeaders), data:
{ CategoryID: 42, Name: "New Category" }
},
{ requestUri: "Categories(1)", method: "PUT", headers: djstest.clone(params.mimeHeaders), 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: djstest.clone(params.mimeHeaders), data:
{ CategoryID: 42, Name: "New Category" }
},
{ requestUri: "Categories(1)", method: "PUT", headers: djstest.clone(params.mimeHeaders), 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 updateOutsideChangeset() {
var batchRequests = [{ requestUri: "Categories", method: "POST", data: { CategoryID: 42, Name: "New Category"}}];
djstest.assertsExpected(1);
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 response error message");
djstest.done();
}, unexpectedErrorHandler, OData.batchHandler
);
}, "Update outside changeset");
djstest.addTest(function retrieveInsideChangeset() {
var batchRequests = [
{ requestUri: "Foods(0)", method: "GET" },
{ __changeRequests: [
{ requestUri: "Categories", method: "POST", data: { CategoryID: 42, Name: "New Category"} },
{ requestUri: "Categories(1)", method: "PUT", data: { CategoryID: 1, Name: "Updated Category"} }
]
},
{ requestUri: "Foods(1)", method: "GET" },
{ __changeRequests: [
{ requestUri: "Categories", method: "POST", data: { CategoryID: 42, Name: "New Category"} },
{ requestUri: "Categories(1)", method: "PUT", data: { CategoryID: 1, Name: "Updated Category"} },
{ requestUri: "Foods", method: "GET" }
]
}
];
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, OData.batchHandler);
}, "Retrieve inside changeset");
})(this);