Repository: redhat-cip/hardware

Issue:
Mem benchmark fails with Python 3
MEM benchmarking fails with error "a bytes-like object is required, not 'str'"

```
hardware-detect --benchmark mem
...
Memory Performance: 8 logical CPU to test (ETA: 350 seconds)
Benchmarking memory @1K from CPU 0 for 5 seconds (1 threads)
Traceback (most recent call last):
  File "/usr/bin/hardware-detect", line 10, in <module>
    sys.exit(main())
  File "/usr/lib/python3.6/site-packages/hardware/detect.py", line 981, in main
    bm_mem.mem_perf(hrdw)
  File "/usr/lib/python3.6/site-packages/hardware/benchmark/mem.py", line 152, in mem_perf
    block_size, 1, cpu_nb)
  File "/usr/lib/python3.6/site-packages/hardware/benchmark/mem.py", line 91, in run_sysbench_memory_threaded
    if "transferred" in line:
TypeError: a bytes-like object is required, not 'str'
```

Original report:
https://bugzilla.redhat.com/show_bug.cgi?id=1753653

Discussion:

Patch:
diff --git a/hardware/benchmark/mem.py b/hardware/benchmark/mem.py
index abd4fd02..1a30ba36 100644
--- a/hardware/benchmark/mem.py
+++ b/hardware/benchmark/mem.py
@@ -22,6 +22,8 @@ import re
 import subprocess
 import sys
 
+import six
+
 from hardware.benchmark import utils
 
 
@@ -88,6 +90,8 @@ def run_sysbench_memory_threaded(hw_lst, max_time, block_size, cpu_count,
                                     shell=True, stdout=subprocess.PIPE)
 
     for line in sysbench_cmd.stdout:
+        if isinstance(line, six.binary_type):
+            line = line.decode()
         if "transferred" in line:
             _, right = line.rstrip('\n').replace(' ', '').split('(')
             perf, _ = right.split('.')
@@ -125,6 +129,8 @@ def run_sysbench_memory_forked(hw_lst, max_time, block_size, cpu_count):
     process = subprocess.Popen(
         sysbench_cmd, shell=True, stdout=subprocess.PIPE)
     for line in process.stdout:
+        if isinstance(line, six.binary_type):
+            line = line.decode()
         if "transferred" in line:
             _, right = line.rstrip('\n').replace(' ', '').split('(')
             perf, _ = right.split('.')


Test patch:
diff --git a/hardware/tests/test_benchmark_mem.py b/hardware/tests/test_benchmark_mem.py
index 1c0e9e2c..445a4c50 100644
--- a/hardware/tests/test_benchmark_mem.py
+++ b/hardware/tests/test_benchmark_mem.py
@@ -41,7 +41,40 @@ Test execution summary:
 
 Threads fairness:
     events (avg/stddev):           1957354.0000/0.00
