diff --git a/lib/fedorabase.pm b/lib/fedorabase.pm
--- a/lib/fedorabase.pm
+++ b/lib/fedorabase.pm
@@ -149,19 +149,6 @@
     send_key "ret";
 }
 
-sub boot_to_login_screen {
-    my $self = shift;
-    my $boot_done_screen = shift; # what to expect when system is booted (e. g. GDM), can be ""
-    my $stillscreen = shift || 10;
-    my $timeout = shift || 60;
-
-    wait_still_screen $stillscreen, $timeout;
-
-    if ($boot_done_screen ne "") {
-        assert_screen $boot_done_screen;
-    }
-}
-
 sub get_milestone {
     my $self = shift;
     # FIXME: we don't know how to do this with Pungi 4 yet.
diff --git a/lib/main_common.pm b/lib/main_common.pm
--- a/lib/main_common.pm
+++ b/lib/main_common.pm
@@ -6,7 +6,7 @@
 use Exporter;
 
 use testapi;
-our @EXPORT = qw/run_with_error_check check_type_string type_safely type_very_safely desktop_vt/;
+our @EXPORT = qw/run_with_error_check check_type_string type_safely type_very_safely desktop_vt boot_to_login_screen/;
 
 sub run_with_error_check {
     my ($func, $error_screen) = @_;
@@ -62,3 +62,25 @@
     }
     send_key "ctrl-alt-f${tty}";
 }
+
+# Wait for login screen to appear. Handle the annoying GPU buffer
+# problem where we see a stale copy of the login screen from the
+# previous boot. Will suffer a ~30 second delay if there's a chance
+# we're *already at* the expected login screen.
+sub boot_to_login_screen {
+    my %args = @_;
+    $args{timeout} //= 300;
+    # we may start at a screen that matches one of the needles; if so,
+    # wait till we don't (e.g. when rebooting at end of live install,
+    # we match text_console_login until the console disappears)
+    my $count = 5;
+    while (check_screen("login_screen", 3) && $count > 0) {
+        sleep 5;
+        $count -= 1;
+    }
+    assert_screen "login_screen", $args{timeout};
+    if (match_has_tag "graphical_login") {
+        wait_still_screen 10, 30;
+        assert_screen "login_screen";
+    }
+}
diff --git a/main.pm b/main.pm
--- a/main.pm
+++ b/main.pm
@@ -103,7 +103,7 @@
     autotest::loadtest "tests/upgrade_preinstall.pm";
     autotest::loadtest "tests/upgrade_run.pm";
     # set postinstall test
