blob: 768417df8ff9e32bda9e79d3680d1d05edf9f294 [file] [log] [blame]
#!/usr/bin/python2
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for the EC-3PO Console interface."""
from __future__ import print_function
import binascii
# pylint: disable=cros-logging-import
import logging
import mock
import multiprocessing
import tempfile
import unittest
import console
import interpreter
ESC_STRING = chr(console.ControlKey.ESC)
class Keys(object):
"""A class that contains the escape sequences for special keys."""
LEFT_ARROW = [console.ControlKey.ESC, ord('['), ord('D')]
RIGHT_ARROW = [console.ControlKey.ESC, ord('['), ord('C')]
UP_ARROW = [console.ControlKey.ESC, ord('['), ord('A')]
DOWN_ARROW = [console.ControlKey.ESC, ord('['), ord('B')]
HOME = [console.ControlKey.ESC, ord('['), ord('1'), ord('~')]
END = [console.ControlKey.ESC, ord('['), ord('8'), ord('~')]
DEL = [console.ControlKey.ESC, ord('['), ord('3'), ord('~')]
class OutputStream(object):
"""A class that has methods which return common console output."""
@staticmethod
def MoveCursorLeft(count):
"""Produces what would be printed to the console if the cursor moved left.
Args:
count: An integer representing how many columns to move left.
Returns:
string: A string which contains what would be printed to the console if
the cursor moved left.
"""
string = ESC_STRING
string += '[' + str(count) + 'D'
return string
@staticmethod
def MoveCursorRight(count):
"""Produces what would be printed to the console if the cursor moved right.
Args:
count: An integer representing how many columns to move right.
Returns:
string: A string which contains what would be printed to the console if
the cursor moved right.
"""
string = ESC_STRING
string += '[' + str(count) + 'C'
return string
BACKSPACE_STRING = ''
# Move cursor left 1 column.
BACKSPACE_STRING += OutputStream.MoveCursorLeft(1)
# Write a space.
BACKSPACE_STRING += ' '
# Move cursor left 1 column.
BACKSPACE_STRING += OutputStream.MoveCursorLeft(1)
def StringToByteList(string):
"""Converts a string to list of bytes.
Args:
string: A literal string to turn into a list of bytes.
Returns:
A list of integers representing the byte value of each character in the
string.
"""
return [ord(c) for c in string]
def BadConsoleOutput(expected, got):
"""Format the console output into readable text.
Args:
expected: A list of bytes representing the expected output console
stream.
got: A list of byte representing the actual output console stream.
Returns:
string: A formatted string which shows the expected console output stream
and the actual console output stream.
"""
esc_state = 0
string = 'Incorrect console output stream.\n'
string += 'exp: |'
count = 0
for char in expected:
if esc_state != 0:
if esc_state == console.EscState.ESC_START:
if char == '[':
esc_state = console.EscState.ESC_BRACKET
elif esc_state == console.EscState.ESC_BRACKET:
if char == 'D':
string += '[cursor left ' + str(count) + ' cols]'
esc_state = 0
elif char == 'C':
string += '[cursor right ' + str(count) + ' cols]'
esc_state = 0
else:
count = int(char)
# Print if it's printable.
elif console.IsPrintable(ord(char)):
string += char
else:
# It might be a sequence of some type.
if ord(char) == console.ControlKey.ESC:
# Need to look at the following sequence.
esc_state = console.EscState.ESC_START
else:
string += '{' + binascii.hexlify(char) + '}'
string += '|\n\ngot: |'
for char in got:
if esc_state != 0:
if esc_state == console.EscState.ESC_START:
if char == '[':
esc_state = console.EscState.ESC_BRACKET
elif esc_state == console.EscState.ESC_BRACKET:
if char == 'D':
string += '[cursor left ' + str(count) + ' cols]'
esc_state = 0
elif char == 'C':
string += '[cursor right ' + str(count) + ' cols]'
esc_state = 0
else:
count = int(char)
# Print if it's printable.
elif console.IsPrintable(ord(char)):
string += char
else:
# It might be a sequence of some type.
if ord(char) == console.ControlKey.ESC:
# Need to look at the following sequence.
esc_state = console.EscState.ESC_START
else:
string += '{' + binascii.hexlify(char) + '}'
string += '|\n\n'
# TODO(aaboagye): It would be nice to replace all those move left 1, ' ',
# move left 1, with backspace.
return string
def CheckConsoleOutput(test_case, exp_console_out):
"""Verify what was sent out the console matches what we expect.
Args:
test_case: A unittest.TestCase object representing the current unit test.
exp_console_out: A string representing the console output stream.
"""
# Read what was sent out the console.
test_case.tempfile.seek(0)
console_out = test_case.tempfile.read()
test_case.assertEqual(exp_console_out,
console_out,
(BadConsoleOutput(exp_console_out, console_out)
+ str(test_case.console)))
def CheckInputBuffer(test_case, exp_input_buffer):
"""Verify that the input buffer contains what we expect.
Args:
test_case: A unittest.TestCase object representing the current unit test.
exp_input_buffer: A string containing the contents of the current input
buffer.
"""
test_case.assertEqual(exp_input_buffer, test_case.console.input_buffer,
('input buffer does not match expected.\n'
'expected: |' + exp_input_buffer + '|\n'
'got: |' + test_case.console.input_buffer +
'|\n' + str(test_case.console)))
def CheckInputBufferPosition(test_case, exp_pos):
"""Verify the input buffer position.
Args:
test_case: A unittest.TestCase object representing the current unit test.
exp_pos: An integer representing the expected input buffer position.
"""
test_case.assertEqual(exp_pos, test_case.console.input_buffer_pos,
'input buffer position is incorrect.\ngot: ' +
str(test_case.console.input_buffer_pos) + '\nexp: ' +
str(exp_pos) + '\n' + str(test_case.console))
def CheckHistoryBuffer(test_case, exp_history):
"""Verify that the items in the history buffer are what we expect.
Args:
test_case: A unittest.TestCase object representing the current unit test.
exp_history: A list of strings representing the expected contents of the
history buffer.
"""
# First, check to see if the length is what we expect.
test_case.assertEqual(len(exp_history), len(test_case.console.history),
('The number of items in the history is unexpected.\n'
'exp: ' + str(len(exp_history)) + '\n'
'got: ' + str(len(test_case.console.history)) + '\n'
'internal state:\n' + str(test_case.console)))
# Next, check the actual contents of the history buffer.
for i in range(len(exp_history)):
test_case.assertEqual(exp_history[i], test_case.console.history[i],
('history buffer contents are incorrect.\n'
'exp: ' + exp_history[i] + '\n'
'got: ' + test_case.console.history[i] + '\n'
'internal state:\n' + str(test_case.console)))
class TestConsoleEditingMethods(unittest.TestCase):
"""Test case to verify all console editing methods."""
def setUp(self):
"""Setup the test harness."""
# Setup logging with a timestamp, the module, and the log level.
logging.basicConfig(level=logging.DEBUG,
format=('%(asctime)s - %(module)s -'
' %(levelname)s - %(message)s'))
# Create a temp file and set both the master and slave PTYs to the file to
# create a loopback.
self.tempfile = tempfile.TemporaryFile()
# Create some dummy pipes. These won't be used since we'll mock out sends
# to the interpreter.
dummy_pipe_end_0, dummy_pipe_end_1 = multiprocessing.Pipe()
self.console = console.Console(self.tempfile.fileno(), self.tempfile,
dummy_pipe_end_0, dummy_pipe_end_1)
# Console editing methods are only valid for enhanced EC images, therefore
# we have to assume that the "EC" we're talking to is enhanced. By default,
# the console believes that the EC it's communicating with is NOT enhanced
# which is why we have to override it here.
self.console.enhanced_ec = True
self.console.CheckForEnhancedECImage = mock.MagicMock(return_value=True)
# Mock out sends to the interpreter.
multiprocessing.Pipe.send = mock.MagicMock()
def test_EnteringChars(self):
"""Verify that characters are echoed onto the console."""
test_str = 'abc'
input_stream = StringToByteList(test_str)
# Send the characters in.
for byte in input_stream:
self.console.HandleChar(byte)
# Check the input position.
exp_pos = len(test_str)
CheckInputBufferPosition(self, exp_pos)
# Verify that the input buffer is correct.
expected_buffer = test_str
CheckInputBuffer(self, expected_buffer)
# Check console output
exp_console_out = test_str
CheckConsoleOutput(self, exp_console_out)
def test_EnteringDeletingMoreCharsThanEntered(self):
"""Verify that we can press backspace more than we have entered chars."""
test_str = 'spamspam'
input_stream = StringToByteList(test_str)
# Send the characters in.
for byte in input_stream:
self.console.HandleChar(byte)
# Now backspace 1 more than what we sent.
input_stream = []
for _ in range(len(test_str) + 1):
input_stream.append(console.ControlKey.BACKSPACE)
# Send that sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# First, verify that input buffer position is 0.
CheckInputBufferPosition(self, 0)
# Next, examine the output stream for the correct sequence.
exp_console_out = test_str
for _ in range(len(test_str)):
exp_console_out += BACKSPACE_STRING
# Now, verify that we got what we expected.
CheckConsoleOutput(self, exp_console_out)
def test_EnteringMoreThanCharLimit(self):
"""Verify that we drop characters when the line is too long."""
test_str = self.console.line_limit * 'o' # All allowed.
test_str += 5 * 'x' # All should be dropped.
input_stream = StringToByteList(test_str)
# Send the characters in.
for byte in input_stream:
self.console.HandleChar(byte)
# First, we expect that input buffer position should be equal to the line
# limit.
exp_pos = self.console.line_limit
CheckInputBufferPosition(self, exp_pos)
# The input buffer should only hold until the line limit.
exp_buffer = test_str[0:self.console.line_limit]
CheckInputBuffer(self, exp_buffer)
# Lastly, check that the extra characters are not printed.
exp_console_out = exp_buffer
CheckConsoleOutput(self, exp_console_out)
def test_ValidKeysOnLongLine(self):
"""Verify that we can still press valid keys if the line is too long."""
# Fill the line.
test_str = self.console.line_limit * 'o'
exp_console_out = test_str
# Try to fill it even more; these should all be dropped.
test_str += 5 * 'x'
input_stream = StringToByteList(test_str)
# We should be able to press the following keys:
# - Backspace
# - Arrow Keys/CTRL+B/CTRL+F/CTRL+P/CTRL+N
# - Delete
# - Home/CTRL+A
# - End/CTRL+E
# - Carriage Return
# Backspace 1 character
input_stream.append(console.ControlKey.BACKSPACE)
exp_console_out += BACKSPACE_STRING
# Refill the line.
input_stream.extend(StringToByteList('o'))
exp_console_out += 'o'
# Left arrow key.
input_stream.extend(Keys.LEFT_ARROW)
exp_console_out += OutputStream.MoveCursorLeft(1)
# Right arrow key.
input_stream.extend(Keys.RIGHT_ARROW)
exp_console_out += OutputStream.MoveCursorRight(1)
# CTRL+B
input_stream.append(console.ControlKey.CTRL_B)
exp_console_out += OutputStream.MoveCursorLeft(1)
# CTRL+F
input_stream.append(console.ControlKey.CTRL_F)
exp_console_out += OutputStream.MoveCursorRight(1)
# Let's press enter now so we can test up and down.
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
exp_console_out += '\r\n' + self.console.prompt
# Up arrow key.
input_stream.extend(Keys.UP_ARROW)
exp_console_out += test_str[:self.console.line_limit]
# Down arrow key.
input_stream.extend(Keys.DOWN_ARROW)
# Since the line was blank, we have to backspace the entire line.
exp_console_out += self.console.line_limit * BACKSPACE_STRING
# CTRL+P
input_stream.append(console.ControlKey.CTRL_P)
exp_console_out += test_str[:self.console.line_limit]
# CTRL+N
input_stream.append(console.ControlKey.CTRL_N)
# Since the line was blank, we have to backspace the entire line.
exp_console_out += self.console.line_limit * BACKSPACE_STRING
# Press the Up arrow key to reprint the long line.
input_stream.extend(Keys.UP_ARROW)
exp_console_out += test_str[:self.console.line_limit]
# Press the Home key to jump to the beginning of the line.
input_stream.extend(Keys.HOME)
exp_console_out += OutputStream.MoveCursorLeft(self.console.line_limit)
# Press the End key to jump to the end of the line.
input_stream.extend(Keys.END)
exp_console_out += OutputStream.MoveCursorRight(self.console.line_limit)
# Press CTRL+A to jump to the beginning of the line.
input_stream.append(console.ControlKey.CTRL_A)
exp_console_out += OutputStream.MoveCursorLeft(self.console.line_limit)
# Press CTRL+E to jump to the end of the line.
input_stream.extend(Keys.END)
exp_console_out += OutputStream.MoveCursorRight(self.console.line_limit)
# Move left one column so we can delete a character.
input_stream.extend(Keys.LEFT_ARROW)
exp_console_out += OutputStream.MoveCursorLeft(1)
# Press the delete key.
input_stream.extend(Keys.DEL)
# This should look like a space, and then move cursor left 1 column since
# we're at the end of line.
exp_console_out += ' ' + OutputStream.MoveCursorLeft(1)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify everything happened correctly.
CheckConsoleOutput(self, exp_console_out)
def test_BackspaceOnEmptyLine(self):
"""Verify that we can backspace on an empty line with no bad effects."""
# Send a single backspace.
test_str = [console.ControlKey.BACKSPACE]
# Send the characters in.
for byte in test_str:
self.console.HandleChar(byte)
# Check the input position.
exp_pos = 0
CheckInputBufferPosition(self, exp_pos)
# Check that buffer is empty.
exp_input_buffer = ''
CheckInputBuffer(self, exp_input_buffer)
# Check that the console output is empty.
exp_console_out = ''
CheckConsoleOutput(self, exp_console_out)
def test_BackspaceWithinLine(self):
"""Verify that we shift the chars over when backspacing within a line."""
# Misspell 'help'
test_str = 'heelp'
input_stream = StringToByteList(test_str)
# Use the arrow key to go back to fix it.
# Move cursor left 1 column.
input_stream.extend(2*Keys.LEFT_ARROW)
# Backspace once to remove the extra 'e'.
input_stream.append(console.ControlKey.BACKSPACE)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify the input buffer
exp_input_buffer = 'help'
CheckInputBuffer(self, exp_input_buffer)
# Verify the input buffer position. It should be at 2 (cursor over the 'l')
CheckInputBufferPosition(self, 2)
# We expect the console output to be the test string, with two moves to the
# left, another move left, and then the rest of the line followed by a
# space.
exp_console_out = test_str
exp_console_out += 2 * OutputStream.MoveCursorLeft(1)
# Move cursor left 1 column.
exp_console_out += OutputStream.MoveCursorLeft(1)
# Rest of the line and a space. (test_str in this case)
exp_console_out += 'lp '
# Reset the cursor 2 + 1 to the left.
exp_console_out += OutputStream.MoveCursorLeft(3)
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
def test_JumpToBeginningOfLineViaCtrlA(self):
"""Verify that we can jump to the beginning of a line with Ctrl+A."""
# Enter some chars and press CTRL+A
test_str = 'abc'
input_stream = StringToByteList(test_str) + [console.ControlKey.CTRL_A]
# Send the characters in.
for byte in input_stream:
self.console.HandleChar(byte)
# We expect to see our test string followed by a move cursor left.
exp_console_out = test_str
exp_console_out += OutputStream.MoveCursorLeft(len(test_str))
# Check to see what whas printed on the console.
CheckConsoleOutput(self, exp_console_out)
# Check that the input buffer position is now 0.
CheckInputBufferPosition(self, 0)
# Check input buffer still contains our test string.
CheckInputBuffer(self, test_str)
def test_JumpToBeginningOfLineViaHomeKey(self):
"""Jump to beginning of line via HOME key."""
test_str = 'version'
input_stream = StringToByteList(test_str)
input_stream.extend(Keys.HOME)
# Send out the stream.
for byte in input_stream:
self.console.HandleChar(byte)
# First, verify that input buffer position is now 0.
CheckInputBufferPosition(self, 0)
# Next, verify that the input buffer did not change.
CheckInputBuffer(self, test_str)
# Lastly, check that the cursor moved correctly.
exp_console_out = test_str
exp_console_out += OutputStream.MoveCursorLeft(len(test_str))
CheckConsoleOutput(self, exp_console_out)
def test_JumpToEndOfLineViaEndKey(self):
"""Jump to the end of the line using the END key."""
test_str = 'version'
input_stream = StringToByteList(test_str)
input_stream += [console.ControlKey.CTRL_A]
# Now, jump to the end of the line.
input_stream.extend(Keys.END)
# Send out the stream.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify that the input buffer position is correct. This should be at the
# end of the test string.
CheckInputBufferPosition(self, len(test_str))
# The expected output should be the test string, followed by a jump to the
# beginning of the line, and lastly a jump to the end of the line.
exp_console_out = test_str
exp_console_out += OutputStream.MoveCursorLeft(len(test_str))
# Now the jump back to the end of the line.
exp_console_out += OutputStream.MoveCursorRight(len(test_str))
# Verify console output stream.
CheckConsoleOutput(self, exp_console_out)
def test_JumpToEndOfLineViaCtrlE(self):
"""Enter some chars and then try to jump to the end. (Should be a no-op)"""
test_str = 'sysinfo'
input_stream = StringToByteList(test_str)
input_stream.append(console.ControlKey.CTRL_E)
# Send out the stream
for byte in input_stream:
self.console.HandleChar(byte)
# Verify that the input buffer position isn't any further than we expect.
# At this point, the position should be at the end of the test string.
CheckInputBufferPosition(self, len(test_str))
# Now, let's try to jump to the beginning and then jump back to the end.
input_stream = [console.ControlKey.CTRL_A, console.ControlKey.CTRL_E]
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Perform the same verification.
CheckInputBufferPosition(self, len(test_str))
# Lastly try to jump again, beyond the end.
input_stream = [console.ControlKey.CTRL_E]
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Perform the same verification.
CheckInputBufferPosition(self, len(test_str))
# We expect to see the test string, a jump to the beginning of the line, and
# one jump to the end of the line.
exp_console_out = test_str
# Jump to beginning.
exp_console_out += OutputStream.MoveCursorLeft(len(test_str))
# Jump back to end.
exp_console_out += OutputStream.MoveCursorRight(len(test_str))
# Verify the console output.
CheckConsoleOutput(self, exp_console_out)
def test_MoveLeftWithArrowKey(self):
"""Move cursor left one column with arrow key."""
test_str = 'tastyspam'
input_stream = StringToByteList(test_str)
input_stream.extend(Keys.LEFT_ARROW)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify that the input buffer position is 1 less than the length.
CheckInputBufferPosition(self, len(test_str) - 1)
# Also, verify that the input buffer is not modified.
CheckInputBuffer(self, test_str)
# We expect the test string, followed by a one column move left.
exp_console_out = test_str + OutputStream.MoveCursorLeft(1)
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
def test_MoveLeftWithCtrlB(self):
"""Move cursor back one column with Ctrl+B."""
test_str = 'tastyspam'
input_stream = StringToByteList(test_str)
input_stream.append(console.ControlKey.CTRL_B)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify that the input buffer position is 1 less than the length.
CheckInputBufferPosition(self, len(test_str) - 1)
# Also, verify that the input buffer is not modified.
CheckInputBuffer(self, test_str)
# We expect the test string, followed by a one column move left.
exp_console_out = test_str + OutputStream.MoveCursorLeft(1)
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
def test_MoveRightWithArrowKey(self):
"""Move cursor one column to the right with the arrow key."""
test_str = 'version'
input_stream = StringToByteList(test_str)
# Jump to beginning of line.
input_stream.append(console.ControlKey.CTRL_A)
# Press right arrow key.
input_stream.extend(Keys.RIGHT_ARROW)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify that the input buffer position is 1.
CheckInputBufferPosition(self, 1)
# Also, verify that the input buffer is not modified.
CheckInputBuffer(self, test_str)
# We expect the test string, followed by a jump to the beginning of the
# line, and finally a move right 1.
exp_console_out = test_str + OutputStream.MoveCursorLeft(len((test_str)))
# A move right 1 column.
exp_console_out += OutputStream.MoveCursorRight(1)
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
def test_MoveRightWithCtrlF(self):
"""Move cursor forward one column with Ctrl+F."""
test_str = 'panicinfo'
input_stream = StringToByteList(test_str)
input_stream.append(console.ControlKey.CTRL_A)
# Now, move right one column.
input_stream.append(console.ControlKey.CTRL_F)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify that the input buffer position is 1.
CheckInputBufferPosition(self, 1)
# Also, verify that the input buffer is not modified.
CheckInputBuffer(self, test_str)
# We expect the test string, followed by a jump to the beginning of the
# line, and finally a move right 1.
exp_console_out = test_str + OutputStream.MoveCursorLeft(len((test_str)))
# A move right 1 column.
exp_console_out += OutputStream.MoveCursorRight(1)
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
def test_ImpossibleMoveLeftWithArrowKey(self):
"""Verify that we can't move left at the beginning of the line."""
# We shouldn't be able to move left if we're at the beginning of the line.
input_stream = Keys.LEFT_ARROW
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Nothing should have been output.
exp_console_output = ''
CheckConsoleOutput(self, exp_console_output)
# The input buffer position should still be 0.
CheckInputBufferPosition(self, 0)
# The input buffer itself should be empty.
CheckInputBuffer(self, '')
def test_ImpossibleMoveRightWithArrowKey(self):
"""Verify that we can't move right at the end of the line."""
# We shouldn't be able to move right if we're at the end of the line.
input_stream = Keys.RIGHT_ARROW
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Nothing should have been output.
exp_console_output = ''
CheckConsoleOutput(self, exp_console_output)
# The input buffer position should still be 0.
CheckInputBufferPosition(self, 0)
# The input buffer itself should be empty.
CheckInputBuffer(self, '')
def test_KillEntireLine(self):
"""Verify that we can kill an entire line with Ctrl+K."""
test_str = 'accelinfo on'
input_stream = StringToByteList(test_str)
# Jump to beginning of line and then kill it with Ctrl+K.
input_stream.extend([console.ControlKey.CTRL_A, console.ControlKey.CTRL_K])
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# First, we expect that the input buffer is empty.
CheckInputBuffer(self, '')
# The buffer position should be 0.
CheckInputBufferPosition(self, 0)
# What we expect to see on the console stream should be the following. The
# test string, a jump to the beginning of the line, then jump back to the
# end of the line and replace the line with spaces.
exp_console_out = test_str
# Jump to beginning of line.
exp_console_out += OutputStream.MoveCursorLeft(len(test_str))
# Jump to end of line.
exp_console_out += OutputStream.MoveCursorRight(len(test_str))
# Replace line with spaces, which looks like backspaces.
for _ in range(len(test_str)):
exp_console_out += BACKSPACE_STRING
# Verify the console output.
CheckConsoleOutput(self, exp_console_out)
def test_KillPartialLine(self):
"""Verify that we can kill a portion of a line."""
test_str = 'accelread 0 1'
input_stream = StringToByteList(test_str)
len_to_kill = 5
for _ in range(len_to_kill):
# Move cursor left
input_stream.extend(Keys.LEFT_ARROW)
# Now kill
input_stream.append(console.ControlKey.CTRL_K)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# First, check that the input buffer was truncated.
exp_input_buffer = test_str[:-len_to_kill]
CheckInputBuffer(self, exp_input_buffer)
# Verify the input buffer position.
CheckInputBufferPosition(self, len(test_str) - len_to_kill)
# The console output stream that we expect is the test string followed by a
# move left of len_to_kill, then a jump to the end of the line and backspace
# of len_to_kill.
exp_console_out = test_str
for _ in range(len_to_kill):
# Move left 1 column.
exp_console_out += OutputStream.MoveCursorLeft(1)
# Then jump to the end of the line
exp_console_out += OutputStream.MoveCursorRight(len_to_kill)
# Backspace of len_to_kill
for _ in range(len_to_kill):
exp_console_out += BACKSPACE_STRING
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
def test_InsertingCharacters(self):
"""Verify that we can insert charcters within the line."""
test_str = 'accel 0 1' # Here we forgot the 'read' part in 'accelread'
input_stream = StringToByteList(test_str)
# We need to move over to the 'l' and add read.
insertion_point = test_str.find('l') + 1
for i in range(len(test_str) - insertion_point):
# Move cursor left.
input_stream.extend(Keys.LEFT_ARROW)
# Now, add in 'read'
added_str = 'read'
input_stream.extend(StringToByteList(added_str))
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# First, verify that the input buffer is correct.
exp_input_buffer = test_str[:insertion_point] + added_str
exp_input_buffer += test_str[insertion_point:]
CheckInputBuffer(self, exp_input_buffer)
# Verify that the input buffer position is correct.
exp_input_buffer_pos = insertion_point + len(added_str)
CheckInputBufferPosition(self, exp_input_buffer_pos)
# The console output stream that we expect is the test string, followed by
# move cursor left until the 'l' was found, the added test string while
# shifting characters around.
exp_console_out = test_str
for i in range(len(test_str) - insertion_point):
# Move cursor left.
exp_console_out += OutputStream.MoveCursorLeft(1)
# Now for each character, write the rest of the line will be shifted to the
# right one column.
for i in range(len(added_str)):
# Printed character.
exp_console_out += added_str[i]
# The rest of the line
exp_console_out += test_str[insertion_point:]
# Reset the cursor back left
reset_dist = len(test_str[insertion_point:])
exp_console_out += OutputStream.MoveCursorLeft(reset_dist)
# Verify the console output.
CheckConsoleOutput(self, exp_console_out)
def test_StoreCommandHistory(self):
"""Verify that entered commands are stored in the history."""
test_commands = []
test_commands.append('help')
test_commands.append('version')
test_commands.append('accelread 0 1')
input_stream = []
for c in test_commands:
input_stream.extend(StringToByteList(c))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# We expect to have the test commands in the history buffer.
exp_history_buf = test_commands
CheckHistoryBuffer(self, exp_history_buf)
def test_CycleUpThruCommandHistory(self):
"""Verify that the UP arrow key will print itmes in the history buffer."""
# Enter some commands.
test_commands = ['version', 'accelrange 0', 'battery', 'gettime']
input_stream = []
for command in test_commands:
input_stream.extend(StringToByteList(command))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Now, hit the UP arrow key to print the previous entries.
for i in range(len(test_commands)):
input_stream.extend(Keys.UP_ARROW)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# The expected output should be test commands with prompts printed in
# between, followed by line kills with the previous test commands printed.
exp_console_out = ''
for i in range(len(test_commands)):
exp_console_out += test_commands[i] + '\r\n' + self.console.prompt
# When we press up, the line should be cleared and print the previous buffer
# entry.
for i in range(len(test_commands)-1, 0, -1):
exp_console_out += test_commands[i]
# Backspace to the beginning.
for i in range(len(test_commands[i])):
exp_console_out += BACKSPACE_STRING
# The last command should just be printed out with no backspacing.
exp_console_out += test_commands[0]
# Now, verify.
CheckConsoleOutput(self, exp_console_out)
def test_UpArrowOnEmptyHistory(self):
"""Ensure nothing happens if the history is empty."""
# Press the up arrow key twice.
input_stream = 2 * Keys.UP_ARROW
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# We expect nothing to have happened.
exp_console_out = ''
exp_input_buffer = ''
exp_input_buffer_pos = 0
exp_history_buf = []
# Verify.
CheckConsoleOutput(self, exp_console_out)
CheckInputBufferPosition(self, exp_input_buffer_pos)
CheckInputBuffer(self, exp_input_buffer)
CheckHistoryBuffer(self, exp_history_buf)
def test_UpArrowDoesNotGoOutOfBounds(self):
"""Verify that pressing the up arrow many times won't go out of bounds."""
# Enter one command.
test_str = 'help version'
input_stream = StringToByteList(test_str)
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Then press the up arrow key twice.
input_stream.extend(2 * Keys.UP_ARROW)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify that the history buffer is correct.
exp_history_buf = [test_str]
CheckHistoryBuffer(self, exp_history_buf)
# We expect that the console output should only contain our entered command,
# a new prompt, and then our command aggain.
exp_console_out = test_str + '\r\n' + self.console.prompt
# Pressing up should reprint the command we entered.
exp_console_out += test_str
# Verify.
CheckConsoleOutput(self, exp_console_out)
def test_CycleDownThruCommandHistory(self):
"""Verify that we can select entries by hitting the down arrow."""
# Enter at least 4 commands.
test_commands = ['version', 'accelrange 0', 'battery', 'gettime']
input_stream = []
for command in test_commands:
input_stream.extend(StringToByteList(command))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Now, hit the UP arrow key twice to print the previous two entries.
for i in range(2):
input_stream.extend(Keys.UP_ARROW)
# Now, hit the DOWN arrow key twice to print the newer entries.
input_stream.extend(2*Keys.DOWN_ARROW)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# The expected output should be commands that we entered, followed by
# prompts, then followed by our last two commands in reverse. Then, we
# should see the last entry in the list, followed by the saved partial cmd
# of a blank line.
exp_console_out = ''
for i in range(len(test_commands)):
exp_console_out += test_commands[i] + '\r\n' + self.console.prompt
# When we press up, the line should be cleared and print the previous buffer
# entry.
for i in range(len(test_commands)-1, 1, -1):
exp_console_out += test_commands[i]
# Backspace to the beginning.
for i in range(len(test_commands[i])):
exp_console_out += BACKSPACE_STRING
# When we press down, it should have cleared the last command (which we
# covered with the previous for loop), and then prints the next command.
exp_console_out += test_commands[3]
for i in range(len(test_commands[3])):
exp_console_out += BACKSPACE_STRING
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
# Verify input buffer.
exp_input_buffer = '' # Empty because our partial command was empty.
exp_input_buffer_pos = len(exp_input_buffer)
CheckInputBuffer(self, exp_input_buffer)
CheckInputBufferPosition(self, exp_input_buffer_pos)
def test_SavingPartialCommandWhenNavigatingHistory(self):
"""Verify that partial commands are saved when navigating history."""
# Enter a command.
test_str = 'accelinfo'
input_stream = StringToByteList(test_str)
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Enter a partial command.
partial_cmd = 'ver'
input_stream.extend(StringToByteList(partial_cmd))
# Hit the UP arrow key.
input_stream.extend(Keys.UP_ARROW)
# Then, the DOWN arrow key.
input_stream.extend(Keys.DOWN_ARROW)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# The expected output should be the command we entered, a prompt, the
# partial command, clearing of the partial command, the command entered,
# clearing of the command entered, and then the partial command.
exp_console_out = test_str + '\r\n' + self.console.prompt
exp_console_out += partial_cmd
for _ in range(len(partial_cmd)):
exp_console_out += BACKSPACE_STRING
exp_console_out += test_str
for _ in range(len(test_str)):
exp_console_out += BACKSPACE_STRING
exp_console_out += partial_cmd
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
# Verify input buffer.
exp_input_buffer = partial_cmd
exp_input_buffer_pos = len(exp_input_buffer)
CheckInputBuffer(self, exp_input_buffer)
CheckInputBufferPosition(self, exp_input_buffer_pos)
def test_DownArrowOnEmptyHistory(self):
"""Ensure nothing happens if the history is empty."""
# Then press the up down arrow twice.
input_stream = 2 * Keys.DOWN_ARROW
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# We expect nothing to have happened.
exp_console_out = ''
exp_input_buffer = ''
exp_input_buffer_pos = 0
exp_history_buf = []
# Verify.
CheckConsoleOutput(self, exp_console_out)
CheckInputBufferPosition(self, exp_input_buffer_pos)
CheckInputBuffer(self, exp_input_buffer)
CheckHistoryBuffer(self, exp_history_buf)
def test_DeleteCharsUsingDELKey(self):
"""Verify that we can delete characters using the DEL key."""
test_str = 'version'
input_stream = StringToByteList(test_str)
# Hit the left arrow key 2 times.
input_stream.extend(2 * Keys.LEFT_ARROW)
# Press the DEL key.
input_stream.extend(Keys.DEL)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# The expected output should be the command we entered, 2 individual cursor
# moves to the left, and then removing a char and shifting everything to the
# left one column.
exp_console_out = test_str
exp_console_out += 2 * OutputStream.MoveCursorLeft(1)
# Remove the char by shifting everything to the left one, slicing out the
# remove char.
exp_console_out += test_str[-1:] + ' '
# Reset the cursor by moving back 2 columns because of the 'n' and space.
exp_console_out += OutputStream.MoveCursorLeft(2)
# Verify console output.
CheckConsoleOutput(self, exp_console_out)
# Verify input buffer. The input buffer should have the char sliced out and
# be positioned where the char was removed.
exp_input_buffer = test_str[:-2] + test_str[-1:]
exp_input_buffer_pos = len(exp_input_buffer) - 1
CheckInputBuffer(self, exp_input_buffer)
CheckInputBufferPosition(self, exp_input_buffer_pos)
def test_RepeatedCommandInHistory(self):
"""Verify that we don't store 2 consecutive identical commands in history"""
# Enter a few commands.
test_commands = ['version', 'accelrange 0', 'battery', 'gettime']
# Repeat the last command.
test_commands.append(test_commands[len(test_commands)-1])
input_stream = []
for command in test_commands:
input_stream.extend(StringToByteList(command))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Verify that the history buffer is correct. The last command, since
# it was repeated, should not have been added to the history.
exp_history_buf = test_commands[0:len(test_commands)-1]
CheckHistoryBuffer(self, exp_history_buf)
class TestConsoleCompatibility(unittest.TestCase):
"""Verify that console can speak to enhanced and non-enhanced EC images."""
def setUp(self):
"""Setup the test harness."""
# Setup logging with a timestamp, the module, and the log level.
logging.basicConfig(level=logging.DEBUG,
format=('%(asctime)s - %(module)s -'
' %(levelname)s - %(message)s'))
# Create a temp file and set both the master and slave PTYs to the file to
# create a loopback.
self.tempfile = tempfile.TemporaryFile()
# Mock out the pipes.
dummy_pipe_end_0, dummy_pipe_end_1 = mock.MagicMock(), mock.MagicMock()
self.console = console.Console(self.tempfile.fileno(), self.tempfile,
dummy_pipe_end_0, dummy_pipe_end_1)
@mock.patch('console.Console.CheckForEnhancedECImage')
def test_ActAsPassThruInNonEnhancedMode(self, mock_check):
"""Verify we simply pass everything thru to non-enhanced ECs.
Args:
mock_check: A MagicMock object replacing the CheckForEnhancedECImage()
method.
"""
# Set the interrogation mode to always so that we actually interrogate.
self.console.interrogation_mode = 'always'
# Assume EC interrogations indicate that the image is non-enhanced.
mock_check.return_value = False
# Press enter, followed by the command, and another enter.
input_stream = []
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
test_command = 'version'
input_stream.extend(StringToByteList(test_command))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Expected calls to send down the pipe would be each character of the test
# command.
expected_calls = []
expected_calls.append(mock.call(chr(console.ControlKey.CARRIAGE_RETURN)))
for char in test_command:
expected_calls.append(mock.call(char))
expected_calls.append(mock.call(chr(console.ControlKey.CARRIAGE_RETURN)))
# Verify that the calls happened.
self.console.cmd_pipe.send.assert_has_calls(expected_calls)
# Since we're acting as a pass-thru, the input buffer should be empty and
# input_buffer_pos is 0.
CheckInputBuffer(self, '')
CheckInputBufferPosition(self, 0)
@mock.patch('console.Console.CheckForEnhancedECImage')
def test_TransitionFromNonEnhancedToEnhanced(self, mock_check):
"""Verify that we transition correctly to enhanced mode.
Args:
mock_check: A MagicMock object replacing the CheckForEnhancedECImage()
method.
"""
# Set the interrogation mode to always so that we actually interrogate.
self.console.interrogation_mode = 'always'
# First, assume that the EC interrogations indicate an enhanced EC image.
mock_check.return_value = True
# But our current knowledge of the EC image (which was actually the
# 'previous' EC) was a non-enhanced image.
self.console.enhanced_ec = False
test_command = 'sysinfo'
input_stream = []
input_stream.extend(StringToByteList(test_command))
expected_calls = []
# All keystrokes to the console should be directed straight through to the
# EC until we press the enter key.
for char in test_command:
expected_calls.append(mock.call(char))
# Press the enter key.
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# The enter key should not be sent to the pipe since we should negotiate
# to an enhanced EC image.
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# At this point, we should have negotiated to enhanced.
self.assertTrue(self.console.enhanced_ec, msg=('Did not negotiate to '
'enhanced EC image.'))
# The command would have been dropped however, so verify this...
CheckInputBuffer(self, '')
CheckInputBufferPosition(self, 0)
# ...and repeat the command.
input_stream = StringToByteList(test_command)
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Since we're enhanced now, we should have sent the entire command as one
# string with no trailing carriage return
expected_calls.append(mock.call(test_command))
# Verify all of the calls.
self.console.cmd_pipe.send.assert_has_calls(expected_calls)
@mock.patch('console.Console.CheckForEnhancedECImage')
def test_TransitionFromEnhancedToNonEnhanced(self, mock_check):
"""Verify that we transition correctly to non-enhanced mode.
Args:
mock_check: A MagicMock object replacing the CheckForEnhancedECImage()
method.
"""
# Set the interrogation mode to always so that we actually interrogate.
self.console.interrogation_mode = 'always'
# First, assume that the EC interrogations indicate an non-enhanced EC
# image.
mock_check.return_value = False
# But our current knowledge of the EC image (which was actually the
# 'previous' EC) was an enhanced image.
self.console.enhanced_ec = True
test_command = 'sysinfo'
input_stream = []
input_stream.extend(StringToByteList(test_command))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# But, we will negotiate to non-enhanced however, dropping this command.
# Verify this.
self.assertFalse(self.console.enhanced_ec, msg=('Did not negotiate to'
'non-enhanced EC image.'))
CheckInputBuffer(self, '')
CheckInputBufferPosition(self, 0)
# The carriage return should have passed through though.
expected_calls = []
expected_calls.append(mock.call(chr(console.ControlKey.CARRIAGE_RETURN)))
# Since the command was dropped, repeat the command.
input_stream = StringToByteList(test_command)
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# Since we're not enhanced now, we should have sent each character in the
# entire command separately and a carriage return.
for char in test_command:
expected_calls.append(mock.call(char))
expected_calls.append(mock.call(chr(console.ControlKey.CARRIAGE_RETURN)))
# Verify all of the calls.
self.console.cmd_pipe.send.assert_has_calls(expected_calls)
def test_EnhancedCheckIfTimedOut(self):
"""Verify that the check returns false if it times out."""
# Make the debug pipe "time out".
self.console.dbg_pipe.poll.return_value = False
self.assertFalse(self.console.CheckForEnhancedECImage())
def test_EnhancedCheckIfACKReceived(self):
"""Verify that the check returns true if the ACK is received."""
# Make the debug pipe return EC_ACK.
self.console.dbg_pipe.poll.return_value = True
self.console.dbg_pipe.recv.return_value = interpreter.EC_ACK
self.assertTrue(self.console.CheckForEnhancedECImage())
def test_EnhancedCheckIfWrong(self):
"""Verify that the check returns false if byte received is wrong."""
# Make the debug pipe return the wrong byte.
self.console.dbg_pipe.poll.return_value = True
self.console.dbg_pipe.recv.return_value = '\xff'
self.assertFalse(self.console.CheckForEnhancedECImage())
def test_EnhancedCheckUsingBuffer(self):
"""Verify that given reboot output, enhanced EC images are detected."""
enhanced_output_stream = """
--- UART initialized after reboot ---
[Reset cause: reset-pin soft]
[Image: RO, jerry_v1.1.4363-2af8572-dirty 2016-02-23 13:26:20 aaboagye@lithium.mtv.corp.google.com]
[0.001695 KB boot key 0]
[0.001790 Inits done]
[0.001923 not sysjump; forcing AP shutdown]
[0.002047 EC triggered warm reboot]
[0.002155 assert GPIO_PMIC_WARM_RESET_L for 4 ms]
[0.006326 auto_power_on set due to reset_flag 0x22]
[0.006477 Wait for battery stabilized during 1000000]
[0.007368 battery responded with status c0]
[0.009099 hash start 0x00010000 0x0000eb7c]
[0.009307 KB init state: -- -- -- -- -- -- -- -- -- -- -- -- --]
[0.009531 KB wait]
Enhanced Console is enabled (v1.0.0); type HELP for help.
> [0.009782 event set 0x00002000]
[0.009903 hostcmd init 0x2000]
[0.010031 power state 0 = G3, in 0x0000]
[0.010173 power state 4 = G3->S5, in 0x0000]
[0.010324 power state 1 = S5, in 0x0000]
[0.010466 power on 2]
[0.010566 power state 5 = S5->S3, in 0x0000]
[0.037713 event set 0x00000080]
[0.037836 event set 0x00400000]
[0.038675 Battery 89% / 1092h:15 to empty]
[0.224060 hash done 41dac382e3a6e3d2ea5b4d789c1bc46525cae7cc5ff6758f0de8d8369b506f57]
[0.375150 POWER_GOOD seen]
"""
for line in enhanced_output_stream.split('\n'):
self.console.CheckBufferForEnhancedImage(line)
# Since the enhanced console string was present in the output, the console
# should have caught it.
self.assertTrue(self.console.enhanced_ec)
# Also should check that the command was sent to the interpreter.
self.console.cmd_pipe.send.assert_called_once_with('enhanced True')
# Now test the non-enhanced EC image.
self.console.cmd_pipe.reset_mock()
non_enhanced_output_stream = """
--- UART initialized after reboot ---
[Reset cause: reset-pin soft]
[Image: RO, jerry_v1.1.4363-2af8572-dirty 2016-02-23 13:03:15 aaboagye@lithium.mtv.corp.google.com]
[0.001695 KB boot key 0]
[0.001790 Inits done]
[0.001923 not sysjump; forcing AP shutdown]
[0.002047 EC triggered warm reboot]
[0.002156 assert GPIO_PMIC_WARM_RESET_L for 4 ms]
[0.006326 auto_power_on set due to reset_flag 0x22]
[0.006477 Wait for battery stabilized during 1000000]
[0.007368 battery responded with status c0]
[0.008951 hash start 0x00010000 0x0000ed78]
[0.009159 KB init state: -- -- -- -- -- -- -- -- -- -- -- -- --]
[0.009383 KB wait]
Console is enabled; type HELP for help.
> [0.009602 event set 0x00002000]
[0.009722 hostcmd init 0x2000]
[0.009851 power state 0 = G3, in 0x0000]
[0.009993 power state 4 = G3->S5, in 0x0000]
[0.010144 power state 1 = S5, in 0x0000]
[0.010285 power on 2]
[0.010385 power state 5 = S5->S3, in 0x0000]
"""
for line in non_enhanced_output_stream.split('\n'):
self.console.CheckBufferForEnhancedImage(line)
# Since the default console string is present in the output, it should be
# determined to be non enhanced now.
self.assertFalse(self.console.enhanced_ec)
# Check that command was also sent to the interpreter.
self.console.cmd_pipe.send.assert_called_once_with('enhanced False')
class TestOOBMConsoleCommands(unittest.TestCase):
"""Verify that OOBM console commands work correctly."""
def setUp(self):
"""Setup the test harness."""
# Setup logging with a timestamp, the module, and the log level.
logging.basicConfig(level=logging.DEBUG,
format=('%(asctime)s - %(module)s -'
' %(levelname)s - %(message)s'))
# Create a temp file and set both the master and slave PTYs to the file to
# create a loopback.
self.tempfile = tempfile.TemporaryFile()
# Mock out the pipes.
dummy_pipe_end_0, dummy_pipe_end_1 = mock.MagicMock(), mock.MagicMock()
self.console = console.Console(self.tempfile.fileno(), self.tempfile,
dummy_pipe_end_0, dummy_pipe_end_1)
self.console.oobm_queue = mock.MagicMock()
@mock.patch('console.Console.CheckForEnhancedECImage')
def test_InterrogateCommand(self, mock_check):
"""Verify that 'interrogate' command works as expected.
Args:
mock_check: A MagicMock object replacing the CheckForEnhancedECIMage()
method.
"""
input_stream = []
expected_calls = []
mock_check.side_effect = [False]
# 'interrogate never' should disable the interrogation from happening at
# all.
cmd = 'interrogate never'
# Enter the OOBM prompt.
input_stream.extend(StringToByteList('%'))
# Type the command
input_stream.extend(StringToByteList(cmd))
# Press enter.
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
input_stream = []
# The OOBM queue should have been called with the command being put.
expected_calls.append(mock.call.put(cmd))
self.console.oobm_queue.assert_has_calls(expected_calls)
# Process the OOBM queue.
self.console.oobm_queue.get.side_effect = [cmd]
self.console.ProcessOOBMQueue()
# Type out a few commands.
input_stream.extend(StringToByteList('version'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
input_stream.extend(StringToByteList('flashinfo'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
input_stream.extend(StringToByteList('sysinfo'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# The Check function should NOT have been called at all.
mock_check.assert_not_called()
# The EC image should be assumed to be not enhanced.
self.assertFalse(self.console.enhanced_ec, 'The image should be assumed to'
' be NOT enhanced.')
# Reset the mocks.
mock_check.reset_mock()
self.console.oobm_queue.reset_mock()
# 'interrogate auto' should not interrogate at all. It should only be
# scanning the output stream for the 'console is enabled' strings.
cmd = 'interrogate auto'
# Enter the OOBM prompt.
input_stream.extend(StringToByteList('%'))
# Type the command
input_stream.extend(StringToByteList(cmd))
# Press enter.
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
input_stream = []
expected_calls = []
# The OOBM queue should have been called with the command being put.
expected_calls.append(mock.call.put(cmd))
self.console.oobm_queue.assert_has_calls(expected_calls)
# Process the OOBM queue.
self.console.oobm_queue.get.side_effect = [cmd]
self.console.ProcessOOBMQueue()
# Type out a few commands.
input_stream.extend(StringToByteList('version'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
input_stream.extend(StringToByteList('flashinfo'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
input_stream.extend(StringToByteList('sysinfo'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# The Check function should NOT have been called at all.
mock_check.assert_not_called()
# The EC image should be assumed to be not enhanced.
self.assertFalse(self.console.enhanced_ec, 'The image should be assumed to'
' be NOT enhanced.')
# Reset the mocks.
mock_check.reset_mock()
self.console.oobm_queue.reset_mock()
# 'interrogate always' should, like its name implies, interrogate always
# after each press of the enter key. This was the former way of doing
# interrogation.
cmd = 'interrogate always'
# Enter the OOBM prompt.
input_stream.extend(StringToByteList('%'))
# Type the command
input_stream.extend(StringToByteList(cmd))
# Press enter.
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
input_stream = []
expected_calls = []
# The OOBM queue should have been called with the command being put.
expected_calls.append(mock.call.put(cmd))
self.console.oobm_queue.assert_has_calls(expected_calls)
# Process the OOBM queue.
self.console.oobm_queue.get.side_effect = [cmd]
self.console.ProcessOOBMQueue()
# The Check method should be called 3 times here.
mock_check.side_effect = [False, False, False]
# Type out a few commands.
input_stream.extend(StringToByteList('help list'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
input_stream.extend(StringToByteList('taskinfo'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
input_stream.extend(StringToByteList('hibdelay'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# The Check method should have been called 3 times here.
expected_calls = [mock.call(), mock.call(), mock.call()]
mock_check.assert_has_calls(expected_calls)
# The EC image should be assumed to be not enhanced.
self.assertFalse(self.console.enhanced_ec, 'The image should be assumed to'
' be NOT enhanced.')
# Now, let's try to assume that the image is enhanced while still disabling
# interrogation.
mock_check.reset_mock()
self.console.oobm_queue.reset_mock()
input_stream = []
cmd = 'interrogate never enhanced'
# Enter the OOBM prompt.
input_stream.extend(StringToByteList('%'))
# Type the command
input_stream.extend(StringToByteList(cmd))
# Press enter.
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
input_stream = []
expected_calls = []
# The OOBM queue should have been called with the command being put.
expected_calls.append(mock.call.put(cmd))
self.console.oobm_queue.assert_has_calls(expected_calls)
# Process the OOBM queue.
self.console.oobm_queue.get.side_effect = [cmd]
self.console.ProcessOOBMQueue()
# Type out a few commands.
input_stream.extend(StringToByteList('chgstate'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
input_stream.extend(StringToByteList('hash'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
input_stream.extend(StringToByteList('sysjump rw'))
input_stream.append(console.ControlKey.CARRIAGE_RETURN)
# Send the sequence out.
for byte in input_stream:
self.console.HandleChar(byte)
# The check method should have never been called.
mock_check.assert_not_called()
# The EC image should be assumed to be enhanced.
self.assertTrue(self.console.enhanced_ec, 'The image should be'
' assumed to be enhanced.')
if __name__ == '__main__':
unittest.main()