#3 Add test cases for reporter.consolelog
Merged 7 years ago by nkondras. Opened 7 years ago by agustinhenze.
agustinhenze/skt test-cases-for-reporter  into  master

file modified
+4
@@ -11,6 +11,10 @@ 

  

      $ sudo yum install python2 python2-junit_xml beaker-client

  

+ Extra dependencies needed for running the testsuite:

+ 

+     $ sudo yum install python2-mock

+ 

  Run tests

  ---------

  

file modified
+2
@@ -162,6 +162,8 @@ 

          insplat = False

          inct = False

          tmpdata = []

+         # FIXME Check if line == True otherwise it adds an empty line at the

+         # end of the extracted trace.

          for line in self.data:

              if self.oopspattern.search(line):

                  insplat = True

@@ -0,0 +1,43 @@ 

+ [     0.000000] Linux version 4-5-fake (debian-kernel@lists.debian.org) (gcc version 7.3.0 (Debian 7.3.0-3)) #1 SMP Debian 4.15.4-1 (2018-02-18)

+ [166357.529863] BUG: unable to handle kernel paging request at ffffffe8

+ [166357.529901] IP: [<c131ef5a>] alloc_vmap_area.isra.20+0x12a/0x2c0

+ [166357.529924] *pdpt = 0000000001f1c001 *pde = 0000000001f20067 *pte = 0000000000000000

