From 0e2f68cff39f617c1571cf98e48002c7c05890ab Mon Sep 17 00:00:00 2001 From: Sylvain Pineau Date: Tue, 14 Jul 2020 13:46:47 +0200 Subject: bin:window_test -> window_test.py --- bin/window_test | 342 ---------------------------------------------- bin/window_test.py | 342 ++++++++++++++++++++++++++++++++++++++++++++++ units/graphics/jobs.pxu | 8 +- units/graphics/legacy.pxu | 8 +- 4 files changed, 350 insertions(+), 350 deletions(-) delete mode 100755 bin/window_test create mode 100755 bin/window_test.py diff --git a/bin/window_test b/bin/window_test deleted file mode 100755 index 23b6f3b..0000000 --- a/bin/window_test +++ /dev/null @@ -1,342 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# window_test -# -# This file is part of Checkbox. -# -# Copyright 2012 Canonical Ltd. -# -# Authors: Alberto Milone -# -# Checkbox is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 3, -# as published by the Free Software Foundation. - -# -# Checkbox is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Checkbox. If not, see . - -import threading -import time -import os -import sys - -from signal import SIGTSTP, SIGCONT, SIGTERM -from subprocess import check_call, check_output, Popen, PIPE -from argparse import ArgumentParser - - -class AppThread(threading.Thread): - - def __init__(self, app_name): - self._appname = app_name - self.stdout = None - self.stderr = None - self.pid = None - threading.Thread.__init__(self) - - def run(self): - proc = Popen(self._appname, stdout=PIPE, stderr=PIPE) - self.pid = proc.pid - print(' Starting "%s", PID: %d' % - (self._appname, self.pid)) - self.stdout, self.stderr = proc.communicate() - - -def open_close_process(app, timeout): - '''Open and close a process after a timeout''' - status = 0 - # Start the process in a separate thread - app_thread = AppThread(app) - app_thread.start() - - # Wait until we have a pid - while app_thread.pid is None: - continue - pid = app_thread.pid - - # Wait a bit and kill the process - time.sleep(timeout) - print(' Killing "%s", PID: %d' % (app, pid)) - os.kill(pid, SIGTERM) - - if app_thread.stderr: - print('Errors:\n%s' % app_thread.stderr, file=sys.stderr) - status = 1 - - time.sleep(timeout) - - return status - - -def open_close_multi_process(app, timeout, apps_num): - '''Open and close multiple processes after a timeout''' - status = 0 - threads = [] - - for thread in range(apps_num): - app_thread = AppThread(app) - app_thread.start() - threads.append(app_thread) - - for thread in threads: - # Wait until we have a pid - while thread.pid is None: - continue - - # Wait a bit and kill the process - time.sleep(timeout) - for thread in threads: - print(' Killing "%s", PID: %d' % (app, thread.pid)) - os.kill(thread.pid, SIGTERM) - if thread.stderr: - print('Errors:\n%s' % thread.stderr, file=sys.stderr) - status = 1 - - time.sleep(timeout) - - return status - - -def open_suspend_close_process(app, timeout): - '''Open, suspend and close a process after a timeout''' - status = 0 - # Start the process in a separate thread - app_thread = AppThread(app) - app_thread.start() - - # Wait until we have a pid - while app_thread.pid is None: - continue - pid = app_thread.pid - - # Wait a bit and suspend the process - time.sleep(timeout) - print(' Suspending "%s", PID: %d' % (app, pid)) - os.kill(pid, SIGTSTP) - - # Wait a bit and resume the process - time.sleep(timeout) - print(' Resuming "%s", PID: %d' % (app, pid)) - os.kill(pid, SIGCONT) - - # Wait a bit and kill the process - time.sleep(timeout) - print(' Killing "%s", PID: %d' % (app, pid)) - os.kill(pid, SIGTERM) - - if app_thread.stderr: - print('Errors:\n%s' % app_thread.stderr, file=sys.stderr) - status = 1 - - time.sleep(timeout) - - return status - - -def move_window(app, timeout): - status = 0 - - # Start the process in a separate thread - app_thread = AppThread(app) - app_thread.start() - - while app_thread.pid is None: - continue - - pid = app_thread.pid - - time.sleep(3) - - window_list = check_output(['wmctrl', '-l'], universal_newlines=True) - window_id = '' - - for line in window_list.split('\n'): - if app in line: - window_id = line.split()[0] - - if window_id: - # Get the screen information from GDK - from gi.repository import Gdk - - screen = Gdk.Screen.get_default() - geom = screen.get_monitor_geometry(screen.get_primary_monitor()) - - # Find out the window information from xwininfo - win_x = '' - win_y = '' - win_width = '' - win_height = '' - - for line in check_output(['xwininfo', '-name', app], - universal_newlines=True).split('\n'): - if 'Absolute upper-left X' in line: - win_x = line.split(': ')[-1].strip() - elif 'Absolute upper-left Y' in line: - win_y = line.split(': ')[-1].strip() - elif 'Width' in line: - win_width = line.split(': ')[-1].strip() - elif 'Height' in line: - win_height = line.split(': ')[-1].strip() - - move_line = ["0", win_x, win_y, win_width, win_height] - - directions = {'RIGHT': geom.width, - 'DOWN': geom.height, - 'LEFT': win_x, - 'UP': win_y, - 'STOP': None} - current = 'RIGHT' - - while current != 'STOP': - if current == 'RIGHT': - # Check if top right corner of window reached top right point - if int(move_line[1]) + int(win_width) != directions[current]: - new_x = int(move_line[1]) + 1 - move_line[1] = str(new_x) - else: - current = 'DOWN' - elif current == 'DOWN': - if int(move_line[2]) + int(win_height) != directions[current]: - new_y = int(move_line[2]) + 1 - move_line[2] = str(new_y) - else: - current = 'LEFT' - elif current == 'LEFT': - if int(move_line[1]) != int(directions[current]): - new_x = int(move_line[1]) - 1 - move_line[1] = str(new_x) - else: - current = 'UP' - elif current == 'UP': - if int(move_line[2]) != int(directions[current]): - new_y = int(move_line[2]) - 1 - move_line[2] = str(new_y) - else: - current = 'STOP' - - check_call(['wmctrl', '-i', '-r', window_id, - '-e', ','.join(move_line)]) - - os.kill(pid, SIGTERM) - else: - print("Could not get window handle for %s" % app, file=sys.stderr) - status = 1 - - return status - - -def print_open_close(iterations, timeout, *args): - status = 0 - print('Opening and closing a 3D window') - for it in range(iterations): - print('Iteration %d of %d:' % (it + 1, iterations)) - exit_status = open_close_process('glxgears', timeout) - if exit_status != 0: - status = 1 - print('') - return status - - -def print_suspend_resume(iterations, timeout, *args): - status = 0 - print('Opening, suspending, resuming and closing a 3D window') - for it in range(iterations): - print('Iteration %d of %d:' % (it + 1, iterations)) - exit_status = open_suspend_close_process('glxgears', timeout) - if exit_status != 0: - status = 1 - print('') - return status - - -def print_open_close_multi(iterations, timeout, windows_number): - status = 0 - print('Opening and closing %d 3D windows at the same time' - % windows_number) - for it in range(iterations): - print('Iteration %d of %d:' % (it + 1, iterations)) - exit_status = open_close_multi_process('glxgears', - timeout, - windows_number) - if exit_status != 0: - status = 1 - print('') - return status - - -def print_move_window(iterations, timeout, *args): - status = 0 - print('Moving a 3D window across the screen') - - for it in range(iterations): - print('Iteration %d of %d:' % (it + 1, iterations)) - exit_status = move_window('glxgears', - timeout) - - print('') - return status - - -def main(): - tests = {'open-close': print_open_close, - 'suspend-resume': print_suspend_resume, - 'open-close-multi': print_open_close_multi, - 'move': print_move_window} - - parser = ArgumentParser(description='Script that performs window operation') - parser.add_argument('-t', '--test', - default='all', - help='The name of the test to run. \ - Available tests: \ - %s, all. \ - Default is all' % (', '.join(tests))) - parser.add_argument('-i', '--iterations', - type=int, - default=1, - help='The number of times to run the test. \ - Default is 1') - parser.add_argument('-a', '--application', - default='glxgears', - help='The 3D application to launch. \ - Default is "glxgears"') - parser.add_argument('-to', '--timeout', - type=int, - default=3, - help='The time in seconds between each test. \ - Default is 3') - parser.add_argument('-w', '--windows-number', - type=int, - default=4, - help='The number of windows to open.') - - args = parser.parse_args() - - status = 0 - - test = tests.get(args.test) - - if test: - status = test(args.iterations, args.timeout, args.windows_number) - else: - if args.test == 'all': - for test in tests: - exit_status = tests[test](args.iterations, args.timeout, - args.windows_number) - if exit_status != 0: - status = exit_status - else: - parser.error('-t or --test can only be used with one ' - 'of the following tests: ' - '%s, all' % (', '.join(tests))) - - return status - -if __name__ == '__main__': - exit(main()) diff --git a/bin/window_test.py b/bin/window_test.py new file mode 100755 index 0000000..ee79a89 --- /dev/null +++ b/bin/window_test.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# window_test.py +# +# This file is part of Checkbox. +# +# Copyright 2012 Canonical Ltd. +# +# Authors: Alberto Milone +# +# Checkbox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. + +# +# Checkbox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Checkbox. If not, see . + +import threading +import time +import os +import sys + +from signal import SIGTSTP, SIGCONT, SIGTERM +from subprocess import check_call, check_output, Popen, PIPE +from argparse import ArgumentParser + + +class AppThread(threading.Thread): + + def __init__(self, app_name): + self._appname = app_name + self.stdout = None + self.stderr = None + self.pid = None + threading.Thread.__init__(self) + + def run(self): + proc = Popen(self._appname, stdout=PIPE, stderr=PIPE) + self.pid = proc.pid + print(' Starting "%s", PID: %d' % + (self._appname, self.pid)) + self.stdout, self.stderr = proc.communicate() + + +def open_close_process(app, timeout): + '''Open and close a process after a timeout''' + status = 0 + # Start the process in a separate thread + app_thread = AppThread(app) + app_thread.start() + + # Wait until we have a pid + while app_thread.pid is None: + continue + pid = app_thread.pid + + # Wait a bit and kill the process + time.sleep(timeout) + print(' Killing "%s", PID: %d' % (app, pid)) + os.kill(pid, SIGTERM) + + if app_thread.stderr: + print('Errors:\n%s' % app_thread.stderr, file=sys.stderr) + status = 1 + + time.sleep(timeout) + + return status + + +def open_close_multi_process(app, timeout, apps_num): + '''Open and close multiple processes after a timeout''' + status = 0 + threads = [] + + for thread in range(apps_num): + app_thread = AppThread(app) + app_thread.start() + threads.append(app_thread) + + for thread in threads: + # Wait until we have a pid + while thread.pid is None: + continue + + # Wait a bit and kill the process + time.sleep(timeout) + for thread in threads: + print(' Killing "%s", PID: %d' % (app, thread.pid)) + os.kill(thread.pid, SIGTERM) + if thread.stderr: + print('Errors:\n%s' % thread.stderr, file=sys.stderr) + status = 1 + + time.sleep(timeout) + + return status + + +def open_suspend_close_process(app, timeout): + '''Open, suspend and close a process after a timeout''' + status = 0 + # Start the process in a separate thread + app_thread = AppThread(app) + app_thread.start() + + # Wait until we have a pid + while app_thread.pid is None: + continue + pid = app_thread.pid + + # Wait a bit and suspend the process + time.sleep(timeout) + print(' Suspending "%s", PID: %d' % (app, pid)) + os.kill(pid, SIGTSTP) + + # Wait a bit and resume the process + time.sleep(timeout) + print(' Resuming "%s", PID: %d' % (app, pid)) + os.kill(pid, SIGCONT) + + # Wait a bit and kill the process + time.sleep(timeout) + print(' Killing "%s", PID: %d' % (app, pid)) + os.kill(pid, SIGTERM) + + if app_thread.stderr: + print('Errors:\n%s' % app_thread.stderr, file=sys.stderr) + status = 1 + + time.sleep(timeout) + + return status + + +def move_window(app, timeout): + status = 0 + + # Start the process in a separate thread + app_thread = AppThread(app) + app_thread.start() + + while app_thread.pid is None: + continue + + pid = app_thread.pid + + time.sleep(3) + + window_list = check_output(['wmctrl', '-l'], universal_newlines=True) + window_id = '' + + for line in window_list.split('\n'): + if app in line: + window_id = line.split()[0] + + if window_id: + # Get the screen information from GDK + from gi.repository import Gdk + + screen = Gdk.Screen.get_default() + geom = screen.get_monitor_geometry(screen.get_primary_monitor()) + + # Find out the window information from xwininfo + win_x = '' + win_y = '' + win_width = '' + win_height = '' + + for line in check_output(['xwininfo', '-name', app], + universal_newlines=True).split('\n'): + if 'Absolute upper-left X' in line: + win_x = line.split(': ')[-1].strip() + elif 'Absolute upper-left Y' in line: + win_y = line.split(': ')[-1].strip() + elif 'Width' in line: + win_width = line.split(': ')[-1].strip() + elif 'Height' in line: + win_height = line.split(': ')[-1].strip() + + move_line = ["0", win_x, win_y, win_width, win_height] + + directions = {'RIGHT': geom.width, + 'DOWN': geom.height, + 'LEFT': win_x, + 'UP': win_y, + 'STOP': None} + current = 'RIGHT' + + while current != 'STOP': + if current == 'RIGHT': + # Check if top right corner of window reached top right point + if int(move_line[1]) + int(win_width) != directions[current]: + new_x = int(move_line[1]) + 1 + move_line[1] = str(new_x) + else: + current = 'DOWN' + elif current == 'DOWN': + if int(move_line[2]) + int(win_height) != directions[current]: + new_y = int(move_line[2]) + 1 + move_line[2] = str(new_y) + else: + current = 'LEFT' + elif current == 'LEFT': + if int(move_line[1]) != int(directions[current]): + new_x = int(move_line[1]) - 1 + move_line[1] = str(new_x) + else: + current = 'UP' + elif current == 'UP': + if int(move_line[2]) != int(directions[current]): + new_y = int(move_line[2]) - 1 + move_line[2] = str(new_y) + else: + current = 'STOP' + + check_call(['wmctrl', '-i', '-r', window_id, + '-e', ','.join(move_line)]) + + os.kill(pid, SIGTERM) + else: + print("Could not get window handle for %s" % app, file=sys.stderr) + status = 1 + + return status + + +def print_open_close(iterations, timeout, *args): + status = 0 + print('Opening and closing a 3D window') + for it in range(iterations): + print('Iteration %d of %d:' % (it + 1, iterations)) + exit_status = open_close_process('glxgears', timeout) + if exit_status != 0: + status = 1 + print('') + return status + + +def print_suspend_resume(iterations, timeout, *args): + status = 0 + print('Opening, suspending, resuming and closing a 3D window') + for it in range(iterations): + print('Iteration %d of %d:' % (it + 1, iterations)) + exit_status = open_suspend_close_process('glxgears', timeout) + if exit_status != 0: + status = 1 + print('') + return status + + +def print_open_close_multi(iterations, timeout, windows_number): + status = 0 + print('Opening and closing %d 3D windows at the same time' + % windows_number) + for it in range(iterations): + print('Iteration %d of %d:' % (it + 1, iterations)) + exit_status = open_close_multi_process('glxgears', + timeout, + windows_number) + if exit_status != 0: + status = 1 + print('') + return status + + +def print_move_window(iterations, timeout, *args): + status = 0 + print('Moving a 3D window across the screen') + + for it in range(iterations): + print('Iteration %d of %d:' % (it + 1, iterations)) + exit_status = move_window('glxgears', + timeout) + + print('') + return status + + +def main(): + tests = {'open-close': print_open_close, + 'suspend-resume': print_suspend_resume, + 'open-close-multi': print_open_close_multi, + 'move': print_move_window} + + parser = ArgumentParser(description='Script that performs window operation') + parser.add_argument('-t', '--test', + default='all', + help='The name of the test to run. \ + Available tests: \ + %s, all. \ + Default is all' % (', '.join(tests))) + parser.add_argument('-i', '--iterations', + type=int, + default=1, + help='The number of times to run the test. \ + Default is 1') + parser.add_argument('-a', '--application', + default='glxgears', + help='The 3D application to launch. \ + Default is "glxgears"') + parser.add_argument('-to', '--timeout', + type=int, + default=3, + help='The time in seconds between each test. \ + Default is 3') + parser.add_argument('-w', '--windows-number', + type=int, + default=4, + help='The number of windows to open.') + + args = parser.parse_args() + + status = 0 + + test = tests.get(args.test) + + if test: + status = test(args.iterations, args.timeout, args.windows_number) + else: + if args.test == 'all': + for test in tests: + exit_status = tests[test](args.iterations, args.timeout, + args.windows_number) + if exit_status != 0: + status = exit_status + else: + parser.error('-t or --test can only be used with one ' + 'of the following tests: ' + '%s, all' % (', '.join(tests))) + + return status + +if __name__ == '__main__': + exit(main()) diff --git a/units/graphics/jobs.pxu b/units/graphics/jobs.pxu index 7cf080d..09ce03c 100644 --- a/units/graphics/jobs.pxu +++ b/units/graphics/jobs.pxu @@ -327,7 +327,7 @@ plugin: shell category_id: com.canonical.plainbox::graphics id: graphics/{index}_3d_window_open_close_{product_slug} requires: executable.name == 'glxgears' -command: window_test -t open-close -i 10 +command: window_test.py -t open-close -i 10 estimated_duration: 60.525 _description: Open and close a 3D window multiple times on the {vendor} {product} video card _summary: Test 3D window open/close for {vendor} {product} @@ -338,7 +338,7 @@ plugin: shell category_id: com.canonical.plainbox::graphics id: graphics/{index}_3d_window_suspend_resume_{product_slug} requires: executable.name == 'glxgears' -command: window_test -t suspend-resume -i 10 +command: window_test.py -t suspend-resume -i 10 estimated_duration: 121.00 _description: Open, suspend resume and close a 3D window multiple times on the {vendor} {product} video card _summary: Test a 3D window with suspend/resume for {vendor} {product} @@ -349,7 +349,7 @@ plugin: shell category_id: com.canonical.plainbox::graphics id: graphics/{index}_multi_3d_windows_open_close_{product_slug} requires: executable.name == 'glxgears' -command: window_test -t open-close-multi -i 10 -w 4 +command: window_test.py -t open-close-multi -i 10 -w 4 estimated_duration: 60.000 _description: Open and close 4 3D windows multiple times on the {vendor} {product} video card _summary: Test Multi 3D window open/close for {vendor} {product} @@ -362,7 +362,7 @@ id: graphics/{index}_3d_window_move_{product_slug} requires: executable.name == 'glxgears' executable.name == 'wmctrl' -command: window_test -t move +command: window_test.py -t move estimated_duration: 50.000 _description: Move a 3D window around the screen on the {vendor} {product} video card _summary: Test 3D window movement for {vendor} {product} diff --git a/units/graphics/legacy.pxu b/units/graphics/legacy.pxu index 7b8d860..498c559 100644 --- a/units/graphics/legacy.pxu +++ b/units/graphics/legacy.pxu @@ -182,7 +182,7 @@ plugin: shell category_id: com.canonical.plainbox::graphics id: graphics/3d_window_open_close requires: executable.name == 'glxgears' -command: window_test -t open-close -i 10 +command: window_test.py -t open-close -i 10 estimated_duration: 60.525 _summary: Test 3D window open/close _description: Open and close a 3D window multiple times @@ -191,7 +191,7 @@ plugin: shell category_id: com.canonical.plainbox::graphics id: graphics/3d_window_suspend_resume requires: executable.name == 'glxgears' -command: window_test -t suspend-resume -i 10 +command: window_test.py -t suspend-resume -i 10 estimated_duration: 121.00 _description: Open, suspend resume and close a 3D window multiple times _summary: Test a 3D window with suspend/resume @@ -200,7 +200,7 @@ plugin: shell category_id: com.canonical.plainbox::graphics id: graphics/multi_3d_windows_open_close requires: executable.name == 'glxgears' -command: window_test -t open-close-multi -i 10 -w 4 +command: window_test.py -t open-close-multi -i 10 -w 4 estimated_duration: 60.000 _description: Open and close 4 3D windows multiple times _summary: Test Multi 3D window open/close @@ -209,7 +209,7 @@ plugin: shell category_id: com.canonical.plainbox::graphics id: graphics/3d_window_move requires: executable.name == 'glxgears' -command: window_test -t move +command: window_test.py -t move estimated_duration: 50.000 _description: Move a 3D window around the screen _summary: Test 3D window movement -- cgit v1.2.3