-    execution time (avg/stddev):   3.0686/0.00""".splitlines()
+    execution time (avg/stddev):   3.0686/0.00"""
+
+EXPECTED_RESULT = [
+    ('cpu', 'logical', 'number', 2),
+    ('cpu', 'physical', 'number', 2),
+    ('cpu', 'logical_0', 'bandwidth_1K', '382'),
+    ('cpu', 'logical_0', 'bandwidth_4K', '382'),
+    ('cpu', 'logical_0', 'bandwidth_1M', '382'),
+    ('cpu', 'logical_0', 'bandwidth_16M', '382'),
+    ('cpu', 'logical_0', 'bandwidth_128M', '382'),
+    ('cpu', 'logical_0', 'bandwidth_1G', '382'),
+    ('cpu', 'logical_0', 'bandwidth_2G', '382'),
+    ('cpu', 'logical_1', 'bandwidth_1K', '382'),
+    ('cpu', 'logical_1', 'bandwidth_4K', '382'),
+    ('cpu', 'logical_1', 'bandwidth_1M', '382'),
+    ('cpu', 'logical_1', 'bandwidth_16M', '382'),
+    ('cpu', 'logical_1', 'bandwidth_128M', '382'),
+    ('cpu', 'logical_1', 'bandwidth_1G', '382'),
+    ('cpu', 'logical_1', 'bandwidth_2G', '382'),
+    ('cpu', 'logical', 'threaded_bandwidth_1K', '382'),
+    ('cpu', 'logical', 'threaded_bandwidth_4K', '382'),
+    ('cpu', 'logical', 'threaded_bandwidth_1M', '382'),
+    ('cpu', 'logical', 'threaded_bandwidth_16M', '382'),
+    ('cpu', 'logical', 'threaded_bandwidth_128M', '382'),
+    ('cpu', 'logical', 'threaded_bandwidth_1G', '382'),
+    ('cpu', 'logical', 'threaded_bandwidth_2G', '382'),
+    ('cpu', 'logical', 'forked_bandwidth_1K', '382'),
+    ('cpu', 'logical', 'forked_bandwidth_4K', '382'),
+    ('cpu', 'logical', 'forked_bandwidth_1M', '382'),
+    ('cpu', 'logical', 'forked_bandwidth_16M', '382'),
+    ('cpu', 'logical', 'forked_bandwidth_128M', '382'),
+    ('cpu', 'logical', 'forked_bandwidth_1G', '382'),
+    ('cpu', 'logical', 'forked_bandwidth_2G', '382')
+]
 
 
 @mock.patch.object(mem, 'get_available_memory')
@@ -54,44 +87,26 @@ class TestBenchmarkMem(unittest.TestCase):
         self.hw_data = [('cpu', 'logical', 'number', 2),
                         ('cpu', 'physical', 'number', 2)]
 
-    def test_mem_perf(self, mock_popen, mock_cpu_socket, mock_get_memory):
+    def test_mem_perf_bytes(self, mock_popen, mock_cpu_socket,
+                            mock_get_memory):
         mock_get_memory.return_value = 123456789012
-        mock_popen.return_value = mock.Mock(stdout=SYSBENCH_OUTPUT)
+        mock_popen.return_value = mock.Mock(
+            stdout=SYSBENCH_OUTPUT.encode().splitlines())
         mock_cpu_socket.return_value = range(2)
         mem.mem_perf(self.hw_data)
 