+ [166357.529950] Oops: 0000 [#1] PREEMPT SMP

+ [166357.529973] Modules linked in: atomisp_css2300 lm3554 mt9m114 ov8830 compat(O) rmi4 st_drv videobuf_vmalloc videobuf_core matrix(O) hdmi_audio pvrsgx wl12xx(O) mac80211(O) cfg80211(O) wl12xx_sdio(O) pnwdisp

+ [166357.530079] CPU: 1 PID: 6779 Comm: iptables Tainted: G        W  O 3.10.20-262458-ge1b992c #1

+ [166357.530090] Hardware name: Intel Corporation CloverTrail/FFRD, BIOS 406 2013.10.16:10.18.10

+ [166357.530102] task: cd195110 ti: cd5b8000 task.ti: cd5b8000

+ [166357.530117] EIP: 0060:[<c131ef5a>] EFLAGS: 00010213 CPU: 1

+ [166357.530134] EIP is at alloc_vmap_area.isra.20+0x12a/0x2c0

+ [166357.530145] EAX: e8db4000 EBX: 00000000 ECX: 00000000 EDX: e8db2000

+ [166357.530154] ESI: ffffffe8 EDI: 00001000 EBP: cd5b9dcc ESP: cd5b9d98

+ [166357.530165]  DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068

+ [166357.530175] CR0: 80050033 CR2: ffffffe8 CR3: 0d5b6000 CR4: 000007f0

+ [166357.530185] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000

+ [166357.530195] DR6: ffff0ff0 DR7: 00000400

+ [166357.530204] Stack:

+ [166357.530212]  cd5b9dcc c132b08a 00002000 c75ca600 00000000 00000000 dec00000 ffffffff

+ [166357.530261]  dec00000 00000001 c75ca180 00000022 00000001 cd5b9dec c131f177 ffbfe000

+ [166357.530304]  000080d2 00001000 ffbfe000 80000000 ffffffff cd5b9e20 c131fe47 dec00000

+ [166357.530354] Call Trace:

+ [166357.530371]  [<c132b08a>] ? kmem_cache_alloc_trace+0xaa/0x170

+ [166357.530388]  [<c131f177>] __get_vm_area_node.isra.21+0x87/0x160

+ [166357.530402]  [<c131fe47>] __vmalloc_node_range+0x57/0x200

+ [166357.530417]  [<c18c3da6>] ? do_ipt_get_ctl+0x1a6/0x320

+ [166357.530431]  [<c1320052>] __vmalloc_node+0x62/0x70

+ [166357.530445]  [<c18c3da6>] ? do_ipt_get_ctl+0x1a6/0x320

+ [166357.530459]  [<c1320278>] vzalloc+0x38/0x40

+ [166357.530473]  [<c18c3da6>] ? do_ipt_get_ctl+0x1a6/0x320

+ [166357.530488]  [<c18c3da6>] do_ipt_get_ctl+0x1a6/0x320

+ [166357.530503]  [<c1460fc7>] ? avc_has_perm_flags+0xc7/0x170

+ [166357.530521]  [<c1862d10>] nf_getsockopt+0x40/0x60

+ [166357.530536]  [<c1883804>] ip_getsockopt+0x84/0xc0

+ [166357.530551]  [<c18a2982>] raw_getsockopt+0x32/0xb0

+ [166357.530567]  [<c1830e77>] sock_common_getsockopt+0x27/0x40

+ [166357.530582]  [<c183035e>] SyS_getsockopt+0x6e/0xe0

+ [166357.530598]  [<c1830be9>] SyS_socketcall+0x2b9/0x300

+ [166357.530615]  [<c14b88b8>] ? trace_hardirqs_on_thunk+0xc/0x10

+ [166357.530631]  [<c195e698>] syscall_call+0x7/0xb

+ [166357.530642] Code: 16 01 00 00 39 45 08 72 60 8b 3d 40 09 fb c1 89 5d d4 eb 27 90 8d 74 26 00 8b 4e 18 81 f9 fc c3 de c1 0f 84 e9 00 00 00 8d 71 e8 <8b> 49 e8 39 c1 0f 83 db 00 00 00 3b 45 08 77 20 8d 04 17 89 cb

+ [166357.530945] EIP: [<c131ef5a>] alloc_vmap_area.isra.20+0x12a/0x2c0 SS:ESP 0068:cd5b9d98

+ [166357.530971] CR2: 00000000ffffffe8

@@ -0,0 +1,110 @@ 

+ [    0.000000] Linux version 4.16-fake (debian-kernel@lists.debian.org) (gcc version 7.3.0 (Debian 7.3.0-3)) #1 SMP Debian 4.15.4-1 (2018-02-18)

+ [    0.066297] general protection fault: 0000 [#1] SMP PTI

+ [    0.067000] Modules linked in:

+ [    0.067000] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.16.0-rc1-00044-g11d88c812 #153

+ [    0.067000] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014

+ [    0.067000] RIP: 0010:sync_sched_exp_handler+0x14/0x96

+ [    0.067000] RSP: 0000:ffffb08f40197d10 EFLAGS: 00010287

+ [    0.067000] RAX: deacd7b935400000 RBX: ffffffffb6a831c0 RCX: 0000000000000003

+ [    0.067000] RDX: 0000000000000000 RSI: ffffffffb6a7f2c0 RDI: ffffffffb6a835c8

+ [    0.067000] RBP: ffffffffb6a831c0 R08: 00000000e272d5c3 R09: 0000000000000004

+ [    0.067000] R10: ffff890c349c8040 R11: 0000000000000001 R12: 0000000fffffffe0

+ [    0.067000] R13: ffffffffb511fa14 R14: ffffffffb6a835c8 R15: 0000000000000000

+ [    0.067000] FS:  0000000000000000(0000) GS:ffff890c35400000(0000) knlGS:0000000000000000

+ [    0.067000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033

+ [    0.067000] CR2: 00000000ffffffff CR3: 0000000031a24000 CR4: 00000000000006f0

+ [    0.067000] Call Trace:

+ [    0.067000]  sync_rcu_exp_select_cpus+0x3da/0x44c

+ [    0.067000]  _synchronize_rcu_expedited+0x6e2/0x83f

+ [    0.067000]  ? _raw_spin_unlock_irq+0x29/0x39

+ [    0.067000]  ? finish_task_switch+0x163/0x22d

+ [    0.067000]  ? finish_task_switch+0x1dc/0x22d

+ [    0.067000]  ? __schedule+0xa24/0xa8d

+ [    0.067000]  synchronize_sched+0xca/0x102

+ [    0.067000]  ? trace_hardirqs_on_caller+0x177/0x191

+ [    0.067000]  ? unregister_nmi_handler+0xac/0xbb

+ [    0.067000]  test_nmi_ipi+0x6e/0x7f

+ [    0.067000]  dotest+0x7/0x65

+ [    0.067000]  nmi_selftest+0x59/0x152

+ [    0.067000]  native_smp_cpus_done+0x65/0xfc

+ [    0.067000]  kernel_init_freeable+0x123/0x25a

+ [    0.067000]  ? rest_init+0x22e/0x22e

+ [    0.067000]  kernel_init+0xa/0xf0

+ [    0.067000]  ret_from_fork+0x3a/0x50

+ [    0.067000] Code: 4a 48 89 df e8 10 88 ce 00 66 c7 83 3a 17 00 00 06 00 e9 b1 ec ff ff 66 66 66 66 90 48 8b 87 98 16 00 00 65 48 03 05 10 f7 ee 4a <48> 8b 50 20 48 8b 52 70 48 85 50 28 74 73 65 8a 05 dc 36 0c 4b

+ [    0.067000] RIP: sync_sched_exp_handler+0x14/0x96 RSP: ffffb08f40197d10

+ [    0.067040] ---[ end trace 52ba43a846e7343b ]---

+ nt [92047.021654] IPv6: ADDRCONF(NETDEV_CHANGE): wlp5s0: link becomes ready

+ nt [92029.923741] IRQ 122: no longer affine to CPU3

+ nt [92029.924766] smpboot: CPU 3 is now offline

+ [    0.066297] general protection fault: 0000 [#1] SMP PTI

+ [    0.067000] Modules linked in:

+ [    0.067000] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.16.0-rc1-00044-g11d88c812 #153

+ [    0.067000] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014

+ [    0.067000] RIP: 0010:sync_sched_exp_handler+0x14/0x96

+ [    0.067000] RSP: 0000:ffffb08f40197d10 EFLAGS: 00010287

+ [    0.067000] RAX: deacd7b935400000 RBX: ffffffffb6a831c0 RCX: 0000000000000003

+ [    0.067000] RDX: 0000000000000000 RSI: ffffffffb6a7f2c0 RDI: ffffffffb6a835c8

+ [    0.067000] RBP: ffffffffb6a831c0 R08: 00000000e272d5c3 R09: 0000000000000004

+ [    0.067000] R10: ffff890c349c8040 R11: 0000000000000001 R12: 0000000fffffffe0

+ [    0.067000] R13: ffffffffb511fa14 R14: ffffffffb6a835c8 R15: 0000000000000000

+ [    0.067000] FS:  0000000000000000(0000) GS:ffff890c35400000(0000) knlGS:0000000000000000

+ [    0.067000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033

+ [    0.067000] CR2: 00000000ffffffff CR3: 0000000031a24000 CR4: 00000000000006f0

+ [    0.067000] Call Trace:

+ [    0.067000]  sync_rcu_exp_select_cpus+0x3da/0x44c

+ [    0.067000]  _synchronize_rcu_expedited+0x6e2/0x83f

+ [    0.067000]  ? _raw_spin_unlock_irq+0x29/0x39

+ [    0.067000]  ? finish_task_switch+0x163/0x22d

+ [    0.067000]  ? finish_task_switch+0x1dc/0x22d

+ [    0.067000]  ? __schedule+0xa24/0xa8d

+ [    0.067000]  synchronize_sched+0xca/0x102

+ [    0.067000]  ? trace_hardirqs_on_caller+0x177/0x191

+ [    0.067000]  ? unregister_nmi_handler+0xac/0xbb

+ [    0.067000]  test_nmi_ipi+0x6e/0x7f

+ [    0.067000]  dotest+0x7/0x65

+ [    0.067000]  nmi_selftest+0x59/0x152

+ [    0.067000]  native_smp_cpus_done+0x65/0xfc

+ [    0.067000]  kernel_init_freeable+0x123/0x25a

+ [    0.067000]  ? rest_init+0x22e/0x22e

+ [    0.067000]  kernel_init+0xa/0xf0

+ [    0.067000]  ret_from_fork+0x3a/0x50

+ [    0.067000] Code: 4a 48 89 df e8 10 88 ce 00 66 c7 83 3a 17 00 00 06 00 e9 b1 ec ff ff 66 66 66 66 90 48 8b 87 98 16 00 00 65 48 03 05 10 f7 ee 4a <48> 8b 50 20 48 8b 52 70 48 85 50 28 74 73 65 8a 05 dc 36 0c 4b

+ [    0.067000] RIP: sync_sched_exp_handler+0x14/0x96 RSP: ffffb08f40197d10

+ [    0.067040] ---[ end trace 52ba43a846e7343b ]---

+ nt [92032.111092] PM: suspend exit

+ [    0.066297] general protection fault: 0000 [#1] SMP PTI

+ [    0.067000] Modules linked in:

+ [    0.067000] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.16.0-rc1-00044-g11d88c812 #153

+ [    0.067000] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014

+ [    0.067000] RIP: 0010:sync_sched_exp_handler+0x14/0x96

+ [    0.067000] RSP: 0000:ffffb08f40197d10 EFLAGS: 00010287

+ [    0.067000] RAX: deacd7b935400000 RBX: ffffffffb6a831c0 RCX: 0000000000000003

+ [    0.067000] RDX: 0000000000000000 RSI: ffffffffb6a7f2c0 RDI: ffffffffb6a835c8

+ [    0.067000] RBP: ffffffffb6a831c0 R08: 00000000e272d5c3 R09: 0000000000000004

+ [    0.067000] R10: ffff890c349c8040 R11: 0000000000000001 R12: 0000000fffffffe0

+ [    0.067000] R13: ffffffffb511fa14 R14: ffffffffb6a835c8 R15: 0000000000000000

+ [    0.067000] FS:  0000000000000000(0000) GS:ffff890c35400000(0000) knlGS:0000000000000000

+ [    0.067000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033

+ [    0.067000] CR2: 00000000ffffffff CR3: 0000000031a24000 CR4: 00000000000006f0

+ [    0.067000] Call Trace:

+ [    0.067000]  sync_rcu_exp_select_cpus+0x3da/0x44c

+ [    0.067000]  _synchronize_rcu_expedited+0x6e2/0x83f

+ [    0.067000]  ? _raw_spin_unlock_irq+0x29/0x39

+ [    0.067000]  ? finish_task_switch+0x163/0x22d

+ [    0.067000]  ? finish_task_switch+0x1dc/0x22d

+ [    0.067000]  ? __schedule+0xa24/0xa8d

+ [    0.067000]  synchronize_sched+0xca/0x102

+ [    0.067000]  ? trace_hardirqs_on_caller+0x177/0x191

+ [    0.067000]  ? unregister_nmi_handler+0xac/0xbb

+ [    0.067000]  test_nmi_ipi+0x6e/0x7f

+ [    0.067000]  dotest+0x7/0x65

+ [    0.067000]  nmi_selftest+0x59/0x152

+ [    0.067000]  native_smp_cpus_done+0x65/0xfc

+ [    0.067000]  kernel_init_freeable+0x123/0x25a

+ [    0.067000]  ? rest_init+0x22e/0x22e

+ [    0.067000]  kernel_init+0xa/0xf0

+ [    0.067000]  ret_from_fork+0x3a/0x50

+ [    0.067000] Code: 4a 48 89 df e8 10 88 ce 00 66 c7 83 3a 17 00 00 06 00 e9 b1 ec ff ff 66 66 66 66 90 48 8b 87 98 16 00 00 65 48 03 05 10 f7 ee 4a <48> 8b 50 20 48 8b 52 70 48 85 50 28 74 73 65 8a 05 dc 36 0c 4b

+ [    0.067000] RIP: sync_sched_exp_handler+0x14/0x96 RSP: ffffb08f40197d10

+ [    0.067040] ---[ end trace 52ba43a846e7343b ]---

file added
+42
@@ -0,0 +1,42 @@ 

+ """

+ Miscellaneous for tests.

+ """

+ # Copyright (c) 2018 Red Hat, Inc. All rights reserved. This copyrighted material

+ # is made available to anyone wishing to use, modify, copy, or

+ # redistribute it subject to the terms and conditions of the GNU General

+ # Public License v.2 or later.

+ #

+ # This program 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 this program; if not, write to the Free Software

+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

+ import os

+ 

+ 

+ ASSETS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'assets')

+ 

+ 

+ def get_asset_path(filename):

+     """Return the absolute path of an asset passed as parameter.

+ 

+     Args:

+         filename: Asset's filename.

+     Returns:

+         The absolute path of the corresponding asset.

+     """

+     return os.path.join(ASSETS_DIR, filename)

+ 

+ 

+ def get_asset_content(filename):

+     """Return the content of an asset passed as parameter.

+ 

+     Args:

+         filename: Asset's filename.

+     Returns:

+         The content of the corresponding asset.

+     """

+     with open(get_asset_path(filename)) as asset:

+         return asset.read()

file modified
+17
@@ -1,8 +1,25 @@ 

+ """

+ Test cases for publisher module.

+ """

+ # Copyright (c) 2018 Red Hat, Inc. All rights reserved. This copyrighted material

+ # is made available to anyone wishing to use, modify, copy, or

+ # redistribute it subject to the terms and conditions of the GNU General

+ # Public License v.2 or later.

+ #

+ # This program 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 this program; if not, write to the Free Software

+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  import unittest

  from skt import publisher

  

  

  class TestPublisher(unittest.TestCase):

+     """Test cases for publisher.publisher class"""

      def test_geturl(self):

+         """Check if the source url is built correctly"""

          pub = publisher.publisher('dest', 'file:///tmp/test')

          self.assertEqual(pub.geturl('source'), 'file:///tmp/test/source')

@@ -0,0 +1,93 @@ 

+ """

+ Test cases for reporter module.

+ """

+ # Copyright (c) 2018 Red Hat, Inc. All rights reserved. This copyrighted material

+ # is made available to anyone wishing to use, modify, copy, or

+ # redistribute it subject to the terms and conditions of the GNU General

+ # Public License v.2 or later.

+ #

+ # This program 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 this program; if not, write to the Free Software

+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

+ import unittest

+ from contextlib import contextmanager

+ import re

+ import mock

+ from skt import reporter

+ from tests import misc

+ 

+ 

+ class TestConsoleLog(unittest.TestCase):

+     """Test cases for reporter.consolelog class"""

+     @staticmethod

+     @contextmanager

+     def request_get_mocked(filename):

+         """Mock request.get to allow feeding consolelog with known inputs. When

+         request.get is called, it "fetches" the content of the asset passed as

+         parameter.

+ 

+         Args:

+             filename: Asset's filename.

+         """

+         get_mocked = mock.Mock()

+         def remove_nt_marker(line):

+             """Filter function for removing the 'nt ' markers on assets"""

+             return not re.match(r'^nt ', line)

+         get_mocked.text = filter(remove_nt_marker,

+                                  misc.get_asset_content(filename))

+         with mock.patch('requests.get', mock.Mock(return_value=get_mocked)):

+             yield

+ 

+     @staticmethod

+     def get_expected_traces(filename):

+         """Return expected traces from an asset. Each line started with 'nt '

+         is discarded.

+ 

+         Args:

+             filename: Asset's filename.

+         Returns:

+             A list where every member is a trace.

+         """

+         expected_traces = []

+         tmp_trace = []

+         for line in misc.get_asset_content(filename).splitlines()[1:]:

+             if line.startswith('nt '):

+                 if tmp_trace:

+                     expected_traces.append('\n'.join(tmp_trace))

+                     tmp_trace = []

+             else:

+                 tmp_trace.append(line)

+         expected_traces.append('\n'.join(tmp_trace))

+         return expected_traces

+ 

+     def test_kernel_version_unmatch(self):

+         """Check it doesn't catch any trace when kernel version doesn't match"""

+         consolelog = reporter.consolelog('4-4', 'someurl')

+         with self.request_get_mocked('x86_one_trace.txt'):

+             traces = consolelog.gettraces()

+         self.assertListEqual(traces, [])

+ 

+     def test_match_one_trace(self):

+         """Check one trace can be extracted from a console log"""

+         consolelog = reporter.consolelog('4-5-fake', 'someurl')

+         with self.request_get_mocked('x86_one_trace.txt'):

+             traces = consolelog.gettraces()

+             self.assertEqual(len(traces), 1)

+         expected_trace = self.get_expected_traces('x86_one_trace.txt')[0] + '\n'

+         self.assertEqual(expected_trace, traces[0])

+ 

+     def test_match_three_traces(self):

+         """Check three traces can be extracted from a console log"""

+         consolelog = reporter.consolelog('4.16-fake', 'someurl')

+         with self.request_get_mocked('x86_three_traces.txt'):

+             traces = consolelog.gettraces()

+             self.assertEqual(len(traces), 3)

+         expected_traces = self.get_expected_traces('x86_three_traces.txt')

+         for idx, trace in enumerate(traces):

+             msg = ("Trace_{} doesn't match.\n"

+                    "{!r} != {!r}").format(idx, trace, expected_traces[idx])

+             self.assertEqual(trace, expected_traces[idx], msg=msg)

  • Add basic reporter tests
  • Add license header to tests/test_publisher.py
  • Document tests/test_publisher.py code
  • Add FIXME about consolelog.gettraces() output

I don't have them handy, but, @asavkov, do you perhaps have a stash of console logs somewhere from the time you implemented the parsing?

Augustin, could you please document the code, following the Google Python Style Guide?

And yeah, I missed that in the previous PR, can you add documentation to that code too, please?

Thank you.

I don't have them handy, but, @asavkov, do you perhaps have a stash of console logs somewhere from the time you implemented the parsing?

No, sorry, this is a port from a perl-script I've been tweaking a lot over long periods of time.

Thank you, Artem.

Agustin, perhaps you can find something by searching for the typical strings that appear in oops'es and call traces (e.g. taken from the regex lists) on sites like lkml.org. E.g. https://duckduckgo.com/?q=general+protection+fault+site%3Alkml.org

I don't have them handy, but, @asavkov, do you perhaps have a stash of console logs somewhere from the time you implemented the parsing?
Augustin, could you please document the code, following the Google Python Style Guide?

Sure. Are you thinking about using pep8 as well?

And yeah, I missed that in the previous PR, can you add documentation to that code too, please?

No problem. Just to see if we are talking about the same. Are you suggesting to add docstring on every test case? Usually a best practice is just pick the right name for the test case.

Thank you, Artem.
Agustin, perhaps you can find something by searching for the typical strings that appear in oops'es and call traces (e.g. taken from the regex lists) on sites like lkml.org. E.g. https://duckduckgo.com/?q=general+protection+fault+site%3Alkml.org

Thanks :). I was wondering how reliable the test cases will be if I do this. Using actual output is the best way to go for me because it will ensure that the test case cover the current desired behavior. So, if you can get some real cases (the output that you used when wrote the code) I'll really appreciate it.

rebased onto 4512c87

7 years ago

Sure. Are you thinking about using pep8 as well?

Yes, we're thinking about using the whole Google Python Style Guide, that requires pylint, which in turn requires pep8, as far as I understand.

No problem. Just to see if we are talking about the same. Are you suggesting to add docstring on every test case? Usually a best practice is just pick the right name for the test case.

Yeah, that's what I meant. The TestPublisher is trivial and might not really need documentation apart from just sticking to the style guide, but the new ones are not so obvious. Just a sentence for each class and function would be enough.

Unfortunately I don't have any actual data yet. I'll keep on the lookout. Otherwise, I think something pulled off maillists would be a good start, if they're not mangled.

Let's stick to documenting everything for now. It will help me understand what you're testing and doing, especially since I'm not familiar with the "unittest" framework. If we find out the documentation is redundant, we can drop it. Thank you.

                  Let's stick to documenting everything for now. It will help me understand what you're testing and doing, especially since I'm not familiar with the "unittest" framework. If we find out the documentation is redundant, we can drop it. Thank you.

Fair enough. I really like the idea of sticking to the PSG :)

6 new commits added

  • docstring to be compliant with pylint
  • Add test case for extract three traces
  • Rename asset from x86_oops.txt to x86_one_trace.txt
  • Check the amount of traces extracted
  • Better naming for test case
  • Remove unused module
7 years ago

Hi @nkondras, I have tried to address all your comments please take a look at it.

On the other hands, I have to say that I don't know what is the expected behavior of the parser... If there is a kernel panic after a trace, it returns two traces. The first one with the trace extracted and the second one with the single line [ 0.068014] Kernel panic - not syncing: Fatal exception. I'm pretty sure it's a bug but I'm using console logs from the internet so I'm not 100% sure they are ok.

Thank you, Agustin!

That might well be a bug. Can you give a link to the problematic trace, so we can ask Artem?

I'll go on to posting in-line comments, but here are a few style things, in general:

  • Please stick to 80-character long lines. This makes the code easier to read, for the same reason that newspapers use columns (not because we use hardware text terminals from the past).
  • Please start commit subjects with a verb in imperative mood. I.e. "Fix" instead of "Fixes", "Add docstrings" instead of just "Docstrings". Also please start with a capital, i.e. "Add", not "add". This makes it easier to read the log and reason about commits, e.g. when merging or reverting, at least for me. E.g. it's easy for me to mentally reverse the meaning of "Add docstrings" to be "Remove docstrings", than to reverse just "Docstrings".
  • Please describe the functions using imperative mood as well, don't repeat the function name or use "it". Also put the verb describing the function's action first. I.e. instead of "Given the asset filename, it returns its content" write "Return asset's content given its filename". IMO, this makes it easier to quickly grasp the function's meaning and reason about it. I think, a further improvement might be "Retrieve asset's content given its filename", trying to give a little more information of what the function is doing.
  • Following that logic, all the test case descriptions would start with "Check". E.g. not "Extract one trace from a console log", but "Check one trace can be extracted from a console log", or similar.

For better or worse, the class being tested is called "consolelog" at this moment. I think the code would be easier to read if the instance was named similarly. E.g. "consolelog", or "log", or just "l". Otherwise I feel like "log_parser" is not an instance of "consolelog", but the latter is being fed to the former, when simply scanning the code.

Could you put this FIXME to the function which is responsible for doing that?

This is a somewhat obscure Python feature, and one which many kernel developers, not really familiar with Python, would find confusing. Could you just compare to empty string explicitly here?

I think it's a good idea to have the expected traces marked in the logs to be parsed. However, I see that the parser also sees those markings, possibly affecting its output, plus the parser interface doesn't say anything about extracted parts being continuous in the original log. How about we store the console logs with every line marked somehow to signify whether it will appear in the extracted trace or not? E.g. with a couple characters prefixing every line? Then we can remove all the markings when fetching the "original" log, and extract the expected traces when comparing the output? What do you think?

Alright, I don't have any more comments at this moment.

Thank you, Agustin!
That might well be a bug. Can you give a link to the problematic trace, so we can ask Artem?

Here it goes https://lkml.org/lkml/2018/2/22/937

I'll go on to posting in-line comments, but here are a few style things, in general:

Please stick to 80-character long lines. This makes the code easier to read, for the same reason that newspapers use columns (not because we use hardware text terminals from the past).

I would like to see the computer science updating this thing of 80-character long lines hehe. I think that today with the resolution screens we have, it can be moved easily to 100 or so. Anyway I have changed the lines that didn't respect it because as we said before we are sticking to GPSG :).
BTW pylint by default warn you only when you write lines longer than 100 characters hehe.

Please start commit subjects with a verb in imperative mood. I.e. "Fix" instead of "Fixes", "Add docstrings" instead of just "Docstrings". Also please start with a capital, i.e. "Add", not "add". This makes it easier to read the log and reason about commits, e.g. when merging or reverting, at least for me. E.g. it's easy for me to mentally reverse the meaning of "Add docstrings" to be "Remove docstrings", than to reverse just "Docstrings".

Ok, np. I understand the idea and I like it. I just have to get used to it, so bear with me :).

Please describe the functions using imperative mood as well, don't repeat the function name or use "it". Also put the verb describing the function's action first. I.e. instead of "Given the asset filename, it returns its content" write "Return asset's content given its filename". IMO, this makes it easier to quickly grasp the function's meaning and reason about it. I think, a further improvement might be "Retrieve asset's content given its filename", trying to give a little more information of what the function is doing.
Following that logic, all the test case descriptions would start with "Check". E.g. not "Extract one trace from a console log", but "Check one trace can be extracted from a console log", or similar.

Ok, thank you for the explanation :).

6 new commits added

  • Use imperative mood on docstring
  • Modify approach for trace assets
  • Stick to 80 characters long lines
  • Use imports for packages and modules only
  • Rename log_parser to consolelog
  • Move FIXME sentence to the right place
7 years ago

Alright, I don't have any more comments at this moment.

Thank you for your great review! Please take a look if have addressed all your comments correctly. About

This is a somewhat obscure Python feature, and one which many kernel developers, not really familiar with Python, would find confusing. Could you just compare to empty string explicitly here?

The answer is no and the explanation is here https://google.github.io/styleguide/pyguide.html?showone=True/False_evaluations#True/False_evaluations
I think that every developer has to learn which are the best practices of each language that is going to use daily. It's the best way to get the best of every language and I think that Python is a really good language, very expresive and no, it's no C or C++.

@asavkov, can you tell if the following behavior of the console log parser is correct?

@agustinhenze noticed that the console log in an LKML message is parsed as two "traces". The first one being the trace, but the second just the [ 0.068014] Kernel panic - not syncing: Fatal exception line. Is this the intended behavior? Thank you.

The answer is no and the explanation is here
https://google.github.io/styleguide/pyguide.html?showone=True/False_evaluations#True/False_evaluations
I think that every developer has to learn which are the best practices of
each language that is going to use daily. It's the best way to get the best
of every language and I think that Python is a really good language, very
expresive and no, it's no C or C++.

I agree, we should stick to Python's best practices. I'm still uncomfortable
with this comparison style, and don't think it's the best, though, but I'll
listen to you and the style guide. Let's stick to it and see how it works.

On Mon, Mar 05, 2018 at 12:26:25PM +0000, Nikolai Kondrashov wrote:

nkondras commented on the pull-request: Add test cases for reporter.consolelog that you are following:
``
@asavkov, can you tell if the following behavior of the console log parser is correct?

@agustinhenze noticed that the console log in an LKML message is parsed as two "traces". The first one being the trace, but the second just the [ 0.068014] Kernel panic - not syncing: Fatal exception line. Is this the intended behavior? Thank you.

If you are getting 2 traces out of one failure - it is obviously not
intended behavior.

--
Regards,
Artem

I don't think we should limit request_get_mocked usage to just the consolelog testing. So, we shouldn't mention it here. Otherwise we would need to keep updating the description to list all the callers, or leave it unchanged and misleading.

OTOH, if we do limit it to using with consolelog, then we should move it to the same file.

This and the following uses of request_get_mocked still supply consolelog with console logs in on-disk format, i.e. including the nt markers, which may introduce side-effects (if not now, then later). Could you remove the markers before feeding the log to consolelog?

I'm having a difficulty imagining how this will look without actually running this (sorry), but wouldn't this be hard to read if the mismatched traces have more than just a few lines? I.e. wouldn't it be hard to notice the little != in the output?

Just a little English comment: "well known" would be something that is widely known. As in the 127.0.0.1 address or "Lord of the Rings", but in this case you may want to write just "known".

I don't have any more comments for this round, thank you, Agustin!

On a side note, we'll be moving to GitHub to get better review support and easier CI. Hope you're OK with that. Let's finish this PR here, though.

Good catch! Ok, I'm going to move the mock impl here and remove the nt markers.

It's true, there is no other way than running this with something changed to see how it's the output shown. I kept the same output format that unittests showns i.e. when the text is a multiline text it sucks. I think I'm going to introduce the testfixtures module, it supports really well multiline comparison and more, if you have no objection.

Haha, thanks for the catch and the explanation :)

I think that you are right, I am going to move this function to the test_reporter.py file then.

Regarding introducing "testfixtures", sure, if it's just a little more code, and we don't need to add another (non-stock) dependency. Otherwise let's keep it simple for this PR and make a new PR adding it and switching to it once we see we need it.

2 new commits added

  • Remove the 'nt ' markers from the mocked content
  • Move request_get_mocked from utils to test_reporter
7 years ago

Regarding introducing "testfixtures", sure, if it's just a little more code, and we don't need to add another (non-stock) dependency. Otherwise let's keep it simple for this PR and make a new PR adding it and switching to it once we see we need it.

Introducing "testfixtures" is straight forward and just the module itself is necessary to depend on. I'd like to put this and the trace + kernel panic double trace detection on issues but I don't have permission on this repo. I can do it on my fork, but I think that the proper place is here.

Thank you for your detailed review :smile:

I don't have any more comments for this round, thank you, Agustin!
On a side note, we'll be moving to GitHub to get better review support and easier CI. Hope you're OK with that. Let's finish this PR here, though.

Oh yeah! I had missed this message! That would be awesome! I find this interface unfinished or maybe unpolished to use it with the PR workflow.

Alright, here's our GitHub repo: https://github.com/RH-FMK/skt
Please feel free to post issues and open new PRs there.
I'll proceed to another review round.

I think this should say "built".

Shouldn't this be using get_expected_traces too?

Could you please move this function to the top of the class, above any test functions? This doesn't make difference for Python, but makes more sense for humans.

Could you please move this to the top of the class as well?

Wouldn't a lambda be better here, perhaps?

I think it should be "feeding" here, not "feed". And to avoid two "ing's" in a row which are harder to read, we can write: "Mock request.get to allow feeding...".

Could you please terminate sentences with dots (full stops)? I.e. like this:

"""Return the absolute path of an asset passed as parameter.

Args:
    filename: Asset's filename.
Returns:
    The absolute path of the corresponding asset.
"""

This makes the description a bit easier to read.

If the description contains only one sentence, we don't need to terminate it then. E.g.

"""Check one trace can be extracted from a console log"""

is fine.

Thank you!

Could you please follow the above with all the descriptions (docstrings)?

Do you think we can call this file just "misc.py", not "utils.py"? As in "miscellaneous stuff"?

The intended logic is such files are usually used just for putting various stuff in, and not "useful stuff" (what "utility" implies). I.e. the code is full of useful stuff, it's not in just this file. OTOH, we're using it for storing common stuff which has no place anywhere else (otherwise we would create a specifically-named module for it). This way we get to be honest with ourselves, which is always good.

I think "... of the extracted trace" would read a little better here.

Thank you, Agustin. I have no more inline comments. Just one general request.

I appreciate your commitment to small atomic commits, and I think they are very useful for development in a personal repo. However, from the POV of a maintainer and a reviewer, it is difficult to deal with such fine granularity. Can I ask you to view your PR and its history as a product, or work you present to somebody, and to make it easier for them to review and deal with in the future?

With the present history, it would be difficult for me as a maintainer to e.g. extract all the required patches if I need to merge the reporter tests to another branch. As a reviewer, I need to ensure every commit makes sense and is logically-atomic, but reviewing every intermediate state leading to the resulting work takes time and extra effort.

I think this PR can be expressed in four commits:

  • Add license header to tests/test_publisher.py
  • Document tests/test_publisher.py code
  • Add FIXME about consolelog.gettraces() output
  • Add basic reporter tests

Do you think you could do that?
Thank you!

Agustin, I might be too perfectionist here. Happens to me sometimes, sorry. We can discuss and polish the fine details later. I don't want to make this simple PR an insurmountable obstacle. Could you please just check we can't use get_expected_traces everywhere, and reduce the number of commits? Thank you :)

