forked from rust-embedded/rust-raspberrypi-OS-tutorials
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconsole_io_test.rb
117 lines (96 loc) · 2.97 KB
/
console_io_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# frozen_string_literal: true
# SPDX-License-Identifier: MIT OR Apache-2.0
#
# Copyright (c) 2019-2023 Andre Richter <andre.o.richter@gmail.com>
require 'expect'
require 'pty'
require 'timeout'
require_relative 'test'
# Error class for when expect times out.
class ExpectTimeoutError < StandardError
def initialize(string)
super("Timeout while expecting string: #{string}")
end
end
# Provide boilderplate for expecting a string and throwing an error on failure.
class SubtestBase
TIMEOUT_SECONDS = 3
def expect_or_raise(io, string, timeout = TIMEOUT_SECONDS)
raise ExpectTimeoutError, string if io.expect(string, timeout).nil?
end
end
# Monkey-patch IO so that we get access to the buffer of a previously unsuccessful expect().
class IO
def unused_buf
@unusedBuf
end
end
# A wrapper class that records characters that have been received from a PTY.
class PTYLoggerWrapper
def initialize(pty, linebreak = "\n")
@pty = pty
@linebreak = linebreak
@log = []
end
def expect(pattern, timeout)
result = @pty.expect(pattern, timeout)
@log << if result.nil?
@pty.unused_buf
else
result
end
result
end
def log
@log.join.split(@linebreak)
end
end
# A test doing console I/O with the QEMU binary.
class ConsoleIOTest < Test
MAX_TIME_ALL_TESTS_SECONDS = 20
def initialize(qemu_cmd, test_name, console_subtests)
super()
@qemu_cmd = qemu_cmd
@console_subtests = console_subtests
@test_name = test_name
@test_description = "Running #{@console_subtests.length} console I/O tests"
@test_output = []
@test_error = nil
end
private
def format_test_name(number, name)
formatted_name = "#{number.to_s.rjust(3)}. #{name}"
formatted_name.ljust(63, '.')
end
def run_subtest(subtest, test_id, qemu_out, qemu_in)
@test_output << format_test_name(test_id, subtest.name)
subtest.run(qemu_out, qemu_in)
@test_output.last.concat('[ok]')
end
# override
def setup
qemu_out, @qemu_in = PTY.spawn(@qemu_cmd)
@qemu_out_wrapped = PTYLoggerWrapper.new(qemu_out)
end
# override
def finish
@test_output << ''
@test_output << 'Console log:'
@test_output += @qemu_out_wrapped.log.map { |line| " #{line}" }
end
# override
def run_concrete_test
@test_error = false
Timeout.timeout(MAX_TIME_ALL_TESTS_SECONDS) do
@console_subtests.each_with_index do |t, i|
run_subtest(t, i + 1, @qemu_out_wrapped, @qemu_in)
end
end
rescue Errno::EIO => e
@test_error = "#{e.inspect} - QEMU might have quit early"
rescue Timeout::Error
@test_error = "Overall time for tests exceeded (#{MAX_TIME_ALL_TESTS_SECONDS}s)"
rescue StandardError => e
@test_error = e.inspect
end
end