-        expected = [
-            ('cpu', 'logical', 'number', 2),
-            ('cpu', 'physical', 'number', 2),
-            ('cpu', 'logical_0', 'bandwidth_1K', '382'),
-            ('cpu', 'logical_0', 'bandwidth_4K', '382'),
-            ('cpu', 'logical_0', 'bandwidth_1M', '382'),
-            ('cpu', 'logical_0', 'bandwidth_16M', '382'),
-            ('cpu', 'logical_0', 'bandwidth_128M', '382'),
-            ('cpu', 'logical_0', 'bandwidth_1G', '382'),
-            ('cpu', 'logical_0', 'bandwidth_2G', '382'),
-            ('cpu', 'logical_1', 'bandwidth_1K', '382'),
-            ('cpu', 'logical_1', 'bandwidth_4K', '382'),
-            ('cpu', 'logical_1', 'bandwidth_1M', '382'),
-            ('cpu', 'logical_1', 'bandwidth_16M', '382'),
-            ('cpu', 'logical_1', 'bandwidth_128M', '382'),
-            ('cpu', 'logical_1', 'bandwidth_1G', '382'),
-            ('cpu', 'logical_1', 'bandwidth_2G', '382'),
-            ('cpu', 'logical', 'threaded_bandwidth_1K', '382'),
-            ('cpu', 'logical', 'threaded_bandwidth_4K', '382'),
-            ('cpu', 'logical', 'threaded_bandwidth_1M', '382'),
-            ('cpu', 'logical', 'threaded_bandwidth_16M', '382'),
-            ('cpu', 'logical', 'threaded_bandwidth_128M', '382'),
-            ('cpu', 'logical', 'threaded_bandwidth_1G', '382'),
-            ('cpu', 'logical', 'threaded_bandwidth_2G', '382'),
-            ('cpu', 'logical', 'forked_bandwidth_1K', '382'),
-            ('cpu', 'logical', 'forked_bandwidth_4K', '382'),
-            ('cpu', 'logical', 'forked_bandwidth_1M', '382'),
-            ('cpu', 'logical', 'forked_bandwidth_16M', '382'),
-            ('cpu', 'logical', 'forked_bandwidth_128M', '382'),
-            ('cpu', 'logical', 'forked_bandwidth_1G', '382'),
-            ('cpu', 'logical', 'forked_bandwidth_2G', '382')
-        ]
+        expected = EXPECTED_RESULT
+        self.assertEqual(sorted(expected), sorted(self.hw_data))
+
+    def test_mem_perf_text(self, mock_popen, mock_cpu_socket,
+                           mock_get_memory):
+        mock_get_memory.return_value = 123456789012
+        mock_popen.return_value = mock.Mock(
+            stdout=SYSBENCH_OUTPUT.splitlines())
+        mock_cpu_socket.return_value = range(2)
+        mem.mem_perf(self.hw_data)
+
+        expected = EXPECTED_RESULT
         self.assertEqual(sorted(expected), sorted(self.hw_data))
 
     def test_check_mem_size(self, mock_popen, mock_cpu_socket,
@@ -107,20 +122,47 @@ class TestBenchmarkMem(unittest.TestCase):
         for block_size in block_size_list:
             self.assertFalse(mem.check_mem_size(block_size, 2))
 
-    def test_run_sysbench_memory_forked(self, mock_popen, mock_cpu_socket,
-                                        mock_get_memory):
+    def test_run_sysbench_memory_forked_text(self, mock_popen, mock_cpu_socket,
+                                             mock_get_memory):
         mock_get_memory.return_value = 123456789012
-        mock_popen.return_value = mock.Mock(stdout=SYSBENCH_OUTPUT)
+        mock_popen.return_value = mock.Mock(
+            stdout=SYSBENCH_OUTPUT.splitlines())
 
         hw_data = []
         mem.run_sysbench_memory_forked(hw_data, 10, '1K', 2)
         self.assertEqual([('cpu', 'logical', 'forked_bandwidth_1K', '382')],
                          hw_data)
 
-    def test_run_sysbench_memory_threaded(self, mock_popen, mock_cpu_socket,
-                                          mock_get_memory):
+    def test_run_sysbench_memory_forked_bytes(self, mock_popen,
+                                              mock_cpu_socket,
+                                              mock_get_memory):
+        mock_get_memory.return_value = 123456789012
+        mock_popen.return_value = mock.Mock(
+            stdout=SYSBENCH_OUTPUT.encode().splitlines())
+
+        hw_data = []
+        mem.run_sysbench_memory_forked(hw_data, 10, '1K', 2)
+        self.assertEqual([('cpu', 'logical', 'forked_bandwidth_1K', '382')],
+                         hw_data)
+
+    def test_run_sysbench_memory_threaded_text(self, mock_popen,
+                                               mock_cpu_socket,
+                                               mock_get_memory):
+        mock_get_memory.return_value = 123456789012
+        mock_popen.return_value = mock.Mock(
+            stdout=SYSBENCH_OUTPUT.splitlines())
+
+        hw_data = []
+        mem.run_sysbench_memory_threaded(hw_data, 10, '1K', 2)
+        self.assertEqual([('cpu', 'logical', 'threaded_bandwidth_1K', '382')],
+                         hw_data)
+
+    def test_run_sysbench_memory_threaded_bytes(self, mock_popen,
+                                                mock_cpu_socket,
+                                                mock_get_memory):
         mock_get_memory.return_value = 123456789012
-        mock_popen.return_value = mock.Mock(stdout=SYSBENCH_OUTPUT)
+        mock_popen.return_value = mock.Mock(
+            stdout=SYSBENCH_OUTPUT.encode().splitlines())
 
         hw_data = []
         mem.run_sysbench_memory_threaded(hw_data, 10, '1K', 2)