Yes of course! Good catch :)

Ok, maybe we have different concept about what are humans hehe. But ok, I don't have any preferences for this

Actually pylint complained about using lambda, it suggested me to use a list comprehension but I preferred an explicit function instead.

Thank you, Agustin. I have no more inline comments. Just one general request.
I appreciate your commitment to small atomic commits, and I think they are very useful for development in a personal repo. However, from the POV of a maintainer and a reviewer, it is difficult to deal with such fine granularity. Can I ask you to view your PR and its history as a product, or work you present to somebody, and to make it easier for them to review and deal with in the future?
With the present history, it would be difficult for me as a maintainer to e.g. extract all the required patches if I need to merge the reporter tests to another branch. As a reviewer, I need to ensure every commit makes sense and is logically-atomic, but reviewing every intermediate state leading to the resulting work takes time and extra effort.
I think this PR can be expressed in four commits:

Add license header to tests/test_publisher.py
Document tests/test_publisher.py code
Add FIXME about consolelog.gettraces() output
Add basic reporter tests

Do you think you could do that?

I think that... The best workflow for a team is the one that the whole team follows no matter what. I am get used to use the feature branch workflow and if you want to add "the feature" or patch with "the feature" another branch, you need merge all my branch. That was the main reason why I had not added the FIXME on the reporter module.

