• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2021 Huawei Device Co., Ltd.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14module TestRunner
15
16  ERROR_NODATA = 86
17  ERROR_CANNOT_CREATE_PROCESS = 87
18  ERROR_TIMEOUT = 88
19
20  def self.log(level, *args)
21    puts args if level <= $VERBOSITY
22  end
23
24  def self.print_exception(exception)
25    puts "Exception: exception class   : #{exception.class}"
26    puts "           exception message : #{exception.message}"
27    exception.backtrace.each do |t|
28      puts "                       trace : #{t}"
29    end
30  end
31
32  def self.split_separated_by_colon(string)
33    string.split(':')
34                   .drop(1)
35                   .flat_map { |s| s.split(',').map(&:strip) }
36  end
37
38  class CommandRunner
39    def initialize(command, reporter)
40      @command = command
41      @reporter = reporter
42    end
43
44    def dump_output(t, output_err, output)
45      start = Time.now
46
47      while (Time.now - start) <= $TIMEOUT and t.alive?
48        Kernel.select([output_err], nil, nil, 1)
49        begin
50          output << output_err.read_nonblock(256)
51        rescue IO::WaitReadable
52        rescue EOFError
53          return true
54        end
55      end
56      !t.alive?
57    end
58
59    def start_process_timeout
60      begin
61        input, output_err, t = if $enable_core
62          Open3.popen2e(@command, :pgroup => true)
63        else
64          Open3.popen2e(@command, :pgroup => true, :rlimit_core => 0)
65        end
66        pid = t[:pid]
67        output = ""
68        finished = dump_output t, output_err, output
69
70        input.close
71        output_err.close
72
73        if !finished
74          output << "Process hangs for #{$TIMEOUT}s '#{@command}'\n" \
75                    "Killing pid:#{pid}"
76          begin
77            Process.kill('-TERM', Process.getpgid(pid))
78          rescue Errno::ESRCH
79          rescue Exception => e
80            TestRunner.print_exception e
81          end
82          return output, ERROR_TIMEOUT, false
83        end
84
85        exitstatus = if t.value.coredump?
86                           t.value.termsig + 128
87                         else
88                           t.value.exitstatus
89                         end
90
91        return output, exitstatus, t.value.coredump?
92      rescue Errno::ENOENT  => e
93        return "Failed to start #{@command} - no executable",
94          ERROR_CANNOT_CREATE_PROCESS, false
95      rescue
96        return "Failed to start #{@command}",
97          ERROR_CANNOT_CREATE_PROCESS, false
98      end
99    end
100
101    def run_cmd()
102      @reporter.log_start_command @command
103      StringIO.open do |content|
104        content.puts "# Start command: #{@command}"
105        output, exitstatus, core = start_process_timeout
106        content.puts output
107        return content.string, exitstatus, core
108      end
109    end
110
111  end # Runner
112end # module
113