1#!/usr/bin/env python3 2# 3# Copyright © 2020 Igalia, S.L. 4# 5# Permission is hereby granted, free of charge, to any person obtaining a 6# copy of this software and associated documentation files (the "Software"), 7# to deal in the Software without restriction, including without limitation 8# the rights to use, copy, modify, merge, publish, distribute, sublicense, 9# and/or sell copies of the Software, and to permit persons to whom the 10# Software is furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice (including the next 13# paragraph) shall be included in all copies or substantial portions of the 14# Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22# IN THE SOFTWARE. 23 24import argparse 25import os 26import re 27import sys 28import threading 29 30from custom_logger import CustomLogger 31from serial_buffer import SerialBuffer 32 33class PoERun: 34 def __init__(self, args, boot_timeout, test_timeout, logger): 35 self.powerup = args.powerup 36 self.powerdown = args.powerdown 37 self.ser = SerialBuffer( 38 args.dev, "results/serial-output.txt", ": ") 39 self.boot_timeout = boot_timeout 40 self.test_timeout = test_timeout 41 self.logger = logger 42 43 def print_error(self, message): 44 RED = '\033[0;31m' 45 NO_COLOR = '\033[0m' 46 print(RED + message + NO_COLOR) 47 self.logger.update_status_fail(message) 48 49 def logged_system(self, cmd): 50 print("Running '{}'".format(cmd)) 51 return os.system(cmd) 52 53 def run(self): 54 if self.logged_system(self.powerup) != 0: 55 self.logger.update_status_fail("powerup failed") 56 return 1 57 58 boot_detected = False 59 self.logger.create_job_phase("boot") 60 for line in self.ser.lines(timeout=self.boot_timeout, phase="bootloader"): 61 if re.search("Booting Linux", line): 62 boot_detected = True 63 break 64 65 if not boot_detected: 66 self.print_error( 67 "Something wrong; couldn't detect the boot start up sequence") 68 return 2 69 70 self.logger.create_job_phase("test") 71 for line in self.ser.lines(timeout=self.test_timeout, phase="test"): 72 if re.search("---. end Kernel panic", line): 73 self.logger.update_status_fail("kernel panic") 74 return 1 75 76 # Binning memory problems 77 if re.search("binner overflow mem", line): 78 self.print_error("Memory overflow in the binner; GPU hang") 79 return 1 80 81 if re.search("nouveau 57000000.gpu: bus: MMIO read of 00000000 FAULT at 137000", line): 82 self.print_error("nouveau jetson boot bug, abandoning run.") 83 return 1 84 85 # network fail on tk1 86 if re.search("NETDEV WATCHDOG:.* transmit queue 0 timed out", line): 87 self.print_error("nouveau jetson tk1 network fail, abandoning run.") 88 return 1 89 90 result = re.search(r"hwci: mesa: (\S*), exit_code: (\d+)", line) 91 if result: 92 status = result.group(1) 93 exit_code = int(result.group(2)) 94 95 if status == "pass": 96 self.logger.update_dut_job("status", "pass") 97 else: 98 self.logger.update_status_fail("test fail") 99 100 self.logger.update_dut_job("exit_code", exit_code) 101 return exit_code 102 103 self.print_error( 104 "Reached the end of the CPU serial log without finding a result") 105 return 1 106 107 108def main(): 109 parser = argparse.ArgumentParser() 110 parser.add_argument('--dev', type=str, 111 help='Serial device to monitor', required=True) 112 parser.add_argument('--powerup', type=str, 113 help='shell command for rebooting', required=True) 114 parser.add_argument('--powerdown', type=str, 115 help='shell command for powering off', required=True) 116 parser.add_argument( 117 '--boot-timeout-seconds', type=int, help='Boot phase timeout (seconds)', required=True) 118 parser.add_argument( 119 '--test-timeout-minutes', type=int, help='Test phase timeout (minutes)', required=True) 120 args = parser.parse_args() 121 122 logger = CustomLogger("results/job_detail.json") 123 logger.update_dut_time("start", None) 124 poe = PoERun(args, args.boot_timeout_seconds, args.test_timeout_minutes * 60, logger) 125 retval = poe.run() 126 127 poe.logged_system(args.powerdown) 128 logger.update_dut_time("end", None) 129 130 sys.exit(retval) 131 132 133if __name__ == '__main__': 134 main() 135