You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
os-autoinst/1508.patch

375 lines
14 KiB

From 6442f889a3e45e782ad4c2e4c737442e09f895f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20R=C5=AF=C5=BEi=C4=8Dka?=
<lruzicka@redhat.com>
Date: Mon, 17 Aug 2020 13:35:10 +0200
Subject: [PATCH 1/3] Add `mouse_drag` subroutine to support click and drag in
tests
1. This PR adds the `mouse_drag` subroutine that enables the mouse and drag
support for OpenQA tests. To use the subroutine, it is possible to either
provide a "starting" and "ending" needle from which the starting and finishing
points will be calculated (using the centres of the needle tag), or
coordinates might be provided directly. If both needles and coordinates are
provided at the same time, then the coordinates precede over the needles.
Combinations are possible, too, which means that one of the points can
be passed as a needle and the other as coordinates.
2. In order not to repete code, the part responsible for calculating the
center of needle was removed from the `click_lastmatch` subroutine and moved
into a standalone non-exported subroutine called `calculate_clickpoint` to be
also used by the `mouse_drag` subroutine, as well as by the original
`click_lastmatch`.
3. This PR solves action #39335
---
testapi.pm | 109 +++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 93 insertions(+), 16 deletions(-)
diff --git a/testapi.pm b/testapi.pm
index ed94bd5875..22a062e873 100755
--- a/testapi.pm
+++ b/testapi.pm
@@ -48,7 +48,7 @@ our @EXPORT = qw($realname $username $password $serialdev %cmd %vars
assert_screen check_screen assert_and_dclick save_screenshot
assert_and_click mouse_hide mouse_set mouse_click
- mouse_dclick mouse_tclick match_has_tag click_lastmatch
+ mouse_dclick mouse_tclick match_has_tag click_lastmatch mouse_drag
assert_script_run script_run assert_script_sudo script_sudo
script_output validate_script_output
@@ -108,6 +108,36 @@ os-autoinst is used in the openQA project.
=head1 internal
+=head2 _calculate_clickpoint
+
+This subroutine is used to by several subroutines dealing with mouse clicks to calculate
+a clickpoint, when only the needle area is available. It takes the area coordinates and
+returns the center of that area. It is meant to be a helper subroutine not available
+to be used in tests.
+
+=cut
+
+sub _calculate_clickpoint {
+ my ($needle_to_use, $needle_area, $click_point) = @_;
+ # If there is no needle area defined, take it from the needle itself.
+ if (!$needle_area) {
+ $needle_area = $needle_to_use->{area}->[-1];
+ }
+ # If there is no clickpoint defined, or if it has been specifically defined as "center"
+ # then calculate the click point as a central point of the specified area.
+ if (!$click_point || $click_point eq 'center') {
+ $click_point = {
+ xpos => $needle_area->{w} / 2,
+ ypos => $needle_area->{h} / 2,
+ };
+ }
+ # Use the click point coordinates (which are relative numbers inside of the area)
+ # to calculate the absolute click point position.
+ my $x = int($needle_area->{x} + $click_point->{xpos});
+ my $y = int($needle_area->{y} + $click_point->{ypos});
+ return $x, $y;
+}
+
=for stopwords xen hvc0 xvc0 ipmi ttyS
=head2 init
@@ -522,25 +552,12 @@ sub click_lastmatch {
my $relative_click_point;
for my $area (reverse @{$last_matched_needle->{area}}) {
next unless ($relative_click_point = $area->{click_point});
-
$relevant_area = $area;
last;
}
- # use center of the last area if no area contains click coordinates
- if (!$relevant_area) {
- $relevant_area = $last_matched_needle->{area}->[-1];
- }
- if (!$relative_click_point || $relative_click_point eq 'center') {
- $relative_click_point = {
- xpos => $relevant_area->{w} / 2,
- ypos => $relevant_area->{h} / 2,
- };
- }
-
- # calculate absolute click position and click
- my $x = int($relevant_area->{x} + $relative_click_point->{xpos});
- my $y = int($relevant_area->{y} + $relative_click_point->{ypos});
+ # Calculate the absolute click point.
+ my ($x, $y) = _calculate_clickpoint($last_matched_needle, $relevant_area, $relative_click_point);
bmwqemu::diag("clicking at $x/$y");
mouse_set($x, $y);
if ($args{dclick}) {
@@ -1549,6 +1566,66 @@ sub mouse_hide(;$) {
query_isotovideo('backend_mouse_hide', {offset => $border_offset});
}
+=head2 mouse_drag
+ mouse_drag([$startpoint, $endpoint, $startx, $starty, $endx, $endy, $button, $timeout]);
+
+Click mouse C<$button>, C<'left'> or C<'right'>, at a given location, hold the button and drag
+the mouse to another location where the button is released. You can set the C<$startpoint>
+and C<$endpoint> by passing the name of the needle tag, i.e. the mouse drag happens between
+the two needle areas. Alternatively, you can set all the coordinates explicitly with C<$startx>,
+C<$starty>, C<$endx>, and C<$endy>. You can also set one point using a needle and another one
+using coordinates. If both the coordinates and the needle are provided, the coordinates
+will be used to set up the locations and the needle location will be overridden.
+
+=cut
+
+sub mouse_drag {
+ my %args = @_;
+ my ($startx, $starty, $endx, $endy);
+ # If full coordinates are provided, work with them as a priority,
+ if (defined $args{startx} and defined $args{starty}) {
+ $startx = $args{startx};
+ $starty = $args{starty};
+ }
+ # If the coordinates were not complete, use the needle as a fallback solution.
+ elsif (defined $args{startpoint}) {
+ my $startmatch = $args{startpoint};
+ # Check that the needle exists.
+ my $start_matched_needle = assert_screen($startmatch, $args{timeout});
+ # Calculate the click point from the area defined by the needle (take the center of it)
+ ($startx, $starty) = _calculate_clickpoint($start_matched_needle);
+ }
+ # If neither coordinates nor a needle is provided, report an error and quit.
+ else {
+ die "The starting point of the drag was not correctly provided. Either provide the 'startx' and 'starty' coordinates, or a needle marking the starting point.";
+ }
+
+ # Repeat the same for endpoint coordinates or needles.
+ if (defined $args{endx} and defined $args{endy}) {
+ $endx = $args{endx};
+ $endy = $args{endy};
+ }
+ elsif (defined $args{endpoint}) {
+ my $endmatch = $args{endpoint};
+ my $end_matched_needle = assert_screen($endmatch, $args{timeout});
+ ($endx, $endy) = _calculate_clickpoint($end_matched_needle);
+ }
+ else {
+ die "The ending point of the drag was not correctly provided. Either provide the 'endx' and 'endy' coordinates, or a needle marking the end point.";
+ }
+ # Get the button variable. If no button has been provided, assume the "left" button.
+ my $button = $args{button} // "left";
+ bmwqemu::log_call("mouse dragged", button => $button);
+
+ # Now, perform the actual mouse drag. Navigate to the startpoint location,
+ # press and hold the mouse button, then navigate to the endpoint location
+ # and release the mouse button.
+ mouse_set($startx, $starty);
+ query_isotovideo('backend_mouse_button', {button => $button, bstate => 1});
+ mouse_set($endx, $endy);
+ query_isotovideo('backend_mouse_button', {button => $button, bstate => 0});
+}
+
=head1 multi console support
All C<testapi> commands that interact with the system under test do that
From 5e6d7d1f868430de25cbd1ae6f1168d74d29bed6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20R=C5=AF=C5=BEi=C4=8Dka?=
<lruzicka@redhat.com>
Date: Tue, 25 Aug 2020 10:04:01 +0200
Subject: [PATCH 2/3] Write tests for _calculate_clickpoint
---
t/03-testapi.t | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/t/03-testapi.t b/t/03-testapi.t
index d53aa12590..edca0eb418 100755
--- a/t/03-testapi.t
+++ b/t/03-testapi.t
@@ -683,4 +683,32 @@ subtest 'autoinst_url' => sub {
is(autoinst_url('foo'), 'http://localhost:1/foo', 'we can configure the hostname that autoinst_url returns');
};
+subtest '_calculate_clickpoint' => sub {
+ my %fake_needle = (
+ area => [{x => 10, y => 10, w => 20, h => 30}],
+ );
+ my %fake_needle_area = (x => 100, y => 100, w => 50, h => 40);
+ my %fake_click_point = (xpos => 20, ypos => 10);
+
+ # Everything is provided.
+ my ($x, $y) = testapi::_calculate_clickpoint(\%fake_needle, \%fake_needle_area, \%fake_click_point);
+ is($x, 120);
+ is($y, 110);
+
+ # Everything is provided but the click point is 'center'
+ ($x, $y) = testapi::_calculate_clickpoint(\%fake_needle, \%fake_needle_area, "center");
+ is($x, 125);
+ is($y, 120);
+
+ # Just the area is provided and no click point.
+ ($x, $y) = testapi::_calculate_clickpoint(\%fake_needle, \%fake_needle_area);
+ is($x, 125);
+ is($y, 120);
+
+ # Just the needle is provided and no area and click point.
+ ($x, $y) = testapi::_calculate_clickpoint(\%fake_needle);
+ is($x, 20);
+ is($y, 25);
+};
+
done_testing;
From 168d4437c7de938c50609331ffb26a6241a343a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20R=C5=AF=C5=BEi=C4=8Dka?=
<lruzicka@redhat.com>
Date: Wed, 26 Aug 2020 10:32:02 +0200
Subject: [PATCH 3/3] Write tests for mouse_drag
---
t/03-testapi.t | 113 +++++++++++++++++++++++++++++++++++++++++++++++++
testapi.pm | 2 +-
2 files changed, 114 insertions(+), 1 deletion(-)
diff --git a/t/03-testapi.t b/t/03-testapi.t
index edca0eb418..e25b831765 100755
--- a/t/03-testapi.t
+++ b/t/03-testapi.t
@@ -711,4 +711,117 @@ subtest '_calculate_clickpoint' => sub {
is($y, 25);
};
+subtest 'mouse_drag' => sub {
+ my $mock_testapi = Test::MockModule->new('testapi');
+ my @area = ({x => 100, y => 100, w => 20, h => 20});
+ $mock_testapi->redefine(assert_screen => {area => \@area});
+
+ my ($startx, $starty) = (0, 0);
+ my ($endx, $endy) = (200, 200);
+ my $button = "left";
+ $cmds = [];
+ # Startpoint from a needle. Endpoint coordinates.
+ mouse_drag(startpoint => 'foo', endx => $endx, endy => $endy, button => $button, timeout => 30);
+ is_deeply($cmds, [
+ {
+ cmd => 'backend_mouse_set',
+ x => 110,
+ y => 110
+ },
+ {
+ bstate => 1,
+ button => 'left',
+ cmd => 'backend_mouse_button'
+ },
+ {
+ cmd => 'backend_mouse_set',
+ x => 200,
+ y => 200
+ },
+ {
+ bstate => 0,
+ button => 'left',
+ cmd => 'backend_mouse_button'
+ },
+ ], 'mouse drag (startpoint defined by a needle)') or diag explain $cmds;
+
+ # Startpoint from coordinates, endpoint from a needle.
+ $cmds = [];
+ mouse_drag(endpoint => 'foo', startx => $startx, starty => $starty, button => $button, timeout => 30);
+ is_deeply($cmds, [
+ {
+ cmd => 'backend_mouse_set',
+ x => 0,
+ y => 0
+ },
+ {
+ bstate => 1,
+ button => 'left',
+ cmd => 'backend_mouse_button'
+ },
+ {
+ cmd => 'backend_mouse_set',
+ x => 110,
+ y => 110
+ },
+ {
+ bstate => 0,
+ button => 'left',
+ cmd => 'backend_mouse_button'
+ },
+ ], 'mouse drag (endpoint defined by a needle)') or diag explain $cmds;
+
+ # Using coordinates only.
+ $cmds = [];
+ mouse_drag(endx => $endx, endy => $endy, startx => $startx, starty => $starty, button => $button, timeout => 30);
+ is_deeply($cmds, [
+ {
+ cmd => 'backend_mouse_set',
+ x => 0,
+ y => 0
+ },
+ {
+ bstate => 1,
+ button => 'left',
+ cmd => 'backend_mouse_button'
+ },
+ {
+ cmd => 'backend_mouse_set',
+ x => 200,
+ y => 200
+ },
+ {
+ bstate => 0,
+ button => 'left',
+ cmd => 'backend_mouse_button'
+ },
+ ], 'mouse drag (start and endpoints defined by coordinates)') or diag explain $cmds;
+
+ # Both needle and coordinates provided for startpoint (coordinates should win).
+ $cmds = [];
+ mouse_drag(startpoint => "foo", endx => $endx, endy => $endy, startx => $startx, starty => $starty, button => $button, timeout => 30);
+ is_deeply($cmds, [
+ {
+ cmd => 'backend_mouse_set',
+ x => 0,
+ y => 0
+ },
+ {
+ bstate => 1,
+ button => 'left',
+ cmd => 'backend_mouse_button'
+ },
+ {
+ cmd => 'backend_mouse_set',
+ x => 200,
+ y => 200
+ },
+ {
+ bstate => 0,
+ button => 'left',
+ cmd => 'backend_mouse_button'
+ },
+ ], 'mouse drag (redundant definiton by a needle)') or diag explain $cmds;
+};
+
done_testing;
diff --git a/testapi.pm b/testapi.pm
index 22a062e873..fe16c29b07 100755
--- a/testapi.pm
+++ b/testapi.pm
@@ -1615,7 +1615,6 @@ sub mouse_drag {
}
# Get the button variable. If no button has been provided, assume the "left" button.
my $button = $args{button} // "left";
- bmwqemu::log_call("mouse dragged", button => $button);
# Now, perform the actual mouse drag. Navigate to the startpoint location,
# press and hold the mouse button, then navigate to the endpoint location
@@ -1624,6 +1623,7 @@ sub mouse_drag {
query_isotovideo('backend_mouse_button', {button => $button, bstate => 1});
mouse_set($endx, $endy);
query_isotovideo('backend_mouse_button', {button => $button, bstate => 0});
+ bmwqemu::log_call(message => "Mouse dragged from $startx,$starty to $endx, $endy", button => $button);
}
=head1 multi console support