1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 var shellCommand = 'shell\n';
6 var catCommand = 'cat\n';
7 var catErrCommand = 'cat 1>&2\n';
9 // Ensure this has all distinct characters.
10 var testLine = 'abcdefgh\n';
12 var startCharacter = '#';
14 var croshName = 'crosh';
15 var invalidName = 'some name';
17 var invalidNameError = 'Invalid process name.';
20 var testProcessTotal = 2;
22 var testProcessCount = 0;
23 var testProcesses = [];
25 function TestProcess(pid, type) {
29 this.lineExpectation_ = '';
30 this.linesLeftToCheck_ = -1;
31 // We receive two streams from the process.
32 this.checkedStreamEnd_ = [0, 0];
35 this.startCharactersFound_ = 0;
36 this.started_ = false;
39 // Method to test validity of received input. We will receive two streams of
40 // the same data. (input will be echoed twice by the testing process). Each
41 // stream will contain the same string repeated |kTestLineNum| times. So we
42 // have to match 2 * |kTestLineNum| lines. The problem is the received lines
43 // from different streams may be interleaved (e.g. we may receive
44 // abc|abcdef|defgh|gh). To deal with that, we allow to test received text
45 // against two lines. The lines MUST NOT have two same characters for this
47 TestProcess.prototype.testExpectation = function(text) {
48 chrome.test.assertTrue(this.linesLeftToCheck_ >= 0,
49 "Test expectations not set.")
50 for (var i = 0; i < text.length; i++) {
51 if (this.processReceivedCharacter_(text[i], 0))
53 if (this.processReceivedCharacter_(text[i], 1))
55 chrome.test.fail("Received: " + text);
59 TestProcess.prototype.processReceivedCharacter_ = function(char, stream) {
60 if (this.checkedStreamEnd_[stream] >= this.lineExpectation_.length)
63 var expectedChar = this.lineExpectation_[this.checkedStreamEnd_[stream]];
64 if (expectedChar != char)
67 this.checkedStreamEnd_[stream]++;
69 if (this.checkedStreamEnd_[stream] == this.lineExpectation_.length &&
70 this.linesLeftToCheck_ > 0) {
71 this.checkedStreamEnd_[stream] = 0;
72 this.linesLeftToCheck_--;
77 TestProcess.prototype.testOutputType = function(receivedType) {
78 if (receivedType == 'exit')
79 chrome.test.assertTrue(this.done());
81 chrome.test.assertEq('stdout', receivedType);
84 TestProcess.prototype.pid = function() {
88 TestProcess.prototype.started = function() {
92 TestProcess.prototype.done = function() {
93 return this.checkedStreamEnd_[0] == this.lineExpectation_.length &&
94 this.checkedStreamEnd_[1] == this.lineExpectation_.length &&
95 this.linesLeftToCheck_ == 0;
98 TestProcess.prototype.isClosed = function() {
102 TestProcess.prototype.setClosed = function() {
106 TestProcess.prototype.canStart = function() {
107 return (this.startCharactersFound_ == 2);
110 TestProcess.prototype.startCharacterFound = function() {
111 this.startCharactersFound_++;
114 TestProcess.prototype.getCatCommand = function() {
115 if (this.type_ == "stdout")
117 return catErrCommand;
120 TestProcess.prototype.addLineExpectation = function(line, times) {
121 this.lineExpectation_ = line.replace(/\n/g, "\r\n");
122 this.linesLeftToCheck_ = times - 2;
125 // Set of commands we use to setup terminal for testing (start cat) will produce
126 // some output. We don't care about that output, to avoid having to set that
127 // output in test expectations, we will send |startCharacter| right after cat is
128 // started. After we detect second |startCharacter|s in output, we know process
129 // won't produce any output by itself, so it is safe to start actual test.
130 TestProcess.prototype.maybeKickOffTest = function(text) {
132 while (index != -1) {
133 index = text.indexOf(startCharacter, index);
135 this.startCharacterFound();
136 if (this.canStart()) {
137 this.kickOffTest_(testLine, testLineNum);
145 TestProcess.prototype.kickOffTest_ = function(line, lineNum) {
146 this.started_ = true;
147 // Each line will be echoed twice.
148 this.addLineExpectation(line, lineNum * 2);
150 for (var i = 0; i < lineNum; i++)
151 chrome.terminalPrivate.sendInput(this.pid_, line,
153 chrome.test.assertTrue(result);
159 function getProcessIndexForPid(pid) {
160 for (var i = 0; i < testProcessTotal; i++) {
161 if (testProcesses[i] && pid == testProcesses[i].pid())
167 function processOutputListener(pid, type, text) {
168 var processIndex = getProcessIndexForPid(pid);
169 if (processIndex == undefined)
172 var process = testProcesses[processIndex];
174 if (!process.started()) {
175 process.maybeKickOffTest(text);
179 process.testOutputType(type);
181 process.testExpectation(text);
184 closeTerminal(processIndex);
187 function maybeEndTest() {
188 for (var i = 0; i < testProcessTotal; i++) {
189 if (!testProcesses[i] || !testProcesses[i].isClosed())
193 chrome.test.succeed();
196 function closeTerminal(index) {
197 var process = testProcesses[index];
198 chrome.terminalPrivate.closeTerminalProcess(
201 chrome.test.assertTrue(result);
208 function initTest(process) {
209 var sendStartCharacter = function() {
210 chrome.terminalPrivate.sendInput(
212 startCharacter + '\n',
214 chrome.test.assertTrue(result);
219 var startCat = function() {
220 chrome.terminalPrivate.sendInput(
222 process.getCatCommand(),
224 chrome.test.assertTrue(result);
225 sendStartCharacter();
230 chrome.terminalPrivate.sendInput(
234 chrome.test.assertTrue(result);
240 chrome.test.runTests([
241 function terminalTest() {
242 chrome.terminalPrivate.onProcessOutput.addListener(processOutputListener);
244 for (var i = 0; i < testProcessTotal; i++) {
245 chrome.terminalPrivate.openTerminalProcess(croshName, function(result) {
246 chrome.test.assertTrue(result >= 0);
247 var type = (testProcessCount % 2) ? 'stderr' : 'stdout';
248 var newProcess = new TestProcess(result, type);
249 testProcesses[testProcessCount] = newProcess;
251 initTest(newProcess);
256 function invalidProcessNameTest() {
257 chrome.terminalPrivate.openTerminalProcess(invalidName,
258 chrome.test.callbackFail(invalidNameError));