def test_recursive_import_error(self): '''Errors that happen inside recursively-fetched targets should have context information about the targets that caused them. This test is especially important for checking that context isn't lost in GatheredExceptions.''' # Project NOTABLE_NAME has a BAD_MODULE in it. dir_notable = shared.create_dir() # Create the peru.yaml file for NOTABLE_NAME. self.write_yaml('''\ imports: BAD_MODULE: ./ git module BAD_MODULE: bad_field: stuff # The error we get here will actually be that `url` is missing. ''', dir=dir_notable) # Now make our test project import it. self.write_yaml( '''\ imports: NOTABLE_NAME: ./notable cp module NOTABLE_NAME: recursive: true path: {} ''', dir_notable) with self.assertRaises(peru.error.PrintableError) as cm: run_peru_command(['sync'], self.test_dir) self.assertIn("NOTABLE_NAME", cm.exception.message) self.assertIn("BAD_MODULE", cm.exception.message)
def test_identical_plugin_cache_fields(self): # Plugins that use caching also need to avoid running in parallel, if # their cache directories are the same. The noop_cache plugin (created # for this test) uses the path field (but not the nonce field) in its # plugin cache key. Check that these two modules are not fetched in # parallel, even though their module fields aren't exactly the same. foo = shared.create_dir() peru_yaml = dedent('''\ imports: foo1: ./ foo2: ./ noop_cache module foo1: path: {} # nonce is ignored, but it makes foo1 different from foo2 as # far as the module cache is concerned nonce: '1' noop_cache module foo2: path: {} nonce: '2' '''.format(foo, foo)) test_dir = shared.create_dir({'peru.yaml': peru_yaml}) shared.run_peru_command(['sync'], test_dir) assert_parallel(1)
def test_flags_override_vars(self): flag_cache_dir = shared.create_dir() env_cache_dir = shared.create_dir() shared.run_peru_command(['--cache-dir', flag_cache_dir, 'sync'], self.cwd, env={'PERU_CACHE_DIR': env_cache_dir}) self.assert_success(self.project_dir, self.state_dir, flag_cache_dir)
def test_relative_override_from_subdir(self): self.write_peru_yaml('''\ empty module foo: imports: foo: ./ ''') # Create some subdirs inside the project. subdir = os.path.join(self.test_dir, 'a', 'b') peru.compat.makedirs(subdir) # Create an override dir outside the project. override_dir = shared.create_dir({'foo': 'override'}) # Set the override from inside subdir, using the relative path that's # valid from that location. Peru is going to store this path in # .peru/overrides/ at the root, so this tests that we resolve the # stored path properly. relative_path = os.path.relpath(override_dir, start=subdir) run_peru_command(['override', 'add', 'foo', relative_path], subdir) # Confirm that the right path is stored on disk. expected_stored_path = os.path.relpath( override_dir, start=self.test_dir) with open(os.path.join(self.peru_dir, "overrides", "foo")) as f: actual_stored_path = f.read() self.assertEqual(expected_stored_path, actual_stored_path) # Confirm that `peru override` prints output that respects the cwd. output = run_peru_command(['override'], subdir) self.assertEqual("foo: {}\n".format(relative_path), output) # Confirm that syncing works. self.do_integration_test(['sync'], {'foo': 'override'}, cwd=subdir)
def test_rules_in_override(self): def _write_peru_yaml(target): self.write_peru_yaml('''\ imports: TARGET: ./ cp module foo: path: {} rule test_build: build: | printf fee >> fi mkdir -p subdir printf fo >> subdir/fum rule test_export: export: subdir '''.replace('TARGET', target)) _write_peru_yaml('foo|test_build') override_dir = shared.create_dir() run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) # Syncing against a build rule should build in the override. self.do_integration_test(['sync'], {'fi': 'fee', 'subdir/fum': 'fo'}) # Another sync should run the build again. self.do_integration_test( ['sync'], {'fi': 'feefee', 'subdir/fum': 'fofo'}) # Make sure export dirs are respected in rules that come after. _write_peru_yaml('foo|test_build|test_export|test_build') self.do_integration_test( ['sync'], {'fum': 'fofofo', 'fi': 'fee', 'subdir/fum': 'fo'})
def test_recursive_import_error(self): '''Errors that happen inside recursively-fetched targets should have context information about the targets that caused them. This test is especially important for checking that context isn't lost in GatheredExceptions.''' # Project NOTABLE_NAME has a BAD_MODULE in it. dir_notable = shared.create_dir() # Create the peru.yaml file for NOTABLE_NAME. self.write_yaml('''\ imports: BAD_MODULE: ./ git module BAD_MODULE: bad_field: stuff # The error we get here will actually be that `url` is missing. ''', dir=dir_notable) # Now make our test project import it. self.write_yaml('''\ imports: NOTABLE_NAME: ./notable cp module NOTABLE_NAME: recursive: true path: {} ''', dir_notable) with self.assertRaises(peru.error.PrintableError) as cm: run_peru_command(['sync'], self.test_dir) self.assertIn("NOTABLE_NAME", cm.exception.message) self.assertIn("BAD_MODULE", cm.exception.message)
def test_reup_all(self): yaml_with_imports = dedent('''\ imports: foo: ./ bar: ./ git module foo: url: {} rev: {} git module bar: url: {} reup: otherbranch ''').format(self.foo_dir, self.foo_master, self.bar_dir) test_dir = shared.create_dir({'peru.yaml': yaml_with_imports}) expected = dedent('''\ imports: foo: ./ bar: ./ git module foo: url: {} rev: {} git module bar: url: {} reup: otherbranch rev: {} ''').format(self.foo_dir, self.foo_master, self.bar_dir, self.bar_otherbranch) run_peru_command(['reup'], test_dir) # This time we finally pull in barfile. assert_contents(test_dir, {'peru.yaml': expected, 'a': 'b', 'barfile': 'new'}, excludes=['.peru'])
def test_relative_override_from_subdir(self): self.write_yaml('''\ empty module foo: imports: foo: ./ ''') # Create some subdirs inside the project. subdir = os.path.join(self.test_dir, 'a', 'b') peru.compat.makedirs(subdir) # Create an override dir outside the project. override_dir = shared.create_dir({'foo': 'override'}) # Set the override from inside subdir, using the relative path that's # valid from that location. Peru is going to store this path in # .peru/overrides/ at the root, so this tests that we resolve the # stored path properly. relative_path = os.path.relpath(override_dir, start=subdir) run_peru_command(['override', 'add', 'foo', relative_path], subdir) # Confirm that the right path is stored on disk. expected_stored_path = os.path.relpath(override_dir, start=self.test_dir) with open(os.path.join(self.peru_dir, 'overrides', 'foo')) as f: actual_stored_path = f.read() self.assertEqual(expected_stored_path, actual_stored_path) # Confirm that `peru override` prints output that respects the cwd. output = run_peru_command(['override'], subdir) self.assertEqual('foo: {}\n'.format(relative_path), output) # Confirm that syncing works. self.do_integration_test(['sync'], {'foo': 'override'}, cwd=subdir)
def do_integration_test(self, args, expected, *, cwd=None, **peru_cmd_kwargs): if not cwd: cwd = self.test_dir run_peru_command(args, cwd, **peru_cmd_kwargs) assert_contents(self.test_dir, expected, excludes=[DEFAULT_PERU_FILE_NAME, '.peru'])
def test_default_file_name(self): shutil.move(self.peru_file, os.path.join(self.project_dir, 'xxx')) shared.run_peru_command(['--file-basename', 'xxx', 'sync'], cwd=self.cwd) self.assert_success(self.project_dir, self.state_dir, self.cache_dir, more_excludes=['xxx'])
def test_setting_all_env_vars(self): cache_dir = shared.create_dir() shared.run_peru_command(['sync'], self.cwd, env={ 'PERU_CACHE_DIR': cache_dir, }) self.assert_success(self.project_dir, self.state_dir, cache_dir)
def test_relative_paths(self): '''We ran into a bug where calling os.path.dirname(peru_file) was returning "", which got passed as the cwd of a plugin job and blew up. This test repros that case. We've switched to pathlib.Path.parent to fix the issue.''' shared.run_peru_command( ['--file', 'peru.yaml', '--sync-dir', '.', 'sync'], cwd=self.project_dir) self.assert_success(self.project_dir, self.state_dir, self.cache_dir)
def test_override_after_regular_sync(self): self.write_peru_yaml(self.override_test_yaml) # First, do a regular sync. self.do_integration_test(['sync'], {'builtfoo': 'bar!'}) # Now, add an override, and confirm that the new sync works. override_dir = shared.create_dir({'foo': 'override'}) run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) self.do_integration_test(['sync'], {'builtfoo': 'override!'})
def test_setting_all_flags(self): cwd = shared.create_dir() sync_dir = shared.create_dir() state_dir = shared.create_dir() cache_dir = shared.create_dir() shared.run_peru_command([ '--file', self.peru_file, '--sync-dir', sync_dir, '--state-dir', state_dir, '--cache-dir', cache_dir, 'sync' ], cwd) self.assert_success(sync_dir, state_dir, cache_dir)
def test_setting_all_flags(self): cwd = shared.create_dir() sync_dir = shared.create_dir() state_dir = shared.create_dir() cache_dir = shared.create_dir() shared.run_peru_command( ['--file', self.peru_file, '--sync-dir', sync_dir, '--state-dir', state_dir, '--cache-dir', cache_dir, 'sync'], cwd) self.assert_success(sync_dir, state_dir, cache_dir)
def test_override_excludes_dotperu(self): self.write_peru_yaml('''\ empty module foo: imports: foo: ./ ''') override_dir = shared.create_dir( {'foo': 'override', '.peru/bar': 'baz'}) run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) self.do_integration_test(['sync'], {'foo': 'override'})
def test_number_of_git_commands(self): '''A no-op sync should be a single git command. Also check that index files are deleted after any sync error.''' module_dir = shared.create_dir({'foo': 'bar'}) self.write_yaml( '''\ cp module foo: path: {} imports: foo: subdir ''', module_dir) index_path = os.path.join(self.test_dir, '.peru/lastimports.index') # The first sync should take multiple operations and create a # lastimports.index file. peru.cache.DEBUG_GIT_COMMAND_COUNT = 0 self.do_integration_test(['sync'], {'subdir/foo': 'bar'}) assert peru.cache.DEBUG_GIT_COMMAND_COUNT > 1, \ 'The first sync should take multiple operations.' assert os.path.exists(index_path), \ 'The first sync should create an index file.' # The second sync should reuse the index file and only take one # operation. peru.cache.DEBUG_GIT_COMMAND_COUNT = 0 self.do_integration_test(['sync'], {'subdir/foo': 'bar'}) assert peru.cache.DEBUG_GIT_COMMAND_COUNT == 1, \ 'The second sync should take only one operation.' assert os.path.exists(index_path), \ 'The second sync should preserve the index file.' # Now force an error. This should delete the index file. with open(os.path.join(self.test_dir, 'subdir/foo'), 'w') as f: f.write('dirty') with self.assertRaises(peru.cache.DirtyWorkingCopyError): run_peru_command(['sync'], self.test_dir) assert not os.path.exists(index_path), \ 'The error should delete the index file.' # Fix the error and resync with new module contents. This should # recreate the index file with the current tree and then succeed, # rather than using an empty index and treating the current files as # conflicting. with open(os.path.join(self.test_dir, 'subdir/foo'), 'w') as f: f.write('bar') with open(os.path.join(module_dir, 'foo'), 'w') as f: f.write('new bar') self.do_integration_test(['sync', '--no-cache'], {'subdir/foo': 'new bar'}) assert os.path.exists(index_path), \ 'The index should have been recreated.'
def test_single_reup(self): expected = dedent('''\ git module foo: url: {} rev: {} git module bar: url: {} reup: otherbranch ''').format(self.foo_dir, self.foo_master, self.bar_dir) run_peru_command(['reup', 'foo'], self.test_dir) assert_contents(self.test_dir, {'peru.yaml': expected}, excludes=['.peru'])
def test_override_excludes_dotperu(self): self.write_yaml('''\ empty module foo: imports: foo: ./ ''') override_dir = shared.create_dir({ 'foo': 'override', '.peru/bar': 'baz' }) run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) self.do_integration_test(['sync'], {'foo': 'override'})
def test_override(self): module_dir = shared.create_dir({'foo': 'bar'}) self.write_yaml( '''\ cp module foo: path: {} imports: foo: ./ ''', module_dir) override_dir = shared.create_dir({'foo': 'override'}) # Set the override. run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) # Confirm that the override is configured. output = run_peru_command(['override'], self.test_dir) self.assertEqual(output, 'foo: {}\n'.format(override_dir)) # Make sure 'override list' gives the same output as 'override'. output = run_peru_command(['override', 'list'], self.test_dir) self.assertEqual(output, 'foo: {}\n'.format(override_dir)) # Same as above, but as JSON (with --json flag). output = run_peru_command(['override', '--json'], self.test_dir) override_dict = json.loads(output) self.assertEqual(override_dict, {'foo': override_dir}) # Run the sync with --no-overrides and confirm nothing changes. Also # check that there's no overrides-related output. output = self.do_integration_test(['sync', '--no-overrides'], {'foo': 'bar'}) self.assertNotIn('overrides', output) # Now run the sync normally and confirm that the override worked. Also # confirm that we mentioned the override in output, and that the unused # overrides warning is not printed. output = self.do_integration_test(['sync'], {'foo': 'override'}) self.assertIn('overrides', output) self.assertNotIn('WARNING unused overrides', output) # Delete the override. run_peru_command(['override', 'delete', 'foo'], self.test_dir) # Confirm that the override was deleted. output = run_peru_command(['override'], self.test_dir) self.assertEqual(output, '') # Rerun the sync and confirm the original content is back. self.do_integration_test(['sync'], {'foo': 'bar'}) # Add a bogus override and confirm the unused overrides warning is # printed. run_peru_command(['override', 'add', 'bogus', override_dir], self.test_dir) output = self.do_integration_test(['sync'], {'foo': 'bar'}) self.assertIn('WARNING unused overrides', output)
def test_build_output(self): # Make sure build commands are sending their output to the display like # they're supposed do. This also has the effect of testing that modules # and rules are cached like they're supposed to be -- if not, they'll # show up in the output more than once. self.write_peru_yaml('''\ imports: basic: dir1/ basic|complicated: dir2/ cp module basic: path: {} build: echo foo rule complicated: build: echo bar ''') expected_output = dedent('''\ === started basic === === finished basic === foo bar ''') output = run_peru_command(['sync', '-v'], self.test_dir) self.assertEqual(expected_output, output)
def test_module_list(self): self.write_yaml('''\ git module foo: url: blah git module bar: url: blah ''') output = run_peru_command(['module'], self.test_dir) self.assertEqual(output, "bar\nfoo\n") output = run_peru_command(['module', 'list'], self.test_dir) self.assertEqual(output, "bar\nfoo\n") output = run_peru_command(['module', 'list', '--json'], self.test_dir) self.assertEqual(output, '["bar", "foo"]\n')
def test_override_after_regular_sync(self): module_dir = shared.create_dir({'foo': 'bar'}) self.write_yaml('''\ cp module foo: path: {} imports: foo: ./ ''', module_dir) # First, do a regular sync. self.do_integration_test(['sync'], {'foo': 'bar'}) # Now, add an override, and confirm that the new sync works. override_dir = shared.create_dir({'foo': 'override'}) run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) self.do_integration_test(['sync'], {'foo': 'override'})
def test_override_recursive(self): # Module A just includes the file 'foo'. module_a_dir = shared.create_dir({'foo': 'bar'}) # Module B imports module A. module_b_dir = shared.create_dir() self.write_yaml( '''\ cp module A: path: {} imports: A: A/ ''', module_a_dir, dir=module_b_dir) # Module C (in self.test_dir) imports module B, and also directly # imports module A. When we set an override for module A below, we'll # want to check that *both* of these imports get overridden. self.write_yaml( '''\ cp module B: path: {} recursive: true # Note that module business happens before rule business, so # 'drop: peru.yaml' will not affect the recursion, just the # final output. drop: peru.yaml imports: B.A: A/ B: B/ ''', module_b_dir) # First, do a regular sync. self.do_integration_test(['sync'], { 'A/foo': 'bar', 'B/A/foo': 'bar', }) # Now set an override for B.A. override_dir = shared.create_dir({'foo': 'override'}) run_peru_command(['override', 'add', 'B.A', override_dir], self.test_dir) # Now do another sync. *Both* the directly imported copy of A *and* the # copy synced inside of B should be overridden. self.do_integration_test(['sync'], { 'A/foo': 'override', 'B/A/foo': 'override', })
def test_rules_in_override(self): module_dir = shared.create_dir({'a/b': 'c'}) yaml = ''' imports: foo|get_a: ./ cp module foo: path: {} rule get_a: export: a ''' self.write_yaml(yaml, module_dir) override_dir = shared.create_dir({'a/b': 'override'}) run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) self.do_integration_test(['sync'], {'b': 'override'})
def test_override_after_regular_sync(self): module_dir = shared.create_dir({'foo': 'bar'}) self.write_yaml( '''\ cp module foo: path: {} imports: foo: ./ ''', module_dir) # First, do a regular sync. self.do_integration_test(['sync'], {'foo': 'bar'}) # Now, add an override, and confirm that the new sync works. override_dir = shared.create_dir({'foo': 'override'}) run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) self.do_integration_test(['sync'], {'foo': 'override'})
def test_duplicate_keys_warning(self): self.write_yaml('''\ git module foo: git module foo: ''') buffer = io.StringIO() with redirect_stderr(buffer): run_peru_command(['sync'], self.test_dir) assert('WARNING' in buffer.getvalue()) assert('git module foo' in buffer.getvalue()) # Make sure --quiet suppresses the warning. buffer = io.StringIO() with redirect_stderr(buffer): run_peru_command(['sync', '--quiet'], self.test_dir) # Don't literally check that stderr is empty, because that could get # tripped up on other Python warnings (like asyncio taking too long). assert 'git module foo' not in buffer.getvalue()
def test_duplicate_keys_warning(self): self.write_yaml('''\ git module foo: git module foo: ''') buffer = io.StringIO() with redirect_stderr(buffer): run_peru_command(['sync'], self.test_dir) assert ('WARNING' in buffer.getvalue()) assert ('git module foo' in buffer.getvalue()) # Make sure --quiet suppresses the warning. buffer = io.StringIO() with redirect_stderr(buffer): run_peru_command(['sync', '--quiet'], self.test_dir) # Don't literally check that stderr is empty, because that could get # tripped up on other Python warnings (like asyncio taking too long). assert 'git module foo' not in buffer.getvalue()
def test_override_recursive(self): # Module A just includes the file 'foo'. module_a_dir = shared.create_dir({'foo': 'bar'}) # Module B imports module A. module_b_dir = shared.create_dir() self.write_yaml('''\ cp module A: path: {} imports: A: A/ ''', module_a_dir, dir=module_b_dir) # Module C (in self.test_dir) imports module B, and also directly # imports module A. When we set an override for module A below, we'll # want to check that *both* of these imports get overridden. self.write_yaml( '''\ cp module B: path: {} recursive: true # Note that module business happens before rule business, so # 'drop: peru.yaml' will not affect the recursion, just the # final output. drop: peru.yaml imports: B.A: A/ B: B/ ''', module_b_dir) # First, do a regular sync. self.do_integration_test(['sync'], { 'A/foo': 'bar', 'B/A/foo': 'bar', }) # Now set an override for B.A. override_dir = shared.create_dir({'foo': 'override'}) run_peru_command(['override', 'add', 'B.A', override_dir], self.test_dir) # Now do another sync. *Both* the directly imported copy of A *and* the # copy synced inside of B should be overridden. self.do_integration_test(['sync'], { 'A/foo': 'override', 'B/A/foo': 'override', })
def test_override(self): module_dir = shared.create_dir({'foo': 'bar'}) self.write_yaml('''\ cp module foo: path: {} imports: foo: ./ ''', module_dir) override_dir = shared.create_dir({'foo': 'override'}) # Set the override. run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) # Confirm that the override is configured. output = run_peru_command(['override'], self.test_dir) self.assertEqual(output, 'foo: {}\n'.format(override_dir)) # Make sure 'override list' gives the same output as 'override'. output = run_peru_command(['override', 'list'], self.test_dir) self.assertEqual(output, 'foo: {}\n'.format(override_dir)) # Run the sync and confirm that the override worked. self.do_integration_test(['sync'], {'foo': 'override'}) # Delete the override. run_peru_command(['override', 'delete', 'foo'], self.test_dir) # Confirm that the override was deleted. output = run_peru_command(['override'], self.test_dir) self.assertEqual(output, '') # Rerun the sync and confirm the original content is back. self.do_integration_test(['sync'], {'foo': 'bar'})
def test_override(self): module_dir = shared.create_dir({'foo': 'bar'}) self.write_yaml( '''\ cp module foo: path: {} imports: foo: ./ ''', module_dir) override_dir = shared.create_dir({'foo': 'override'}) # Set the override. run_peru_command(['override', 'add', 'foo', override_dir], self.test_dir) # Confirm that the override is configured. output = run_peru_command(['override'], self.test_dir) self.assertEqual(output, 'foo: {}\n'.format(override_dir)) # Make sure 'override list' gives the same output as 'override'. output = run_peru_command(['override', 'list'], self.test_dir) self.assertEqual(output, 'foo: {}\n'.format(override_dir)) # Run the sync and confirm that the override worked. self.do_integration_test(['sync'], {'foo': 'override'}) # Delete the override. run_peru_command(['override', 'delete', 'foo'], self.test_dir) # Confirm that the override was deleted. output = run_peru_command(['override'], self.test_dir) self.assertEqual(output, '') # Rerun the sync and confirm the original content is back. self.do_integration_test(['sync'], {'foo': 'bar'})
def test_sync_from_subdir(self): peru_yaml = dedent('''\ # Use a relative module path, to make sure it gets resolved # relative to the project root and not the dir where peru was # called. cp module relative_foo: path: {} imports: relative_foo: subdir '''.format(os.path.relpath(self.module_dir, start=self.test_dir))) shared.write_files(self.test_dir, {'peru.yaml': peru_yaml}) subdir = os.path.join(self.test_dir, 'a', 'b') peru.compat.makedirs(subdir) run_peru_command(['sync'], subdir) self.assertTrue(os.path.isdir(os.path.join(self.test_dir, '.peru')), msg=".peru dir didn't end up in the right place") assert_contents(os.path.join(self.test_dir, 'subdir'), {'foo': 'bar'})
def test_identical_fields(self): # This checks that modules with identical fields are not fetched in # parallel. This is the same logic that protects us from fetching a # given module twice, like when two other modules both import it. foo = shared.create_dir() peru_yaml = dedent('''\ imports: foo1: ./ foo2: ./ cp module foo1: path: {} cp module foo2: path: {} '''.format(foo, foo)) test_dir = shared.create_dir({'peru.yaml': peru_yaml}) shared.run_peru_command(['sync'], test_dir) assert_parallel(1)
def test_sync_from_subdir(self): module_dir = shared.create_dir({'foo': 'bar'}) self.write_yaml( '''\ # Use a relative module path, to make sure it gets resolved # relative to the project root and not the dir where peru was # called. cp module relative_foo: path: {} imports: relative_foo: subdir ''', os.path.relpath(module_dir, start=self.test_dir)) subdir = os.path.join(self.test_dir, 'a', 'b') peru.compat.makedirs(subdir) run_peru_command(['sync'], subdir) self.assertTrue(os.path.isdir(os.path.join(self.test_dir, '.peru')), msg=".peru dir didn't end up in the right place") assert_contents(os.path.join(self.test_dir, 'subdir'), {'foo': 'bar'})
def test_drop_then_pick_is_an_error(self): '''We want drop to run before pick, so that deleting a bunch of stuff and then trying to pick it turns into an error. The opposite execution order would make this silently succeed. See the discussion at https://github.com/buildinspace/peru/issues/150#issuecomment-212580912. ''' content = {'foo': 'stuff'} module_dir = shared.create_dir(content) self.write_yaml('''\ cp module foobar: path: {} drop: foo pick: foo imports: foobar: ./ ''', module_dir) with raises_gathered(peru.rule.NoMatchingFilesError): run_peru_command(['sync'], self.test_dir)
def test_jobs_flag(self): # This checks that the --jobs flag is respected, even when two modules # could have been fetched in parallel. foo = shared.create_dir() bar = shared.create_dir() peru_yaml = dedent('''\ imports: foo: ./ bar: ./ cp module foo: path: {} cp module bar: path: {} '''.format(foo, bar)) test_dir = shared.create_dir({'peru.yaml': peru_yaml}) shared.run_peru_command(['sync', '-j1'], test_dir) assert_parallel(1)
def test_two_jobs_in_parallel(self): # This just checks that two different modules can actually be fetched # in parallel. foo = shared.create_dir() bar = shared.create_dir() peru_yaml = dedent('''\ imports: foo: ./ bar: ./ cp module foo: path: {} cp module bar: path: {} '''.format(foo, bar)) test_dir = shared.create_dir({'peru.yaml': peru_yaml}) shared.run_peru_command(['sync'], test_dir) assert_parallel(2)
def test_identical_fields(self): # This checks that modules with identical fields are not fetched in # parallel. This is the same logic that protects us from fetching a # given module twice, like when it's imported with two different named # rules. foo = shared.create_dir() peru_yaml = dedent('''\ imports: foo1: ./ foo2: ./ cp module foo1: path: {} cp module foo2: path: {} '''.format(foo, foo)) test_dir = shared.create_dir({'peru.yaml': peru_yaml}) shared.run_peru_command(['sync'], test_dir) assert_parallel(1)
def test_drop_then_pick_is_an_error(self): '''We want drop to run before pick, so that deleting a bunch of stuff and then trying to pick it turns into an error. The opposite execution order would make this silently succeed. See the discussion at https://github.com/buildinspace/peru/issues/150#issuecomment-212580912. ''' content = {'foo': 'stuff'} module_dir = shared.create_dir(content) self.write_yaml( '''\ cp module foobar: path: {} drop: foo pick: foo imports: foobar: ./ ''', module_dir) with raises_gathered(peru.rule.NoMatchingFilesError): run_peru_command(['sync'], self.test_dir)
def test_reup_sync(self): yaml_with_imports = dedent('''\ imports: foo: ./ bar: ./ git module foo: url: {} rev: {} git module bar: url: {} reup: otherbranch ''').format(self.foo_dir, self.foo_master, self.bar_dir) test_dir = shared.create_dir({'peru.yaml': yaml_with_imports}) # First reup without the sync. run_peru_command(['reup', 'foo', '--nosync'], test_dir) assert_contents(test_dir, {}, excludes=['.peru', 'peru.yaml']) # Now do it with the sync. run_peru_command(['reup', 'foo', '--quiet'], test_dir) assert_contents(test_dir, {'a': 'b'}, excludes=['.peru', 'peru.yaml'])
def test_single_reup(self): yaml_without_imports = dedent('''\ git module foo: url: {} rev: master git module bar: url: {} reup: otherbranch ''').format(self.foo_dir, self.bar_dir) test_dir = shared.create_dir({'peru.yaml': yaml_without_imports}) expected = dedent('''\ git module foo: url: {} rev: {} git module bar: url: {} reup: otherbranch ''').format(self.foo_dir, self.foo_master, self.bar_dir) run_peru_command(['reup', 'foo'], test_dir) assert_contents(test_dir, {'peru.yaml': expected}, excludes=['.peru'])
def test_reup_all(self): yaml_with_imports = dedent('''\ imports: foo: ./ bar: ./ git module foo: url: {} rev: {} git module bar: url: {} reup: otherbranch ''').format(self.foo_dir, self.foo_master, self.bar_dir) test_dir = shared.create_dir({'peru.yaml': yaml_with_imports}) expected = dedent('''\ imports: foo: ./ bar: ./ git module foo: url: {} rev: {} git module bar: url: {} reup: otherbranch rev: {} ''').format(self.foo_dir, self.foo_master, self.bar_dir, self.bar_otherbranch) run_peru_command(['reup'], test_dir) # This time we finally pull in barfile. assert_contents(test_dir, { 'peru.yaml': expected, 'a': 'b', 'barfile': 'new' }, excludes=['.peru'])
def test_recursive_import_error(self): '''Errors that happen inside recursively-fetched targets should have context information about the targets that caused them.''' # Project NOTABLE_NAME has a BAD_MODULE in it. dir_notable = shared.create_dir() # Create the peru.yaml file for NOTABLE_NAME. self.write_yaml('''\ imports: BAD_MODULE: ./ git module BAD_MODULE: bad_field: stuff ''', dir=dir_notable) # Now make our test project import it. self.write_yaml('''\ imports: NOTABLE_NAME: ./ cp module NOTABLE_NAME: path: {} ''', dir_notable) with self.assertRaises(peru.error.PrintableError) as cm: run_peru_command(['sync'], self.test_dir) self.assertIn("NOTABLE_NAME", cm.exception.message) self.assertIn("BAD_MODULE", cm.exception.message)
def test_help(self): flag_output = run_peru_command(['--help'], self.test_dir) self.assertEqual(peru.main.__doc__, flag_output) command_output = run_peru_command(['help'], self.test_dir) self.assertEqual(peru.main.__doc__, command_output) clean_help = peru.main.COMMAND_DOCS['clean'] pre_flag_output = run_peru_command(['-h', 'clean'], self.test_dir) self.assertEqual(clean_help, pre_flag_output) post_flag_output = run_peru_command(['clean', '-h'], self.test_dir) self.assertEqual(clean_help, post_flag_output) buffer = io.StringIO() with redirect_stderr(buffer): run_peru_command(['foobarbaz'], self.test_dir, expected_error=1) self.assertEqual(peru.main.__doc__, buffer.getvalue())
def test_file_and_file_basename_incompatible(self): with self.assertRaises(CommandLineError): shared.run_peru_command([ '--file=foo', '--sync-dir=bar', '--file-basename=baz', 'sync' ], cwd=self.cwd)
def test_version(self): version_output = run_peru_command(["--version"], self.test_dir) self.assertEqual(peru.main.get_version(), version_output.strip())