Very handy for debugging failures...

New decorator: ui_driver.screenshot created. It should be applied on test methods.

Screenshot is saved on each exception except SkipTest.

Configuration:
- add: `save_screenshots: True` to ~/.ipa/ui_test.conf to enable saving screenshots
- optionally add `screenshot_dir: /path/to/dir` to specify target directory
  otherwise screenshots are saved to current directory
--
Petr Vobornik
From 179c2dca196d211ef9454dae84e9cc7a0580af71 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Tue, 29 Apr 2014 09:16:24 +0200
Subject: [PATCH] webui-ci: decorate all webui tests with screenshot decorator

---
 ipatests/test_webui/test_automember.py     | 4 ++++
 ipatests/test_webui/test_automount.py      | 2 ++
 ipatests/test_webui/test_cert.py           | 2 ++
 ipatests/test_webui/test_config.py         | 2 ++
 ipatests/test_webui/test_delegation.py     | 2 ++
 ipatests/test_webui/test_dns.py            | 4 ++++
 ipatests/test_webui/test_group.py          | 5 +++++
 ipatests/test_webui/test_hbac.py           | 5 +++++
 ipatests/test_webui/test_host.py           | 7 +++++++
 ipatests/test_webui/test_hostgroup.py      | 4 ++++
 ipatests/test_webui/test_krbtpolicy.py     | 2 ++
 ipatests/test_webui/test_navigation.py     | 3 +++
 ipatests/test_webui/test_netgroup.py       | 3 +++
 ipatests/test_webui/test_pwpolicy.py       | 2 ++
 ipatests/test_webui/test_range.py          | 3 +++
 ipatests/test_webui/test_rbac.py           | 2 ++
 ipatests/test_webui/test_realmdomains.py   | 2 ++
 ipatests/test_webui/test_selfservice.py    | 2 ++
 ipatests/test_webui/test_selinuxusermap.py | 4 ++++
 ipatests/test_webui/test_service.py        | 5 +++++
 ipatests/test_webui/test_sudo.py           | 4 ++++
 ipatests/test_webui/test_trust.py          | 4 ++++
 ipatests/test_webui/test_user.py           | 6 ++++++
 23 files changed, 79 insertions(+)

diff --git a/ipatests/test_webui/test_automember.py b/ipatests/test_webui/test_automember.py
index 57cc7c989f9a3e012a609030fc047e24fcf1c6c3..3166fbd29d447833a4b873e37f960fa2a84899af 100644
--- a/ipatests/test_webui/test_automember.py
+++ b/ipatests/test_webui/test_automember.py
@@ -22,6 +22,7 @@ Automember tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_hostgroup as hostgroup
 from ipatests.test_webui.test_host import host_tasks
 