I have been using the "feature branch workflow" for a couple of years successfully so I think it depends what the project needs. I mean, using this tool (pagure) it is impossible to use it hehe but using github or gitlab it's awesome! If one member ask you about something and you answer him via a commit and then you do a rebase, you lost the information about the discussion. Even on this PR, we are going to loose the whole information about our discussions and nobody including you and me are going to remember them after a while.

When someone new enters to the project, it's easier (browsing old PR) to see how the rest of team introduces new changes, an easy one, a complex one, etc. If you do a rebase after a review, you are loosing really valuable information about how the team got to that result.

Anyway, I'm not trying to convince you of using a different workflow. I was trying to explain you, why I do commits so atomically.

Agustin, I might be too perfectionist here. Happens to me sometimes, sorry. We can discuss and polish the fine details later. I don't want to make this simple PR an insurmountable obstacle. Could you please just check we can't use get_expected_traces everywhere, and reduce the number of commits? Thank you :)

Don't worry, I really like your reviews. Contributing in a project is about people and we need to know each other. I'm pretty sure the discussions are going to become more interesting on next PRs :).

rebased onto 8e22a00

7 years ago

4 new commits added

  • Add license header to tests/test_publisher.py
  • Document tests/test_publisher.py code
  • Add basic reporter tests
  • Add FIXME about consolelog.gettraces() output
