| <!-- |
| /* |
| * 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. |
| */ |
| --> |
| <job> |
| <runtime> |
| <description>Test driver for running datajs tests - run from the same directory as the script</description> |
| <comment> |
| Result codes: |
| 0 - success |
| 1 - failed to launch tests |
| 2 - tests failed |
| </comment> |
| </runtime> |
| <script language="JScript" src="test-list.js" /> |
| <script language="JScript"> |
| |
| var exitCode; |
| var fso = WScript.CreateObject("Scripting.FileSystemObject"); |
| var shell = WScript.CreateObject("WScript.Shell"); |
| |
| function attempt(action, interval, maxAttempts) { |
| /// <summary>Attempt an action at an interval, optionally for a maximum number of attempts</summary> |
| /// <param name="action">Action callback; should return boolean whether it succeeded</param> |
| /// <param name="interval">Interval (milliseconds) between attempts</param> |
| /// <param name="maxAttempts">(Optional) Maximum number of attempts. Infinite if undefined.</param> |
| /// <returns>Whether the action succeeded</returns> |
| var done = false; |
| var attempts = 0; |
| while (!done) { |
| var success = action(); |
| if (maxAttempts !== undefined) { |
| attempts++; |
| } |
| done = success === true || (maxAttempts !== undefined && attempts >= maxAttempts); |
| if (!done) { |
| WScript.Sleep(interval); |
| } |
| } |
| |
| return success; |
| } |
| |
| function parseJson(text) { |
| /// <summary>Parses a JSON document, removes the 'd' wrapper.</summary> |
| try { |
| return eval("(" + text + ")").d; |
| } catch (e) { |
| throw { message: "Error parsing JSON: [" + text + "]" }; |
| } |
| } |
| |
| function SaveTextToFile(content, path) { |
| /// <summary>Saves text content into a file.</summary> |
| /// <param name="content" type="String">Content to save.</param> |
| /// <param name="path" type="String">Path of file to save into.</param> |
| var ForReading = 1, ForWriting = 2; |
| var file = fso.OpenTextFile(path, ForWriting, true, -1 /* open as unicode */); |
| file.Write(content); |
| file.Close(); |
| } |
| |
| function GetUrlSync(url) { |
| var xhr; |
| xhr = WScript.CreateObject("Msxml2.ServerXMLHTTP.6.0"); |
| xhr.open("GET", url, false); |
| xhr.send(); |
| return xhr.responseText; |
| } |
| |
| function LaunchBrowser(browsers, serviceRoot, followingPages, url, testRunId, outputDirectory) { |
| /// <summary>Launches a browsers and waits until the service tells us the run is complete.</summary> |
| /// <param name="browsers">Browsers to run.</param> |
| /// <param name="serviceRoot" type="String">Root URL of the logging service.</param> |
| /// <param name="followingPages" type="Array">Array of pages that should follow the given url.</param> |
| /// <param name="url" type="String">URL of the page to start the browser on.</param> |
| /// <param name="testRunId" type="String">ID of the test run being monitored.</param> |
| /// <param name="outputDirectory" type="String">Directory in which to output screenshots.</param> |
| |
| for (browserName in browsers) { |
| var xhr; |
| var markInProgressUrl = serviceRoot + "MarkInProgress?testRunId=" + testRunId; |
| GetUrlSync(markInProgressUrl); |
| |
| // Add all the pages that follow the given URL. |
| if (followingPages && followingPages.length > 0) { |
| var addFilesUrl = serviceRoot + "AddTestPages?testRunId=" + testRunId + "&pages=" + followingPages.join(); |
| GetUrlSync(addFilesUrl); |
| } |
| |
| var setPrefixUrl = serviceRoot + "SetTestNamePrefix?testRunId=" + testRunId + "&prefix=" + browserName + "-"; |
| GetUrlSync(setPrefixUrl); |
| |
| exitCode = 0; |
| var response; |
| |
| // Only the first location found from the browsers array is used. If none of the listed locations of the browser exist and the browser argument was |
| // explicitly used then an exception is thrown. |
| var browserFound = false; |
| for (var i = 0; i < browsers[browserName].length && !browserFound; i++) { |
| var path = shell.ExpandEnvironmentStrings(browsers[browserName][i]); |
| if (fso.FileExists(path)) { |
| browserFound = true; |
| |
| WScript.Echo("Navigating to " + url + " with " + path); |
| var browser = shell.Exec("\"" + path + "\" " + url); |
| |
| var checkRunUrl = serviceRoot + "IsTestRunInProgress?testRunId=" + testRunId; |
| WScript.Echo("Monitoring status on " + checkRunUrl); |
| |
| var interval = 2000; |
| var maxAttempts = WScript.Arguments.Named.Exists("timeout") ? Math.floor((WScript.Arguments.Named.Item("timeout") / interval) * 1000) : undefined; |
| var success = attempt(function () { |
| return parseJson(GetUrlSync(checkRunUrl)) !== true; |
| }, interval, maxAttempts); |
| if (!success) { |
| WScript.Echo("Timed out waiting for test to complete"); |
| exitCode = 2; |
| } |
| |
| RunCommand("taskkill.exe /pid " + browser.ProcessID, true); |
| } |
| } |
| |
| // If the "/browsers" argument was explicitly used and all location have been checked, then throw an exception. |
| if (!browserFound) { |
| var message = "Unable to find browser at: " + path; |
| if (WScript.Arguments.Named.Exists("browsers")) { |
| throw { message: message }; |
| } else { |
| WScript.Echo(message); |
| } |
| } |
| } |
| } |
| |
| function WriteTestRunResults(serviceRoot, testRunId, outputDirectory) { |
| /// <summary>Writes the results of the test run to disk and updates the overall status.</summary> |
| /// <param name="serviceRoot" type="String">Root URL of the logging service.</param> |
| /// <param name="testRunId" type="String">ID of the test run being monitored.</param> |
| /// <param name="outputDirectory" type="String">Directory in which to write test result files.</param> |
| |
| var getResultsUrl = serviceRoot + "GetTestRunResults?testRunId=" + testRunId; |
| WScript.Echo("Querying " + getResultsUrl); |
| |
| var response = GetUrlSync(getResultsUrl); |
| |
| var resultsPath = outputDirectory + "\\results.trx"; |
| WScript.Echo("Writing results.trx file to " + resultsPath); |
| SaveTextToFile(response, resultsPath); |
| |
| var xml = new ActiveXObject("Msxml2.DOMDocument.6.0"); |
| xml.loadXML(response); |
| xml.setProperty("SelectionNamespaces", "xmlns:trx='http://microsoft.com/schemas/VisualStudio/TeamTest/2010'"); |
| xml.setProperty("SelectionLanguage", "XPath"); |
| var resultNode = xml.selectSingleNode("/trx:TestRun/trx:ResultSummary"); |
| if (resultNode === null) { |
| throw { message: "Unable to find results summary" }; |
| } |
| |
| var outcome = resultNode.getAttribute("outcome"); |
| if (outcome !== "Passed") { |
| WScript.Echo("Outcome: " + outcome); |
| var failedTests = xml.selectNodes("/trx:TestRun/trx:Results/trx:UnitTestResult[@outcome != 'Passed']/@testName"); |
| for (var i = 0; i < failedTests.length; i++) { |
| WScript.Echo(" Failed test: " + failedTests[i].value); |
| } |
| exitCode = 2; |
| } else { |
| WScript.Echo("All tests passed."); |
| } |
| } |
| |
| function CheckUrl(url) { |
| var xhr = WScript.CreateObject("Msxml2.ServerXMLHTTP.6.0"); |
| xhr.open("GET", url, false); |
| var success = false; |
| try { |
| xhr.send(); |
| success = (xhr.status === 200); |
| if (!success) { |
| WScript.Echo("status: " + xhr.status + " - " + xhr.statusText); |
| } |
| } catch (err) { |
| WScript.Echo("error: " + err.message); |
| } |
| |
| return success; |
| } |
| |
| function ExpandWildcard(path) { |
| var wcRegEx = /\\\*\*?\\/; |
| var wcMatch = wcRegEx.exec(path); |
| |
| var paths = []; |
| if (wcMatch !== null) { |
| var recursive = wcMatch[0] === "\\**\\"; |
| var basePath = path.substring(0, wcMatch.index); |
| var relativePath = path.substring(wcMatch.index + wcMatch[0].length); |
| |
| if (fso.FolderExists(basePath)) { |
| var folder = fso.GetFolder(basePath); |
| var subFolders = new Enumerator(folder.SubFolders); |
| |
| paths = paths.concat(ExpandWildcard(basePath + "\\" + relativePath)); |
| |
| for (; !subFolders.atEnd(); subFolders.moveNext()) { |
| var expandedPath = subFolders.item().Path + "\\" |
| if (recursive) { |
| expandedPath += "**\\"; |
| } |
| expandedPath += path.substring(wcMatch.index + wcMatch[0].length); |
| paths = paths.concat(ExpandWildcard(expandedPath)); |
| } |
| } |
| } else { |
| paths.push(path); |
| } |
| return paths; |
| } |
| |
| function FindFirstPath(candidates) { |
| /// <summary>Finds the first path present from a candidate list.</summary> |
| /// <param name="candidates" type="Array">Array of paths (possibly with environment variables).</param> |
| /// <returns type="String">The first folder on disk found; null if none are present.</returns> |
| |
| var paths = []; |
| |
| for (var i = 0; i < candidates.length; i++) { |
| var path = shell.ExpandEnvironmentStrings(candidates[i]); |
| paths = paths.concat(ExpandWildcard(path)); |
| } |
| |
| for (var i = 0; i < paths.length; i++) { |
| if (fso.FolderExists(paths[i]) || fso.FileExists(paths[i])) { |
| return paths[i]; |
| } |
| } |
| return null; |
| } |
| |
| function RunCommand(command, waitForExit, expectedExitCode) { |
| /// <summary>Runs a command or program</summary> |
| /// <param name="command" type="String">Command to run</param> |
| /// <param name="waitForExit" type="Boolean">Whether to wait for program to exit</param> |
| /// <param name="expectedExitCode" type="Integer">If waitForExit is true, throw if the exit code is not expected</param> |
| /// <returns type="Integer">The exitcode if waitForExit is true; always 0 if waitForExit is false</returns> |
| WScript.Echo("[cmd] " + command); |
| var exitCode = shell.Run(command, 0, waitForExit); |
| if (expectedExitCode !== undefined && exitCode !== expectedExitCode) { |
| throw { message: "Process exited with unexpected exit code. (Expected: " + expectedExitCode + ", Actual: " + exitCode + ")" }; |
| } else { |
| return exitCode; |
| } |
| } |
| |
| function SetupWebDevServer() { |
| /// <summary>Starts up IIS Express if it's not running.</summary> |
| /// <returns type="String">The URL to the server root.</returns> |
| var siteName = "DataJS Development Site"; |
| var appName = "datajs"; |
| var port = "8989"; |
| var result = "http://" + shell.ExpandEnvironmentStrings("%COMPUTERNAME%").toLowerCase() + ":" + port + "/" + appName + "/"; |
| var url = result + "tests/common/TestLogger.svc"; |
| |
| var success = CheckUrl(url); |
| |
| if (!success) { |
| // Assume that we need to launch this. |
| var src = fso.GetAbsolutePathName(".."); |
| |
| var folder = FindFirstPath([ |
| "%ProgramFiles(x86)%\\IIS Express", |
| "%ProgramFiles%\\IIS Express"]); |
| |
| if (!folder) { |
| throw { message: "Unable to find path to IIS Express" }; |
| } |
| |
| var appCmd = "\"" + folder + "\\appcmd.exe\""; |
| var iisExpress = "\"" + folder + "\\iisexpress.exe\""; |
| |
| // Delete site if it already exists |
| WScript.Echo("Checking if site '" + siteName + "' already exists..."); |
| if (RunCommand(appCmd + " list site \"" + siteName + "\"", true) === 0) { |
| WScript.Echo("Deleting existing site '" + siteName + "'..."); |
| RunCommand(appCmd + " delete site \"" + siteName + "\"", true, 0); |
| } |
| |
| // Create site and app |
| WScript.Echo("Creating site '" + siteName + "'..."); |
| RunCommand(appCmd + " add site /name:\"" + siteName + "\" /bindings:http/*:" + port + ": /physicalPath:%IIS_BIN%\\AppServer\\empty_wwwroot", true, 0); |
| |
| WScript.Echo("Creating application '" + appName + "'..."); |
| RunCommand(appCmd + " add app /site.name:\"" + siteName + "\" /path:\"/" + appName + "\" /physicalPath:\"" + src + "\"", true, 0); |
| |
| // Start the server |
| WScript.Echo("Starting IIS Express server..."); |
| RunCommand(iisExpress + " /site:\"" + siteName + "\" /trace:error"); |
| |
| WScript.Sleep(2 * 1000); |
| success = attempt(function () { |
| WScript.Echo("Waiting for server to come up, looking for " + url + " ..."); |
| return CheckUrl(url); |
| }, 5 * 1000, 3); |
| |
| if (!success) { |
| throw { message: "Unable to verify the URL at " + url }; |
| } |
| } |
| return result; |
| } |
| |
| function CreateTestRunId(serviceRoot) { |
| /// <summary>Creates a new test run ID from the service.</summary> |
| /// <param name="serviceRoot" type="String">Root of logger service.</param> |
| /// <returns type="String">The test run ID created.</returns> |
| var xhr = WScript.CreateObject("Msxml2.ServerXMLHTTP.6.0"); |
| var url = serviceRoot + "CreateTestRun"; |
| xhr.open("GET", url, false); |
| WScript.Echo("URL: " + url); |
| xhr.send(); |
| |
| var response = xhr.responseText; |
| var result = parseJson(response); |
| return result; |
| } |
| |
| function GetBrowsers() { |
| /// <summary>Gets the browsers that should be used for running the tests.</summary> |
| /// <returns type="Object">Dictionary object containing the browser and its executable path as key value pairs.</returns> |
| var localAppData = fso.FolderExists(shell.ExpandEnvironmentStrings("%LOCALAPPDATA%")) ? "%LOCALAPPDATA%" : "%USERPROFILE%\\Local Settings\\Application Data"; |
| var programFiles = fso.FolderExists(shell.ExpandEnvironmentStrings("%ProgramFiles(x86)%")) ? "%ProgramFiles(x86)%" : "%ProgramFiles%"; |
| var browsers = { |
| IE8: [programFiles + "\\Internet Explorer\\iexplore.exe"], |
| Firefox4: [programFiles + "\\Mozilla Firefox\\firefox.exe"], |
| Chrome: [programFiles + "\\Google\\Chrome\\Application\\chrome.exe", localAppData + "\\Google\\Chrome\\Application\\chrome.exe"], |
| Safari5: [programFiles + "\\Safari\\safari.exe"], |
| Opera: [programFiles + "\\Opera\\opera.exe"] |
| }; |
| |
| var browsersToRun = {}; |
| |
| if (WScript.Arguments.Named.Exists("browsers")) { |
| browserNames = WScript.Arguments.Named.Item("browsers").split(','); |
| for (i in browserNames) { |
| var browserName = browserNames[i]; |
| if (browsers[browserName]) { |
| browsersToRun[browserName] = browsers[browserName]; |
| } else { |
| throw { message: "Unknown browser: " + browserName }; |
| } |
| } |
| } |
| else { |
| browsersToRun = browsers; |
| } |
| |
| return browsersToRun; |
| } |
| |
| function GetTestFilesList() { |
| /// <summary>Gets the list of test files that are going to be executed in the test run.</summary> |
| /// <returns type="Array">The list of test files.</returns> |
| var testFilesList = null; |
| if (WScript.Arguments.Named.Exists("testFiles")) { |
| testFilesList = WScript.Arguments.Named.Item("testFiles").split(','); |
| } |
| |
| if (testFilesList === null) { |
| testFilesList = getAllTestFiles(); |
| } |
| |
| WScript.Echo("Test files to be executed: " + testFilesList.toString()); |
| return testFilesList; |
| } |
| |
| function GetOutputDirectory() { |
| /// <summary>Gets the test run output directory.</summary> |
| /// <returns type="String">Output directory.</returns> |
| var result; |
| if (WScript.Arguments.Named.Exists("outputDirectory")) { |
| result = WScript.Arguments.Named.Item("outputDirectory"); |
| } else { |
| result = shell.ExpandEnvironmentStrings("%DJSOUT%\\JSLib.sln\\tests"); |
| } |
| |
| |
| return result; |
| } |
| |
| try { |
| var root = SetupWebDevServer(); |
| var serviceRoot = root + "tests/common/TestLogger.svc/"; |
| var testRunId = CreateTestRunId(serviceRoot); |
| WScript.Echo("Test Run ID: " + testRunId); |
| |
| var testFilesList = GetTestFilesList(); |
| var browsers = GetBrowsers(); |
| var outputDirectory = GetOutputDirectory(); |
| |
| if (testFilesList.length > 0) { |
| var url = root + "tests/" + testFilesList[0] + "?testRunId=" + testRunId; |
| LaunchBrowser(browsers, serviceRoot, testFilesList.splice(1, testFilesList.length), url, testRunId, outputDirectory); |
| WriteTestRunResults(serviceRoot, testRunId, outputDirectory); |
| } |
| else { |
| WScript.Echo("No test files specified to run."); |
| } |
| } catch (e) { |
| WScript.Echo("Error running tests"); |
| for (var p in e) WScript.Echo(p + ": " + e[p]); |
| exitCode = 1; |
| } |
| |
| WScript.Quit(exitCode); |
| |
| </script> |
| </job> |