test_generate.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import os
  2. import sys
  3. from io import StringIO
  4. import pytest
  5. from flexmock import flexmock
  6. from borgmatic.config import generate as module
  7. def test_insert_newline_before_comment_does_not_raise():
  8. field_name = 'foo'
  9. config = module.ruamel.yaml.comments.CommentedMap([(field_name, 33)])
  10. config.yaml_set_comment_before_after_key(key=field_name, before='Comment')
  11. module.insert_newline_before_comment(config, field_name)
  12. def test_comment_out_line_skips_blank_line():
  13. line = ' \n'
  14. assert module.comment_out_line(line) == line
  15. def test_comment_out_line_skips_already_commented_out_line():
  16. line = ' # foo'
  17. assert module.comment_out_line(line) == line
  18. def test_comment_out_line_comments_section_name():
  19. line = 'figgy-pudding:'
  20. assert module.comment_out_line(line) == '# ' + line
  21. def test_comment_out_line_comments_indented_option():
  22. line = ' enabled: true'
  23. assert module.comment_out_line(line) == ' # enabled: true'
  24. def test_comment_out_line_comments_twice_indented_option():
  25. line = ' - item'
  26. assert module.comment_out_line(line) == ' # - item'
  27. def test_comment_out_optional_configuration_comments_optional_config_only():
  28. # The "# COMMENT_OUT" comment is a sentinel used to express that the following key is optional.
  29. # It's stripped out of the final output.
  30. flexmock(module).comment_out_line = lambda line: '# ' + line
  31. config = '''
  32. # COMMENT_OUT
  33. foo:
  34. # COMMENT_OUT
  35. bar:
  36. - baz
  37. - quux
  38. repositories:
  39. - one
  40. - two
  41. # This comment should be kept.
  42. # COMMENT_OUT
  43. other: thing
  44. '''
  45. # flake8: noqa
  46. expected_config = '''
  47. # foo:
  48. # bar:
  49. # - baz
  50. # - quux
  51. repositories:
  52. - one
  53. - two
  54. # This comment should be kept.
  55. # other: thing
  56. '''
  57. assert module.comment_out_optional_configuration(config.strip()) == expected_config.strip()
  58. def test_render_configuration_converts_configuration_to_yaml_string():
  59. yaml_string = module.render_configuration({'foo': 'bar'})
  60. assert yaml_string == 'foo: bar\n'
  61. def test_write_configuration_does_not_raise():
  62. flexmock(os.path).should_receive('exists').and_return(False)
  63. flexmock(os).should_receive('makedirs')
  64. builtins = flexmock(sys.modules['builtins'])
  65. builtins.should_receive('open').and_return(StringIO())
  66. flexmock(os).should_receive('chmod')
  67. module.write_configuration('config.yaml', 'config: yaml')
  68. def test_write_configuration_with_already_existing_file_raises():
  69. flexmock(os.path).should_receive('exists').and_return(True)
  70. with pytest.raises(FileExistsError):
  71. module.write_configuration('config.yaml', 'config: yaml')
  72. def test_write_configuration_with_already_existing_file_and_overwrite_does_not_raise():
  73. flexmock(os.path).should_receive('exists').and_return(True)
  74. module.write_configuration('/tmp/config.yaml', 'config: yaml', overwrite=True)
  75. def test_write_configuration_with_already_existing_directory_does_not_raise():
  76. flexmock(os.path).should_receive('exists').and_return(False)
  77. flexmock(os).should_receive('makedirs').and_raise(FileExistsError)
  78. builtins = flexmock(sys.modules['builtins'])
  79. builtins.should_receive('open').and_return(StringIO())
  80. flexmock(os).should_receive('chmod')
  81. module.write_configuration('config.yaml', 'config: yaml')
  82. def test_add_comments_to_configuration_sequence_of_strings_does_not_raise():
  83. config = module.ruamel.yaml.comments.CommentedSeq(['foo', 'bar'])
  84. schema = {'type': 'array', 'items': {'type': 'string'}}
  85. module.add_comments_to_configuration_sequence(config, schema)
  86. def test_add_comments_to_configuration_sequence_of_maps_does_not_raise():
  87. config = module.ruamel.yaml.comments.CommentedSeq(
  88. [module.ruamel.yaml.comments.CommentedMap([('foo', 'yo')])]
  89. )
  90. schema = {
  91. 'type': 'array',
  92. 'items': {'type': 'object', 'properties': {'foo': {'description': 'yo'}}},
  93. }
  94. module.add_comments_to_configuration_sequence(config, schema)
  95. def test_add_comments_to_configuration_sequence_of_maps_without_description_does_not_raise():
  96. config = module.ruamel.yaml.comments.CommentedSeq(
  97. [module.ruamel.yaml.comments.CommentedMap([('foo', 'yo')])]
  98. )
  99. schema = {'type': 'array', 'items': {'type': 'object', 'properties': {'foo': {}}}}
  100. module.add_comments_to_configuration_sequence(config, schema)
  101. def test_add_comments_to_configuration_object_does_not_raise():
  102. # Ensure that it can deal with fields both in the schema and missing from the schema.
  103. config = module.ruamel.yaml.comments.CommentedMap([('foo', 33), ('bar', 44), ('baz', 55)])
  104. schema = {
  105. 'type': 'object',
  106. 'properties': {'foo': {'description': 'Foo'}, 'bar': {'description': 'Bar'}},
  107. }
  108. module.add_comments_to_configuration_object(config, schema)
  109. def test_add_comments_to_configuration_object_with_skip_first_does_not_raise():
  110. config = module.ruamel.yaml.comments.CommentedMap([('foo', 33)])
  111. schema = {'type': 'object', 'properties': {'foo': {'description': 'Foo'}}}
  112. module.add_comments_to_configuration_object(config, schema, skip_first=True)
  113. def test_remove_commented_out_sentinel_keeps_other_comments():
  114. field_name = 'foo'
  115. config = module.ruamel.yaml.comments.CommentedMap([(field_name, 33)])
  116. config.yaml_set_comment_before_after_key(key=field_name, before='Actual comment.\nCOMMENT_OUT')
  117. module.remove_commented_out_sentinel(config, field_name)
  118. comments = config.ca.items[field_name][module.RUAMEL_YAML_COMMENTS_INDEX]
  119. assert len(comments) == 1
  120. assert comments[0].value == '# Actual comment.\n'
  121. def test_remove_commented_out_sentinel_without_sentinel_keeps_other_comments():
  122. field_name = 'foo'
  123. config = module.ruamel.yaml.comments.CommentedMap([(field_name, 33)])
  124. config.yaml_set_comment_before_after_key(key=field_name, before='Actual comment.')
  125. module.remove_commented_out_sentinel(config, field_name)
  126. comments = config.ca.items[field_name][module.RUAMEL_YAML_COMMENTS_INDEX]
  127. assert len(comments) == 1
  128. assert comments[0].value == '# Actual comment.\n'
  129. def test_remove_commented_out_sentinel_on_unknown_field_does_not_raise():
  130. field_name = 'foo'
  131. config = module.ruamel.yaml.comments.CommentedMap([(field_name, 33)])
  132. config.yaml_set_comment_before_after_key(key=field_name, before='Actual comment.')
  133. module.remove_commented_out_sentinel(config, 'unknown')
  134. def test_generate_sample_configuration_does_not_raise():
  135. builtins = flexmock(sys.modules['builtins'])
  136. builtins.should_receive('open').with_args('schema.yaml').and_return('')
  137. flexmock(module.ruamel.yaml).should_receive('YAML').and_return(
  138. flexmock(load=lambda filename: {})
  139. )
  140. flexmock(module).should_receive('schema_to_sample_configuration')
  141. flexmock(module).should_receive('merge_source_configuration_into_destination')
  142. flexmock(module).should_receive('render_configuration')
  143. flexmock(module).should_receive('comment_out_optional_configuration')
  144. flexmock(module).should_receive('write_configuration')
  145. module.generate_sample_configuration(False, None, 'dest.yaml', 'schema.yaml')
  146. def test_generate_sample_configuration_with_source_filename_does_not_raise():
  147. builtins = flexmock(sys.modules['builtins'])
  148. builtins.should_receive('open').with_args('schema.yaml').and_return('')
  149. flexmock(module.ruamel.yaml).should_receive('YAML').and_return(
  150. flexmock(load=lambda filename: {})
  151. )
  152. flexmock(module.load).should_receive('load_configuration')
  153. flexmock(module.normalize).should_receive('normalize')
  154. flexmock(module).should_receive('schema_to_sample_configuration')
  155. flexmock(module).should_receive('merge_source_configuration_into_destination')
  156. flexmock(module).should_receive('render_configuration')
  157. flexmock(module).should_receive('comment_out_optional_configuration')
  158. flexmock(module).should_receive('write_configuration')
  159. module.generate_sample_configuration(False, 'source.yaml', 'dest.yaml', 'schema.yaml')
  160. def test_generate_sample_configuration_with_dry_run_does_not_write_file():
  161. builtins = flexmock(sys.modules['builtins'])
  162. builtins.should_receive('open').with_args('schema.yaml').and_return('')
  163. flexmock(module.ruamel.yaml).should_receive('YAML').and_return(
  164. flexmock(load=lambda filename: {})
  165. )
  166. flexmock(module).should_receive('schema_to_sample_configuration')
  167. flexmock(module).should_receive('merge_source_configuration_into_destination')
  168. flexmock(module).should_receive('render_configuration')
  169. flexmock(module).should_receive('comment_out_optional_configuration')
  170. flexmock(module).should_receive('write_configuration').never()
  171. module.generate_sample_configuration(True, None, 'dest.yaml', 'schema.yaml')