-    set_var('POSTINSTALL', "upgrade" );
+    set_var('POSTINSTALL', "upgrade_postinstall" );
 }
 
 sub load_install_tests() {
@@ -208,7 +208,7 @@
     if (get_var("POSTINSTALL")) {
         my @pis = split(/ /, get_var("POSTINSTALL"));
         foreach my $pi (@pis) {
-            autotest::loadtest "tests/${pi}_postinstall.pm";
+            autotest::loadtest "tests/${pi}.pm";
         }
     }
 
@@ -233,9 +233,9 @@
 elsif (get_var("UPGRADE")) {
     load_upgrade_tests;
 }
-elsif (!get_var("BOOTFROM")) {
-    # for now we can assume BOOTFROM means this test picks up
-    # after an install, so we skip to post-install
+elsif (!get_var("START_AFTER_TEST") && !get_var("BOOTFROM")) {
+    # for now we can assume START_AFTER_TEST and BOOTFROM mean the
+    # test picks up after an install, so we skip to post-install
     load_install_tests;
 }
 
diff --git a/needles/console/text_console_login.json b/needles/console/text_console_login.json
--- a/needles/console/text_console_login.json
+++ b/needles/console/text_console_login.json
@@ -11,7 +11,8 @@
     "properties": [],
     "tags": [
         "text_console_login",
+        "login_screen",
         "ENV-DISTRI-fedora",
         "ENV-FLAVOR-develop"
     ]
-}
\ No newline at end of file
+}
diff --git a/needles/gnome/login_gdm.json b/needles/gnome/login_gdm.json
--- a/needles/gnome/login_gdm.json
+++ b/needles/gnome/login_gdm.json
@@ -1,6 +1,7 @@
 {
   "tags": [
     "graphical_login",
+    "login_screen",
     "DESKTOP-gnome",
     "ENV-DISTRI-fedora",
     "LANGUAGE-english",
diff --git a/needles/kde/login_sddm-20160518.json b/needles/kde/login_sddm-20160518.json
--- a/needles/kde/login_sddm-20160518.json
+++ b/needles/kde/login_sddm-20160518.json
@@ -18,8 +18,9 @@
   ],
   "tags": [
     "graphical_login",
+    "login_screen",
     "DESKTOP-kde",
     "LANGUAGE-english",
     "ENV-FLAVOR-kde_live"
   ]
-}
\ No newline at end of file
+}
diff --git a/needles/kde/login_sddm-20160628.json b/needles/kde/login_sddm-20160628.json
deleted file mode 100644
--- a/needles/kde/login_sddm-20160628.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "tags": [
-    "graphical_login",
-    "DESKTOP-kde",
-    "LANGUAGE-english"
-  ],
-  "area": [
-    {
-      "xpos": 455,
-      "ypos": 298,
-      "width": 115,
-      "height": 113,
-      "type": "match"
-    },
-    {
-      "xpos": 7,
-      "ypos": 743,
-      "width": 48,
-      "height": 16,
-      "type": "match"
-    }
-  ],
-  "properties": []
-}
\ No newline at end of file
diff --git a/needles/kde/login_sddm-20160628.png b/needles/kde/login_sddm-20160628.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/needles/kde/login_sddm-20160701_f24updated.json b/needles/kde/login_sddm-20160701_f24updated.json
deleted file mode 100644
--- a/needles/kde/login_sddm-20160701_f24updated.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "area": [
-    {
-      "width": 54,
-      "xpos": 17,
-      "ypos": 444,
-      "type": "match",
-      "height": 18
-    },
-    {
-      "width": 47,
-      "type": "match",
-      "height": 19,
-      "ypos": 444,
-      "xpos": 542
-    }
-  ],
-  "properties": [],
-  "tags": [
-    "DESKTOP-kde",
-    "LANGUAGE-english",
-    "graphical_login"
-  ]
-}
\ No newline at end of file
diff --git a/needles/kde/login_sddm-20160701_f24updated.png b/needles/kde/login_sddm-20160701_f24updated.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/needles/kde/login_sddm-20160830.json b/needles/kde/login_sddm-20160830.json
--- a/needles/kde/login_sddm-20160830.json
+++ b/needles/kde/login_sddm-20160830.json
@@ -18,8 +18,9 @@
   ],
   "tags": [
     "graphical_login",
+    "login_screen",
     "DESKTOP-kde",
     "LANGUAGE-english",
     "ENV-FLAVOR-kde_live"
   ]
