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:18 UTC
[11/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/common/TestLogger.svc
----------------------------------------------------------------------
diff --git a/odatajs/tests/common/TestLogger.svc b/odatajs/tests/common/TestLogger.svc
new file mode 100644
index 0000000..164d207
--- /dev/null
+++ b/odatajs/tests/common/TestLogger.svc
@@ -0,0 +1,852 @@
+/*
+ * 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.
+*/
+
+<%@ ServiceHost Language="C#" Debug="true" Factory="DataJS.Tests.TestSynchronizerFactory" Service="DataJS.Tests.TestSynchronizer" %>
+
+namespace DataJS.Tests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using System.ServiceModel;
+ using System.ServiceModel.Activation;
+ using System.ServiceModel.Channels;
+ using System.ServiceModel.Description;
+ using System.ServiceModel.Dispatcher;
+ using System.ServiceModel.Web;
+ using System.Text;
+ using System.Threading;
+ using System.Xml;
+
+ /// <summary>
+ /// This factory supports reconfiguring the service to allow incoming messages
+ /// to be larger than the default.
+ /// </summary>
+ public class TestSynchronizerFactory : WebScriptServiceHostFactory
+ {
+ protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
+ {
+ var result = base.CreateServiceHost(serviceType, baseAddresses);
+ result.Opening += ServiceHostOpening;
+ return result;
+ }
+
+ private static void UpdateService(ServiceDescription description)
+ {
+ const long LargeMaxReceivedMessageSize = 1024 * 1024 * 16;
+ foreach (var endpoint in description.Endpoints)
+ {
+ var basic = endpoint.Binding as BasicHttpBinding;
+ if (basic != null)
+ {
+ basic.MaxReceivedMessageSize = LargeMaxReceivedMessageSize;
+ }
+
+ var http = endpoint.Binding as WebHttpBinding;
+ if (http != null)
+ {
+ http.MaxReceivedMessageSize = LargeMaxReceivedMessageSize;
+ }
+ }
+ }
+
+ private void ServiceHostOpening(object sender, EventArgs e)
+ {
+ UpdateService((sender as ServiceHost).Description);
+ }
+ }
+
+ /// <summary>Use this class to log test activity.</summary>
+ /// <remarks>
+ /// A test run can be created by invoking CreateTestRun. With a test
+ /// run ID, the following operations can be invoked:
+ ///
+ /// - AddTestPages: adds test pages to be made available to future callers (typically to support tests from different files)
+ /// - SetTestNamePrefix: sets a string that will be prefixed to every test name in logs (typically to include a browser name)
+ /// - MarkInProgress: resets the test run to "in-progress" for another variation (typically to run a different browser)
+ /// - IsTestRunInProgress: checks whether it's still in progress
+ /// - GetTestRunResults: returns the test results in TRX format
+ /// - LogAssert: logs a single assertion in the current test for the run
+ /// - LogTestStart: logs a test that has begun execution
+ /// - LogTestDone: logs a test that has ended execution
+ /// - TestCompleted: logs that a test has completed execution; returns the next page with tests or an empty string
+ /// </remarks>
+ [ServiceContract]
+ [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
+ [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
+ public class TestSynchronizer
+ {
+ private static readonly Dictionary<string, TestRunContext> testRuns = new Dictionary<string, TestRunContext>();
+ private const string Inconclusive = "Inconclusive";
+ private const string InProgress = "InProgress";
+ private const string Failed = "Failed";
+ private const string Passed = "Passed";
+ private const string Completed = "Completed";
+
+ /// <summary>
+ /// Adds test pages to the specified runs; replaces existing files (helps with reliablity when something
+ /// fails part-way).
+ /// </summary>
+ /// <remarks>This method is typically called by the test harness.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public int AddTestPages(string testRunId, string pages, string filter)
+ {
+ DisableResponseCaching();
+
+ TestRunContext context = GetTestRunContext(testRunId);
+ lock (context)
+ {
+ context.TestPages.Clear();
+ context.TestPages.AddRange(pages.Split(',').Select(page => page + "?testRunId=" + testRunId + (filter == null ? string.Empty : "?filter=" + filter)));
+ return context.TestPages.Count;
+ }
+ }
+
+ /// <remarks>This method is typically called by the test harness.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public string CreateTestRun()
+ {
+ DisableResponseCaching();
+
+ Guid value = Guid.NewGuid();
+ string result = value.ToString();
+ TestRunContext context = CreateTestRunContextWithId(value);
+
+ lock (testRuns)
+ {
+ testRuns.Add(result, context);
+ }
+
+ return result;
+ }
+
+ /// <summary>Checks whether the test run is in progress.</summary>
+ /// <remarks>This method is typically called by the test harness.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public bool IsTestRunInProgress(string testRunId)
+ {
+ DisableResponseCaching();
+
+ TestRunContext context = GetTestRunContext(testRunId);
+ return context.TestRun.ResultSummary.Outcome == InProgress;
+ }
+
+ /// <summary>Provides a list of all test runs being tracked.</summary>
+ [OperationContract]
+ [WebGet(ResponseFormat=WebMessageFormat.Json)]
+ public IEnumerable<string> GetActiveTestRuns()
+ {
+ DisableResponseCaching();
+
+ List<string> result;
+ lock (testRuns)
+ {
+ result = new List<string>(testRuns.Keys);
+ }
+
+ return result;
+ }
+
+ /// <remarks>This method is typically called by the test harness.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Xml)]
+ public Message GetTestRunResults(string testRunId)
+ {
+ DisableResponseCaching();
+
+ TestRunContext context = GetTestRunContext(testRunId);
+ lock (context)
+ {
+ TestRun run = context.TestRun;
+ this.CompleteTestRun(run);
+
+ TestRunXmlBodyWriter writer = new TestRunXmlBodyWriter(run);
+ return Message.CreateMessage(
+ MessageVersion.None,
+ OperationContext.Current.OutgoingMessageHeaders.Action,
+ writer);
+ }
+ }
+
+ /// <remarks>This method is typically called by the test case.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public void LogAssert(string testRunId, bool pass, string message, string name, string actual, string expected)
+ {
+ DisableResponseCaching();
+
+ TestRunContext context = GetTestRunContext(testRunId);
+ lock (context)
+ {
+ TestRun run = context.TestRun;
+ string prefixedName = context.TestNamePrefix + name;
+ TestResult result = run.TestResults.LastOrDefault(r => r.TestName == prefixedName);
+ if (result == null)
+ {
+ throw new InvalidOperationException("Unable to find test " + prefixedName + " in run " + testRunId);
+ }
+
+ result.DebugTrace.AppendLine(message);
+ if (!pass)
+ {
+ result.ErrorMessages.AppendLine(message);
+ result.ErrorMessages.AppendLine("Expected: " + expected);
+ result.ErrorMessages.AppendLine("Actual: " + actual);
+ }
+ }
+ }
+
+ /// <remarks>This method is typically called by the test case.</remarks>
+ [OperationContract]
+ [WebInvoke(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
+ public void LogBatch(string[] urls)
+ {
+ DisableResponseCaching();
+
+ foreach (var url in urls)
+ {
+ Uri parsed = new Uri(OperationContext.Current.Channel.LocalAddress.Uri, url);
+ string methodName = parsed.Segments[parsed.Segments.Length - 1];
+ System.Reflection.MethodInfo method = this.GetType().GetMethod(methodName);
+ System.Reflection.ParameterInfo[] parameterInfos = method.GetParameters();
+ object[] parameters = new object[parameterInfos.Length];
+ System.Collections.Specialized.NameValueCollection query = System.Web.HttpUtility.ParseQueryString(parsed.Query);
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ object value = query[parameterInfos[i].Name];
+ parameters[i] = Convert.ChangeType(value, parameterInfos[i].ParameterType, System.Globalization.CultureInfo.InvariantCulture);
+ }
+
+ method.Invoke(this, parameters);
+ }
+ }
+
+ /// <remarks>This method is typically called by the test case.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public void LogTestStart(string testRunId, string name, DateTime startTime)
+ {
+ DisableResponseCaching();
+
+ TestRunContext context = GetTestRunContext(testRunId);
+ lock (context)
+ {
+ TestRun run = context.TestRun;
+ string prefixedName = context.TestNamePrefix + name;
+ Guid testId = Guid.NewGuid();
+ Guid executionId = Guid.NewGuid();
+ Guid testListId = run.TestLists.Single().Id;
+ run.TestDefinitions.Add(new TestDefinition()
+ {
+ Id = testId,
+ Name = prefixedName,
+ ExecutionId = executionId,
+ });
+ run.TestEntries.Add(new TestEntry()
+ {
+ TestId = testId,
+ ExecutionId = executionId,
+ TestListId = testListId
+ });
+ run.TestResults.Add(new TestResult()
+ {
+ ExecutionId = executionId,
+ TestId = testId,
+ TestListId = testListId,
+ TestName = prefixedName,
+ ComputerName = Environment.MachineName,
+ StartTime = startTime,
+ EndTime = startTime,
+ TestType = Guid.Parse("13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b"),
+ Outcome = InProgress,
+ // RelativeResultsDirectory?
+ });
+ }
+ }
+
+ /// <remarks>This method is typically called by the test case.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public void LogTestDone(string testRunId, string name, int failures, int total, DateTime endTime)
+ {
+ DisableResponseCaching();
+
+ TestRunContext context = GetTestRunContext(testRunId);
+ lock (context)
+ {
+ TestRun run = context.TestRun;
+ string prefixedName = context.TestNamePrefix + name;
+ TestResult result = run.TestResults.LastOrDefault(r => r.TestName == prefixedName);
+ if (failures > 0)
+ {
+ result.Outcome = Failed;
+ }
+ else
+ {
+ result.Outcome = Passed;
+ }
+
+ result.EndTime = endTime;
+ }
+ }
+
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public void MarkInProgress(string testRunId)
+ {
+ DisableResponseCaching();
+
+ TestRunContext context = GetTestRunContext(testRunId);
+ lock (context)
+ {
+ context.TestRun.ResultSummary.Outcome = InProgress;
+ }
+ }
+
+ /// <remarks>This method is typically called by the test harness.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public void SetTestNamePrefix(string testRunId, string prefix)
+ {
+ DisableResponseCaching();
+
+ TestRunContext context = GetTestRunContext(testRunId);
+ lock (context)
+ {
+ context.TestNamePrefix = prefix;
+ }
+ }
+
+ /// <remarks>This method is typically called by the test case.</remarks>
+ [OperationContract]
+ [WebGet(ResponseFormat = WebMessageFormat.Json)]
+ public string TestCompleted(string testRunId, int failures, int total)
+ {
+ DisableResponseCaching();
+
+ var context = GetTestRunContext(testRunId);
+ lock (context)
+ {
+ string result;
+ if (context.TestPages.Count == 0)
+ {
+ context.TestRun.ResultSummary.Outcome = Completed;
+ result = "";
+ }
+ else
+ {
+ result = context.TestPages[0];
+ context.TestPages.RemoveAt(0);
+ }
+
+ return result;
+ }
+ }
+
+ private static TestRunContext CreateTestRunContextWithId(Guid value)
+ {
+ TestRun run = new TestRun();
+ run.Id = value;
+ run.Name = "Test run";
+ run.TestTimes.Creation = DateTime.Now;
+ run.TestTimes.Queueing = DateTime.Now;
+ run.TestLists.Add(new TestList()
+ {
+ Name = "All Results",
+ Id = Guid.NewGuid()
+ });
+
+ // For the time being, set up a fake test settings.
+ run.TestSettings.Id = Guid.NewGuid();
+
+ run.ResultSummary.Outcome = InProgress;
+
+ TestRunContext context = new TestRunContext();
+ context.TestRun = run;
+
+ return context;
+ }
+
+ private static void DisableResponseCaching()
+ {
+ WebOperationContext.Current.OutgoingResponse.Headers[HttpResponseHeader.CacheControl] = "no-cache";
+ }
+
+ private static TestRunContext GetTestRunContext(string testRunId)
+ {
+ if (testRunId == null)
+ {
+ throw new ArgumentNullException("testRunId");
+ }
+
+ lock (testRuns)
+ {
+ // For an 0-filled GUID, allow create-on-demand to simplify ad-hoc testing.
+ // Something like:
+ // http://localhost:8989/tests/odata-qunit-tests.htm?testRunId=00000000-0000-0000-0000-000000000000
+ if (!testRuns.ContainsKey(testRunId))
+ {
+ Guid value = Guid.Parse(testRunId);
+ if (value == Guid.Empty)
+ {
+ TestRunContext context = CreateTestRunContextWithId(value);
+ testRuns.Add(testRunId, context);
+ }
+ }
+
+ return testRuns[testRunId];
+ }
+ }
+
+ private void CompleteTestRun(TestRun run)
+ {
+ run.TestTimes.Finish = DateTime.Now;
+
+ // Fill counts in result object.
+ var summary = run.ResultSummary;
+ summary.Executed = 0;
+ summary.Error = 0;
+ summary.Failed = 0;
+ summary.Timeout = 0;
+ summary.Aborted = 0;
+ summary.Inconclusive = 0;
+ summary.PassedButRunAborted = 0;
+ summary.NotRunnable = 0;
+ summary.NotExecuted = 0;
+ summary.Disconnected = 0;
+ summary.Warning = 0;
+ summary.Passed = 0;
+ summary.Completed = 0;
+ summary.InProgress = 0;
+ summary.Pending = 0;
+
+ foreach (var testResult in run.TestResults)
+ {
+ string outcome = testResult.Outcome;
+ switch (outcome)
+ {
+ case InProgress:
+ summary.Executed++;
+ summary.InProgress++;
+ break;
+ case Failed:
+ summary.Executed++;
+ summary.Completed++;
+ summary.Failed++;
+ break;
+ case Passed:
+ summary.Executed++;
+ summary.Completed++;
+ summary.Passed++;
+ break;
+ default:
+ summary.Failed++;
+ break;
+ }
+ }
+
+ summary.Total = run.TestResults.Count;
+
+ if (summary.Failed != 0)
+ {
+ summary.Outcome = Failed;
+ }
+ else if (summary.Total <= 0 || summary.Passed < summary.Total)
+ {
+ summary.Outcome = Inconclusive;
+ }
+ else
+ {
+ summary.Outcome = Passed;
+ }
+ }
+ }
+
+ public class TestRunContext
+ {
+ public TestRunContext()
+ {
+ this.TestPages = new List<string>();
+ }
+
+ public TestRun TestRun { get; set; }
+ public string TestNamePrefix { get; set; }
+ public List<string> TestPages { get; set; }
+ }
+
+ public class TestResultWriter
+ {
+ private const string TestNamespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010";
+
+ public static void WriteTestRun(TestRun run, string path)
+ {
+ if (run == null)
+ {
+ throw new ArgumentNullException("run");
+ }
+ if (path == null)
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ using (XmlWriter writer = XmlWriter.Create(path))
+ {
+ WriteTestRun(run, path);
+ }
+ }
+
+ public static void WriteTestRun(TestRun run, XmlWriter writer)
+ {
+ if (run == null)
+ {
+ throw new ArgumentNullException("run");
+ }
+ if (writer == null)
+ {
+ throw new ArgumentNullException("writer");
+ }
+
+ writer.WriteStartElement("TestRun", TestNamespace);
+ writer.WriteGuidIfPresent("id", run.Id);
+ writer.WriteAttributeString("name", run.Name);
+ writer.WriteAttributeString("runUser", run.RunUser);
+
+ WriteTestSettings(run.TestSettings, writer);
+ WriteResultSummary(run.ResultSummary, writer);
+
+ // Write test definitions.
+ writer.WriteStartElement("TestDefinitions", TestNamespace);
+ foreach (var definition in run.TestDefinitions)
+ {
+ WriteTestDefinition(definition, writer);
+ }
+
+ writer.WriteEndElement();
+
+ // Write test lists.
+ writer.WriteStartElement("TestLists", TestNamespace);
+ foreach (var list in run.TestLists)
+ {
+ WriteTestList(list, writer);
+ }
+
+ writer.WriteEndElement();
+
+ // Write test entries.
+ writer.WriteStartElement("TestEntries", TestNamespace);
+ foreach (var entry in run.TestEntries)
+ {
+ WriteTestEntry(entry, writer);
+ }
+
+ writer.WriteEndElement();
+
+ // Write test results.
+ writer.WriteStartElement("Results", TestNamespace);
+ foreach (var result in run.TestResults)
+ {
+ WriteTestResults(result, writer);
+ }
+
+ writer.WriteEndElement();
+
+ // Close the test run element.
+ writer.WriteEndElement();
+ }
+
+ private static void WriteTestResults(TestResult result, XmlWriter writer)
+ {
+ if (result == null)
+ {
+ throw new ArgumentNullException("result");
+ }
+
+ writer.WriteStartElement("UnitTestResult", TestNamespace);
+ writer.WriteGuidIfPresent("testId", result.TestId);
+ writer.WriteGuidIfPresent("testListId", result.TestListId);
+ writer.WriteGuidIfPresent("executionId", result.ExecutionId);
+ writer.WriteGuidIfPresent("RelativeResultsDirectory", result.RelativeResultsDirectory);
+
+ writer.WriteAttributeString("testName", result.TestName);
+ writer.WriteAttributeString("computerName", result.ComputerName);
+ writer.WriteAttributeString("duration", result.Duration.ToString());
+ writer.WriteAttributeString("startTime", XmlConvert.ToString(result.StartTime));
+ writer.WriteAttributeString("endTime", XmlConvert.ToString(result.EndTime));
+ writer.WriteAttributeString("outcome", result.Outcome);
+
+ writer.WriteGuidIfPresent("testType", result.TestType);
+
+ if (result.DebugTrace.Length > 0)
+ {
+ writer.WriteStartElement("Output");
+
+ writer.WriteStartElement("DebugTrace");
+ writer.WriteString(result.DebugTrace.ToString());
+ writer.WriteEndElement();
+
+ writer.WriteStartElement("ErrorInfo");
+ writer.WriteStartElement("Message");
+ writer.WriteString(result.ErrorMessages.ToString());
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+
+ writer.WriteEndElement();
+ }
+
+ writer.WriteEndElement();
+ }
+
+ private static void WriteTestEntry(TestEntry entry, XmlWriter writer)
+ {
+ if (entry == null)
+ {
+ throw new ArgumentNullException("entry");
+ }
+
+ writer.WriteStartElement("TestEntry", TestNamespace);
+ writer.WriteGuidIfPresent("testId", entry.TestId);
+ writer.WriteGuidIfPresent("testListId", entry.TestListId);
+ writer.WriteGuidIfPresent("executionId", entry.ExecutionId);
+ writer.WriteEndElement();
+ }
+
+ private static void WriteTestList(TestList list, XmlWriter writer)
+ {
+ if (list == null)
+ {
+ throw new ArgumentNullException("list");
+ }
+
+ writer.WriteStartElement("TestList", TestNamespace);
+ writer.WriteAttributeString("name", list.Name);
+ writer.WriteGuidIfPresent("id", list.Id);
+ writer.WriteEndElement();
+ }
+
+ private static void WriteTestDefinition(TestDefinition definition, XmlWriter writer)
+ {
+ if (definition == null)
+ {
+ throw new ArgumentNullException("definition");
+ }
+
+ writer.WriteStartElement("UnitTest", TestNamespace);
+ writer.WriteAttributeString("name", definition.Name);
+ writer.WriteAttributeString("storage", definition.Storage);
+ writer.WriteGuidIfPresent("id", definition.Id);
+
+ // There are more thing we could write here: DeploymentItems, Execution, TestMethod
+
+ // This is the minimum needed to load the test in the IDE.
+ writer.WriteStartElement("Execution", TestNamespace);
+ writer.WriteGuidIfPresent("id", definition.ExecutionId);
+ writer.WriteEndElement();
+
+ writer.WriteStartElement("TestMethod", TestNamespace);
+ writer.WriteAttributeString("codeBase", "fake-test-file.js");
+ writer.WriteAttributeString("adapterTypeName", "Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
+ writer.WriteAttributeString("className", "FakeClassName, TestLogging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
+ writer.WriteAttributeString("name", definition.Name);
+ writer.WriteEndElement();
+
+ writer.WriteEndElement();
+ }
+
+ private static void WriteResultSummary(ResultSummary resultSummary, XmlWriter writer)
+ {
+ if (resultSummary == null)
+ {
+ throw new ArgumentNullException("resultSummary");
+ }
+
+ writer.WriteStartElement("ResultSummary", TestNamespace);
+ writer.WriteAttributeString("outcome", resultSummary.Outcome);
+
+ writer.WriteStartElement("Counters", TestNamespace);
+
+ foreach (var p in typeof(ResultSummary).GetProperties())
+ {
+ if (p.PropertyType != typeof(int))
+ {
+ continue;
+ }
+
+ int value = (int)p.GetValue(resultSummary, null);
+ string attributeName = p.Name;
+ attributeName = attributeName.Substring(0, 1).ToLowerInvariant() + attributeName.Substring(1);
+ writer.WriteAttributeString(attributeName, value.ToString());
+ }
+
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ }
+
+ private static void WriteTestSettings(TestSettings testSettings, XmlWriter writer)
+ {
+ if (testSettings == null)
+ {
+ throw new ArgumentNullException("testSettings");
+ }
+
+ writer.WriteStartElement("TestSettings", TestNamespace);
+ writer.WriteAttributeString("name", testSettings.Name);
+ writer.WriteGuidIfPresent("id", testSettings.Id);
+ // There are more things we could write here.
+ writer.WriteEndElement();
+ }
+ }
+
+ public static class XmlWriterExtensions
+ {
+ public static void WriteGuidIfPresent(this XmlWriter writer, string attributeName, Guid value)
+ {
+ if (value != Guid.Empty)
+ {
+ writer.WriteAttributeString(attributeName, value.ToString());
+ }
+ }
+ }
+
+ public class TestRun
+ {
+ public TestRun()
+ {
+ this.TestDefinitions = new List<TestDefinition>();
+ this.TestLists = new List<TestList>();
+ this.TestEntries = new List<TestEntry>();
+ this.TestResults = new List<TestResult>();
+ this.ResultSummary = new ResultSummary();
+ this.TestTimes = new TestTimes();
+ this.TestSettings = new TestSettings();
+
+ this.Id = Guid.NewGuid();
+ this.RunUser = Environment.UserDomainName + "\\" + Environment.UserName;
+ }
+
+ public Guid Id { get; set; }
+ public string Name { get; set; }
+ public string RunUser { get; set; }
+ public TestSettings TestSettings { get; set; }
+ public TestTimes TestTimes { get; set; }
+ public ResultSummary ResultSummary { get; set; }
+ public List<TestDefinition> TestDefinitions { get; set; }
+ public List<TestList> TestLists { get; set; }
+ public List<TestEntry> TestEntries { get; set; }
+ public List<TestResult> TestResults { get; set; }
+ }
+
+ public class TestSettings
+ {
+ public Guid Id { get; set; }
+ public string Name { get; set; }
+ }
+
+ public class TestTimes
+ {
+ public DateTime Creation { get; set; }
+ public DateTime Queueing { get; set; }
+ public DateTime Start { get; set; }
+ public DateTime Finish { get; set; }
+ }
+
+ public class ResultSummary
+ {
+ public string Outcome { get; set; }
+ public int Total { get; set; }
+ public int Executed { get; set; }
+ public int Error { get; set; }
+ public int Failed { get; set; }
+ public int Timeout { get; set; }
+ public int Aborted { get; set; }
+ public int Inconclusive { get; set; }
+ public int PassedButRunAborted { get; set; }
+ public int NotRunnable { get; set; }
+ public int NotExecuted { get; set; }
+ public int Disconnected { get; set; }
+ public int Warning { get; set; }
+ public int Passed { get; set; }
+ public int Completed { get; set; }
+ public int InProgress { get; set; }
+ public int Pending { get; set; }
+ }
+
+ public class TestDefinition
+ {
+ public string Name { get; set; }
+ public string Storage { get; set; }
+ public Guid Id { get; set; }
+ public Guid ExecutionId { get; set; }
+ }
+
+ public class TestList
+ {
+ public string Name { get; set; }
+ public Guid Id { get; set; }
+ }
+
+ public class TestEntry
+ {
+ public Guid TestId { get; set; }
+ public Guid ExecutionId { get; set; }
+ public Guid TestListId { get; set; }
+ }
+
+ public class TestResult
+ {
+ public TestResult()
+ {
+ this.DebugTrace = new StringBuilder();
+ this.ErrorMessages = new StringBuilder();
+ }
+
+ public Guid ExecutionId { get; set; }
+ public Guid TestId { get; set; }
+ public string TestName { get; set; }
+ public string ComputerName { get; set; }
+ public TimeSpan Duration { get { return this.EndTime - this.StartTime; } }
+ public DateTime StartTime { get; set; }
+ public DateTime EndTime { get; set; }
+ public Guid TestType { get; set; }
+ public string Outcome { get; set; }
+ public Guid TestListId { get; set; }
+ public Guid RelativeResultsDirectory { get; set; }
+ public StringBuilder DebugTrace { get; set; }
+ public StringBuilder ErrorMessages { get; set; }
+ }
+
+ class TestRunXmlBodyWriter : BodyWriter
+ {
+ private readonly TestRun run;
+
+ public TestRunXmlBodyWriter(TestRun run)
+ : base(true)
+ {
+ this.run = run;
+ }
+
+ protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
+ {
+ TestResultWriter.WriteTestRun(this.run, writer);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/common/TestSynchronizerClient.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/common/TestSynchronizerClient.js b/odatajs/tests/common/TestSynchronizerClient.js
new file mode 100644
index 0000000..157654e
--- /dev/null
+++ b/odatajs/tests/common/TestSynchronizerClient.js
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+// TestSynchronizer Client
+// Use to log assert pass/fails and notify mstest a test has completed execution
+
+(function (window, undefined) {
+ var testRunId = "";
+ var serviceRoot = "./common/TestLogger.svc/";
+ var recording = null;
+ var recordingLength = 0;
+ var maxStringLength = 8192;
+ var maxPostLength = 2097152;
+
+ var callTestSynchronizer = function (methodName, parameterUrl) {
+ /** Invokes a function on the test synchronizer.
+ * @param {String} [partialUrl] -
+ * @returns {String} A response from the server, possibly null.
+
+ * If the recording variable is assigned, then the call is logged
+ * but nothing is invoked.
+ */
+
+
+ var partialUrl;
+ if (testRunId) {
+ partialUrl = methodName + "?testRunId=" + testRunId + "&" + parameterUrl;
+ }
+ else {
+ partialUrl = methodName + "?" + parameterUrl;
+ }
+
+ var url = serviceRoot + partialUrl;
+
+ if (recording) {
+ if (url.length > maxStringLength) {
+ url = url.substr(0, maxStringLength);
+ }
+
+ recordingLength += url.length;
+ if (recordingLength > maxPostLength) {
+ submitRecording();
+ recording = [];
+ recordingLength = url.length;
+ }
+
+ recording.push(url);
+ return null;
+ }
+
+ var xhr;
+ if (window.XMLHttpRequest) {
+ xhr = new window.XMLHttpRequest();
+ } else {
+ xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }
+
+ xhr.open("GET", url, false);
+ xhr.send();
+ return xhr.responseText;
+ };
+
+ var getLogPrefix = function (result) {
+ /** Returns the log prefix for a given result
+ * @param {Boolean} result - Whether the result is pass or fail. If null, the log line is assumed to be diagnostic
+ */
+ return "[" + getShortDate() + "] " + (result === true ? "[PASS] " : (result === false ? "[FAIL] " : ""));
+ };
+
+ var getShortDate = function () {
+ /** Returns the current date and time formatted as "yyyy-mm-dd hh:mm:ss.nnn".*/
+ var padToLength = function (number, length) {
+ var result = number + "";
+ var lengthDiff = length - result.length;
+ for (var i = 0; i < lengthDiff; i++) {
+ result = "0" + result;
+ }
+
+ return result;
+ }
+
+ var date = new Date();
+ var day = padToLength(date.getDate(), 2);
+ var month = padToLength(date.getMonth() + 1, 2);
+ var year = date.getFullYear();
+
+ var hours = padToLength(date.getHours(), 2);
+ var minutes = padToLength(date.getMinutes(), 2);
+ var seconds = padToLength(date.getSeconds(), 2);
+ var milliseconds = padToLength(date.getMilliseconds(), 3);
+
+ return year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds + "." + milliseconds;
+ };
+
+ var submitRecording = function () {
+ var body = { urls: recording };
+ postToUrl("LogBatch", body);
+ };
+
+ var postToUrl = function (methodName, body) {
+ /** POSTs body to the designated methodName.
+ */
+ var xhr;
+ if (window.XMLHttpRequest) {
+ xhr = new window.XMLHttpRequest();
+ } else {
+ xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }
+
+ var url = serviceRoot + methodName;
+ xhr.open("POST", url, false);
+ xhr.setRequestHeader("Content-Type", "application/json");
+ xhr.send(window.JSON.stringify(body));
+ if (xhr.status < 200 || xhr.status > 299) {
+ throw { message: "Unable to POST to url.\r\n" + xhr.responseText };
+ }
+
+ return xhr.responseText;
+ }
+
+ function LogAssert(result, message, name, expected, actual) {
+ var parameterUrl = "pass=" + result + "&message=" + encodeURIComponent(message) + "&name=" + encodeURIComponent(name);
+
+ if (!result) {
+ parameterUrl += "&actual=" + encodeURIComponent(actual) + "&expected=" + encodeURIComponent(expected);
+ }
+
+ callTestSynchronizer("LogAssert", parameterUrl);
+ }
+
+ function LogTestStart(name) {
+ callTestSynchronizer("LogTestStart", "name=" + encodeURIComponent(name) + "&startTime=" + encodeURIComponent(getShortDate()));
+ }
+
+ function LogTestDone(name, failures, total) {
+ callTestSynchronizer("LogTestDone", "name=" + encodeURIComponent(name) + "&failures=" + failures + "&total=" + total + "&endTime=" + encodeURIComponent(getShortDate()));
+ }
+
+ function TestCompleted(failures, total) {
+ return callTestSynchronizer("TestCompleted", "failures=" + failures + "&total=" + total);
+ }
+
+ var extractTestRunId = function () {
+ /** Extracts the testRunId value from the window query string.
+ * @returns {String} testRunId, possibly empty.
+ */
+ var i, len;
+ var uri = window.location.search;
+ if (uri) {
+ var parameters = uri.split("&");
+ for (i = 0, len = parameters.length; i < len; i++) {
+ var index = parameters[i].indexOf("testRunId=");
+ if (index >= 0) {
+ return parameters[i].substring(index + "testRunId=".length);
+ }
+ }
+ }
+
+ return "";
+ };
+
+ var init = function (qunit) {
+ /** Initializes the test logger synchronizer.
+ * @param qunit - Unit testing to hook into.
+ * If there is no testRunId present, the QUnit functions are left as they are.</remarks>
+ */
+ var logToConsole = function (context) {
+ if (window.console && window.console.log) {
+ window.console.log(context.result + ' :: ' + context.message);
+ }
+ };
+
+ testRunId = extractTestRunId();
+ if (!testRunId) {
+ qunit.log = logToConsole;
+ } else {
+ recording = [];
+ qunit.log = function (context) {
+ logToConsole(context);
+
+ var name = qunit.config.current.testName;
+ if (!(context.actual && context.expected)) {
+ context.actual = context.result;
+ context.expected = true;
+ }
+ LogAssert(context.result, getLogPrefix(context.result) + context.message, name, window.JSON.stringify(context.expected), window.JSON.stringify(context.actual));
+ };
+
+ qunit.testStart = function (context) {
+ LogTestStart(context.name);
+ };
+
+ qunit.testDone = function (context) {
+ LogTestDone(context.name, context.failed, context.total);
+ }
+
+ qunit.done = function (context) {
+ submitRecording();
+ recording = null;
+
+ var nextUrl = TestCompleted(context.failed, context.total);
+ nextUrl = JSON.parse(nextUrl).d;
+ if (nextUrl) {
+ window.location.href = nextUrl;
+ }
+ }
+ }
+ };
+
+ window.TestSynchronizer = {
+ init: init
+ };
+})(window);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/common/common.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/common/common.js b/odatajs/tests/common/common.js
new file mode 100644
index 0000000..8151fc1
--- /dev/null
+++ b/odatajs/tests/common/common.js
@@ -0,0 +1,25 @@
+/*
+ * 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) {
+ window.temp = window.odatajs;
+ window.temp.store = window.odatajs.store;
+ window.temp.cache = window.odatajs.cache;
+ window.odatajs = window.temp;
+ delete window.temp;
+})(this);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/common/djstest-browser.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/common/djstest-browser.js b/odatajs/tests/common/djstest-browser.js
new file mode 100644
index 0000000..366ca33
--- /dev/null
+++ b/odatajs/tests/common/djstest-browser.js
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+
+// Because this code contains a init function to be useable directly inside the browser as well as in nodejs
+// we define the @namespace djstest here instead of the a @module name djstest
+
+/** Create namespace djstest in window.djstest when this file is loaded as java script by the browser
+ * @namespace djstest
+ */
+
+
+var init = function init () {
+
+ var localDjstest = {};
+
+ // Initialize indexedDB if the window object is available
+ localDjstest.indexedDB = window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.indexedDB;
+
+ /** Cleans all the test data saved in the IndexedDb database.
+ * @param {Array} storeNames - Array of store objects with a property that is the name of the store
+ * @param {Function} done - Callback function
+ */
+ localDjstest.cleanStoreOnIndexedDb = function (storeObjects, done) {
+ var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || {};
+
+ function deleteObjectStores(db) {
+ for ( var i = 0 ; i < db.objectStoreNames.length ; i ++) {
+ db.deleteObjectStore(db.objectStoreNames[i]);
+ }
+ }
+ var job;
+
+ if (localDjstest.indexedDB) {
+ job = new djstest.Job();
+ for ( var i = 0 ; i < storeObjects.length ; i ++) {
+ storeObject = storeObjects[i];
+ job.queue((function (storeObject) {
+ return function (success, fail) {
+ var dbname = "_datajs_" + storeObject.name;
+ var request = localDjstest.indexedDB.open(dbname);
+ request.onsuccess = function (event) {
+ var db = request.result;
+
+ if ("setVersion" in db) {
+ var versionRequest = db.setVersion("0.1");
+ versionRequest.onsuccess = function (event) {
+ var transaction = versionRequest.transaction;
+ transaction.oncomplete = function () {
+ db.close();
+ success();
+ };
+ deleteObjectStores(db);
+ };
+ versionRequest.onerror = function (e) {
+ djstest.fail("Error on cleanup - code: " + e.code + " name: " + e.name + "message: " + message);
+ fail();
+ };
+ return;
+ }
+
+ // new api cleanup
+ db.close();
+ var deleteRequest = localDjstest.indexedDB.deleteDatabase(dbname);
+ deleteRequest.onsuccess = function (event) {
+ djstest.log("djstest indexeddb cleanup - deleted database " + dbname);
+ success();
+ };
+ deleteRequest.onerror = function (e) {
+ djstest.fail("djstest indexeddb cleanup - error deleting database " + dbname);
+ fail();
+ };
+ djstest.log("djstest indexeddb cleanup - requested deletion of database " + dbname);
+ };
+
+ request.onerror = function (e) {
+ djstest.fail(e.code + ": " + e.message);
+ };
+ };
+ })(storeObject));
+ }
+ }
+
+ if (job) {
+ job.run(function (succeeded) {
+ if (!succeeded) {
+ djstest.fail("cleanup job failed");
+ }
+ done();
+ });
+ }
+ else {
+ done();
+ }
+ };
+
+
+ // Disable caching to ensure that every test-related AJAX request is actually being sent,
+ // and set up a default error handler
+ if (typeof window !== undefined) {
+ $.ajaxSetup({
+ cache: false,
+ error: function (jqXHR, textStatus, errorThrown) {
+ // Work around bug in IE-Mobile on Windows Phone 7
+ if (jqXHR.status !== 1223) {
+ var err = {
+ status: jqXHR.status,
+ statusText: jqXHR.statusText,
+ responseText: jqXHR.responseText
+ };
+ djstest.fail("AJAX request failed with: " + djstest.toString(err));
+ }
+ djstest.done();
+ }
+ });
+ }
+ return localDjstest;
+};
+
+//export djstest
+
+if (typeof window !== 'undefined') {
+ //expose to browsers window object
+ if ( window.djstest === undefined) {
+ window.djstest = init();
+ } else {
+ var tmp = init();
+ $.extend( window.djstest,tmp);
+ }
+} else {
+ //expose in commonjs style
+ module.exports = init();
+}
+
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/common/djstest.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/common/djstest.js b/odatajs/tests/common/djstest.js
new file mode 100644
index 0000000..5dda9ff
--- /dev/null
+++ b/odatajs/tests/common/djstest.js
@@ -0,0 +1,419 @@
+/*
+ * 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.
+ */
+
+
+// Because this code contains a init function to be useable directly inside the browser as well as in nodejs
+// we define the @namespace djstest here instead of the a @module name djstest
+
+/** Create namespace djstest in window.djstest when this file is loaded as java script by the browser
+ * @namespace djstest
+ */
+
+
+var init = function init () {
+ var djstest = {};
+
+
+ /** Constructs a Job object that allows for enqueuing and synchronizing the execution of functions.
+ * @class Job
+ * @constructor
+ * @returns {Object} Job object
+ */
+ djstest.Job = function () {
+
+ var currentTask = -1;
+ var tasks = [];
+
+ var failedTasks = 0;
+
+ /** Adds a function to the job queue regardless if the queue is already executing or not.
+ * @method djstest.Job#queue
+ * @param {Function} fn - Function to execute.
+ */
+ this.queue = function (fn) {
+
+ tasks.push(fn);
+ };
+
+ /** Adds a function to the front of the job queue regardless if the queue is already executing or not.
+ * @method djstest.Job#queueNext
+ * @param {Function} fn - Function to execute.
+ */
+ this.queueNext = function (fn) {
+
+ if (currentTask < 0) {
+ tasks.unshift(fn);
+ } else {
+ tasks.splice(currentTask + 1, 0, fn);
+ }
+ };
+
+ /** Starts the execution of this job.
+ * @method djstest.Job#run
+ * @param {Function} done - Callback invoked when the job has finished executing all of its enqueued tasks.
+ */
+ this.run = function (done) {
+ /// This method does nothing if called on a unit of work that is already executing.
+ if (currentTask >= 0) {
+ return;
+ }
+
+ if (tasks.length === 0) {
+ done(true);
+ return;
+ }
+
+ /**
+ * @method djstest.Job~makeTaskDoneCallBack
+ */
+ function makeTaskDoneCallBack(failed) {
+ return function () {
+ // Track the failed task and continue the execution of the job.
+ if (failed) {
+ failedTasks++;
+ }
+ currentTask++;
+ if (currentTask === tasks.length) {
+ done(failedTasks === 0);
+ } else {
+ runNextTask();
+ }
+ };
+ }
+
+ /** Executes the next function in the queue.
+ * @method djstest.Job~runNextTask
+ */
+ function runNextTask() {
+ defer(function () {
+ try {
+ tasks[currentTask](makeTaskDoneCallBack(false), makeTaskDoneCallBack(true));
+ } catch (e) {
+ makeTaskDoneCallBack(true)();
+ }
+ });
+ }
+
+ currentTask = 0;
+ runNextTask();
+ };
+ };
+
+ /** Defers the execution of an arbitrary function that takes no parameters.
+ * @memberof djstest
+ * @inner
+ * @param {Function} fn - Function to schedule for later execution.
+ */
+ function defer(fn) {
+ setTimeout(fn, 0);
+ }
+
+ /** Exposes date values for Date objects to facilitate debugging
+ * @memberof djstest
+ * @inner
+ * @param {Object} data - The object to operate on
+ */
+ function exposeDateValues(data) {
+
+ if (typeof data === "object") {
+ if (data instanceof Date) {
+ data.__date__ = data.toUTCString();
+ }
+ else {
+ for (var prop in data) {
+ exposeDateValues(data[prop]);
+ }
+ }
+ }
+
+ return data;
+ }
+
+ /** Determines the name of a function.
+ * @memberof djstest
+ * @inner
+ * @param {String} text - Function text.
+ * @returns {String} The name of the function from text if found; the original text otherwise.
+ */
+ function extractFunctionName(text) {
+
+ var index = text.indexOf("function ");
+ if (index < 0) {
+ return text;
+ }
+
+ var nameStart = index + "function ".length;
+ var parensIndex = text.indexOf("(", nameStart);
+ if (parensIndex < 0) {
+ return text;
+ }
+
+ var result = text.substr(nameStart, parensIndex - nameStart);
+ if (result.indexOf("test") === 0) {
+ result = result.substr("test".length);
+ }
+
+ return result;
+ }
+
+ /** Removes metadata annotations from the specified object.
+ * @memberof djstest
+ * @inner
+ * @param data - Object to remove metadata from; possibly null.
+ */
+ function removeMetadata(data) {
+
+ if (typeof data === "object" && data !== null) {
+ delete data.__metadata;
+ for (var prop in data) {
+ removeMetadata(data[prop]);
+ }
+ }
+ }
+
+ /** Add the unit test cases
+ * @param disable - Indicate whether this test case should be disabled
+ */
+ djstest.addFullTest = function (disable, fn, name, arg, timeout) {
+
+ if (disable !== true) {
+ djstest.addTest(fn, name, arg, timeout);
+ }
+ };
+
+ /** Add the unit test cases
+ * @param disable - Indicate whether this test case should be disabled
+ */
+ djstest.addTest = function (fn, name, arg, timeout) {
+ if (!name) {
+ name = extractFunctionName(fn.toString());
+ }
+
+ test(name, function () {
+ if (!timeout) {
+ timeout = 20000;
+ }
+
+ QUnit.config.testTimeout = timeout;
+ QUnit.stop();
+ fn.call(this, arg);
+ });
+ };
+
+ /** Asserts that a condition is true.
+ * @param {Boolean} test - Condition to test.
+ * @param {String} message - Text message for condition being tested.
+ */
+ djstest.assert = function (test, message) {
+
+ QUnit.ok(test, message);
+ };
+
+ /** Asserts that the values of the expected and actualobjects are equal.
+ * @memberof djstest
+ * @inner
+ */
+ djstest.assertAreEqual = function (actual, expected, message) {
+ QUnit.equal(actual, expected, message);
+ };
+
+ /** Asserts that the actual and expected objects are the same.
+ */
+ djstest.assertAreEqualDeep = function (actual, expected, message) {
+ QUnit.deepEqual(exposeDateValues(actual), exposeDateValues(expected), message);
+ };
+
+ /** Asserts that the actual and expected objects are the same but removes the metadata bevore
+ */
+ djstest.assertWithoutMetadata = function (actual, expected, message) {
+ removeMetadata(actual);
+ removeMetadata(expected);
+ djstest.assertAreEqualDeep(actual, expected, message);
+ };
+
+ /** Calls each async action in asyncActions, passing each action a function which keeps a count and
+ * calls the passed done function when all async actions complete
+ * @param {Array} asyncActions -Array of asynchronous actions to be executed,
+ * each taking a single parameter - the callback function to call when the action is done.</param>
+ * @param {Function} done - Function to be executed in the last async action to complete.
+ */
+ djstest.asyncDo = function (asyncActions, done) {
+
+ var count = 0;
+ var doneOne = function () {
+ count++;
+ if (count >= asyncActions.length) {
+ done();
+ }
+ };
+
+ if (asyncActions.length > 0) {
+ for ( var i = 0; i < asyncActions.length; i++) {
+ asyncActions[i](doneOne);
+ }
+ } else {
+ done();
+ }
+ };
+
+ /** Makes a deep copy of an object.
+ */
+ djstest.clone = function (object) {
+ if ( object === undefined ) {
+ return undefined;
+ } else if (object === null) {
+ return null;
+ } else if (typeof(object) !== 'object') {
+ return object;
+ } else {
+ var ret = {};
+ for(var key in object) {
+ if(object.hasOwnProperty(key)) {
+ ret[key] = this.clone(object[key]);
+ }
+ }
+ return ret;
+ }
+ throw("Error cloning an object");
+ };
+
+ /** Destroys the cache and then completes the test
+ * @param cache - The cache to destroy
+ */
+ djstest.destroyCacheAndDone = function (cache) {
+
+ cache.clear().then(function () {
+ djstest.done();
+ }, function (err) {
+ djstest.fail("Failed to destroy cache: " + djstest.toString(err));
+ djstest.done();
+ });
+ };
+
+ /** Indicates that the currently running test has finished.
+ */
+ djstest.done = function () {
+
+ QUnit.start();
+ };
+
+ /** Test passes if and only if an exception is thrown.
+ */
+ djstest.expectException = function (testFunction, message) {
+
+ try {
+ testFunction();
+ djstest.fail("Expected exception but function succeeded: " + " " + message);
+ }
+ catch (e) {
+ // Swallow exception.
+ djstest.pass("Thrown exception expected");
+ }
+ };
+
+ /** Indicates the expected number of asserts, fails test if number is not met.
+ * @param {Number} asserts - Number of asserts expected in test.
+ */
+ djstest.assertsExpected = function (asserts) {
+
+ expect(asserts);
+ };
+ /** Marks the current test as failed.
+ * @param {String} message - Failure message.
+ */
+ djstest.fail = function (message) {
+
+ QUnit.ok(false, message);
+ };
+
+ /** Returns a function that when invoked will fail this test and be done with it.
+ * @param {String} message - Failure message.
+ * @param {Function} [cleanupCallback] -
+ * @returns {Function} A new function.
+ */
+ djstest.failAndDoneCallback = function (message, cleanupCallback) {
+
+ return function (err) {
+ message = "" + message + (err) ? JSON.stringify(err) : "";
+ djstest.fail(message);
+ if (cleanupCallback) {
+ try {
+ cleanupCallback();
+ } catch (e) {
+ djstest.fail("error during cleanupCallback: " + JSON.stringify(e));
+ }
+ }
+
+ djstest.done();
+ };
+ };
+
+ /** Logs a test message.
+ * @param {String} message - Test message.
+ */
+ djstest.log = function (message) {
+
+ var context = { result: true, actual: true, expected: true, message: message };
+ QUnit.log(context);
+ };
+
+ /** Marks the current test as failed.
+ * @param {String} message - Failure message.
+ */
+ djstest.pass = function (message) {
+ QUnit.ok(true, message);
+ };
+
+ /** Dumps the object as a string
+ * @param {Object} obj - Object to dump
+ */
+ djstest.toString = function (obj) {
+
+ return QUnit.jsDump.parse(obj);
+ };
+
+ /** Executes the function, pausing test execution until the callback is called
+ * @param {Function} fn - Function to execute; takes one parameter which is the callback
+ * This function is typically used in asynchronous setup/teardown methods</remarks>
+ */
+ djstest.wait = function (fn) {
+ QUnit.stop();
+ fn(function () {
+ QUnit.start();
+ });
+ };
+
+ return djstest;
+};
+
+//export djstest
+
+if (typeof window !== 'undefined') {
+ //expose to browsers window object
+ if ( window.djstest === undefined) {
+ window.djstest = init();
+ } else {
+ var tmp = init();
+ $.extend( window.djstest,tmp);
+ }
+} else {
+ //expose in commonjs style
+ module.exports = init();
+}
+
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/common/mockHttpClient.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/common/mockHttpClient.js b/odatajs/tests/common/mockHttpClient.js
new file mode 100644
index 0000000..f5b2bd0
--- /dev/null
+++ b/odatajs/tests/common/mockHttpClient.js
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+//mockHttpClient.js
+//this object allows for associating a uri with a requestVerfier and mock responses that will be sent back to the client of the httpStack.
+//It can be used to replace OData's httpClient for testing purposes.
+//
+//RequestVerifiers
+//
+// A request verifier is a function associated to a particular URI that will be executed by the mockHttpClient when it receives a request with the matching URI.
+// the callback receives as its only parameter the request object passed to the mockHttpClient.
+//
+// To register a request verifier, simply do
+//
+// MockHttpClient.addRequestVerifier("http://someUri", function(request) {
+// djstest.assertAreEqual(request.requestUri,"http://someUri");
+// }
+//
+//Responses
+// Mock responses can be associated with a particular URI. When the MockHttpClient receives a request with a URI mapped to a response, then it will,
+// depending on the response status code invoke either the success or the error callbacks.
+//
+// To register a response,
+//
+// MockHttpClient.addResponse("http://someUri", {status: 200, body:"some body"});
+//
+//Exceptions
+// MockHttpClient will throw an exception if it receives a request to a URI that is not mapped to either a request verifier or a response.
+//
+
+function init(window, undefined) {
+
+ var httpClient = {};
+
+ var responses = {};
+ var requestVerifiers = {};
+
+ httpClient.addRequestVerifier = function (uri, verifier) {
+ requestVerifiers[uri] = verifier;
+ return this;
+ };
+
+ httpClient.addResponse = function (uri, response) {
+ responses[uri] = response;
+ return this;
+ };
+
+ httpClient.async = false;
+
+ httpClient.clear = function () {
+ /** Clears all registered responses and verifiers.
+ * @returns this client
+ */
+ responses = {};
+ requestVerifiers = {};
+ this.async = false;
+ return this;
+ };
+
+ httpClient.request = function (request, success, error) {
+ var uri = request.requestUri;
+ var verifier = requestVerifiers[uri];
+ var response = responses[uri];
+
+ if (verifier === undefined) {
+ verifier = requestVerifiers["*"];
+ }
+
+ if (response === undefined) {
+ response = responses["*"];
+ }
+
+ if (!verifier && !response) {
+ throw { message: "neither verifier or response defined for uri: " + uri };
+ }
+
+ if (verifier) {
+ verifier(request);
+ }
+
+ if (response) {
+ response.requestUri = uri;
+ if (response.statusCode >= 200 && response.statusCode <= 299) {
+ if (this.async) {
+ setTimeout(function () {
+ success(response);
+ });
+ } else {
+ success(response);
+ }
+ } else {
+ if (this.async) {
+ setTimeout(function () {
+ error({ message: "failed test response", request: request, response: response });
+ });
+ }
+ else {
+ error({ message: "failed test response", request: request, response: response });
+ }
+ }
+ }
+ };
+
+ httpClient.setAsync = function (value) {
+ this.async = value;
+ return this;
+ };
+
+ return httpClient;
+}
+
+
+
+if (typeof window !== 'undefined') {
+ //in browser call init() directly window as context
+ window.MockHttpClient = init(window);
+} else {
+ //expose function init to be called with a custom context
+ module.exports.init = init;
+}
+
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/d5ec5557/odatajs/tests/common/mockXMLHttpRequest.js
----------------------------------------------------------------------
diff --git a/odatajs/tests/common/mockXMLHttpRequest.js b/odatajs/tests/common/mockXMLHttpRequest.js
new file mode 100644
index 0000000..fdd6026
--- /dev/null
+++ b/odatajs/tests/common/mockXMLHttpRequest.js
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+ // mockXMLHttpRequest.js
+//
+// This file provides a window.MockXMLHttpRequest object that can be used
+// to replace or wrap the browser's XMLHttpRequest object for testing.
+//
+// Typically the object is installed, a test run, and then the original
+// object restored. The addResponse and addRequest verifier can be
+// used to set up callbacks; reset is used to clear those values.
+//
+// For a sample demonstrating how to use this functionality, see
+// the httpClientSendRequestTest test in odata-net-tests.js.
+
+(function (window, undefined) {
+
+ if (!window.MockXMLHttpRequest) {
+ window.MockXMLHttpRequest = {};
+ }
+
+ var mockXMLHttpRequest = window.MockXMLHttpRequest;
+
+ var responses = {};
+ var verifiers = {};
+
+ mockXMLHttpRequest.addResponse = function (uri, response) {
+ /** Adds a new response to be returned for the specified uri (* for 'anything').
+ * @param {String} uri - URI to match (* to match anything not otherwise specified).
+ * @param {Object} response - Response object.
+ */
+ responses = responses || {};
+ responses[uri] = response;
+
+ return this;
+ };
+
+ mockXMLHttpRequest.addRequestVerifier = function (uri, verifier) {
+ /** Adds a new request verifier to be invoked for the specified uri (* for 'anything').
+ * @param {String} uri - URI to match (* to match anything not otherwise specified).
+ * @param {Function} response - Verifier callback that takes the request.
+ */
+ verifiers = verifiers || {};
+ verifiers[uri] = verifier;
+
+ return this;
+ };
+
+ mockXMLHttpRequest.reset = function () {
+ /** Resets all configuration from the mock XHR object.
+ */
+
+ responses = {};
+ verifiers = {};
+
+ mockXMLHttpRequest.onCreate = undefined;
+ mockXMLHttpRequest.onAfterSend = undefined;
+
+ return this;
+ };
+
+ var xmlHttpRequest = function () {
+ //properties
+ this.readyState = 0;
+ this.responseXML = undefined;
+
+ //events
+ this.ontimeout = undefined;
+ this.onreadystatechange = undefined;
+
+ if (mockXMLHttpRequest.onCreate) {
+ mockXMLHttpRequest.onCreate(this);
+ }
+ };
+
+ xmlHttpRequest.prototype.open = function (method, url, async, user, password) {
+ if (!method) {
+ throw { method: "method parameter is not defined, empty, or null " };
+ }
+ if (!url) {
+ throw { message: "url parameter is not defined, empty, or null " };
+ }
+
+ this._request = {
+ headers: {},
+ url: url,
+ method: method,
+ async: async,
+ user: user,
+ password: password
+ };
+ };
+
+ xmlHttpRequest.prototype.getAllResponseHeaders = function () {
+ if (!this._response) {
+ throw { message: "_response property is undefined, did you forget to call send() or map the request url to a response?" };
+ }
+
+ var result = "";
+ var header;
+ for (header in this._response.headers) {
+ result = result + header + ": " + this._response.headers[header] + "\n\r";
+ }
+ //remove trailing LFCR
+ return result.substring(0, result.length - 2);
+ };
+
+ xmlHttpRequest.prototype.getResponseHeader = function (header) {
+ if (!this._response) {
+ throw { message: "_response property is undefined, did you forget to call send() or map the request url to a response?" };
+ }
+ return this._response.headers[header];
+ };
+
+ xmlHttpRequest.prototype.abort = function () {
+ //do nothing for now.
+ };
+
+ xmlHttpRequest.prototype.setRequestHeader = function (header, value) {
+ if (!this._request) {
+ throw { message: "_request property is undefined, did you forget to call open() first?" };
+ }
+ this._request.headers[header] = value;
+ };
+
+ xmlHttpRequest.prototype.send = function (data) {
+ if (!this._request) {
+ throw { message: "_request property is undefined, did you forget to call open() first?" };
+ }
+
+ if (this._request.headers["MockNoOp"]) {
+ return;
+ }
+
+ if (this._request.headers["MockTimeOut"]) {
+ if (!this.timeout) {
+ throw { message: "timeout property is not set" };
+ }
+
+ if (this.ontimeout) {
+ (function (xhr) {
+ setTimeout(function () {
+ xhr.ontimeout();
+ }, xhr.timeout);
+ })(this);
+ }
+ return;
+ }
+
+ var url = this._request.url;
+ var verifier = verifiers[url];
+ var response = responses[url];
+
+ if (!verifier) {
+ verifier = verifiers["*"];
+ }
+
+ if (!response) {
+ response = responses["*"];
+ }
+
+ if (!verifier && !response) {
+ throw { message: "neither verifier or response defined for url: " + url };
+ }
+
+ this._request.body = data;
+
+ if (verifier) {
+ verifier(this._request);
+ }
+
+ if (response) {
+ // Execute the respone after a 30ms delay.
+ this._response = response;
+ sendResponseDelay(this, response, 60);
+ }
+ };
+
+ var sendResponseDelay = function (xhr, response, delay) {
+ setTimeout(function () {
+ xhr.status = response.status;
+ xhr.responseText = response.body;
+ xhr.responseBody = response.body;
+
+ xhr.readyState = 4;
+ if (xhr.onreadystatechange) {
+ xhr.onreadystatechange();
+ if (mockXMLHttpRequest.onAfterSend) {
+ mockXMLHttpRequest.onAfterSend();
+ }
+ }
+ }, delay);
+ };
+
+ mockXMLHttpRequest.XMLHttpRequest = xmlHttpRequest;
+
+})(this);