Repository: Azure/WALinuxAgent
Pull request #1563 (2019-06-21 00:30:10)

Improve systemd tests and reset stdout/stderr
Address leftover comments from https://github.com/Azure/WALinuxAgent/pull/1556:
- improve systemd tests
- reset stdout/stderr before invoking another subprocess
- add unit tests for `azurelinuxagent.utils.processutil.read_output`
- add unit tests for logging when calling `azurelinuxagent.common.event.add_event`

<!-- DO NOT DELETE THIS TEMPLATE -->

## Description

Issue # <!-- if any -->
<!--
Please add an informative description that covers that changes made by the pull request. 
This checklist is used to make sure that common issues in a pull request are addressed.
This will expedite the process of getting your pull request merged and avoid extra work on your part to fix issues discovered during the review process.
-->

---

### PR information
- [ ] The title of the PR is clear and informative.
- [ ] There are a small number of commits, each of which has an informative message. This means that previously merged commits do not appear in the history of the PR. For information on cleaning up the commits in your pull request, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md).
- [ ] Except for special cases involving multiple contributors, the PR is started from a fork of the main repository, not a branch.
- [ ] If applicable, the PR references the bug/issue that it fixes in the description.
- [ ] New Unit tests were added for the changes made and Travis.CI is passing.

### Quality of Code and Contribution Guidelines
- [ ] I have read the [contribution guidelines](https://github.com/Azure/WALinuxAgent/blob/master/.github/CONTRIBUTING.md).

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/azure/walinuxagent/1563)
<!-- Reviewable:end -->