@@ -51,6 +52,7 @@ HOST_GROUP_DATA = {
 
 class test_automember(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: automember
@@ -83,6 +85,7 @@ class test_automember(UI_driver):
         # cleanup
         self.delete(hostgroup.ENTITY, [hostgroup.DATA])
 
+    @screenshot
     def test_rebuild_membership_hosts(self):
         """
         Test automember rebuild membership feature for hosts
@@ -169,6 +172,7 @@ class test_automember(UI_driver):
         self.delete('automember', [{'pkey': 'webservers'}],
                     facet='searchhostgroup')
 
+    @screenshot
     def test_rebuild_membership_users(self):
         """
         Test automember rebuild membership feature for users
diff --git a/ipatests/test_webui/test_automount.py b/ipatests/test_webui/test_automount.py
index 0ab33d7fdaadbb1799dfcb13d7d837d2d0fa6ee4..8a748abe4d6551ddb23fff3413d47bce1c44efd7 100644
--- a/ipatests/test_webui/test_automount.py
+++ b/ipatests/test_webui/test_automount.py
@@ -22,6 +22,7 @@ Automount tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 LOC_ENTITY = 'automountlocation'
 MAP_ENTITY = 'automountmap'
@@ -62,6 +63,7 @@ KEY_DATA = {
 
 class test_automount(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: automount
diff --git a/ipatests/test_webui/test_cert.py b/ipatests/test_webui/test_cert.py
index dc56e6c6a537ac2cf8653a8b9a8d4ac96cc14f4e..979a51e84437e7c8dae8de5412095c1e719e7db4 100644
--- a/ipatests/test_webui/test_cert.py
+++ b/ipatests/test_webui/test_cert.py
@@ -22,6 +22,7 @@ Cert tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ENTITY = 'cert'
 
@@ -34,6 +35,7 @@ class test_cert(UI_driver):
         if not self.has_ca():
             self.skip('CA not configured')
 
+    @screenshot
     def test_read(self):
         """
         Basic read: cert
diff --git a/ipatests/test_webui/test_config.py b/ipatests/test_webui/test_config.py
index f7f568f534c9438e1b00a7876f04a9fc35e2e669..edeec10db02c0d0d806b435a857d7443f5eca5bb 100644
--- a/ipatests/test_webui/test_config.py
+++ b/ipatests/test_webui/test_config.py
@@ -22,6 +22,7 @@ Config tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ENTITY = 'config'
 
@@ -42,6 +43,7 @@ DATA2 = {
 
 class test_config(UI_driver):
 
+    @screenshot
     def test_mod(self):
         """
         Config mod tests
diff --git a/ipatests/test_webui/test_delegation.py b/ipatests/test_webui/test_delegation.py
index 2389b92816b9c73e2a3dabe0f4ba8260558856ff..22276c2e710d77283394c45b2385571b01768bbb 100644
--- a/ipatests/test_webui/test_delegation.py
+++ b/ipatests/test_webui/test_delegation.py
@@ -22,6 +22,7 @@ Delegation tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ENTITY = 'delegation'
 PKEY = 'itest-delegation-rule'
@@ -43,6 +44,7 @@ DATA = {
 
 class test_delegation(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: delegation
diff --git a/ipatests/test_webui/test_dns.py b/ipatests/test_webui/test_dns.py
index dbcb2622e692d2b7bdec2155f9f3ac65a8506dc5..c136460ce3bed12112f88668aa5447c6bf72ed97 100644
--- a/ipatests/test_webui/test_dns.py
+++ b/ipatests/test_webui/test_dns.py
@@ -22,6 +22,7 @@ DNS tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ZONE_ENTITY = 'dnszone'
 RECORD_ENTITY = 'dnsrecord'
@@ -76,6 +77,7 @@ class test_dns(UI_driver):
         if not self.has_dns():
             self.skip('DNS not configured')
 
+    @screenshot
     def test_zone_record_crud(self):
         """
         Basic CRUD: dns
@@ -99,6 +101,7 @@ class test_dns(UI_driver):
         self.navigate_by_breadcrumb("DNS Zones")
         self.delete_record(ZONE_PKEY)
 
+    @screenshot
     def test_last_entry_deletion(self):
         """
         Test last entry deletion
@@ -117,6 +120,7 @@ class test_dns(UI_driver):
         self.navigate_by_breadcrumb("DNS Zones")
         self.delete_record(ZONE_PKEY)
 
+    @screenshot
     def test_config_crud(self):
         """
         Basic CRUD: dnsconfig
diff --git a/ipatests/test_webui/test_group.py b/ipatests/test_webui/test_group.py
index fb5a8363dcf4bd2fed3106fc4f76a0d74550dfbb..8f9229b02546f478872ef8c45c5def906cf46ae7 100644
--- a/ipatests/test_webui/test_group.py
+++ b/ipatests/test_webui/test_group.py
@@ -22,6 +22,7 @@ Group tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_group as group
 import ipatests.test_webui.data_user as user
 import ipatests.test_webui.data_netgroup as netgroup
@@ -32,6 +33,7 @@ import ipatests.test_webui.data_sudo as sudo
 
 class test_group(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: group
@@ -40,6 +42,7 @@ class test_group(UI_driver):
         self.basic_crud(group.ENTITY, group.DATA,
                         default_facet=group.DEFAULT_FACET)
 
+    @screenshot
     def test_actions(self):
         """
         Test group actions
@@ -79,6 +82,7 @@ class test_group(UI_driver):
         self.assert_facet(entity, 'search')
         self.assert_record(pkey, negative=True)
 
+    @screenshot
     def test_associations(self):
         """
         Test group associations
@@ -122,6 +126,7 @@ class test_group(UI_driver):
         self.delete(hbac.RULE_ENTITY, [hbac.RULE_DATA])
         self.delete(sudo.RULE_ENTITY, [sudo.RULE_DATA])
 
+    @screenshot
     def test_indirect_associations(self):
         """
         Group indirect associations
diff --git a/ipatests/test_webui/test_hbac.py b/ipatests/test_webui/test_hbac.py
index 7b283e6a317ec7111dcecb87ae1a557adc951854..c497a2acbe8890cad44dbafd6dc78a42c017e807 100644
--- a/ipatests/test_webui/test_hbac.py
+++ b/ipatests/test_webui/test_hbac.py
@@ -22,12 +22,14 @@ HBAC tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_hbac as hbac
 import ipatests.test_webui.data_hostgroup as hostgroup
 
 
 class test_hbac(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: hbac
@@ -38,6 +40,7 @@ class test_hbac(UI_driver):
         self.basic_crud(hbac.SVCGROUP_ENTITY, hbac.SVCGROUP_DATA,
                         default_facet=hbac.SVCGROUP_DEF_FACET)
 
+    @screenshot
     def test_mod(self):
         """
         Mod: hbac
@@ -72,6 +75,7 @@ class test_hbac(UI_driver):
         self.delete(hbac.RULE_ENTITY, [hbac.RULE_DATA])
         self.delete(hostgroup.ENTITY, [hostgroup.DATA])
 
+    @screenshot
     def test_actions(self):
         """
         Test hbac rule actions
@@ -85,6 +89,7 @@ class test_hbac(UI_driver):
         self.enable_action()
         self.delete_action(hbac.RULE_ENTITY, hbac.RULE_PKEY)
 
+    @screenshot
     def test_hbac_test(self):
         """
         Test HBAC test UI
diff --git a/ipatests/test_webui/test_host.py b/ipatests/test_webui/test_host.py
index 055224a0dfb62a423319411026adfc7c2825094b..3e83f733fe2ae93ad095aebb56008bd939651eda 100644
--- a/ipatests/test_webui/test_host.py
+++ b/ipatests/test_webui/test_host.py
@@ -22,6 +22,7 @@ Host tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_hostgroup as hostgroup
 import ipatests.test_webui.data_netgroup as netgroup
 import ipatests.test_webui.data_hbac as hbac
@@ -104,6 +105,7 @@ class host_tasks(UI_driver):
 
 class test_host(host_tasks):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: host
@@ -111,6 +113,7 @@ class test_host(host_tasks):
         self.init_app()
         self.basic_crud(ENTITY, self.data)
 
+    @screenshot
     def test_certificates(self):
         """
         Test host certificate actions
@@ -175,6 +178,7 @@ class test_host(host_tasks):
         self.navigate_to_entity(ENTITY, 'search')
         self.delete_record(self.pkey, self.data.get('del'))
 
+    @screenshot
     def test_ca_less(self):
         """
         Test host certificate actions in CA-less install
@@ -198,6 +202,7 @@ class test_host(host_tasks):
         self.navigate_by_breadcrumb('Hosts')
         self.delete_record(self.pkey, self.data.get('del'))
 
+    @screenshot
     def test_kerberos_flags(self):
         """
         Test Kerberos flags
@@ -220,6 +225,7 @@ class test_host(host_tasks):
         self.validate_fields([('checkbox', name, [])])
         self.delete_record(self.pkey, self.data.get('del'))
 
+    @screenshot
     def test_associations(self):
         """
         Host direct associations
@@ -258,6 +264,7 @@ class test_host(host_tasks):
         self.delete(hbac.RULE_ENTITY, [hbac.RULE_DATA])
         self.delete(sudo.RULE_ENTITY, [sudo.RULE_DATA])
 
+    @screenshot
     def test_indirect_associations(self):
         """
         Host indirect associations
diff --git a/ipatests/test_webui/test_hostgroup.py b/ipatests/test_webui/test_hostgroup.py
index 9ba612116e2057f883732b3963a4eb6d3deddaa8..b83c0b88c512559280bd89df923e633df59ea7f6 100644
--- a/ipatests/test_webui/test_hostgroup.py
+++ b/ipatests/test_webui/test_hostgroup.py
@@ -22,6 +22,7 @@ Hostgroup tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_hostgroup as hostgroup
 from ipatests.test_webui.test_host import host_tasks, ENTITY as HOST_ENTITY
 import ipatests.test_webui.data_netgroup as netgroup
@@ -32,6 +33,7 @@ import ipatests.test_webui.data_sudo as sudo
 
 class test_hostgroup(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: hostgroup
@@ -40,6 +42,7 @@ class test_hostgroup(UI_driver):
         self.basic_crud(hostgroup.ENTITY, hostgroup.DATA,
                         default_facet=hostgroup.DEFAULT_FACET)
 
+    @screenshot
     def test_associations(self):
         """
         Hostgroup associations
@@ -80,6 +83,7 @@ class test_hostgroup(UI_driver):
         self.delete(hbac.RULE_ENTITY, [hbac.RULE_DATA])
         self.delete(sudo.RULE_ENTITY, [sudo.RULE_DATA])
 
+    @screenshot
     def test_indirect_associations(self):
         """
         Hostgroup indirect associations
diff --git a/ipatests/test_webui/test_krbtpolicy.py b/ipatests/test_webui/test_krbtpolicy.py
index e143a1294e41e034e1d71357ab67038747cac7cf..0b9252efcddfe3ee28251360a7b9be1af704e119 100644
--- a/ipatests/test_webui/test_krbtpolicy.py
+++ b/ipatests/test_webui/test_krbtpolicy.py
@@ -22,6 +22,7 @@ Kerberos policy tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ENTITY = 'krbtpolicy'
 
@@ -42,6 +43,7 @@ DATA2 = {
 
 class test_krbtpolicy(UI_driver):
 
+    @screenshot
     def test_mod(self):
         """
         Kerberos policy mod test
diff --git a/ipatests/test_webui/test_navigation.py b/ipatests/test_webui/test_navigation.py
index e656b0f450215ba76c0d13286a2e5d201cb69a92..bf2461a530a98e3a1a0350a8b5b3d851a71b8a42 100644
--- a/ipatests/test_webui/test_navigation.py
+++ b/ipatests/test_webui/test_navigation.py
@@ -22,6 +22,7 @@ Basic ui tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 
 ENTITIES = [
@@ -63,6 +64,7 @@ ENTITIES = [
 
 class test_navigation(UI_driver):
 
+    @screenshot
     def test_url_navigation(self):
         """
         Navigation test: direct url change
@@ -88,6 +90,7 @@ class test_navigation(UI_driver):
             url = self.get_url(e)
             self.assert_e_url(url, e)
 
+    @screenshot
     def test_menu_navigation(self):
         """
         Navigation test: menu items
diff --git a/ipatests/test_webui/test_netgroup.py b/ipatests/test_webui/test_netgroup.py
index 0336639e795c1fd1b5474eb0f73c080d9fe94b36..55333e54bf8f50114c9871c86647cc363f74ac46 100644
--- a/ipatests/test_webui/test_netgroup.py
+++ b/ipatests/test_webui/test_netgroup.py
@@ -22,6 +22,7 @@ Netgroup tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_netgroup as netgroup
 import ipatests.test_webui.data_user as user
 import ipatests.test_webui.data_group as group
@@ -31,6 +32,7 @@ from ipatests.test_webui.test_host import host_tasks, ENTITY as HOST_ENTITY
 
 class test_netgroup(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: netgroup
@@ -38,6 +40,7 @@ class test_netgroup(UI_driver):
         self.init_app()
         self.basic_crud(netgroup.ENTITY, netgroup.DATA)
 
+    @screenshot
     def test_mod(self):
         """
         Mod: netgroup
diff --git a/ipatests/test_webui/test_pwpolicy.py b/ipatests/test_webui/test_pwpolicy.py
index e6a9e872609e02af55c99cb2fdc609964f827ca1..7abdfd66781efd328733003568a5d4def09d23ec 100644
--- a/ipatests/test_webui/test_pwpolicy.py
+++ b/ipatests/test_webui/test_pwpolicy.py
@@ -22,6 +22,7 @@ Password policy tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ENTITY = 'pwpolicy'
 DATA = {
@@ -45,6 +46,7 @@ DATA = {
 
 class test_pwpolicy(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: pwpolicy
diff --git a/ipatests/test_webui/test_range.py b/ipatests/test_webui/test_range.py
index 663ff42cb7e2e383d45b37d077cf2a21f006a7f4..5c2e33b90833d5e03014e72fad302e58c986ca25 100644
--- a/ipatests/test_webui/test_range.py
+++ b/ipatests/test_webui/test_range.py
@@ -22,6 +22,7 @@ Range tests
 """
 
 import ipatests.test_webui.test_trust as trust_mod
+from ipatests.test_webui.ui_driver import screenshot
 from ipatests.test_webui.task_range import range_tasks
 
 ENTITY = 'idrange'
@@ -30,6 +31,7 @@ PKEY = 'itest-range'
 
 class test_range(range_tasks):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: range
@@ -38,6 +40,7 @@ class test_range(range_tasks):
         self.get_shifts()
         self.basic_crud(ENTITY, self.get_data(PKEY))
 
+    @screenshot
     def test_types(self):
         """
         Test range types
diff --git a/ipatests/test_webui/test_rbac.py b/ipatests/test_webui/test_rbac.py
index e785131f550b1c06bbc158ce3846df1de4eb2a3e..8477b118da6cd659158ed96b84d50e8b1a33efb8 100644
--- a/ipatests/test_webui/test_rbac.py
+++ b/ipatests/test_webui/test_rbac.py
@@ -22,6 +22,7 @@ RBAC tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ROLE_ENTITY = 'role'
 ROLE_DEF_FACET = 'member_user'
@@ -71,6 +72,7 @@ PERMISSION_DATA = {
 
 class test_rbac(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: RBAC
diff --git a/ipatests/test_webui/test_realmdomains.py b/ipatests/test_webui/test_realmdomains.py
index 7836f689cc558ed75459c6bc7c6a1b9c5eef677e..8e8f13a5c61ca660d8aa0bf872765ba643bdb8dc 100644
--- a/ipatests/test_webui/test_realmdomains.py
+++ b/ipatests/test_webui/test_realmdomains.py
@@ -22,12 +22,14 @@ Realm domains tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ENTITY = 'realmdomains'
 
 
 class test_realmdomains(UI_driver):
 
+    @screenshot
     def test_read(self):
         """
         Realm domains mod tests
diff --git a/ipatests/test_webui/test_selfservice.py b/ipatests/test_webui/test_selfservice.py
index b1ee7f4585e04e68e92ba06823a76b0f99af8ab1..ce1971e540dba93579cb2bf543f650fa87c4e302 100644
--- a/ipatests/test_webui/test_selfservice.py
+++ b/ipatests/test_webui/test_selfservice.py
@@ -22,6 +22,7 @@ Selfservice tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ENTITY = 'selfservice'
 PKEY = 'itest-selfservice-rule'
@@ -40,6 +41,7 @@ DATA = {
 
 class test_selfservice(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: selfservice entity
diff --git a/ipatests/test_webui/test_selinuxusermap.py b/ipatests/test_webui/test_selinuxusermap.py
index 29b9479aa6457be6af55ac2148b365f10b96cd28..385b8dd0612af178091164d2416e4adc3a1d3429 100644
--- a/ipatests/test_webui/test_selinuxusermap.py
+++ b/ipatests/test_webui/test_selinuxusermap.py
@@ -22,6 +22,7 @@ SELinux user map tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_user as user
 import ipatests.test_webui.data_group as group
 import ipatests.test_webui.data_hostgroup as hostgroup
@@ -43,6 +44,7 @@ DATA = {
 
 class test_selinuxusermap(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: selinuxusermap
@@ -50,6 +52,7 @@ class test_selinuxusermap(UI_driver):
         self.init_app()
         self.basic_crud(ENTITY, DATA)
 
+    @screenshot
     def test_mod(self):
         """
         Mod: selinuxusermap
@@ -91,6 +94,7 @@ class test_selinuxusermap(UI_driver):
         self.delete(HOST_ENTITY, [host.data, host.data2])
         self.delete(hostgroup.ENTITY, [hostgroup.DATA, hostgroup.DATA2])
 
+    @screenshot
     def test_actions(self):
         """
         Test SELinux user map actions
diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index 8ed2e15b5acb200c3aa5ef5a11bb557f39e5f39c..9a2d6f904a1f50cdec9fb7a3c587d4bb5e587602 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -22,6 +22,7 @@ Service tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 
 ENTITY = 'service'
 
@@ -60,6 +61,7 @@ class sevice_tasks(UI_driver):
 
 class test_service(sevice_tasks):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: service
@@ -68,6 +70,7 @@ class test_service(sevice_tasks):
         data = self.prep_data()
         self.basic_crud(ENTITY, data)
 
+    @screenshot
     def test_certificates(self):
         """
         Test service certificate actions
@@ -135,6 +138,7 @@ class test_service(sevice_tasks):
         self.navigate_to_entity(ENTITY, 'search')
         self.delete_record(pkey, data.get('del'))
 
+    @screenshot
     def test_ca_less(self):
         """
         Test service certificate actions in CA-less install
@@ -170,6 +174,7 @@ class test_service(sevice_tasks):
         self.assert_action_panel_action(panel, 'view_cert')
         self.assert_action_panel_action(panel, 'get_cert')
 
+    @screenshot
     def test_kerberos_flags(self):
         """
         Test Kerberos flags
diff --git a/ipatests/test_webui/test_sudo.py b/ipatests/test_webui/test_sudo.py
index 0fd7bcab63bb0ba599a9353bfeb0c57e64cef54e..acc1373ea452376ddcf50a23ea15c1fa04aa8f61 100644
--- a/ipatests/test_webui/test_sudo.py
+++ b/ipatests/test_webui/test_sudo.py
@@ -22,6 +22,7 @@ Sudo tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_sudo as sudo
 import ipatests.test_webui.data_netgroup as netgroup
 import ipatests.test_webui.data_user as user
@@ -32,6 +33,7 @@ from ipatests.test_webui.test_host import host_tasks, ENTITY as HOST_ENTITY
 
 class test_sudo(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: sudo
@@ -42,6 +44,7 @@ class test_sudo(UI_driver):
         self.basic_crud(sudo.CMDGROUP_ENTITY, sudo.CMDGROUP_DATA,
                         default_facet=sudo.CMDGROUP_DEF_FACET)
 
+    @screenshot
     def test_mod(self):
         """
         Mod: sudo
@@ -109,6 +112,7 @@ class test_sudo(UI_driver):
         self.delete(HOST_ENTITY, [host.data, host.data2])
         self.delete(hostgroup.ENTITY, [hostgroup.DATA, hostgroup.DATA2])
 
+    @screenshot
     def test_actions(self):
         """
         Test sudo rule actions
diff --git a/ipatests/test_webui/test_trust.py b/ipatests/test_webui/test_trust.py
index 1e91767772a3a3d19bea76d31488748e7b7416ce..95e0fedda54722e7d9a7e82e238c10d0a127e4ad 100644
--- a/ipatests/test_webui/test_trust.py
+++ b/ipatests/test_webui/test_trust.py
@@ -22,6 +22,7 @@ Trust tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 from ipatests.test_webui.task_range import range_tasks
 
 ENTITY = 'trust'
@@ -100,6 +101,7 @@ class test_trust(trust_tasks):
         if not self.has_trusts():
             self.skip('Trusts not configured')
 
+    @screenshot
     def test_crud(self):
         """
         Basic basic CRUD: trust
@@ -114,6 +116,7 @@ class test_trust(trust_tasks):
         self.navigate_to_entity('idrange')
         self.delete_record(self.get_range_name())
 
+    @screenshot
     def test_range_types(self):
 
         self.init_app()
@@ -144,6 +147,7 @@ class test_trust(trust_tasks):
         self.assert_record_value('Active Directory trust range with POSIX attributes', range_pkey, column)
         self.delete_record(range_pkey)
 
+    @screenshot
     def test_config_mod(self):
 
         self.init_app()
diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py
index e85a9cbad6d7307eb5ac70af23e09e609ee8264d..bf9589d4dbcbfed17ca0f67f297ca5ae99e79284 100644
--- a/ipatests/test_webui/test_user.py
+++ b/ipatests/test_webui/test_user.py
@@ -22,6 +22,7 @@ User tests
 """
 
 from ipatests.test_webui.ui_driver import UI_driver
+from ipatests.test_webui.ui_driver import screenshot
 import ipatests.test_webui.data_user as user
 import ipatests.test_webui.data_group as group
 import ipatests.test_webui.data_netgroup as netgroup
@@ -37,6 +38,7 @@ except ImportError:
 
 class test_user(UI_driver):
 
+    @screenshot
     def test_crud(self):
         """
         Basic CRUD: user
@@ -44,6 +46,7 @@ class test_user(UI_driver):
         self.init_app()
         self.basic_crud(user.ENTITY, user.DATA)
 
+    @screenshot
     def test_associations(self):
         """
         User direct associations
@@ -80,6 +83,7 @@ class test_user(UI_driver):
         self.delete(hbac.RULE_ENTITY, [hbac.RULE_DATA])
         self.delete(sudo.RULE_ENTITY, [sudo.RULE_DATA])
 
+    @screenshot
     def test_indirect_associations(self):
         """
         User indirect associations
@@ -134,6 +138,7 @@ class test_user(UI_driver):
         self.delete(hbac.RULE_ENTITY, [hbac.RULE_DATA])
         self.delete(sudo.RULE_ENTITY, [sudo.RULE_DATA])
 
+    @screenshot
     def test_actions(self):
         """
         Test user actions
@@ -154,6 +159,7 @@ class test_user(UI_driver):
         # delete
         self.delete_action(user.ENTITY, user.PKEY)
 
+    @screenshot
     def test_password_expiration_notification(self):
         """
         Test password expiration notification
-- 
1.9.0

From 8027aa41f54cb4214dca50ce2fad068b14797606 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Mon, 28 Apr 2014 16:59:50 +0200
Subject: [PATCH] webui-ci: save screenshot on test failure

New decorator: ui_driver.screenshot created. It should be applied on test methods.

Screenshot is saved on each exception except SkipTest.

Configuration:
- add: `save_screenshots: True` to ~/.ipa/ui_test.conf to enable saving screenshots
- optionally add `screenshot_dir: /path/to/dir` to specify target directory
  otherwise screenshots are saved to current directory
---
 ipatests/test_webui/ui_driver.py | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 7cfe21ad8985b04fcb296adccf0277a5f02833b9..20e6464fff655e0a327ebeaf898b623d6eccc437 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -24,9 +24,12 @@ Contains browser driver and common tasks.
 """
 
 import nose
+from datetime import datetime
 import time
 import re
 import os
+from functools import wraps
+from nose.plugins.skip import SkipTest
 
 try:
     from selenium import webdriver
@@ -77,6 +80,29 @@ DEFAULT_PORT = 4444
 DEFAULT_TYPE = 'local'
 
 
+def screenshot(fn):
+    """
+    Decorator for saving screenshot on exception (test fail)
+    Should be applied on methods of UI_driver subclasses
+    """
+    @wraps(fn)
+    def screenshot_wrapper(*args):
+        try:
+            return fn(*args)
+        except SkipTest:
+            raise
+        except Exception:
+            self = args[0]
+            name = '%s_%s_%s' % (
+                datetime.now().isoformat(),
+                self.__class__.__name__,
+                fn.__name__)
+            self.take_screenshot(name)
+            raise
+
+    return screenshot_wrapper
+
+
 class UI_driver(object):
     """
     Base class for all UI integration tests
@@ -368,6 +394,14 @@ class UI_driver(object):
         screen = self.get_login_screen()
         return screen and screen.is_displayed()
 
+    def take_screenshot(self, name):
+        if self.config.get('save_screenshots'):
+            scr_dir = self.config.get('screenshot_dir')
+            path = name + '.png'
+            if scr_dir:
+                path = os.path.join(scr_dir, path)
+            self.driver.get_screenshot_as_file(path)
+
     def navigate_to_entity(self, entity, facet=None):
         self.driver.get(self.get_url(entity, facet))
         self.wait_for_request(n=3, d=0.4)
-- 
1.9.0

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to