-}
\ No newline at end of file
+}
diff --git a/needles/kde/login_sddm.json b/needles/kde/login_sddm.json
--- a/needles/kde/login_sddm.json
+++ b/needles/kde/login_sddm.json
@@ -1,12 +1,13 @@
 {
-  "tags": [
+  "tags": [
     "graphical_login",
+    "login_screen",
     "DESKTOP-kde",
     "LANGUAGE-english",
     "ENV-FLAVOR-kde_live"
   ],
   "properties": [],
-  "area": [
+  "area": [
     {
       "xpos": 18,
       "ypos": 444,
diff --git a/templates b/templates
--- a/templates
+++ b/templates
@@ -1962,43 +1962,53 @@
                     {
                       name => "base_selinux",
                       settings => [
-                        { key => "ENTRYPOINT", value => "base_selinux" },
+                        { key => "POSTINSTALL", value => "base_selinux" },
+                        { key => "USER_LOGIN", value => "false" },
+                        { key => "ROOT_PASSWORD", value => "weakpassword" },
                         { key => "START_AFTER_TEST", value => "install_default_upload" },
                         { key => "BOOTFROM", value => "c" },
                         { key => "HDD_1", value => "disk_%FLAVOR%_%MACHINE%.qcow2" },
                       ],
                     },
                     {
                       name => "base_services_start",
                       settings => [
-                        { key => "ENTRYPOINT", value => "base_services_start" },
+                        { key => "POSTINSTALL", value => "base_services_start" },
+                        { key => "USER_LOGIN", value => "false" },
+                        { key => "ROOT_PASSWORD", value => "weakpassword" },
                         { key => "START_AFTER_TEST", value => "install_default_upload" },
                         { key => "BOOTFROM", value => "c" },
                         { key => "HDD_1", value => "disk_%FLAVOR%_%MACHINE%.qcow2" },
                       ],
                     },
                     {
                       name => "base_services_start_arm",
                       settings => [
-                        { key => "ENTRYPOINT", value => "base_services_start" },
+                        { key => "POSTINSTALL", value => "base_services_start" },
+                        { key => "USER_LOGIN", value => "false" },
+                        { key => "ROOT_PASSWORD", value => "weakpassword" },
                         { key => "START_AFTER_TEST", value => "install_arm_image_deployment_upload" },
                         { key => "NUMDISKS", value => "1" },
                         { key => "HDD_1", value => "disk_%FLAVOR%_%MACHINE%.qcow2" },
                       ],
                     },
                     {
                       name => "base_service_manipulation",
                       settings => [
-                        { key => "ENTRYPOINT", value => "base_service_manipulation" },
+                        { key => "POSTINSTALL", value => "base_service_manipulation" },
+                        { key => "USER_LOGIN", value => "false" },
+                        { key => "ROOT_PASSWORD", value => "weakpassword" },
                         { key => "START_AFTER_TEST", value => "install_default_upload" },
                         { key => "BOOTFROM", value => "c" },
                         { key => "HDD_1", value => "disk_%FLAVOR%_%MACHINE%.qcow2" },
                       ],
                     },
                     {
                       name => "base_update_cli",
                       settings => [
-                        { key => "ENTRYPOINT", value => "base_update_cli" },
+                        { key => "POSTINSTALL", value => "base_update_cli" },
+                        { key => "USER_LOGIN", value => "false" },
+                        { key => "ROOT_PASSWORD", value => "weakpassword" },
                         { key => "START_AFTER_TEST", value => "install_default_upload" },
                         { key => "BOOTFROM", value => "c" },
                         { key => "HDD_1", value => "disk_%FLAVOR%_%MACHINE%.qcow2" },
@@ -2037,7 +2047,10 @@
                     {
                       name => "server_role_deploy_domain_controller",
                       settings => [
-                        { key => "ENTRYPOINT", value => "role_deploy_domain_controller" },
+                        { key => "POSTINSTALL", value => "role_deploy_domain_controller" },
+                        { key => "USER_LOGIN", value => "false" },
+                        { key => "ROOT_PASSWORD", value => "weakpassword" },
+                        { key => "GRUB_POSTINSTALL", value => "net.ifnames=0 biosdevname=0" },
                         { key => "START_AFTER_TEST", value => "install_default_upload" },
                         { key => "BOOTFROM", value => "c" },
                         { key => "HDD_1", value => "disk_%FLAVOR%_%MACHINE%.qcow2" },
@@ -2183,7 +2196,7 @@
                     {
                       name => "desktop_notifications_live",
                       settings => [
-                        { key => "ENTRYPOINT", value => "desktop_notifications_postinstall" },
+                        { key => "ENTRYPOINT", value => "desktop_notifications" },
                       ],
                     },
                     {
diff --git a/tests/_console_wait_login.pm b/tests/_console_wait_login.pm
--- a/tests/_console_wait_login.pm
+++ b/tests/_console_wait_login.pm
@@ -1,6 +1,7 @@
 use base "fedorabase";
 use strict;
 use testapi;
+use main_common;
 
 sub run {
     my $self = shift;
@@ -15,7 +16,7 @@
     }
 
     # Wait for the text login
-    assert_screen "text_console_login", $wait_time;
+    boot_to_login_screen(timeout => $wait_time);
 
     # do user login unless USER_LOGIN is set to string 'false'
     unless (get_var("USER_LOGIN") eq "false") {
diff --git a/tests/_graphical_wait_login.pm b/tests/_graphical_wait_login.pm
--- a/tests/_graphical_wait_login.pm
+++ b/tests/_graphical_wait_login.pm
@@ -14,11 +14,7 @@
     $wait_time = 6000 if (get_var("UPGRADE") && !get_var("ENCRYPT_PASSWORD"));
 
     # Wait for the login screen
-    assert_screen "graphical_login", $wait_time;
-    # handle the qemu display buffer sometimes showing the DM from the
-    # *previous* boot - https://openqa.stg.fedoraproject.org/tests/17116
-    wait_still_screen;
-    assert_screen "graphical_login";
+    boot_to_login_screen(timeout => $wait_time);
     # do user login unless USER_LOGIN is set to string 'false'
     unless (get_var("USER_LOGIN") eq "false") {
         if (get_var("DESKTOP") eq 'gnome') {
diff --git a/tests/_support_server_postinstall.pm b/tests/_support_server.pm
rename from tests/_support_server_postinstall.pm
rename to tests/_support_server.pm
diff --git a/tests/base_selinux.pm b/tests/base_selinux.pm
--- a/tests/base_selinux.pm
+++ b/tests/base_selinux.pm
@@ -4,8 +4,6 @@
 
 sub run {
     my $self=shift;
-    # wait for boot to complete
-    $self->boot_to_login_screen("", 30);
     # switch to TTY3 for both, graphical and console tests
     $self->root_console(tty=>3);
     validate_script_output 'getenforce', sub { $_ =~ m/Enforcing/ };
diff --git a/tests/base_service_manipulation.pm b/tests/base_service_manipulation.pm
--- a/tests/base_service_manipulation.pm
+++ b/tests/base_service_manipulation.pm
@@ -1,20 +1,19 @@
 use base "installedtest";
 use strict;
 use testapi;
+use main_common;
 
 sub run {
-    my $self=shift;
-    # wait for boot to complete
-    $self->boot_to_login_screen("", 30);
+    my $self = shift;
     # switch to TTY3 for both, graphical and console tests
     $self->root_console(tty=>3);
     # we could make this slightly more 'efficient' by assuming sshd
     # is always going to be enabled/running at first, but it's safer
     # to force an expected starting state.
     script_run "systemctl stop sshd.service";
     script_run "systemctl disable sshd.service";
     script_run "reboot";
-    $self->boot_to_login_screen("", 30);
+    boot_to_login_screen;
     $self->root_console(tty=>3);
     # note the use of ! here is a bash-ism, but it sure makes life easier
     assert_script_run '! systemctl is-enabled sshd.service';
@@ -33,14 +32,14 @@
     assert_script_run '! systemctl is-active sshd.service';
     assert_script_run '! ps -C sshd';
     script_run "reboot";
-    $self->boot_to_login_screen("", 30);
+    boot_to_login_screen;
     $self->root_console(tty=>3);
     assert_script_run 'systemctl is-enabled sshd.service';
     assert_script_run 'systemctl is-active sshd.service';
     assert_script_run 'ps -C sshd';
     script_run "systemctl disable sshd.service";
     script_run "reboot";
-    $self->boot_to_login_screen("", 30);
+    boot_to_login_screen;
     $self->root_console(tty=>3);
     assert_script_run '! systemctl is-enabled sshd.service';
     assert_script_run '! systemctl is-active sshd.service';
diff --git a/tests/base_services_start.pm b/tests/base_services_start.pm
--- a/tests/base_services_start.pm
+++ b/tests/base_services_start.pm
@@ -3,14 +3,7 @@
 use testapi;
 
 sub run {
-    my $self=shift;
-    if (get_var("ARCH") eq "arm") {
-        # we cannot use boot_to_login_screen, wait_still_screen is unusable during ARM boot (it shows black screen for first few minutes)
-        assert_screen "text_console_login", 150;
-    } else {
-        # wait for boot to complete
-        $self->boot_to_login_screen("", 30);
-    }
+    my $self = shift;
     # switch to TTY3 for both, graphical and console tests
     $self->root_console(tty=>3);
     my $output = script_output 'systemctl --failed';
diff --git a/tests/base_update_cli.pm b/tests/base_update_cli.pm
--- a/tests/base_update_cli.pm
+++ b/tests/base_update_cli.pm
@@ -5,8 +5,6 @@
 
 sub run {
     my $self = shift;
-    # wait for boot to complete
-    $self->boot_to_login_screen("", 30);
     # switch to TTY3 for both, graphical and console tests
     $self->root_console(tty=>3);
     # enable test repos and install test packages
diff --git a/tests/database_client_postinstall.pm b/tests/database_client.pm
rename from tests/database_client_postinstall.pm
rename to tests/database_client.pm
diff --git a/tests/desktop_browser_postinstall.pm b/tests/desktop_browser.pm
rename from tests/desktop_browser_postinstall.pm
rename to tests/desktop_browser.pm
diff --git a/tests/desktop_notifications_postinstall.pm b/tests/desktop_notifications.pm
rename from tests/desktop_notifications_postinstall.pm
rename to tests/desktop_notifications.pm
diff --git a/tests/desktop_terminal_postinstall.pm b/tests/desktop_terminal.pm
rename from tests/desktop_terminal_postinstall.pm
rename to tests/desktop_terminal.pm
diff --git a/tests/desktop_update_graphical_postinstall.pm b/tests/desktop_update_graphical.pm
rename from tests/desktop_update_graphical_postinstall.pm
rename to tests/desktop_update_graphical.pm
--- a/tests/desktop_update_graphical_postinstall.pm
+++ b/tests/desktop_update_graphical.pm
@@ -61,7 +61,7 @@
         if (check_screen 'gnome_reboot_confirm', 15) {
             send_key 'ret';
         }
-        assert_screen 'graphical_login', 300;
+        boot_to_login_screen;
     }
     else {
         # KDE will prompt for authentication if any package is not
diff --git a/tests/firewall_configured_postinstall.pm b/tests/firewall_configured.pm
rename from tests/firewall_configured_postinstall.pm
rename to tests/firewall_configured.pm
diff --git a/tests/firewall_disabled_postinstall.pm b/tests/firewall_disabled.pm
rename from tests/firewall_disabled_postinstall.pm
rename to tests/firewall_disabled.pm
diff --git a/tests/freeipa_client_postinstall.pm b/tests/freeipa_client.pm
rename from tests/freeipa_client_postinstall.pm
rename to tests/freeipa_client.pm
diff --git a/tests/freeipa_password_change_postinstall.pm b/tests/freeipa_password_change.pm
rename from tests/freeipa_password_change_postinstall.pm
rename to tests/freeipa_password_change.pm
diff --git a/tests/freeipa_webui_postinstall.pm b/tests/freeipa_webui.pm
rename from tests/freeipa_webui_postinstall.pm
rename to tests/freeipa_webui.pm
diff --git a/tests/realmd_join_cockpit_postinstall.pm b/tests/realmd_join_cockpit.pm
rename from tests/realmd_join_cockpit_postinstall.pm
rename to tests/realmd_join_cockpit.pm
diff --git a/tests/realmd_join_sssd_postinstall.pm b/tests/realmd_join_sssd.pm
rename from tests/realmd_join_sssd_postinstall.pm
rename to tests/realmd_join_sssd.pm
diff --git a/tests/role_deploy_database_server_postinstall.pm b/tests/role_deploy_database_server.pm
rename from tests/role_deploy_database_server_postinstall.pm
rename to tests/role_deploy_database_server.pm
diff --git a/tests/role_deploy_domain_controller.pm b/tests/role_deploy_domain_controller.pm
--- a/tests/role_deploy_domain_controller.pm
+++ b/tests/role_deploy_domain_controller.pm
@@ -5,11 +5,7 @@
 use mmapi;
 
 sub run {
-    my $self=shift;
-    # boot with kernel params to ensure interface is 'eth0' and not whatever
-    # systemd feels like calling it today
-    $self->do_bootloader(postinstall=>1, params=>"net.ifnames=0 biosdevname=0");
-    $self->boot_to_login_screen("text_console_login", 5, 60);
+    my $self = shift;
     # login
     $self->root_console();
     # clone host's /etc/hosts (for phx2 internal routing to work)
diff --git a/tests/server_cockpit_basic_postinstall.pm b/tests/server_cockpit_basic.pm
rename from tests/server_cockpit_basic_postinstall.pm
rename to tests/server_cockpit_basic.pm
diff --git a/tests/server_cockpit_default_postinstall.pm b/tests/server_cockpit_default.pm
rename from tests/server_cockpit_default_postinstall.pm
rename to tests/server_cockpit_default.pm
diff --git a/tests/server_firewall_default_postinstall.pm b/tests/server_firewall_default.pm
rename from tests/server_firewall_default_postinstall.pm
rename to tests/server_firewall_default.pm
diff --git a/tests/upgrade_preinstall.pm b/tests/upgrade_preinstall.pm
--- a/tests/upgrade_preinstall.pm
+++ b/tests/upgrade_preinstall.pm
@@ -1,41 +1,31 @@
 use base "installedtest";
 use strict;
 use testapi;
+use main_common;
 
 sub run {
     my $self = shift;
     # decrypt disks during boot if necessary
     if (get_var("ENCRYPT_PASSWORD")) {
         $self->boot_decrypt(60);
     }
 
-    # wait for either graphical or text login
-    if (get_var('DESKTOP')) {
-        $self->boot_to_login_screen("graphical_login", 45, 120); # DM takes time to load
-    } else {
-        $self->boot_to_login_screen();
-    }
+    boot_to_login_screen;
     # switch to TTY3 for both, graphical and console tests
     $self->root_console(tty=>3);
     # disable screen blanking (update can take a long time)
     script_run "setterm -blank 0";
 
     # upgrader should be installed on up-to-date system
-
     assert_script_run 'dnf -y update', 1800;
-
     script_run "reboot";
 
     # decrypt if necessary
     if (get_var("ENCRYPT_PASSWORD")) {
         $self->boot_decrypt(60);
     }
 
-    if (get_var('DESKTOP')) {
-        $self->boot_to_login_screen("graphical_login", 45, 120); # DM takes time to load
-    } else {
-        $self->boot_to_login_screen();
-    }
+    boot_to_login_screen;
     $self->root_console(tty=>3);
 
     my $update_command = 'dnf -y install dnf-plugin-system-upgrade';