codecov[bot]: # [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=h1) Report
> Merging [#1563](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=desc) into [develop](https://codecov.io/gh/Azure/WALinuxAgent/commit/8761775464a6f6cb5de073d7bfe6a66eb8312cad?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `33.33%`.

[![Impacted file tree graph](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563/graphs/tree.svg?width=650&token=ae90E2KYCw&height=150&src=pr)](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=tree)

```diff
@@             Coverage Diff             @@
##           develop    #1563      +/-   ##
===========================================
- Coverage    63.38%   63.38%   -0.01%     
===========================================
  Files           78       78              
  Lines        11056    11057       +1     
  Branches      1559     1559              
===========================================
  Hits          7008     7008              
- Misses        3709     3710       +1     
  Partials       339      339
```


| [Impacted Files](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [azurelinuxagent/common/cgroupapi.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi9jZ3JvdXBhcGkucHk=) | `62.5% <0%> (-0.28%)` | :arrow_down: |
| [azurelinuxagent/common/utils/processutil.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi91dGlscy9wcm9jZXNzdXRpbC5weQ==) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=footer). Last update [8761775...42c2570](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

codecov[bot]: # [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=h1) Report
> Merging [#1563](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=desc) into [develop](https://codecov.io/gh/Azure/WALinuxAgent/commit/8761775464a6f6cb5de073d7bfe6a66eb8312cad?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `33.33%`.

[![Impacted file tree graph](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563/graphs/tree.svg?width=650&token=ae90E2KYCw&height=150&src=pr)](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=tree)

```diff
@@             Coverage Diff             @@
##           develop    #1563      +/-   ##
===========================================
- Coverage    63.38%   63.38%   -0.01%     
===========================================
  Files           78       78              
  Lines        11056    11057       +1     
  Branches      1559     1559              
===========================================
  Hits          7008     7008              
- Misses        3709     3710       +1     
  Partials       339      339
```


| [Impacted Files](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [azurelinuxagent/common/cgroupapi.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi9jZ3JvdXBhcGkucHk=) | `62.5% <0%> (-0.28%)` | :arrow_down: |
| [azurelinuxagent/common/utils/processutil.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi91dGlscy9wcm9jZXNzdXRpbC5weQ==) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=footer). Last update [8761775...42c2570](https://codecov.io/gh/Azure/WALinuxAgent/pull/1563?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

vrdmr: We might need to add new tests in test_extension.py, with an implementation in `TestExtensionWithCGroupsEnabled`. Essentially making the `test_ext_handler_with_systemd_cgroup_enabled` work. When looking at the [coverage of the SystemdCgroupAPI](https://codecov.io/gh/Azure/WALinuxAgent/src/systemd-test-improvements/azurelinuxagent/common/cgroupapi.py#L318), I don't see that the tests you added are still exercising the code in there.
pgombar: > We might need to add new tests in test_extension.py, with an implementation in `TestExtensionWithCGroupsEnabled`. Essentially making the `test_ext_handler_with_systemd_cgroup_enabled` work. When looking at the [coverage of the SystemdCgroupAPI](https://codecov.io/gh/Azure/WALinuxAgent/src/systemd-test-improvements/azurelinuxagent/common/cgroupapi.py#L318), I don't see that the tests you added are still exercising the code in there.

I agree, but this PR is contained to improving tests around systemd-run, not against the whole class. I can do that in a separate PR since it will be a lot of changes.

The issue with `test_ext_handler_with_systemd_cgroup_enabled` not working is purely because Travis doesn't support cgroups/systemd. When ran locally, the test passes. For the code coverage you linked, a better candidate for testing this would be `LaunchCommandTestCase`.

Patch:
diff --git a/azurelinuxagent/common/cgroupapi.py b/azurelinuxagent/common/cgroupapi.py
index 36b16a76..da1baa4e 100644
--- a/azurelinuxagent/common/cgroupapi.py
+++ b/azurelinuxagent/common/cgroupapi.py
@@ -438,11 +438,6 @@ After=system-{1}.slice""".format(extension_name, EXTENSIONS_ROOT_CGROUP_NAME)
             # unit's name. Since the scope name is only known to systemd-run, and not to the extension itself,
             # if scope_name appears in the output, we are certain systemd-run managed to run.
             if scope_name not in process_output:
-                logger.warn('Failed to run systemd-run for unit {0}.scope '
-                            'Process exited with code {1} and output {2}'.format(scope_name,
-                                                                                 return_code,
-                                                                                 process_output))
-
                 add_event(AGENT_NAME,
                           version=CURRENT_VERSION,
                           op=WALAEventOperation.InvokeCommandUsingSystemd,
@@ -451,6 +446,9 @@ After=system-{1}.slice""".format(extension_name, EXTENSIONS_ROOT_CGROUP_NAME)
                                   'Process exited with code {1} and output {2}'.format(scope_name,
                                                                                        return_code,
                                                                                        process_output))
+                # Reset the stdout and stderr
+                stdout.truncate(0)
+                stderr.truncate(0)
 
                 # Try starting the process without systemd-run
                 process = subprocess.Popen(
diff --git a/azurelinuxagent/common/utils/processutil.py b/azurelinuxagent/common/utils/processutil.py
index ecddc30c..a70076ec 100644
--- a/azurelinuxagent/common/utils/processutil.py
+++ b/azurelinuxagent/common/utils/processutil.py
@@ -34,7 +34,7 @@ def read_output(stdout, stderr):
 
         return format_stdout_stderr(stdout, stderr)
     except Exception as e:
-        return format_stdout_stderr("", "Cannot read stdout/stderr: {0}".format(str(e)))
+        return format_stdout_stderr("", "Cannot read stdout/stderr: {0}".format(ustr(e)))
 
 
 def format_stdout_stderr(stdout, stderr, max_len=TELEMETRY_MESSAGE_MAX_LEN):


Test patch:
diff --git a/tests/common/test_cgroupapi.py b/tests/common/test_cgroupapi.py
index cdb175d0..817add93 100644
--- a/tests/common/test_cgroupapi.py
+++ b/tests/common/test_cgroupapi.py
@@ -20,7 +20,8 @@ from __future__ import print_function
 import subprocess
 
 from azurelinuxagent.common.cgroupapi import CGroupsApi, FileSystemCgroupsApi, SystemdCgroupsApi
-from azurelinuxagent.common.utils import shellutil, fileutil
+from azurelinuxagent.common.utils import shellutil
+from azurelinuxagent.common.utils.processutil import read_output
 from tests.tools import *
 
 
@@ -281,6 +282,27 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
         os.remove("/etc/systemd/system/{0}".format(unit_name))
         shellutil.run_get_output("systemctl daemon-reload")
 
+    def assert_cgroups_created(self, extension_cgroups):
+        self.assertEqual(len(extension_cgroups), 2,
+                         'start_extension_command did not return the expected number of cgroups')
+
+        cpu_found = memory_found = False
+
+        for cgroup in extension_cgroups:
+            match = re.match(
+                r'^/sys/fs/cgroup/(cpu|memory)/system.slice/Microsoft.Compute.TestExtension_1\.2\.3\_([a-f0-9-]+)\.scope$',
+                cgroup.path)
+
+            self.assertTrue(match is not None, "Unexpected path for cgroup: {0}".format(cgroup.path))
+
+            if match.group(1) == 'cpu':
+                cpu_found = True
+            if match.group(1) == 'memory':
+                memory_found = True
+
+        self.assertTrue(cpu_found, 'start_extension_command did not return a cpu cgroup')
+        self.assertTrue(memory_found, 'start_extension_command did not return a memory cgroup')
+
     def test_start_extension_command_should_create_extension_scopes(self):
         original_popen = subprocess.Popen
 
@@ -300,23 +322,7 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
                 stderr=subprocess.PIPE)
 
             process.wait()
-
-            self.assertEqual(len(extension_cgroups), 2, 'start_extension_command did not return the expected number of cgroups')
-
-            cpu_found = memory_found = False
-
-            for cgroup in extension_cgroups:
-                match = re.match(r'^/sys/fs/cgroup/(cpu|memory)/system.slice/Microsoft.Compute.TestExtension_1\.2\.3\_([a-f0-9-]+)\.scope$', cgroup.path)
-
-                self.assertTrue(match is not None, "Unexpected path for cgroup: {0}".format(cgroup.path))
-
-                if match.group(1) == 'cpu':
-                    cpu_found = True
-                if match.group(1) == 'memory':
-                    memory_found = True
-
-            self.assertTrue(cpu_found, 'start_extension_command did not return a cpu cgroup')
-            self.assertTrue(memory_found, 'start_extension_command did not return a memory cgroup')
+            self.assert_cgroups_created(extension_cgroups)
 
     @skip_if_predicate_false(i_am_root, "Test does not run when normal user")
     def test_start_extension_command_should_use_systemd_if_not_failing(self):
@@ -345,23 +351,10 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
                     self.assertEquals(0, ret)
                     self.assertEquals(1, patch_mock_popen.call_count)
 
-                    # Assert that the extension's cgroups were created as well
-                    self.assertEqual(len(extension_cgroups), 2, 'start_extension_command did not return the expected number of cgroups')
-
-                    cpu_found = memory_found = False
-
-                    for cgroup in extension_cgroups:
-                        match = re.match(r'^/sys/fs/cgroup/(cpu|memory)/system.slice/Microsoft.Compute.TestExtension_1\.2\.3\_([a-f0-9-]+)\.scope$', cgroup.path)
+                    args = patch_mock_popen.call_args[0][0]
+                    self.assertIn("systemd-run --unit", args)
 
-                        self.assertTrue(match is not None, "Unexpected path for cgroup: {0}".format(cgroup.path))
-
-                        if match.group(1) == 'cpu':
-                            cpu_found = True
-                        if match.group(1) == 'memory':
-                            memory_found = True
-
-                    self.assertTrue(cpu_found, 'start_extension_command did not return a cpu cgroup')
-                    self.assertTrue(memory_found, 'start_extension_command did not return a memory cgroup')
+                    self.assert_cgroups_created(extension_cgroups)
 
     @skip_if_predicate_false(i_am_root, "Test does not run when normal user")
     def test_start_extension_command_should_not_use_systemd_if_failing(self):
@@ -375,7 +368,7 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
 
         with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as stdout:
             with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as stderr:
-                with patch("azurelinuxagent.common.cgroupapi.logger.warn") as mock_logger_warn:
+                with patch("azurelinuxagent.common.cgroupapi.add_event") as mock_add_event:
                     with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen", side_effect=mock_popen) as patch_mock_popen:
 
                         # We expect this call to fail because of the syntax error
@@ -390,10 +383,13 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
 
                         process.wait()
 
-                        args, kwargs = mock_logger_warn.call_args
-                        message = args[0]
-                        self.assertIn("Failed to find executable syntax_error: No such file or directory", message)
-                        self.assertIn("Failed to run systemd-run for unit Microsoft.Compute.TestExtension_1.2.3", message)
+                        args, kwargs = mock_add_event.call_args
+                        self.assertIn("Failed to run systemd-run for unit Microsoft.Compute.TestExtension_1.2.3",
+                                      kwargs['message'])
+                        self.assertIn("Failed to find executable syntax_error: No such file or directory",
+                                      kwargs['message'])
+                        self.assertEquals(False, kwargs['is_success'])
+                        self.assertEquals('InvokeCommandUsingSystemd', kwargs['op'])
 
                         # We expect the process to ultimately succeed since the fallback option worked
                         ret = process.poll()
@@ -402,5 +398,39 @@ class SystemdCgroupsApiTestCase(AgentTestCase):
                         # We expect two calls to Popen, first for the systemd-run call, second for the fallback option
                         self.assertEquals(2, patch_mock_popen.call_count)
 
+                        first_call_args = patch_mock_popen.mock_calls[0][1][0]
+                        second_call_args = patch_mock_popen.mock_calls[1][1][0]
+                        self.assertIn("systemd-run --unit", first_call_args)
+                        self.assertNotIn("systemd-run --unit", second_call_args)
+
                         # No cgroups should have been created
                         self.assertEquals(extension_cgroups, [])
+
+    @skip_if_predicate_false(i_am_root, "Test does not run when normal user")
+    def test_start_extension_command_should_capture_only_the_last_subprocess_output(self):
+        original_popen = subprocess.Popen
+
+        def mock_popen(*args, **kwargs):
+            # Inject a syntax error to the call
+            systemd_command = args[0].replace('systemd-run', 'systemd-run syntax_error')
+            new_args = (systemd_command,)
+            return original_popen(new_args, **kwargs)
+
+        with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as stdout:
+            with tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b") as stderr:
+                with patch("azurelinuxagent.common.cgroupapi.add_event") as mock_add_event:
+                    with patch("azurelinuxagent.common.cgroupapi.subprocess.Popen",
+                               side_effect=mock_popen) as patch_mock_popen:
+                        # We expect this call to fail because of the syntax error
+                        process, extension_cgroups = SystemdCgroupsApi().start_extension_command(
+                            extension_name="Microsoft.Compute.TestExtension-1.2.3",
+                            command="echo 'very specific test message'",
+                            shell=True,
+                            cwd=self.tmp_dir,
+                            env={},
+                            stdout=stdout,
+                            stderr=stderr)
+
+                        process.wait()
+                        process_output = read_output(stdout, stderr)
+                        self.assertEquals("[stdout]\nvery specific test message\n\n\n[stderr]\n", process_output)
diff --git a/tests/common/test_event.py b/tests/common/test_event.py
index 201e1b6e..316bc3da 100644
--- a/tests/common/test_event.py
+++ b/tests/common/test_event.py
@@ -20,7 +20,7 @@ from __future__ import print_function
 from datetime import datetime, timedelta
 
 from azurelinuxagent.common.event import add_event, \
-    WALAEventOperation, elapsed_milliseconds
+    WALAEventOperation, elapsed_milliseconds, EventLogger
 from azurelinuxagent.common.future import ustr
 from azurelinuxagent.common.version import CURRENT_VERSION
 
@@ -105,6 +105,58 @@ class TestEvent(AgentTestCase):
             self.assertTrue(event.should_emit_event("Foo", "1.2", op, True))
             self.assertFalse(event.should_emit_event("Foo", "1.2", op, False))
 
+    @patch('azurelinuxagent.common.event.EventLogger')
+    @patch('azurelinuxagent.common.logger.error')
+    @patch('azurelinuxagent.common.logger.warn')
+    @patch('azurelinuxagent.common.logger.info')
+    def test_should_log_errors_if_failed_operation_and_empty_event_dir(self,
+                                                                       mock_logger_info,
+                                                                       mock_logger_warn,
+                                                                       mock_logger_error,
+                                                                       mock_reporter):
+        mock_reporter.event_dir = None
+        add_event("dummy name",
+                  version=CURRENT_VERSION,
+                  op=WALAEventOperation.Download,
+                  is_success=False,
+                  message="dummy event message",
+                  reporter=mock_reporter)
+
+        self.assertEquals(1, mock_logger_error.call_count)
+        self.assertEquals(1, mock_logger_warn.call_count)
+        self.assertEquals(0, mock_logger_info.call_count)
+
+        args = mock_logger_error.call_args[0]
+        self.assertEquals(('dummy name', 'Download', 'dummy event message', 0), args[1:])
+
+    @patch('azurelinuxagent.common.event.EventLogger')
+    @patch('azurelinuxagent.common.logger.error')
+    @patch('azurelinuxagent.common.logger.warn')
+    @patch('azurelinuxagent.common.logger.info')
+    def test_should_log_errors_if_failed_operation_and_not_empty_event_dir(self,
+                                                                           mock_logger_info,
+                                                                           mock_logger_warn,
+                                                                           mock_logger_error,
+                                                                           mock_reporter):
+        mock_reporter.event_dir = "dummy"
+
+        with patch("azurelinuxagent.common.event.should_emit_event", return_value=True) as mock_should_emit_event:
+            with patch("azurelinuxagent.common.event.mark_event_status"):
+                with patch("azurelinuxagent.common.event.EventLogger._add_event"):
+                    add_event("dummy name",
+                              version=CURRENT_VERSION,
+                              op=WALAEventOperation.Download,
+                              is_success=False,
+                              message="dummy event message")
+
+                    self.assertEquals(1, mock_should_emit_event.call_count)
+                    self.assertEquals(1, mock_logger_error.call_count)
+                    self.assertEquals(0, mock_logger_warn.call_count)
+                    self.assertEquals(0, mock_logger_info.call_count)
+
+                    args = mock_logger_error.call_args[0]
+                    self.assertEquals(('dummy name', 'Download', 'dummy event message', 0), args[1:])
+
     @patch('azurelinuxagent.common.event.EventLogger.add_event')
     def test_periodic_emits_if_not_previously_sent(self, mock_event):
         event.__event_logger__.reset_periodic()
diff --git a/tests/utils/test_process_util.py b/tests/utils/test_process_util.py
index b483d094..9ab4f13a 100644
--- a/tests/utils/test_process_util.py
+++ b/tests/utils/test_process_util.py
@@ -14,11 +14,48 @@
 #
 # Requires Python 2.6+ and Openssl 1.0+
 #
-from azurelinuxagent.common.utils.processutil import format_stdout_stderr
+from azurelinuxagent.common.utils.processutil import format_stdout_stderr, read_output
 from tests.tools import *
 
 
 class TestProcessUtils(AgentTestCase):
+    def setUp(self):
+        AgentTestCase.setUp(self)
+        self.tmp_dir = tempfile.mkdtemp()
+        self.stdout = tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b")
+        self.stderr = tempfile.TemporaryFile(dir=self.tmp_dir, mode="w+b")
+
+        self.stdout.write("The quick brown fox jumps over the lazy dog.".encode("utf-8"))
+        self.stderr.write("The five boxing wizards jump quickly.".encode("utf-8"))
+
+    def tearDown(self):
+        if self.tmp_dir is not None:
+            shutil.rmtree(self.tmp_dir)
+
+    def test_read_output_it_should_return_no_content(self):
+        with patch('azurelinuxagent.common.utils.processutil.TELEMETRY_MESSAGE_MAX_LEN', 0):
+            expected = "[stdout]\n\n\n[stderr]\n"
+            actual = read_output(self.stdout, self.stderr)
+            self.assertEqual(expected, actual)
+
+    def test_read_output_it_should_truncate_the_content(self):
+        with patch('azurelinuxagent.common.utils.processutil.TELEMETRY_MESSAGE_MAX_LEN', 10):
+            expected = "[stdout]\nThe quick \n\n[stderr]\nThe five b"
+            actual = read_output(self.stdout, self.stderr)
+            self.assertEqual(expected, actual)
+
+    def test_read_output_it_should_return_all_content(self):
+        with patch('azurelinuxagent.common.utils.processutil.TELEMETRY_MESSAGE_MAX_LEN', 50):
+            expected = "[stdout]\nThe quick brown fox jumps over the lazy dog.\n\n" \
+                       "[stderr]\nThe five boxing wizards jump quickly."
+            actual = read_output(self.stdout, self.stderr)
+            self.assertEqual(expected, actual)
+
+    def test_read_output_it_should_handle_exceptions(self):
+        with patch('azurelinuxagent.common.utils.processutil.TELEMETRY_MESSAGE_MAX_LEN', "type error"):
+            actual = read_output(self.stdout, self.stderr)
+            self.assertIn("Cannot read stdout/stderr", actual)
+
     def test_format_stdout_stderr00(self):
         """
         If stdout and stderr are both smaller than the max length,