test_execute.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import logging
  2. import subprocess
  3. import pytest
  4. from flexmock import flexmock
  5. from borgmatic import execute as module
  6. def test_log_outputs_logs_each_line_separately():
  7. flexmock(module.logger).should_receive('log').with_args(logging.INFO, 'hi').once()
  8. flexmock(module.logger).should_receive('log').with_args(logging.INFO, 'there').once()
  9. flexmock(module).should_receive('exit_code_indicates_error').and_return(False)
  10. hi_process = subprocess.Popen(['echo', 'hi'], stdout=subprocess.PIPE)
  11. flexmock(module).should_receive('output_buffer_for_process').with_args(
  12. hi_process, ()
  13. ).and_return(hi_process.stdout)
  14. there_process = subprocess.Popen(['echo', 'there'], stdout=subprocess.PIPE)
  15. flexmock(module).should_receive('output_buffer_for_process').with_args(
  16. there_process, ()
  17. ).and_return(there_process.stdout)
  18. module.log_outputs(
  19. (hi_process, there_process),
  20. exclude_stdouts=(),
  21. output_log_level=logging.INFO,
  22. borg_local_path='borg',
  23. )
  24. def test_log_outputs_skips_logs_for_process_with_none_stdout():
  25. flexmock(module.logger).should_receive('log').with_args(logging.INFO, 'hi').never()
  26. flexmock(module.logger).should_receive('log').with_args(logging.INFO, 'there').once()
  27. flexmock(module).should_receive('exit_code_indicates_error').and_return(False)
  28. hi_process = subprocess.Popen(['echo', 'hi'], stdout=None)
  29. flexmock(module).should_receive('output_buffer_for_process').with_args(
  30. hi_process, ()
  31. ).and_return(hi_process.stdout)
  32. there_process = subprocess.Popen(['echo', 'there'], stdout=subprocess.PIPE)
  33. flexmock(module).should_receive('output_buffer_for_process').with_args(
  34. there_process, ()
  35. ).and_return(there_process.stdout)
  36. module.log_outputs(
  37. (hi_process, there_process),
  38. exclude_stdouts=(),
  39. output_log_level=logging.INFO,
  40. borg_local_path='borg',
  41. )
  42. def test_log_outputs_includes_error_output_in_exception():
  43. flexmock(module.logger).should_receive('log')
  44. flexmock(module).should_receive('exit_code_indicates_error').and_return(True)
  45. flexmock(module).should_receive('command_for_process').and_return('grep')
  46. process = subprocess.Popen(['grep'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  47. flexmock(module).should_receive('output_buffer_for_process').and_return(process.stdout)
  48. with pytest.raises(subprocess.CalledProcessError) as error:
  49. module.log_outputs(
  50. (process,), exclude_stdouts=(), output_log_level=logging.INFO, borg_local_path='borg'
  51. )
  52. assert error.value.output
  53. def test_log_outputs_skips_error_output_in_exception_for_process_with_none_stdout():
  54. flexmock(module.logger).should_receive('log')
  55. flexmock(module).should_receive('exit_code_indicates_error').and_return(True)
  56. flexmock(module).should_receive('command_for_process').and_return('grep')
  57. process = subprocess.Popen(['grep'], stdout=None)
  58. flexmock(module).should_receive('output_buffer_for_process').and_return(process.stdout)
  59. with pytest.raises(subprocess.CalledProcessError) as error:
  60. module.log_outputs(
  61. (process,), exclude_stdouts=(), output_log_level=logging.INFO, borg_local_path='borg'
  62. )
  63. assert error.value.returncode == 2
  64. assert not error.value.output
  65. def test_log_outputs_kills_other_processes_when_one_errors():
  66. flexmock(module.logger).should_receive('log')
  67. flexmock(module).should_receive('exit_code_indicates_error').and_return(True)
  68. flexmock(module).should_receive('command_for_process').and_return('grep')
  69. process = subprocess.Popen(['grep'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  70. other_process = subprocess.Popen(
  71. ['watch', 'true'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT
  72. )
  73. flexmock(module).should_receive('output_buffer_for_process').with_args(process, ()).and_return(
  74. process.stdout
  75. )
  76. flexmock(module).should_receive('output_buffer_for_process').with_args(
  77. other_process, ()
  78. ).and_return(other_process.stdout)
  79. flexmock(other_process).should_receive('kill').once()
  80. with pytest.raises(subprocess.CalledProcessError) as error:
  81. module.log_outputs(
  82. (process, other_process),
  83. exclude_stdouts=(),
  84. output_log_level=logging.INFO,
  85. borg_local_path='borg',
  86. )
  87. assert error.value.returncode == 2
  88. assert error.value.output
  89. def test_log_outputs_truncates_long_error_output():
  90. flexmock(module).ERROR_OUTPUT_MAX_LINE_COUNT = 0
  91. flexmock(module.logger).should_receive('log')
  92. flexmock(module).should_receive('exit_code_indicates_error').and_return(True)
  93. flexmock(module).should_receive('command_for_process').and_return('grep')
  94. process = subprocess.Popen(['grep'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  95. flexmock(module).should_receive('output_buffer_for_process').and_return(process.stdout)
  96. with pytest.raises(subprocess.CalledProcessError) as error:
  97. module.log_outputs(
  98. (process,), exclude_stdouts=(), output_log_level=logging.INFO, borg_local_path='borg'
  99. )
  100. assert error.value.returncode == 2
  101. assert error.value.output.startswith('...')
  102. def test_log_outputs_with_no_output_logs_nothing():
  103. flexmock(module.logger).should_receive('log').never()
  104. flexmock(module).should_receive('exit_code_indicates_error').and_return(False)
  105. process = subprocess.Popen(['true'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  106. flexmock(module).should_receive('output_buffer_for_process').and_return(process.stdout)
  107. module.log_outputs(
  108. (process,), exclude_stdouts=(), output_log_level=logging.INFO, borg_local_path='borg'
  109. )
  110. def test_log_outputs_with_unfinished_process_re_polls():
  111. flexmock(module.logger).should_receive('log').never()
  112. flexmock(module).should_receive('exit_code_indicates_error').and_return(False)
  113. process = subprocess.Popen(['true'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  114. flexmock(process).should_receive('poll').and_return(None).and_return(0).twice()
  115. flexmock(module).should_receive('output_buffer_for_process').and_return(process.stdout)
  116. module.log_outputs(
  117. (process,), exclude_stdouts=(), output_log_level=logging.INFO, borg_local_path='borg'
  118. )