Make take bug report more convenient to use. (#576)


diff --git a/mobly/controllers/android_device.py b/mobly/controllers/android_device.py
index ce819ac..331d2c1 100644
--- a/mobly/controllers/android_device.py
+++ b/mobly/controllers/android_device.py
@@ -391,7 +391,8 @@
     begin_time = mobly_logger.normalize_log_line_timestamp(str(begin_time))
 
     def take_br(test_name, begin_time, ad, destination):
-        ad.take_bug_report(test_name, begin_time, destination=destination)
+        ad.take_bug_report(
+            test_name, begin_time=begin_time, destination=destination)
 
     args = [(test_name, begin_time, ad, destination) for ad in ads]
     utils.concurrent_exec(take_br, args)
@@ -823,19 +824,29 @@
 
     def take_bug_report(self,
                         test_name,
-                        begin_time,
+                        begin_time=None,
                         timeout=300,
                         destination=None):
         """Takes a bug report on the device and stores it in a file.
 
         Args:
             test_name: Name of the test method that triggered this bug report.
-            begin_time: Timestamp of when the test started.
+            begin_time: Timestamp of when the test started. If not set, then
+                this will default to the current time.
             timeout: float, the number of seconds to wait for bugreport to
                 complete, default is 5min.
             destination: string, path to the directory where the bugreport
                 should be saved.
+
+        Returns:
+          A string containing the absolute path to the bug report on the host
+          machine.
         """
+        if begin_time is None:
+            epoch_time = utils.get_current_epoch_time()
+            timestamp = mobly_logger.epoch_to_log_line_timestamp(epoch_time)
+            begin_time = mobly_logger.normalize_log_line_timestamp(timestamp)
+
         new_br = True
         try:
             stdout = self.adb.shell('bugreportz -v').decode('utf-8')
@@ -872,6 +883,7 @@
                 ' > "%s"' % full_out_path, shell=True, timeout=timeout)
         self.log.info('Bugreport for %s taken at %s.', test_name,
                       full_out_path)
+        return full_out_path
 
     def run_iperf_client(self, server_host, extra_args=''):
         """Start iperf client on the device.
diff --git a/tests/mobly/controllers/android_device_test.py b/tests/mobly/controllers/android_device_test.py
index 1bdcb68..53975aa 100755
--- a/tests/mobly/controllers/android_device_test.py
+++ b/tests/mobly/controllers/android_device_test.py
@@ -220,6 +220,16 @@
         ads[2].skip_logcat = True
         android_device._start_services_on_ads(ads)
 
+    def test_take_bug_reports(self):
+        ads = mock_android_device.get_mock_ads(3)
+        android_device.take_bug_reports(ads, 'test_something', 'sometime')
+        ads[0].take_bug_report.assert_called_once_with(
+            'test_something', begin_time='sometime', destination=None)
+        ads[1].take_bug_report.assert_called_once_with(
+            'test_something', begin_time='sometime', destination=None)
+        ads[2].take_bug_report.assert_called_once_with(
+            'test_something', begin_time='sometime', destination=None)
+
     # Tests for android_device.AndroidDevice class.
     # These tests mock out any interaction with the OS and real android device
     # in AndroidDeivce.
@@ -309,10 +319,14 @@
         """
         mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
-        ad.take_bug_report('test_something', 'sometime')
+        output_path = ad.take_bug_report(
+            'test_something', begin_time='sometime')
         expected_path = os.path.join(
             logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports')
         create_dir_mock.assert_called_with(expected_path)
+        self.assertEqual(output_path,
+                         os.path.join(expected_path,
+                                      'test_something,sometime,1.zip'))
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
@@ -330,7 +344,53 @@
         ad = android_device.AndroidDevice(serial=mock_serial)
         expected_msg = '.* Failed to take bugreport.'
         with self.assertRaisesRegex(android_device.Error, expected_msg):
-            ad.take_bug_report('test_something', 'sometime')
+            ad.take_bug_report('test_something', begin_time='sometime')
+
+    @mock.patch(
+        'mobly.controllers.android_device_lib.adb.AdbProxy',
+        return_value=mock_android_device.MockAdbProxy('1'))
+    @mock.patch(
+        'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
+        return_value=mock_android_device.MockFastbootProxy('1'))
+    @mock.patch('mobly.utils.create_dir')
+    @mock.patch('mobly.utils.get_current_epoch_time')
+    @mock.patch('mobly.logger.epoch_to_log_line_timestamp')
+    def test_AndroidDevice_take_bug_report_without_begin_time(
+            self, epoch_to_log_line_timestamp_mock,
+            get_current_epoch_time_mock, create_dir_mock, FastbootProxy,
+            MockAdbProxy):
+        get_current_epoch_time_mock.return_value = 1557446629606
+        epoch_to_log_line_timestamp_mock.return_value = '05-09 17:03:49.606'
+        mock_serial = '1'
+        ad = android_device.AndroidDevice(serial=mock_serial)
+        output_path = ad.take_bug_report('test_something')
+        expected_path = os.path.join(
+            logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports')
+        create_dir_mock.assert_called_with(expected_path)
+        epoch_to_log_line_timestamp_mock.assert_called_once_with(1557446629606)
+        self.assertEqual(
+            output_path,
+            os.path.join(expected_path,
+                         'test_something,05-09_17-03-49.606,1.zip'))
+
+    @mock.patch(
+        'mobly.controllers.android_device_lib.adb.AdbProxy',
+        return_value=mock_android_device.MockAdbProxy(1))
+    @mock.patch(
+        'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
+        return_value=mock_android_device.MockFastbootProxy(1))
+    @mock.patch('mobly.utils.create_dir')
+    def test_AndroidDevice_take_bug_report_with_positional_begin_time(
+            self, create_dir_mock, FastbootProxy, MockAdbProxy):
+        mock_serial = '1'
+        ad = android_device.AndroidDevice(serial=mock_serial)
+        output_path = ad.take_bug_report('test_something', 'sometime')
+        expected_path = os.path.join(
+            logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports')
+        create_dir_mock.assert_called_with(expected_path)
+        self.assertEqual(output_path,
+                         os.path.join(expected_path,
+                                      'test_something,sometime,1.zip'))
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
@@ -344,9 +404,13 @@
         mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
         dest = tempfile.gettempdir()
-        ad.take_bug_report("test_something", "sometime", destination=dest)
+        output_path = ad.take_bug_report(
+            "test_something", begin_time="sometime", destination=dest)
         expected_path = os.path.join(dest)
         create_dir_mock.assert_called_with(expected_path)
+        self.assertEqual(output_path,
+                         os.path.join(expected_path,
+                                      'test_something,sometime,1.zip'))
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
@@ -363,10 +427,14 @@
         """
         mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
-        ad.take_bug_report('test_something', 'sometime')
+        output_path = ad.take_bug_report(
+            'test_something', begin_time='sometime')
         expected_path = os.path.join(
             logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports')
         create_dir_mock.assert_called_with(expected_path)
+        self.assertEqual(output_path,
+                         os.path.join(expected_path,
+                                      'test_something,sometime,1.txt'))
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',