You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2014/08/28 05:48:11 UTC

[04/51] [partial] rename folder /datajs into /odatajs. no file modification.

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/odata-metadata-awareness-functional-tests.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/odata-metadata-awareness-functional-tests.js b/odatajs/tests/odata-metadata-awareness-functional-tests.js
new file mode 100644
index 0000000..a5d2887
--- /dev/null
+++ b/odatajs/tests/odata-metadata-awareness-functional-tests.js
@@ -0,0 +1,243 @@
+/*
+ * 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) {
+    var unexpectedErrorHandler = function (err) {
+        djstest.assert(false, "Unexpected call to error handler with error: " + djstest.toString(err));
+        djstest.done();
+    };
+
+    var service = "./endpoints/EpmDataService.svc";
+    var metadataUri = service + "/$metadata";
+
+    var httpStatusCode = {
+        ok: 200,
+        created: 201,
+        noContent: 204
+    };
+
+    var acceptHeaders = { Accept: "application/json" };
+    var mimeHeaders = { "Content-Type": "application/json", Accept: "application/json" };
+    var keepInContentVariations = [true, false];
+    var feedUris = { "true": service + "/ReplicatedEntries", "false": service + "/MappedEntries" };
+    var typeNames = { "true": "DataJS.Tests.ReplicatedEntry", "false": "DataJS.Tests.MappedEntry" };
+    var selectProperties = ["Published", "Author", "CustomElement", "NestedElement1", "Published,Author,CustomElement,NestedElement1"];
+
+    var newEntry = {
+        UnmappedField: "Unmapped100",
+        Author: {
+            Email: "AuthorEmail100",
+            Name: "AuthorName100",
+            Uri: "http://www.example.com/AuthorUri100",
+            Contributor: {
+                Email: "ContributorEmail100",
+                Name: "ContributorName100",
+                Uri: "http://www.example.com/ContributorUri1000"
+            }
+        },
+        Published: "2100-01-01T00:00:00-08:00",
+        Rights: "Rights100",
+        Summary: "<xmlElement xmlns=\"http://www.example.com/dummy\" attr=\"value100\">Summary100</xmlElement>",
+        Title: "Title<b>100</b>",
+        Updated: "2100-01-01T00:00:00-08:00",
+        CustomElement: "CustomElement100",
+        CustomAttribute: "CustomAttribute100",
+        NestedElement1: "NestedElement1_100",
+        NestedElement2: "NestedElement2_100",
+        CommonAttribute1: "CommonAttribute1_100",
+        CommonAttribute2: "CommonAttribute2_100",
+        Location: {
+            Lat: 1.23,
+            Long: 4.56
+        }
+    };
+
+    var newSpecialValuesEntry = $.extend(true, {}, newEntry, {
+        Author: {
+            Email: null,
+            Name: "",
+            Uri: " ",
+            Contributor: {
+                Email: null,
+                Name: "",
+                Uri: " "
+            }
+        },
+        Rights: null,
+        Summary: "",
+        Title: " ",
+        CustomElement: null,
+        NestedElement1: "",
+        NestedElement2: " ",
+        CustomAttribute: null,
+        CommonAttribute1: "",
+        CommonAttribute2: " "
+    });
+
+    var nullComplexTypeEntry = $.extend(true, {}, newEntry, {
+        Author: { Contributor: null },
+        Location: null
+    });
+
+    var testEntries = [
+        { data: newEntry, description: "entry" },
+        { data: newSpecialValuesEntry, description: "entry containing null and empty string" },
+        { data: nullComplexTypeEntry, description: "entry containing null complex type value" }
+    ];
+
+    var serviceMetadata;
+    var getMetadata = function (callback) {
+        /** Common function for tests to get and cache metadata, to reduce network calls made by tests
+        */
+        if (!serviceMetadata) {
+            odatajs.oData.read(metadataUri, function (metadata) {
+                serviceMetadata = metadata;
+                callback(metadata);
+            }, unexpectedErrorHandler, OData.metadataHandler);
+        }
+        else {
+            callback(serviceMetadata);
+        }
+    }
+
+    module("Functional", {
+        setup: function () {
+            djstest.wait(function (done) {
+                $.post(service + "/ResetData", done);
+            });
+            OData.defaultMetadata = [];
+            OData.jsonHandler.recognizeDates = false;
+        }
+    });
+
+    $.each(selectProperties, function (_, selectProperty) {
+        djstest.addTest(function getSelectPropertiesOnEntry(propertyToSelect) {
+            var entryUri = feedUris["true"] + "(0)?$select=" + propertyToSelect;
+            djstest.assertsExpected(2);
+            getMetadata(function (metadata) {
+                OData.defaultMetadata.push(metadata);
+                odatajs.oData.read({ requestUri: entryUri, headers: acceptHeaders }, function (data, response) {
+                    djstest.assertAreEqual(response.statusCode, httpStatusCode.ok, "Verify response code");
+                    ODataReadOracle.readJson(entryUri, function (expectedData) {
+                        djstest.assertWithoutMetadata(data, expectedData, "Verify data");
+                        djstest.done();
+                    })
+                }, unexpectedErrorHandler);
+            }, unexpectedErrorHandler, OData.metadataHandler);
+        }, "GET with mapped properties selecting " + selectProperty + " with keepInContent = true", selectProperty);
+    });
+
+    $.each(keepInContentVariations, function (_, keepInContent) {
+        var feedUri = feedUris[keepInContent];
+
+        $.each(testEntries, function (entryIndex, testEntry) {
+            params = {
+                feedUri: feedUri,
+                testEntry: $.extend(true, {}, testEntry, {
+                    data: {
+                        "__metadata": { type: typeNames[keepInContent] }
+                    }
+                })
+            };
+
+            djstest.addTest(function getMappedEntry(params) {
+                var entryUri = params.feedUri + "(" + entryIndex + ")";
+                djstest.assertsExpected(2);
+                getMetadata(function (metadata) {
+                    OData.defaultMetadata.push(metadata);
+                    odatajs.oData.read({ requestUri: entryUri, headers: acceptHeaders }, function (data, response) {
+                        djstest.assertAreEqual(response.statusCode, httpStatusCode.ok, "Verify response code");
+                        ODataReadOracle.readJson(entryUri, function (expectedData) {
+                            djstest.assertWithoutMetadata(data, expectedData, "Verify data");
+                            djstest.done();
+                        })
+                    }, unexpectedErrorHandler);
+                }, unexpectedErrorHandler, OData.metadataHandler);
+            }, "GET " + params.testEntry.description + " with mapped properties: keepInContent = " + keepInContent, params);
+
+            djstest.addTest(function postMappedEntry(params) {
+                var postEntry = $.extend(true, {}, params.testEntry.data, { ID: 100 });
+                djstest.assertsExpected(2);
+                getMetadata(function (metadata) {
+                    odatajs.oData.request({ requestUri: params.feedUri, method: "POST", headers: djstest.clone(mimeHeaders), data: postEntry }, function (data, response) {
+                        djstest.assertAreEqual(response.statusCode, httpStatusCode.created, "Verify response code");
+                        ODataReadOracle.readJson(feedUri + "(" + postEntry.ID + ")", function (actualData) {
+                            djstest.assertWithoutMetadata(actualData, postEntry, "Verify new entry data against server");
+                            djstest.done();
+                        })
+                    }, unexpectedErrorHandler, undefined, undefined, metadata);
+                }, unexpectedErrorHandler, OData.metadataHandler);
+            }, "POST " + params.testEntry.description + " with mapped properties: keepInContent = " + keepInContent, params);
+
+            djstest.addTest(function putMappedEntry(params) {
+                var entryUri = params.feedUri + "(0)";
+                djstest.assertsExpected(2);
+                getMetadata(function (metadata) {
+                    OData.defaultMetadata.push(metadata);
+                    odatajs.oData.request({ requestUri: entryUri, method: "PUT", headers: djstest.clone(mimeHeaders), data: params.testEntry.data }, function (data, response) {
+                        djstest.assertAreEqual(response.statusCode, httpStatusCode.noContent, "Verify response code");
+                        ODataReadOracle.readJson(entryUri, function (actualData) {
+                            djstest.assertWithoutMetadata(actualData, $.extend({ ID: 0 }, params.testEntry.data), "Verify updated entry data against server");
+                            djstest.done();
+                        })
+                    }, unexpectedErrorHandler);
+                }, unexpectedErrorHandler, OData.metadataHandler);
+            }, "PUT " + params.testEntry.description + " with mapped properties: keepInContent = " + keepInContent, params);
+        });
+    });
+
+    var descriptions = ["base type", "derived type"];
+    $.each(descriptions, function (index, _) {
+        djstest.addTest(function getHierarchicalEntry(index) {
+            var entryUri = service + "/HierarchicalEntries(" + index + ")";
+            djstest.assertsExpected(2);
+            getMetadata(function (metadata) {
+                odatajs.oData.read({ requestUri: entryUri, headers: acceptHeaders }, function (data, response) {
+                    djstest.assertAreEqual(response.statusCode, httpStatusCode.ok, "Verify response code");
+                    ODataReadOracle.readJson(entryUri, function (expectedData) {
+                        djstest.assertWithoutMetadata(data, expectedData, "Verify data");
+                        djstest.done();
+                    })
+                }, unexpectedErrorHandler, undefined, undefined, metadata);
+            }, unexpectedErrorHandler, OData.metadataHandler);
+        }, "GET " + descriptions[index] + " with mapped properties: keepInContent = false", index);
+    });
+
+    $.each([false, true], function (_, recognizeDates) {
+        djstest.addTest(function readDateTimeWithMetadataTest(params) {
+            var foodStoreDataService = "./endpoints/FoodStoreDataServiceV4.svc";
+            var specialDaysEndpoint = foodStoreDataService + "/SpecialDays";
+
+            djstest.assertsExpected(1);
+            OData.jsonHandler.recognizeDates = params.recognizeDates;
+            odatajs.oData.read(foodStoreDataService + "/$metadata", function (metadata) {
+                odatajs.oData.read({ requestUri: specialDaysEndpoint, headers: { Accept: params.accept} }, function (data, response) {
+                    // Because our oracle isn't metadata aware, it is not 100% correct, so we will pass in recognizeDates = true
+                    // in all cases and manually fix up the property that was incorrectly converted
+                    window.ODataReadOracle.readFeed(specialDaysEndpoint, function (expectedData) {
+                        // Fix up the string property that has a "date-like" string deliberately injected
+                        expectedData.results[2].Name = "/Date(" + expectedData.results[2].Name.valueOf() + ")/";
+                        djstest.assertAreEqualDeep(data, expectedData, "Verify response data");
+                        djstest.done();
+                    }, params.accept, true);
+                }, unexpectedErrorHandler, undefined, undefined, metadata);
+            }, unexpectedErrorHandler, OData.metadataHandler);
+        }, "GET metadata-aware JSON dates with recognizeDates=" + recognizeDates, { recognizeDates: recognizeDates, accept: "application/json;odata.metadata=minimal" });
+    });
+})(this);

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/odata-metadata-tests.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/odata-metadata-tests.js b/odatajs/tests/odata-metadata-tests.js
new file mode 100644
index 0000000..525dd62
--- /dev/null
+++ b/odatajs/tests/odata-metadata-tests.js
@@ -0,0 +1,499 @@
+/*
+ * 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.
+ */
+
+// odata-metadata-tests.js
+
+(function (window, undefined) {
+    djstest.addTest(function testMetadataHandler() {
+        // Test cases as result / model tuples.
+        var cases = [
+            { i: {}, e: undefined },
+            { i: { headers: { "Content-Type": "application/xml" }, body: '<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" />' },
+                e: { version: "4.0" }
+            }
+        ];
+
+        var i, len;
+        for (i = 0, len = cases.length; i < len; i++) {
+            var response = cases[i].i;
+            var testClient = { request: function (r, success, error) { success(response); } };
+            window.odatajs.oData.read("foo", function (data) {
+                djstest.assertAreEqualDeep(data, cases[i].e, "handler result matches target");
+            }, function (err) {
+                djstest.fail(err.message);
+            }, window.odatajs.oData.metadataHandler, testClient);
+        }
+
+        djstest.done();
+    });
+
+    // DATAJS INTERNAL START
+    djstest.addTest(function testScriptCase() {
+        // Test cases as input/result pairs.
+        var cases = [
+            { i: null, e: null },
+            { i: "", e: "" },
+            { i: "a", e: "a" },
+            { i: "A", e: "a" },
+            { i: "TestCase", e: "testCase" },
+            { i: "123abc", e: "123abc" },
+            { i: "ITEM", e: "ITEM" }
+        ];
+
+        var i, len;
+        for (i = 0, len = cases.length; i < len; i++) {
+            djstest.assertAreEqual(window.odatajs.oData.metadata.scriptCase(cases[i].i), cases[i].e, "processed input matches expected value");
+        }
+
+        djstest.done();
+    });
+
+    djstest.addTest(function testGetChildSchema() {
+        // Test cases as input parent / input element / result tuples.
+        var schema = window.odatajs.oData.metadata.schema;
+        var cases = [
+            { ip: schema.elements.EntityType, ie: "Property", e: { isArray: true, propertyName: "property"} },
+            { ip: schema.elements.EntityType, ie: "Key", e: { isArray: true, propertyName: "key"} },
+            { ip: schema.elements.EntitySet, ie: "SomethingElse", e: null },
+            { ip: schema.elements.Property, ie: "Name", e: null} // this is an attribute, not an element, thus it's no found
+        ];
+
+        var i, len;
+        for (i = 0, len = cases.length; i < len; i++) {
+            var result = window.odatajs.oData.metadata.getChildSchema(cases[i].ip, cases[i].ie);
+            djstest.assertAreEqualDeep(result, cases[i].e, "getChildSchema matches target");
+        }
+
+        djstest.done();
+    });
+
+    var testFullCsdl = '' +
+        '<?xml version="1.0" encoding="utf-8"?>\r\n' +
+        '<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">\r\n' +
+        '  <edmx:DataServices xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" m:MaxDataServiceVersion="4.0" m:DataServiceVersion="4.0">\r\n' +
+        '    <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="TestCatalog.Model">\r\n' +
+        '      <EntityType Name="Genre">\r\n' +
+        '        <Key><PropertyRef Name="Name" /></Key>\r\n' +
+        '        <Property Name="Name" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="false" />\r\n' +
+        '        <NavigationProperty Name="Titles" Type="Collection(TestCatalog.Model.Title)" Partner="Series" />\r\n' +
+        '      </EntityType>\r\n' +
+        '      <EntityType Name="Language">\r\n' +
+        '        <Key><PropertyRef Name="Name" /></Key>\r\n' +
+        '        <Property Name="Name" Type="Edm.String" Nullable="false" MaxLength="80" Unicode="false" />\r\n' +
+        '        <NavigationProperty Name="Titles" Type="Collection(TestCatalog.Model.Title)" Partner="Languages" />\r\n' +
+        '      </EntityType>\r\n' +
+        '      <EntityType Name="Person">\r\n' +
+        '        <Key><PropertyRef Name="Id" /></Key>\r\n' +
+        '        <Property Name="Id" Type="Edm.Int32" Nullable="false" />\r\n' +
+        '        <Property Name="Name" Type="Edm.String" Nullable="false" MaxLength="80" Unicode="true" />\r\n' +
+        '        <NavigationProperty Name="Awards" Type="Collection(TestCatalog.Model.TitleAward)" Partner="Person"/>\r\n' +
+        '        <NavigationProperty Name="TitlesActedIn" Type="Collection(TestCatalog.Model.Title)" Partner="Cast"/>\r\n' +
+        '        <NavigationProperty Name="TitlesDirected" Type="Collection(TestCatalog.Model.Title)" Partner="Directors"/>\r\n' +
+        '      </EntityType>\r\n' +
+        '      <EntityType Name="TitleAudioFormat">\r\n' +
+        '        <Key><PropertyRef Name="TitleId" /><PropertyRef Name="DeliveryFormat" /><PropertyRef Name="Language" /><PropertyRef Name="Format" /></Key>\r\n' +
+        '        <Property Name="TitleId" Type="Edm.String" Nullable="false" MaxLength="30" FixedLength="false" />\r\n' +
+        '        <Property Name="DeliveryFormat" Type="Edm.String" Nullable="false" MaxLength="10" Unicode="false" />\r\n' +
+        '        <Property Name="Language" Type="Edm.String" Nullable="false" MaxLength="30" Unicode="false" FixedLength="false" />\r\n' +
+        '        <Property Name="Format" Type="Edm.String" Nullable="false" MaxLength="30" Unicode="false" FixedLength="false" />\r\n' +
+        '        <NavigationProperty Name="Title" Type="TestCatalog.Model.Title" Partner="AudioFormats" >\r\n' +
+        '            <ReferentialConstraint Property="TitleId" ReferencedProperty="Id" />' +
+        '        </NavigationProperty>' +
+        '      </EntityType>\r\n' +
+        '      <EntityType Name="TitleAward">\r\n' +
+        '        <Key><PropertyRef Name="Id" /></Key>\r\n' +
+        '        <Property Name="Id" Type="Edm.Guid" Nullable="false" />\r\n' +
+        '        <Property Name="Type" Type="Edm.String" Nullable="false" MaxLength="30" Unicode="false" />\r\n' +
+        '        <Property Name="Category" Type="Edm.String" Nullable="false" MaxLength="60" Unicode="false" />\r\n' +
+        '        <Property Name="Year" Type="Edm.Int32" Nullable="true" />\r\n' +
+        '        <Property Name="Won" Type="Edm.Boolean" Nullable="false" />\r\n' +
+        '        <NavigationProperty Name="Title" Type="TestCatalog.Model.Title" Partner="Awards"/>\r\n' +
+        '        <NavigationProperty Name="Person" Type="TestCatalog.Model.Person" Partner="Awards"/>\r\n' +
+        '      </EntityType>\r\n' +
+        '      <EntityType Name="Title" HasStream="true">\r\n' +
+        '        <Key><PropertyRef Name="Id" /></Key>\r\n' +
+        '        <Property Name="Id" Type="Edm.String" Nullable="false" MaxLength="30" />\r\n' +
+        '        <Property Name="Synopsis" Type="Edm.String" Nullable="true" MaxLength="Max" Unicode="false" />\r\n' +
+        '        <Property Name="ShortSynopsis" Type="Edm.String" Nullable="true" MaxLength="Max" Unicode="false" />\r\n' +
+        '        <Property Name="AverageRating" Type="Edm.Double" Nullable="true" />\r\n' +
+        '        <Property Name="ReleaseYear" Type="Edm.Int32" Nullable="true" />\r\n' +
+        '        <Property Name="Url" Type="Edm.String" Nullable="true" MaxLength="200" Unicode="false" />\r\n' +
+        '        <Property Name="Runtime" Type="Edm.Int32" Nullable="true" />\r\n' +
+        '        <Property Name="Rating" Type="Edm.String" Nullable="true" MaxLength="10" Unicode="false" />\r\n' +
+        '        <Property Name="DateModified" Type="Edm.DateTime" Nullable="false" />\r\n' +
+        '        <Property Name="Type" Type="Edm.String" Nullable="false" MaxLength="8" Unicode="false" />\r\n' +
+        '        <Property Name="BoxArt" Type="TestCatalog.Model.BoxArt" Nullable="false" />\r\n' +
+        '        <Property Name="ShortName" Type="Edm.String" Nullable="false" MaxLength="200" Unicode="false" />\r\n' +
+        '        <Property Name="Name" Type="Edm.String" Nullable="false" MaxLength="200" Unicode="false" />\r\n' +
+        '        <Property Name="Instant" Type="TestCatalog.Model.InstantAvailability" Nullable="false" />\r\n' +
+        '        <Property Name="Dvd" Type="TestCatalog.Model.DeliveryFormatAvailability" Nullable="false" />\r\n' +
+        '        <Property Name="BluRay" Type="TestCatalog.Model.DeliveryFormatAvailability" Nullable="false" />\r\n' +
+        '        <Property Name="TinyUrl" Type="Edm.String" Nullable="false" />\r\n' +
+        '        <Property Name="WebsiteUrl" Type="Edm.String" Nullable="true" />\r\n' +
+        '        <Property Name="TestApiId" Type="Edm.String" Nullable="false" />\r\n' +
+        '        <NavigationProperty Name="AudioFormats" Type="Collection(TestCatalog.Model.TitleAudioFormat)" Partner="Title" Nullable="false" />\r\n' +
+        '        <NavigationProperty Name="Awards" Type="Collection(TestCatalog.Model.TitleAward)" Partner="Title" Nullable="false" />\r\n' +
+        '        <NavigationProperty Name="Disc" Type="Collection(TestCatalog.Model.Title)" />\r\n' +
+        '        <NavigationProperty Name="Movie" Type="Collection(TestCatalog.Model.Title)" />\r\n' +
+        '        <NavigationProperty Name="Season" Type="Collection(TestCatalog.Model.Title)" />\r\n' +
+        '        <NavigationProperty Name="Series" Type="Collection(TestCatalog.Model.Title)" />\r\n' +
+        '        <NavigationProperty Name="ScreenFormats" Type="Collection(TestCatalog.Model.TitleScreenFormat)" Partner="Title" Nullable="false" />\r\n' +
+        '        <NavigationProperty Name="Cast" Type="Collection(TestCatalog.Model.Person)" Partner="TitlesActedIn" Nullable="false" />\r\n' +
+        '        <NavigationProperty Name="Languages" Type="Collection(TestCatalog.Model.Language)" Partner="Titles" Nullable="false" />\r\n' +
+        '        <NavigationProperty Name="Directors" Type="Collection(TestCatalog.Model.Person)" Partner="TitlesDirected" Nullable="false" />\r\n' +
+        '        <NavigationProperty Name="Genres" Type="Collection(TestCatalog.Model.Genre)" Partner="Titles" Nullable="false" />\r\n' +
+        '      </EntityType>\r\n' +
+        '      <ComplexType Name="BoxArt">\r\n' +
+        '        <Property Name="SmallUrl" Type="Edm.String" Nullable="true" MaxLength="80" Unicode="false" />\r\n' +
+        '        <Property Name="MediumUrl" Type="Edm.String" Nullable="true" MaxLength="80" Unicode="false" />\r\n' +
+        '        <Property Name="LargeUrl" Type="Edm.String" Nullable="true" MaxLength="80" Unicode="false" />\r\n' +
+        '        <Property Name="HighDefinitionUrl" Type="Edm.String" Nullable="true" MaxLength="80" Unicode="false" />\r\n' +
+        '      </ComplexType>\r\n' +
+        '      <ComplexType Name="InstantAvailability">\r\n' +
+        '        <Property Name="Available" Type="Edm.Boolean" Nullable="false" />\r\n' +
+        '        <Property Name="AvailableFrom" Type="Edm.DateTime" Nullable="true" />\r\n' +
+        '        <Property Name="AvailableTo" Type="Edm.DateTime" Nullable="true" />\r\n' +
+        '        <Property Name="HighDefinitionAvailable" Type="Edm.Boolean" Nullable="false" />\r\n' +
+        '        <Property Name="Runtime" Type="Edm.Int32" Nullable="true" />\r\n' +
+        '        <Property Name="Rating" Type="Edm.String" Nullable="true" MaxLength="10" Unicode="false" />\r\n' +
+        '      </ComplexType>\r\n' +
+        '      <ComplexType Name="DeliveryFormatAvailability">\r\n' +
+        '        <Property Name="Available" Type="Edm.Boolean" Nullable="false" />\r\n' +
+        '        <Property Name="AvailableFrom" Type="Edm.DateTime" Nullable="true" />\r\n' +
+        '        <Property Name="AvailableTo" Type="Edm.DateTime" Nullable="true" />\r\n' +
+        '        <Property Name="Runtime" Type="Edm.Int32" Nullable="true" />\r\n' +
+        '        <Property Name="Rating" Type="Edm.String" Nullable="true" MaxLength="10" Unicode="false" />\r\n' +
+        '      </ComplexType>\r\n' +
+        '      <EntityType Name="TitleScreenFormat">\r\n' +
+        '        <Key><PropertyRef Name="TitleId" /><PropertyRef Name="DeliveryFormat" /><PropertyRef Name="Format" /></Key>\r\n' +
+        '        <Property Name="TitleId" Type="Edm.String" Nullable="false" MaxLength="30" />\r\n' +
+        '        <Property Name="DeliveryFormat" Type="Edm.String" Nullable="false" MaxLength="10" Unicode="false" />\r\n' +
+        '        <Property Name="Format" Type="Edm.String" Nullable="false" MaxLength="30" Unicode="false" />\r\n' +
+        '        <NavigationProperty Name="Title" Type="TestCatalog.Model.Title" Partner="ScreenFormats" >\r\n' +
+        '            <ReferentialConstraint Property="TitleId" ReferencedProperty="Id" />' +
+        '        </NavigationProperty>' +
+        '      </EntityType>\r\n' +
+        '      <Function Name="ProductsByRating">' +
+        '        <ReturnType Type="Collection(TestCatalog.Model.Title)" />\r\n' +
+        '      </Function>\r\n' +
+        '    </Schema>\r\n' +
+        '    <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Test.Catalog">\r\n' +
+        '      <EntityContainer Name="TestCatalog" >\r\n' +
+        '        <FunctionImport Name="Movies" EntitySet="Titles" Function="estCatalog.Model.GetTitles" />\r\n' +
+        '        <FunctionImport Name="Series" EntitySet="Titles" Function="estCatalog.Model.GetTitles" />\r\n' +
+        '        <FunctionImport Name="Seasons" EntitySet="Titles" Function="estCatalog.Model.GetTitles" />\r\n' +
+        '        <FunctionImport Name="Discs" EntitySet="Titles" Function="estCatalog.Model.GetTitles" />\r\n' +
+        '        <FunctionImport Name="Episodes" EntitySet="Titles" Function="estCatalog.Model.GetTitles" />\r\n' +
+        '        <EntitySet Name="Genres" EntityType="TestCatalog.Model.Genre" >\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Titles" />\r\n' +
+        '        </EntitySet>\r\n' +
+        '        <EntitySet Name="Languages" EntityType="TestCatalog.Model.Language" >\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Languages" />\r\n' +
+        '        </EntitySet>\r\n' +
+        '        <EntitySet Name="People" EntityType="TestCatalog.Model.Person" >\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Cast" />\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Directors" />\r\n' +
+        '        </EntitySet>' +
+        '        <EntitySet Name="TitleAudioFormats" EntityType="TestCatalog.Model.TitleAudioFormat" >\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="AudioFormats" />\r\n' +
+        '        </EntitySet>\r\n' +
+        '        <EntitySet Name="TitleAwards" EntityType="TestCatalog.Model.TitleAward" >\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Awards" />\r\n' +
+        '        </EntitySet>\r\n' +
+        '        <EntitySet Name="Titles" EntityType="TestCatalog.Model.Title" >\r\n' +
+        '            <NavigationPropertyBinding Target="TitleAudioFormats" Path="Title" />\r\n' +
+        '            <NavigationPropertyBinding Target="TitleAwards" Path="Title" />\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Disc" />\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Movie" />\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Season" />\r\n' +
+        '            <NavigationPropertyBinding Target="Titles" Path="Series" />\r\n' +
+        '            <NavigationPropertyBinding Target="TitleScreenFormats" Path="ScreenFormats" />\r\n' +
+        '            <NavigationPropertyBinding Target="People" Path="TitlesActedIn" />\r\n' +
+        '            <NavigationPropertyBinding Target="Languages" Path="Titles" />\r\n' +
+        '            <NavigationPropertyBinding Target="People" Path="TitlesDirected" />\r\n' +
+        '            <NavigationPropertyBinding Target="Genres" Path="Genres" />\r\n' +
+        '        </EntitySet>\r\n' +
+        '        <EntitySet Name="TitleScreenFormats" EntityType="TestCatalog.Model.TitleScreenFormat" >\r\n' +
+        '            <NavigationPropertyBinding Target="TitleScreenFormats" Path="Title" />\r\n' +
+        '        </EntitySet>\r\n' +
+        '      </EntityContainer>\r\n' +
+        '    </Schema>\r\n' +
+        '  </edmx:DataServices>\r\n' +
+        '</edmx:Edmx>\r\n' +
+        '';
+
+    var testFullMetadataResult = {
+        "version": "4.0",
+        "dataServices": {
+            "dataServiceVersion": "4.0",
+            "maxDataServiceVersion": "4.0",
+            "schema": [{
+                "namespace": "TestCatalog.Model",
+                "entityType": [{
+                    "name": "Genre",
+                    "key": [{ "propertyRef": [{ "name": "Name"}] }],
+                    "property": [{ "name": "Name", "type": "Edm.String", "nullable": "false", "maxLength": "50", "unicode": "false"}],
+                    "navigationProperty": [{ "name": "Titles", "partner": "Series", "type": "Collection(TestCatalog.Model.Title)"}]
+                }, {
+                    "name": "Language",
+                    "key": [{ "propertyRef": [{ "name": "Name"}] }],
+                    "property": [{ "name": "Name", "type": "Edm.String", "nullable": "false", "maxLength": "80", "unicode": "false"}],
+                    "navigationProperty": [{ "name": "Titles", "partner": "Languages", "type": "Collection(TestCatalog.Model.Title)"}]
+                }, {
+                    "name": "Person",
+                    "key": [{ "propertyRef": [{ "name": "Id"}] }],
+                    "property": [
+                        { "name": "Id", "type": "Edm.Int32", "nullable": "false" },
+                        { "name": "Name", "type": "Edm.String", "nullable": "false", "maxLength": "80", "unicode": "true" }
+                    ],
+                    "navigationProperty": [
+                        { "name": "Awards", "partner": "Person", "type": "Collection(TestCatalog.Model.TitleAward)" },
+                        { "name": "TitlesActedIn", "partner": "Cast", "type": "Collection(TestCatalog.Model.Title)" },
+                        { "name": "TitlesDirected", "partner": "Directors", "type": "Collection(TestCatalog.Model.Title)" }
+                    ]
+                }, {
+                    "name": "TitleAudioFormat",
+                    "key": [{ "propertyRef": [{ "name": "TitleId" }, { "name": "DeliveryFormat" }, { "name": "Language" }, { "name": "Format"}] }],
+                    "property": [
+                        { "name": "TitleId", "type": "Edm.String", "nullable": "false", "maxLength": "30" },
+                        { "name": "DeliveryFormat", "type": "Edm.String", "nullable": "false", "maxLength": "10", "unicode": "false" },
+                        { "name": "Language", "type": "Edm.String", "nullable": "false", "maxLength": "30", "unicode": "false" },
+                        { "name": "Format", "type": "Edm.String", "nullable": "false", "maxLength": "30", "unicode": "false" }
+                    ],
+                    "navigationProperty": [{ "name": "Title", "partner": "AudioFormats", "referentialConstraint": [{"property": "TitleId", "referencedProperty": "Id"}], "type": "TestCatalog.Model.Title" }]
+                }, {
+                    "name": "TitleAward",
+                    "key": [{ "propertyRef": [{ "name": "Id"}] }],
+                    "property": [
+                        { "name": "Id", "type": "Edm.Guid", "nullable": "false" },
+                        { "name": "Type", "type": "Edm.String", "nullable": "false", "maxLength": "30", "unicode": "false" },
+                        { "name": "Category", "type": "Edm.String", "nullable": "false", "maxLength": "60", "unicode": "false" },
+                        { "name": "Year", "type": "Edm.Int32", "nullable": "true" }, { "name": "Won", "type": "Edm.Boolean", "nullable": "false" }
+                    ],
+                    "navigationProperty": [
+                        { "name": "Title", "partner": "Awards", "type": "TestCatalog.Model.Title" },
+                        { "name": "Person", "partner": "Awards", "type": "TestCatalog.Model.Person" }
+                    ]
+                }, {
+                    "name": "Title",
+                    "hasStream": "true",
+                    "key": [{ "propertyRef": [{ "name": "Id"}] }],
+                    "property": [
+                        { "name": "Id", "type": "Edm.String", "nullable": "false", "maxLength": "30" },
+                        { "name": "Synopsis", "type": "Edm.String", "nullable": "true", "maxLength": "Max", "unicode": "false" },
+                        { "name": "ShortSynopsis", "type": "Edm.String", "nullable": "true", "maxLength": "Max", "unicode": "false" },
+                        { "name": "AverageRating", "type": "Edm.Double", "nullable": "true" }, { "name": "ReleaseYear", "type": "Edm.Int32", "nullable": "true" },
+                        { "name": "Url", "type": "Edm.String", "nullable": "true", "maxLength": "200", "unicode": "false" },
+                        { "name": "Runtime", "type": "Edm.Int32", "nullable": "true" },
+                        { "name": "Rating", "type": "Edm.String", "nullable": "true", "maxLength": "10", "unicode": "false" },
+                        { "name": "DateModified", "type": "Edm.DateTime", "nullable": "false"},
+                        { "name": "Type", "type": "Edm.String", "nullable": "false", "maxLength": "8", "unicode": "false" },
+                        { "name": "BoxArt", "type": "TestCatalog.Model.BoxArt", "nullable": "false" },
+                        { "name": "ShortName", "type": "Edm.String", "nullable": "false", "maxLength": "200", "unicode": "false" },
+                        { "name": "Name", "type": "Edm.String", "nullable": "false", "maxLength": "200", "unicode": "false" },
+                        { "name": "Instant", "type": "TestCatalog.Model.InstantAvailability", "nullable": "false" },
+                        { "name": "Dvd", "type": "TestCatalog.Model.DeliveryFormatAvailability", "nullable": "false" },
+                        { "name": "BluRay", "type": "TestCatalog.Model.DeliveryFormatAvailability", "nullable": "false" },
+                        { "name": "TinyUrl", "type": "Edm.String", "nullable": "false" },
+                        { "name": "WebsiteUrl", "type": "Edm.String", "nullable": "true" },
+                        { "name": "TestApiId", "type": "Edm.String", "nullable": "false" }
+                    ],
+                    "navigationProperty": [
+                        { "name": "AudioFormats", "nullable": "false", "partner": "Title", "type": "Collection(TestCatalog.Model.TitleAudioFormat)" },
+                        { "name": "Awards", "nullable": "false", "partner": "Title", "type": "Collection(TestCatalog.Model.TitleAward)" },
+                        { "name": "Disc", "type": "Collection(TestCatalog.Model.Title)" },
+                        { "name": "Movie", "type": "Collection(TestCatalog.Model.Title)" },
+                        { "name": "Season", "type": "Collection(TestCatalog.Model.Title)" },
+                        { "name": "Series", "type": "Collection(TestCatalog.Model.Title)" },
+                        { "name": "ScreenFormats", "nullable": "false", "partner": "Title", "type": "Collection(TestCatalog.Model.TitleScreenFormat)" },
+                        { "name": "Cast", "nullable": "false", "partner": "TitlesActedIn", "type": "Collection(TestCatalog.Model.Person)" },
+                        { "name": "Languages", "nullable": "false", "partner": "Titles", "type": "Collection(TestCatalog.Model.Language)" },
+                        { "name": "Directors", "nullable": "false", "partner": "TitlesDirected", "type": "Collection(TestCatalog.Model.Person)" },
+                        { "name": "Genres", "nullable": "false", "partner": "Titles", "type": "Collection(TestCatalog.Model.Genre)" }
+                    ]
+                }, {
+                    "name": "TitleScreenFormat",
+                    "key": [{ "propertyRef": [{ "name": "TitleId" }, { "name": "DeliveryFormat" }, { "name": "Format"}]}],
+                    "property": [
+                        { "name": "TitleId", "type": "Edm.String", "nullable": "false", "maxLength": "30" },
+                        { "name": "DeliveryFormat", "type": "Edm.String", "nullable": "false", "maxLength": "10", "unicode": "false" },
+                        { "name": "Format", "type": "Edm.String", "nullable": "false", "maxLength": "30", "unicode": "false" }
+                    ],
+                    "navigationProperty": [{ "name": "Title", "partner": "ScreenFormats", "referentialConstraint": [{"property": "TitleId", "referencedProperty": "Id"}], "type": "TestCatalog.Model.Title" }]
+                }],
+                "complexType": [{
+                    "name": "BoxArt",
+                    "property": [
+                        { "name": "SmallUrl", "type": "Edm.String", "nullable": "true", "maxLength": "80", "unicode": "false" },
+                        { "name": "MediumUrl", "type": "Edm.String", "nullable": "true", "maxLength": "80", "unicode": "false" },
+                        { "name": "LargeUrl", "type": "Edm.String", "nullable": "true", "maxLength": "80", "unicode": "false" },
+                        { "name": "HighDefinitionUrl", "type": "Edm.String", "nullable": "true", "maxLength": "80", "unicode": "false" }
+                    ]
+                }, {
+                    "name": "InstantAvailability",
+                    "property": [
+                        { "name": "Available", "type": "Edm.Boolean", "nullable": "false" },
+                        { "name": "AvailableFrom", "type": "Edm.DateTime", "nullable": "true" },
+                        { "name": "AvailableTo", "type": "Edm.DateTime", "nullable": "true" },
+                        { "name": "HighDefinitionAvailable", "type": "Edm.Boolean", "nullable": "false" },
+                        { "name": "Runtime", "type": "Edm.Int32", "nullable": "true" },
+                        { "name": "Rating", "type": "Edm.String", "nullable": "true", "maxLength": "10", "unicode": "false" }
+                    ]
+                }, {
+                    "name": "DeliveryFormatAvailability",
+                    "property": [
+                        { "name": "Available", "type": "Edm.Boolean", "nullable": "false" },
+                        { "name": "AvailableFrom", "type": "Edm.DateTime", "nullable": "true" },
+                        { "name": "AvailableTo", "type": "Edm.DateTime", "nullable": "true" },
+                        { "name": "Runtime", "type": "Edm.Int32", "nullable": "true" },
+                        { "name": "Rating", "type": "Edm.String", "nullable": "true", "maxLength": "10", "unicode": "false" }
+                    ]
+                }],
+                "function": [
+                {
+                   "name": "ProductsByRating",
+                   "returnType": {"type": "Collection(TestCatalog.Model.Title)" }
+                }]
+            }, {
+                "namespace": "Test.Catalog",
+                "entityContainer": {
+                    "name": "TestCatalog",
+                    "functionImport": [
+                        { "entitySet": "Titles", "function": "estCatalog.Model.GetTitles", "name": "Movies"},
+                        { "entitySet": "Titles", "function": "estCatalog.Model.GetTitles", "name": "Series"},
+                        { "entitySet": "Titles", "function": "estCatalog.Model.GetTitles", "name": "Seasons" },
+                        { "entitySet": "Titles", "function": "estCatalog.Model.GetTitles", "name": "Discs" },
+                        { "entitySet": "Titles", "function": "estCatalog.Model.GetTitles", "name": "Episodes" }
+                    ], "entitySet": [
+                        { "name": "Genres", "entityType": "TestCatalog.Model.Genre", "navigationPropertyBinding": [{"path": "Titles", "target": "Titles"}] },
+                        { "name": "Languages", "entityType": "TestCatalog.Model.Language", "navigationPropertyBinding": [{ "path": "Languages", "target": "Titles"}] },
+                        { "name": "People", "entityType": "TestCatalog.Model.Person", "navigationPropertyBinding": [{ "path": "Cast", "target": "Titles" }, { "path": "Directors", "target": "Titles"}] },
+                        { "name": "TitleAudioFormats", "entityType": "TestCatalog.Model.TitleAudioFormat", "navigationPropertyBinding": [{ "path": "AudioFormats", "target": "Titles"}] },
+                        { "name": "TitleAwards", "entityType": "TestCatalog.Model.TitleAward", "navigationPropertyBinding": [{ "path": "Awards", "target": "Titles"}] },
+                        { "name": "Titles", "entityType": "TestCatalog.Model.Title", "navigationPropertyBinding": [{ "path": "Title", "target": "TitleAudioFormats" }, { "path": "Title", "target": "TitleAwards" }, { "path": "Disc", "target": "Titles" }, { "path": "Movie", "target": "Titles" }, { "path": "Season", "target": "Titles" }, { "path": "Series", "target": "Titles" }, { "path": "ScreenFormats", "target": "TitleScreenFormats" }, { "path": "TitlesActedIn", "target": "People" }, { "path": "Titles", "target": "Languages" }, { "path": "TitlesDirected", "target": "People" }, { "path": "Genres", "target": "Genres"}] },
+                        { "name": "TitleScreenFormats", "entityType": "TestCatalog.Model.TitleScreenFormat", "navigationPropertyBinding": [{ "path": "Title", "target": "TitleScreenFormats"}] }
+                    ]
+                }
+            }]
+        }
+    };
+
+    var testCsdlV4 = '' +
+    '<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">\r\n' +
+    '  <edmx:DataServices xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" m:MaxDataServiceVersion="4.0" m:DataServiceVersion="4.0">\r\n' +
+    '    <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="TestCatalog.Model"/>\r\n' +
+    '  </edmx:DataServices>\r\n' +
+    '</edmx:Edmx>';
+
+    var testMetadataV4 = {
+        "version": "4.0",
+        "dataServices": {
+            "maxDataServiceVersion": "4.0",
+            "dataServiceVersion": "4.0",
+            "schema": [{
+                "namespace": "TestCatalog.Model"
+            }]
+        }
+    };
+
+    djstest.addTest(function testParseConceptualModelElement() {
+        // Test cases as input XML text / result tuples.
+        var cases = [
+            { i: "<foo />", e: null },
+            { i: '<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" />', e: { version: "4.0"} },
+            { i: '<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx-invalid" />', e: null },
+            { i: testCsdlV4, e: testMetadataV4 },
+            { i: testFullCsdl, e: testFullMetadataResult }
+        ];
+
+        var i, len;
+        for (i = 0, len = cases.length; i < len; i++) {
+            var doc = window.odatajs.xml.xmlParse(cases[i].i);
+            var schema = window.odatajs.oData.metadata.parseConceptualModelElement(doc.documentElement);
+            djstest.assertAreEqualDeep(schema, cases[i].e, "parseConceptualModelElement result matches target");
+        }
+
+        djstest.done();
+    });
+
+    djstest.addTest(function metadataVocabularyTest() {
+        var testCsdl = '' +
+        '<?xml version="1.0" encoding="utf-8" standalone="yes"?>\r\n' +
+        '<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" >\r\n' +
+        '  <edmx:DataServices xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" m:MaxDataServiceVersion="4.0" m:DataServiceVersion="4.0">\r\n' +
+        '    <Schema Namespace="TestCatalog.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm">\r\n' +
+        '          <Term Name="Rating" Type="Edm.Int32" />\r\n' +
+        '          <Term Name="CanEdit" Type="Edm.String" />\r\n' +
+        '      <EntityType Name="Genre">\r\n' +
+        '        <Key><PropertyRef Name="Name" /></Key>\r\n' +
+        '        <Property Name="Name" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="false" />\r\n' +
+        '      </EntityType></Schema></edmx:DataServices></edmx:Edmx>';
+
+
+        var doc = window.odatajs.xml.xmlParse(testCsdl);
+        var schema = window.odatajs.oData.metadata.parseConceptualModelElement(doc.documentElement);
+
+        djstest.assertAreEqual(schema.dataServices.schema[0].term.length, 2, "schema.DataServices.Schema.Term.length === 2");
+        djstest.assertAreEqual(schema.dataServices.schema[0].term[0].name, "Rating", "schema.DataServices.Schema.Term[0].name === 'Rating'");
+        djstest.assertAreEqual(schema.dataServices.schema[0].term[1].name, "CanEdit", "schema.DataServices.Schema.Term[1].name === 'CanEdit'");
+        djstest.done();
+    });
+
+    djstest.addTest(function metadataAnnotationTest() {
+        var testCsdl = '' +
+        '<?xml version="1.0" encoding="utf-8" standalone="yes"?>\r\n' +
+        '<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" >\r\n' +
+        '  <edmx:DataServices xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" m:MaxDataServiceVersion="4.0" m:DataServiceVersion="4.0">\r\n' +
+        '    <Schema Namespace="TestCatalog.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm">\r\n' +
+        '      <EntityType Name="Genre">\r\n' +
+        '        <Key><PropertyRef Name="Name" /></Key>\r\n' +
+        '        <Property Name="Name" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="false" />\r\n' +
+        '      </EntityType>\r\n' +
+        '      <EntityType Name="Language">\r\n' +
+        '        <Key><PropertyRef Name="Name" /></Key>\r\n' +
+        '        <Property Name="Name" Type="Edm.String" Nullable="false" MaxLength="80" Unicode="false" />\r\n' +
+        '        <Property Name="Id" Type="Edm.Int32" />\r\n' +
+        '      </EntityType>\r\n' +
+        '      <Annotations Target="TestCatalog.Model.Genre/Name">\r\n' +
+        '        <Annotation String="Genre Name" Term="Org.OData.Display.V1.DisplayName"/>\r\n' +
+        '      </Annotations>\r\n' +
+        '      <Annotations Target="TestCatalog.Model.Language/Name">\r\n' +
+        '        <Annotation String="Language Name" Term="Org.OData.Display.V1.DisplayName"/>\r\n' +
+        '        <Annotation String="Language Name 2" Term="Org.OData.Display.V1.DisplayName 2"/>\r\n' +
+        '      </Annotations>\r\n' +
+        '    </Schema></edmx:DataServices></edmx:Edmx>';
+
+
+        var doc = window.odatajs.xml.xmlParse(testCsdl);
+        var schema = window.odatajs.oData.metadata.parseConceptualModelElement(doc.documentElement);
+
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations.length, 2, "Annotations number");
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations[0].annotation.length, 1, "Annotation number");
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations[0].annotation[0].string, "Genre Name", "Annotation name");
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations[0].annotation[0].term, "Org.OData.Display.V1.DisplayName", "Annotation term");
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations[1].annotation.length, 2, "Annotation number");
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations[1].annotation[0].string, "Language Name", "Annotation name");
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations[1].annotation[0].term, "Org.OData.Display.V1.DisplayName", "Annotation term");
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations[1].annotation[1].string, "Language Name 2", "Annotation name");
+        djstest.assertAreEqual(schema.dataServices.schema[0].annotations[1].annotation[1].term, "Org.OData.Display.V1.DisplayName 2", "Annotation term");
+        djstest.done();
+    });
+
+    // DATAJS INTERNAL END
+})(this);

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/odata-net-tests.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/odata-net-tests.js b/odatajs/tests/odata-net-tests.js
new file mode 100644
index 0000000..351b197
--- /dev/null
+++ b/odatajs/tests/odata-net-tests.js
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ */
+
+// odata-net-tests.js
+(function (window, undefined) {
+    module("Unit");
+    djstest.addTest(function httpClientSendRequestTest() {
+        var tests = [
+            { url: "http://localhost/test1", response: { headers: {}, status: 200, body: "test"} },
+            { url: "http://localhost/test2", response: { headers: {}, status: 204, body: "test"} },
+            { url: "http://localhost/test3", response: { headers: {}, status: 299, body: "test"} },
+            { url: "http://localhost/test4", response: { headers: {}, status: 500, body: "error"} }
+        ];
+
+        djstest.assertsExpected(12);
+
+        var sentCount = 0;
+        MockXMLHttpRequest.onAfterSend = function () {
+            sentCount++;
+        };
+
+        var oldXmlHttpRequest = window.XMLHttpRequest;
+        var oldEnableJsonpCallback = window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback;
+        try {
+            window.XMLHttpRequest = MockXMLHttpRequest.XMLHttpRequest;
+            var i, len;
+            for (i = 0, len = tests.length; i < len; i++) {
+                MockXMLHttpRequest.addResponse(tests[i].url, tests[i].response);
+
+                window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = false;
+                //Need a closure to capture the current test being executed. 
+                (function (test) {
+                    window.odatajs.oData.net.defaultHttpClient.request(
+                    { requestUri: test.url, headers: {} },
+                    function (response) {
+                        djstest.assert(response.statusCode >= 200 & response.statusCode <= 299, "response status is in the success range");
+                        djstest.assertAreEqual(response.body, test.response.body, "response body is the expected one");
+                        djstest.assertAreEqualDeep(response.headers, [], "response headers are the expected ones");
+                    },
+                    function (error) {
+                        djstest.assert(error.response.statusCode > 299, "response status is in the error range");
+                        djstest.assertAreEqual(error.response.body, test.response.body, "response body is the expected one");
+                        djstest.assertAreEqualDeep(error.response.headers, [], "response headers are the expected ones");
+                    });
+                })(tests[i]);
+            }
+        }
+        finally {
+            //Cleanup and finish the test after all requests have been sent and processed. Poll every 50 ms
+            var timer = setInterval(function () {
+                if (sentCount === tests.length) {
+                    clearInterval(timer)
+                    window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = oldEnableJsonpCallback;
+                    window.XMLHttpRequest = oldXmlHttpRequest;
+                    MockXMLHttpRequest.reset();
+                    djstest.done();
+                }
+            }, 50);
+        }
+    });
+
+    djstest.addTest(function httpClientRequestTimeoutTest() {
+        var oldXmlHttpRequest = window.XMLHttpRequest;
+        var testDone = false;
+
+        djstest.assertsExpected(1);
+
+        var oldEnableJsonpCallback = window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback;
+        try {
+            window.XMLHttpRequest = MockXMLHttpRequest.XMLHttpRequest;
+            window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = false;
+
+            window.odatajs.oData.net.defaultHttpClient.request(
+               { requestUri: "http://test1", timeoutMS: 10, headers: { MockTimeOut: true} },
+               function (response) {
+                   djstest.fail("success method was hit when not expected");
+                   testDone = true;
+               },
+               function (error) {
+                   djstest.assertAreEqual(error.message, "Request timed out", "error method executes and error is the expected one");
+                   testDone = true;
+               });
+        }
+        finally {
+            //Cleanup and finish the test after all requests have been sent and processed. Poll every 50 ms
+            var timer = setInterval(function () {
+                if (testDone) {
+                    clearInterval(timer);
+                    window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = oldEnableJsonpCallback;
+                    window.XMLHttpRequest = oldXmlHttpRequest;
+                    MockXMLHttpRequest.reset();
+                    djstest.done();
+                }
+            }, 50);
+        }
+    });
+
+    djstest.addTest(function httpClientRequestAbortTest() {
+
+        var oldXmlHttpRequest = window.XMLHttpRequest;
+
+        djstest.assertsExpected(1);
+
+        var oldEnableJsonpCallback = window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback;
+        try {
+            window.XMLHttpRequest = MockXMLHttpRequest.XMLHttpRequest;
+            window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = false;
+
+            var result = window.odatajs.oData.net.defaultHttpClient.request(
+               { requestUri: "http://test1", headers: { MockNoOp: true} },
+               function (response) {
+                   djstest.fail("success method was hit when not expected");
+               },
+               function (error) {
+                   djstest.assertAreEqual(error.message, "Request aborted", "error method executes and error is the expected one");
+               });
+
+            result.abort();
+        }
+        finally {
+            window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = oldEnableJsonpCallback;
+            window.XMLHttpRequest = oldXmlHttpRequest;
+            MockXMLHttpRequest.reset();
+            djstest.done();
+        }
+    });
+
+    djstest.addTest(function httpClientRequestAbortOnCompletedRequestTest() {
+
+        var oldXmlHttpRequest = window.XMLHttpRequest;
+        var testDone = false;
+
+        djstest.assertsExpected(1);
+
+        var oldEnableJsonpCallback = window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback;
+        try {
+            window.XMLHttpRequest = MockXMLHttpRequest.XMLHttpRequest;
+            window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = false;
+
+            MockXMLHttpRequest.addResponse("http://test1", { headers: {}, status: 200, body: "test body" });
+
+            MockXMLHttpRequest.onAfterSend = function () {
+                result.abort();
+                testDone = true;
+            };
+
+            result = window.odatajs.oData.net.defaultHttpClient.request(
+               { requestUri: "http://test1", headers: {} },
+               function (response) {
+                   djstest.pass("success method was hit");
+               },
+               function (error) {
+                   djstest.fail("success method was hit when not expected - [" + error.message + "]");
+               });
+        }
+        finally {
+            // Cleanup after test is done, poll eavery 50ms
+            var timer = setInterval(function () {
+                if (testDone) {
+                    clearInterval(timer);
+                    window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = oldEnableJsonpCallback;
+                    window.XMLHttpRequest = oldXmlHttpRequest;
+                    MockXMLHttpRequest.reset();
+                    djstest.done();
+                }
+            }, 50);
+        }
+    });
+
+    djstest.addTest(function httpClientRequestSendsRequestCorrectlyTest() {
+        var tests = [
+            {
+                request: { requestUri: "http://test1", headers: {}, body: "test" },
+                expected: { headers: {}, url: "http://test1", method: "GET", body: "test", async: true, user: undefined, password: undefined }
+            },
+            {
+                request: { requestUri: "http://test2", headers: {}, method: "POST", body: "test" },
+                expected: { headers: {}, url: "http://test2", method: "POST", body: "test", async: true, user: undefined, password: undefined }
+            },
+            {
+                request: { requestUri: "http://test3", headers: { header1: "value1", header2: "value2" }, body: "test" },
+                expected: { headers: { header1: "value1", header2: "value2" }, url: "http://test3", method: "GET", body: "test", async: true, user: undefined, password: undefined }
+            }
+        ];
+
+        var oldXmlHttpRequest = window.XMLHttpRequest;
+        var oldEnableJsonpCallback = window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback;
+        try {
+            window.XMLHttpRequest = MockXMLHttpRequest.XMLHttpRequest;
+            window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = false;
+            var i, len;
+
+            for (i = 0, len = tests.length; i < len; i++) {
+
+                MockXMLHttpRequest.addRequestVerifier(tests[i].request.requestUri, function (request) {
+                    djstest.assertAreEqualDeep(request, tests[i].expected, "request matches target");
+                });
+
+                window.odatajs.oData.net.defaultHttpClient.request(
+                    tests[i].request,
+                    function (response) { });
+            }
+        }
+        finally {
+            // Restore original values.
+            window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = oldEnableJsonpCallback;
+            window.XMLHttpRequest = oldXmlHttpRequest;
+        }
+        djstest.done();
+    });
+
+    // DATAJS INTERNAL START
+    djstest.addTest(function canUseJSONPTest() {
+        var tests = [
+            { pass: true, input: {} },
+            { pass: true, input: { method: "GET"} },
+            { pass: false, input: { method: "PUT"} },
+            { pass: false, input: { method: "get"} },
+            { pass: true, input: { accept: "*/*"} },
+            { pass: true, input: { accept: "application/json"} },
+            { pass: true, input: { accept: "text/javascript"} },
+            { pass: true, input: { accept: "application/javascript"} },
+            { pass: true, input: { accept: "application/xml"} },
+            { pass: true, input: { headers: { Accept: "application/xml"}} }
+        ];
+        for (var i = 0; i < tests.length; i++) {
+            var actual = window.odatajs.oData.net.canUseJSONP(tests[i].input);
+            djstest.assert(actual === tests[i].pass, "test " + i + " didn't actually match pass (" + tests[i].pass + ")");
+        }
+        djstest.done();
+    });
+
+    djstest.addTest(function isAbsoluteUrlTest() {
+        djstest.assert(window.odatajs.oData.net.isAbsoluteUrl("http://something/"));
+        djstest.assert(window.odatajs.oData.net.isAbsoluteUrl("http://malformed url/"));
+        djstest.assert(window.odatajs.oData.net.isAbsoluteUrl("https://localhost/"));
+        djstest.assert(window.odatajs.oData.net.isAbsoluteUrl("file://another-protocol/"));
+        djstest.assert(!window.odatajs.oData.net.isAbsoluteUrl("/path"));
+        djstest.assert(!window.odatajs.oData.net.isAbsoluteUrl("?query-string"));
+        djstest.assert(!window.odatajs.oData.net.isAbsoluteUrl(""));
+        djstest.assert(!window.odatajs.oData.net.isAbsoluteUrl("mailto:someone"));
+        djstest.done();
+    });
+
+    djstest.addTest(function isLocalUrlTest() {
+        var thisUrl = window.location.href;
+        var localUrls = [
+            "", ".", "/howdy.htm", "  ", "?queryparam",
+            thisUrl, thisUrl + "/foo", thisUrl + "?something-else"
+        ];
+        var remoteUrls = [
+            "http://www.microsoft.com/",
+            "https://www.microsoft.com/",
+            "https://" + window.location.host,
+            "https://" + window.location.hostname,
+        // 21 is FTP, so the test shouldn't collide
+            "http://" + window.location.hostname + ":21"
+        ];
+        var i, len;
+        for (i = 0, len = localUrls.length; i < len; i++) {
+            djstest.assert(window.odatajs.oData.net.isLocalUrl(localUrls[i]), "is local: [" + localUrls[i] + "]");
+        }
+        for (i = 0, len = remoteUrls.length; i < len; i++) {
+            djstest.assert(!window.odatajs.oData.net.isLocalUrl(remoteUrls[i]), "is not local: [" + remoteUrls[i] + "]");
+        }
+        djstest.done();
+    });
+
+    // DATAJS INTERNAL END
+
+    djstest.addTest(function userPasswordTest() {
+        odatajs.oData.request({
+            requestUri: "./endpoints/FoodStoreDataServiceV4.svc/UserNameAndPassword",
+            user: "the-user",
+            password: "the-password"
+        }, function (data) {
+            djstest.assertAreEqualDeep(data.value, "Basic dGhlLXVzZXI6dGhlLXBhc3N3b3Jk", "response matches");
+            djstest.done();
+        }, function (err) {
+            djstest.fail("error: " + err.message);
+            djstest.done();
+        });
+    });
+
+})(this);

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/odata-perf-tests.html
----------------------------------------------------------------------
diff --git a/odatajs/tests/odata-perf-tests.html b/odatajs/tests/odata-perf-tests.html
new file mode 100644
index 0000000..238246f
--- /dev/null
+++ b/odatajs/tests/odata-perf-tests.html
@@ -0,0 +1,50 @@
+<!--
+/*
+ * 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.
+*/
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+    <title>OData perf tests</title>
+    <meta http-equiv="cache-control" content="no-cache"/> 
+    <meta http-equiv="pragma" content="no-cache"/> 
+    <meta http-equiv="expires" content="-1"/> 
+
+    <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.10.0.css" type="text/css" />
+    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js"></script>
+    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
+    <script type="text/javascript" src="http://code.jquery.com/qunit/qunit-1.10.0.js"></script>
+    <script type="text/javascript" src="common/TestSynchronizerClient.js"></script>
+    <script type="text/javascript">
+        window.TestSynchronizer.init(QUnit);
+    </script>
+    <script type="text/javascript" src="../build/odatajs-4.0.0-beta-01.js"></script> 
+    <script type="text/javascript" src="common/common.js"></script> 
+    <script type="text/javascript" src="common/djstest.js"></script>
+    <script type="text/javascript" src="common/Instrument.js"></script>
+
+    <script type="text/javascript" src="odata-perf-tests.js"></script>  
+</head>
+<body>
+ <h1 id="qunit-header">OData perf tests</h1>
+ <h2 id="qunit-banner"></h2>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests"></ol>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/odata-perf-tests.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/odata-perf-tests.js b/odatajs/tests/odata-perf-tests.js
new file mode 100644
index 0000000..cd465fe
--- /dev/null
+++ b/odatajs/tests/odata-perf-tests.js
@@ -0,0 +1,242 @@
+/*
+ * 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) {
+    var unexpectedErrorHandler = function (err) {
+        djstest.assert(false, "Unexpected call to error handler with error: " + djstest.toString(err));
+        djstest.done();
+    };
+
+    var timedHttpClient = {
+        duration: 0,
+        provider: window.odatajs.oData.net.defaultHttpClient,
+        request: function (request, success, error) {
+            var startTime = new Date();
+            return timedHttpClient.provider.request(request, function () {
+                timedHttpClient.duration = new Date() - startTime;
+                success.apply(this, arguments);
+            }, error);
+        }
+    };
+
+    var largeCollectionService = "./endpoints/LargeCollectionService.svc/";
+
+    // null "service" indicates the feed is read-only
+    var feeds = [
+        { service: largeCollectionService, uri: largeCollectionService + "Customers", mimeType: "application/json;odata.metadata=minimal" },
+        { service: largeCollectionService, uri: largeCollectionService + "Customers", mimeType: "application/json;odata.metadata=full" },
+        { service: largeCollectionService, uri: largeCollectionService + "Customers", mimeType: "application/json;odata.metadata=none" },
+        { service: largeCollectionService, uri: largeCollectionService + "Suppliers", mimeType: "application/json" },
+        { service: null, uri: "http://odata.netflix.com/Catalog/Titles", mimeType: "application/json" }
+    ];
+
+    module("Performance", {
+        setup: function () {
+            djstest.wait(function (done) {
+                $.post(largeCollectionService + "ResetData", done);
+            });
+        },
+        teardown: function () {
+            window.odatajs.oData.net.defaultHttpClient = timedHttpClient.provider;
+        }
+    });
+
+    window.odatajs.oData.net.defaultHttpClient.enableJsonpCallback = true;
+    $.each(feeds, function (_, feed) {
+        $.each([5, 500], function (_, items) {
+            var params = $.extend({}, feed, { items: items, readUri: feed.uri + "?$top=" + items });
+            djstest.addTest(function readPerfTest(params) {
+                var measureRead = function (metadata) {
+                    var startTime = new Date();
+                    odatajs.oData.read({ requestUri: params.readUri, headers: { Accept: params.mimeType }, enableJsonpCallback: true }, function () {
+                        var duration = new Date() - startTime - timedHttpClient.duration;
+                        djstest.pass("Duration: " + duration + " ms (Network: " + timedHttpClient.duration + " ms)");
+                        djstest.done();
+                    }, unexpectedErrorHandler, undefined, undefined, metadata);
+                };
+
+                window.odatajs.oData.net.defaultHttpClient = timedHttpClient;
+                djstest.assertsExpected(1);
+                if (params.metadata) {
+                    odatajs.oData.read(params.service + "$metadata", measureRead, unexpectedErrorHandler, OData.metadataHandler);
+                } else {
+                    measureRead();
+                }
+            }, "Time to read (once) " + params.readUri + " with " + params.mimeType, params);
+
+            djstest.addTest(function readParallelMemoryTest(params) {
+                var total = 10;
+                var count = 0;
+                var measureRead = function (metadata) {
+                    Instrument.getBrowserMemorySize(function (memoryBefore) {
+                        for (var i = 0; i < total; i++) {
+                            odatajs.oData.read({ requestUri: params.readUri, headers: { Accept: params.mimeType }, enableJsonpCallback: true }, function (_, response) {
+                                count++;
+                                if (count >= total) {
+                                    Instrument.getBrowserMemorySize(function (memoryAfter) {
+                                        var memory = memoryAfter - memoryBefore;
+                                        djstest.pass("Memory: " + memory + " bytes (Network: " + response.headers["Content-Length"] + " bytes)");
+                                        djstest.done();
+                                    });
+                                }
+                            }, unexpectedErrorHandler, undefined, undefined, metadata);
+                        }
+                    });
+                };
+
+                djstest.assertsExpected(1);
+                if (params.metadata) {
+                    odatajs.oData.read(params.service + "$metadata", measureRead, unexpectedErrorHandler, OData.metadataHandler);
+                } else {
+                    measureRead();
+                }
+            }, "Memory to read (x10 parallel) " + params.readUri + " with " + params.mimeType, params, 300000);
+
+            djstest.addTest(function readSerialMemoryTest(params) {
+                var total = 10;
+                var count = 0;
+                var measureRead = function (metadata) {
+                    Instrument.getBrowserMemorySize(function (memoryBefore) {
+                        var makeRequest = function () {
+                            odatajs.oData.read({ requestUri: params.readUri, headers: { Accept: params.mimeType }, enableJsonpCallback: true }, function (_, response) {
+                                count++;
+                                if (count < total) {
+                                    setTimeout(makeRequest, 0);
+                                } else {
+                                    Instrument.getBrowserMemorySize(function (memoryAfter) {
+                                        var memory = memoryAfter - memoryBefore;
+                                        djstest.pass("Memory: " + memory + " bytes (Network: " + response.headers["Content-Length"] + " bytes)");
+                                        djstest.done();
+                                    });
+                                }
+                            }, unexpectedErrorHandler, undefined, undefined, metadata);
+                        };
+
+                        makeRequest();
+                    });
+                };
+
+                djstest.assertsExpected(1);
+                if (params.metadata) {
+                    odatajs.oData.read(params.service + "$metadata", measureRead, unexpectedErrorHandler, OData.metadataHandler);
+                } else {
+                    measureRead();
+                }
+            }, "Memory to read (x10 serial) " + params.readUri + " with " + params.mimeType, params, 300000);
+        });
+
+        if (feed.service) {
+            var params = $.extend({}, feed, {
+                request: {
+                    requestUri: feed.uri,
+                    method: "POST",
+                    headers: { "Content-Type": feed.mimeType, Accept: feed.mimeType },
+                    data: {
+                        ID: -1,
+                        Name: "New Entity"
+                    }
+                }
+            });
+
+            djstest.addTest(function postPerfTest(params) {
+                var measurePost = function (metadata) {
+                    var startTime = new Date();
+                    odatajs.oData.request(params.request, function () {
+                        var duration = new Date() - startTime - timedHttpClient.duration;
+                        djstest.pass("Duration: " + duration + " ms (Network: " + timedHttpClient.duration + " ms)");
+                        djstest.done();
+                    }, unexpectedErrorHandler, undefined, undefined, metadata);
+                };
+
+                window.odatajs.oData.net.defaultHttpClient = timedHttpClient;
+                djstest.assertsExpected(1);
+
+                if (params.metadata) {
+                    odatajs.oData.read(params.service + "$metadata", measurePost, unexpectedErrorHandler, OData.metadataHandler);
+                } else {
+                    measurePost();
+                }
+            }, "Time to POST " + params.uri + " with " + params.mimeType, params);
+
+            djstest.addTest(function postParallelMemoryTest(params) {
+                var total = 10;
+                var count = 0;
+                var measurePost = function (metadata) {
+                    Instrument.getBrowserMemorySize(function (memoryBefore) {
+                        for (var i = 0; i < total; i++) {
+                            odatajs.oData.request(params.request, function (_, response) {
+                                count++;
+                                if (count >= total) {
+                                    Instrument.getBrowserMemorySize(function (memoryAfter) {
+                                        var memory = memoryAfter - memoryBefore;
+                                        djstest.pass("Memory: " + memory + " bytes (Network: " + response.headers["Content-Length"] + " bytes)");
+                                        djstest.done();
+                                    });
+                                }
+                            }, unexpectedErrorHandler, undefined, undefined, metadata);
+                        }
+                    });
+                };
+
+                window.odatajs.oData.net.defaultHttpClient = timedHttpClient;
+                djstest.assertsExpected(1);
+
+                if (params.metadata) {
+                    odatajs.oData.read(params.service + "$metadata", measurePost, unexpectedErrorHandler, OData.metadataHandler);
+                } else {
+                    measurePost();
+                }
+            }, "Memory to POST (x10 parallel) " + params.uri + " with " + params.mimeType, params);
+
+            djstest.addTest(function postSerialMemoryTest(params) {
+                var total = 10;
+                var count = 0;
+                var measurePost = function (metadata) {
+                    Instrument.getBrowserMemorySize(function (memoryBefore) {
+                        var makeRequest = function () {
+                            odatajs.oData.request(params.request, function (_, response) {
+                                count++;
+                                if (count < total) {
+                                    setTimeout(makeRequest, 0);
+                                } else {
+                                    Instrument.getBrowserMemorySize(function (memoryAfter) {
+                                        var memory = memoryAfter - memoryBefore;
+                                        djstest.pass("Memory: " + memory + " bytes (Network: " + response.headers["Content-Length"] + " bytes)");
+                                        djstest.done();
+                                    });
+                                }
+                            }, unexpectedErrorHandler, undefined, undefined, metadata);
+                        };
+
+                        makeRequest();
+                    });
+                };
+
+                window.odatajs.oData.net.defaultHttpClient = timedHttpClient;
+                djstest.assertsExpected(1);
+
+                if (params.metadata) {
+                    odatajs.oData.read(params.service + "$metadata", measurePost, unexpectedErrorHandler, OData.metadataHandler);
+                } else {
+                    measurePost();
+                }
+            }, "Memory to POST (x10 serial) " + params.uri + " with " + params.mimeType, params);
+        }
+    });
+})(this);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/odata-qunit-tests.htm
----------------------------------------------------------------------
diff --git a/odatajs/tests/odata-qunit-tests.htm b/odatajs/tests/odata-qunit-tests.htm
new file mode 100644
index 0000000..3054691
--- /dev/null
+++ b/odatajs/tests/odata-qunit-tests.htm
@@ -0,0 +1,76 @@
+<!--
+/*
+ * 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.
+ */
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<html>
+  <head>
+    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
+    <meta http-equiv="cache-control" content="no-cache" />
+    <meta http-equiv="pragma" content="no-cache" />
+    <meta http-equiv="expires" content="-1" />
+
+    <title>OData unit tests</title>
+    <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.10.0.css" type="text/css" />
+    
+    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js" ></script>
+
+    <script type="text/javascript" src="http://code.jquery.com/qunit/qunit-1.10.0.js"></script>
+    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js"></script>
+
+    <script type="text/javascript" src="common/ODataReadOracle.js"></script>
+    <script type="text/javascript" src="common/TestSynchronizerClient.js"></script>
+
+    <!--<script type="text/javascript" src="common/rx.js"></script>-->
+    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/rxjs/2.3.5/rx.all.js"></script>
+    <script type="text/javascript">
+        window.TestSynchronizer.init(QUnit);
+    </script>
+    <script type="text/javascript" src="../build/odatajs-4.0.0-beta-01.js"></script>
+    <script type="text/javascript" src="common/common.js"></script>
+
+    <script type="text/javascript" src="./common/mockHttpClient.js"></script>
+    <script type="text/javascript" src="./common/mockXMLHttpRequest.js"></script>
+
+    <script type="text/javascript" src="./common/djstest.js"></script>
+    <script type="text/javascript" src="./common/djstest-browser.js"></script>
+    <script type="text/javascript" src="./common/CacheOracle.js"></script>
+
+<!--bingl: disable the failure test case. Will fix them in the next change set-->
+<!--    <script type="text/javascript" src="odata-tests.js"></script>-->
+    <script type="text/javascript" src="odata-json-tests.js"></script>
+<!--    <script type="text/javascript" src="odata-json-light-tests.js"></script>-->
+    <script type="text/javascript" src="odata-links-functional-tests.js"></script>
+    <script type="text/javascript" src="odata-metadata-tests.js"></script>
+    <script type="text/javascript" src="odata-xml-tests.js"></script>
+    <script type="text/javascript" src="odata-handler-tests.js"></script>
+    <script type="text/javascript" src="odata-net-tests.js"></script>
+    <script type="text/javascript" src="odata-batch-tests.js"></script>
+    <script type="text/javascript" src="cache-tests.js"></script>
+    <script type="text/javascript" src="store-tests.js"></script>
+    <script type="text/javascript" src="store-indexeddb-tests.js"></script>
+  </head>
+  <body>
+    <h1 id="qunit-header">OData Unit Tests</h1>
+    <h2 id="qunit-banner"></h2>
+    <h2 id="qunit-userAgent"></h2>
+    <ol id="qunit-tests">
+    </ol>
+  </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/odata-read-crossdomain-functional-tests.html
----------------------------------------------------------------------
diff --git a/odatajs/tests/odata-read-crossdomain-functional-tests.html b/odatajs/tests/odata-read-crossdomain-functional-tests.html
new file mode 100644
index 0000000..86ce093
--- /dev/null
+++ b/odatajs/tests/odata-read-crossdomain-functional-tests.html
@@ -0,0 +1,49 @@
+<!--
+/*
+ * 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.
+*/
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+    <title>OData tests against local service</title>
+    <meta http-equiv="cache-control" content="no-cache"/> 
+    <meta http-equiv="pragma" content="no-cache"/> 
+    <meta http-equiv="expires" content="-1"/> 
+
+    <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.10.0.css" type="text/css" />
+    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js"></script>
+    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
+    <script type="text/javascript" src="http://code.jquery.com/qunit/qunit-1.10.0.js"></script>
+    <script type="text/javascript" src="common/ODataReadOracle.js"></script>
+    <script type="text/javascript" src="common/TestSynchronizerClient.js"></script>
+        <script type="text/javascript">
+            window.TestSynchronizer.init(QUnit);
+    </script>
+    <script type="text/javascript" src="../build/odatajs-4.0.0-beta-01.js"></script>
+    <script type="text/javascript" src="common/common.js"></script> 
+    <script type="text/javascript" src="common/djstest.js"></script>
+    <script type="text/javascript" src="odata-read-crossdomain-functional-tests.js"></script>  
+</head>
+<body>
+ <h1 id="qunit-header">OData.Read tests against cross domain endpoints</h1>
+ <h2 id="qunit-banner"></h2>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests"></ol>
+</body>
+</html>
\ No newline at end of file