7 years ago

Pull-Request has been merged by nkondras

7 years ago

Thank you very much, Agustin, merged!
I really appreciate your positive and cooperative attitude!

I see that you find it valuable to be able to see discussion history behind a change and be able to refer to it. I agree this can be useful.

On my side, I've been following the approach the Linux kernel (and other projects) use, for quite a while. The idea with this approach is to produce Git history with logically-separate commits, which are clear, and provide enough information to understand why something was done, a distillation of development and discussion, if you will. During each round of reviews, the commits are kept this way, and not rebased as the last step only. I would normally ask this, but wanted to keep this PR simpler.

The Linux kernel and other large projects simply cannot afford storing all the minute development and discussion details in their history. Both from the tool performance point (history size vs processing speed and storage required) and human mental capacity point (time to understand and pick out commits corresponding to certain changes, and also time for a 3rd person to join the review).

Even though skt is a small project, for people participating in it it can be just one project out of dozens they work on, and they might not have time, nor spare energy to explore the discussions and all the development details each time they want to fix or add something. For them newspaper-like style, punching out the main points about a certain commit first, to quickly grasp it, but providing enough details in the commit message and code documentation to understand the details, works well.

This is the reasoning behind my approach. However, I would like to learn more about your approach. I find it intriguing that you found it successful over a couple years and I'm sure I can learn from that. I would be glad to talk about it with you, perhaps even face-to-face, if we get the chance, and maybe we can arrive at something new together.

Regarding putting request_get_mocked and get_expected_traces at the top, my idea was that people normally would look for common functions before they're being used, as there are languages for which declaration order is important, and also because those act as a sort of test functions' "foundation" or a "back-story", and those are normally laid first. What was your idea for that ordering?

Now, let's move to GitHub and file some issues and submit PRs!