def test_split_tutorial_workflow(tmp_path, keep_cwd: pathlib.Path, simplified_nist_catalog: oscatalog.Catalog, monkeypatch: MonkeyPatch) -> None: """Test split operations and final re-merge in workflow tutorial.""" # prepare trestle project dir with the file cat_name = 'mycat' trestle_root = test_utils.create_trestle_project_with_model( tmp_path, simplified_nist_catalog, cat_name, monkeypatch) catalog_dir = trestle_root / 'catalogs' / cat_name catalog_file: pathlib.Path = catalog_dir / 'catalog.json' orig_model = oscatalog.Catalog.oscal_read(catalog_file) # step0 os.chdir(catalog_dir) args = argparse.Namespace( file='catalog.json', element='catalog.metadata,catalog.groups,catalog.back-matter', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 # step1 os.chdir('catalog') args = argparse.Namespace(file='metadata.json', element='metadata.roles,metadata.parties', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 # step2 os.chdir('metadata') args = argparse.Namespace(file='roles.json', element='roles.*', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 args = argparse.Namespace(file='parties.json', element='parties.*', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 # step3 os.chdir('..') args = argparse.Namespace(file='./groups.json', element='groups.*.controls.*', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 # step4 os.chdir(catalog_dir) args = argparse.Namespace(element='catalog.*', verbose=1, trestle_root=trestle_root) assert MergeCmd()._run(args) == 0 new_model = oscatalog.Catalog.oscal_read(catalog_file) assert test_utils.models_are_equivalent(orig_model, new_model)
def test_no_file_given(tmp_path, keep_cwd: pathlib.Path, simplified_nist_catalog: oscatalog.Catalog, monkeypatch: MonkeyPatch) -> None: """Test split with no file specified.""" # prepare trestle project dir with the file cat_name = 'mycat' trestle_root = test_utils.create_trestle_project_with_model( tmp_path, simplified_nist_catalog, cat_name, monkeypatch) orig_model: oscatalog.Catalog = simplified_nist_catalog catalog_dir = trestle_root / 'catalogs' / cat_name catalog_file: pathlib.Path = catalog_dir / 'catalog.json' # no file given and cwd not in trestle directory should fail os.chdir(tmp_path) args = argparse.Namespace(file=None, element='catalog.groups', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 1 os.chdir(catalog_dir) args = argparse.Namespace(file=None, element='catalog.groups,catalog.metadata', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 assert (catalog_dir / 'catalog/groups.json').exists() assert (catalog_dir / 'catalog/metadata.json').exists() os.chdir('./catalog') args = argparse.Namespace(file=None, element='groups.*', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 assert (catalog_dir / 'catalog/groups/00000__group.json').exists() os.chdir('./groups') args = argparse.Namespace(file='00000__group.json', element='group.*', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 os.chdir(catalog_dir) args = argparse.Namespace(file=None, element='catalog.*', verbose=1, trestle_root=trestle_root) assert MergeCmd()._run(args) == 0 new_model: oscatalog.Catalog = oscatalog.Catalog.oscal_read(catalog_file) assert test_utils.models_are_equivalent(orig_model, new_model)
def test_split_comp_def( mode, tmp_path, keep_cwd: pathlib.Path, sample_component_definition: component.ComponentDefinition, monkeypatch: MonkeyPatch) -> None: """Test splitting of component definition and its dictionary.""" compdef_name = 'mycomp' trestle_root = test_utils.create_trestle_project_with_model( tmp_path, sample_component_definition, compdef_name, monkeypatch) compdef_dir = trestle_root / 'component-definitions' / compdef_name compdef_file: pathlib.Path = compdef_dir / 'component-definition.json' original_model = sample_component_definition os.chdir(compdef_dir) # do the split in different ways - then re-merge if mode == 'normal_split.*': args = argparse.Namespace(file='component-definition.json', element='component-definition.components.*', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 elif mode == 'split_two_steps': args = argparse.Namespace(file='component-definition.json', element='component-definition.components', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 os.chdir('component-definition') args = argparse.Namespace(file='components.json', element='components.*', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 elif mode == 'split_in_lower_dir': args = argparse.Namespace( file='component-definition.json', element='component-definition.components.*.props', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 os.chdir(compdef_dir) args = argparse.Namespace(element='component-definition.*', verbose=1, trestle_root=trestle_root) assert MergeCmd()._run(args) == 0 new_model = component.ComponentDefinition.oscal_read(compdef_file) assert test_utils.models_are_equivalent(new_model, original_model)
def test_split_relative_path(tmp_path, keep_cwd: pathlib.Path, simplified_nist_catalog: oscatalog.Catalog, monkeypatch: MonkeyPatch) -> None: """Test split with relative path.""" # prepare trestle project dir with the file cat_name = 'mycat' trestle_root = test_utils.create_trestle_project_with_model( tmp_path, simplified_nist_catalog, cat_name, monkeypatch) orig_model: oscatalog.Catalog = simplified_nist_catalog os.chdir(trestle_root) catalog_dir = trestle_root / 'catalogs' / cat_name catalog_file: pathlib.Path = catalog_dir / 'catalog.json' args = argparse.Namespace(file='catalogs/mycat/catalog.json', element='catalog.metadata', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 # merge receives an element path not a file path # so need to chdir to where the file is os.chdir(catalog_dir) args = argparse.Namespace(element='catalog.*', verbose=1, trestle_root=trestle_root) assert MergeCmd()._run(args) == 0 new_model: oscatalog.Catalog = oscatalog.Catalog.oscal_read(catalog_file) assert test_utils.models_are_equivalent(orig_model, new_model)
def test_split_deep(tmp_path, keep_cwd: pathlib.Path, simplified_nist_catalog: oscatalog.Catalog, monkeypatch: MonkeyPatch) -> None: """Test deep split of model.""" # prepare trestle project dir with the file cat_name = 'mycat' trestle_root = test_utils.create_trestle_project_with_model( tmp_path, simplified_nist_catalog, cat_name, monkeypatch) orig_model: oscatalog.Catalog = simplified_nist_catalog catalog_dir = trestle_root / 'catalogs' / cat_name catalog_file: pathlib.Path = catalog_dir / 'catalog.json' os.chdir(catalog_dir) args = argparse.Namespace(file='catalog.json', element='catalog.groups.*.controls.*.controls.*', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 0 args = argparse.Namespace(element='catalog.*', verbose=1, trestle_root=trestle_root) assert MergeCmd()._run(args) == 0 new_model: oscatalog.Catalog = oscatalog.Catalog.oscal_read(catalog_file) assert test_utils.models_are_equivalent(orig_model, new_model)
def test_split_run(tmp_path: pathlib.Path, sample_target_def: ostarget.TargetDefinition) -> None: """Test split run.""" # common variables target_def_dir: pathlib.Path = tmp_path / 'target-definitions' / 'mytarget' target_def_file: pathlib.Path = target_def_dir / 'target-definition.yaml' cwd = os.getcwd() args = {} cmd = SplitCmd() # inner function for checking split files def check_split_files(): assert target_def_dir.joinpath( 'target-definition/metadata.yaml').exists() assert target_def_dir.joinpath('target-definition.yaml').exists() assert target_def_dir.joinpath('target-definition/targets').exists() assert target_def_dir.joinpath('target-definition/targets').is_dir() targets: Dict = Element(sample_target_def).get_at( ElementPath('target-definition.targets.*')) for uuid in targets: target_file = target_def_dir / f'target-definition/targets/{uuid}{const.IDX_SEP}defined-target.yaml' assert target_file.exists() assert trash.to_trash_file_path(target_def_file).exists() # prepare trestle project dir with the file def prepare_target_def_file() -> None: test_utils.ensure_trestle_config_dir(tmp_path) target_def_dir.mkdir(exist_ok=True, parents=True) sample_target_def.oscal_write(target_def_file) # test prepare_target_def_file() args = argparse.Namespace( file='target-definition.yaml', element='target-definition.targets.*,target-definition.metadata', verbose=0) os.chdir(target_def_dir) cmd._run(args) os.chdir(cwd) check_split_files() # clean before the next test test_utils.clean_tmp_path(target_def_dir) # reverse order test prepare_target_def_file() args = argparse.Namespace( file='target-definition.yaml', element='target-definition.metadata,target-definition.targets.*', verbose=0) os.chdir(target_def_dir) cmd._run(args) os.chdir(cwd) check_split_files()
def test_split_run(tmp_dir, sample_target_def: ostarget.TargetDefinition): """Test split run.""" # common variables target_def_dir: pathlib.Path = tmp_dir / 'target-definitions' / 'mytarget' target_def_file: pathlib.Path = target_def_dir / 'target-definition.yaml' cwd = os.getcwd() args = {} cmd = SplitCmd() parser = cmd.parser # inner function for checking split files def check_split_files(): assert target_def_dir.joinpath( 'target-definition/metadata.yaml').exists() assert target_def_dir.joinpath('target-definition.yaml').exists() assert target_def_dir.joinpath('target-definition/targets').exists() assert target_def_dir.joinpath('target-definition/targets').is_dir() targets: dict = Element(sample_target_def).get_at( ElementPath('target-definition.targets.*')) for uuid in targets: target_file = target_def_dir / f'target-definition/targets/{uuid}{const.IDX_SEP}target.yaml' assert target_file.exists() assert trash.to_trash_file_path(target_def_file).exists() # prepare trestle project dir with the file def prepare_target_def_file(): test_utils.ensure_trestle_config_dir(tmp_dir) fs.ensure_directory(target_def_dir) sample_target_def.oscal_write(target_def_file) # test prepare_target_def_file() args = parser.parse_args([ '-f', 'target-definition.yaml', '-e', 'target-definition.targets.*,target-definition.metadata' ]) os.chdir(target_def_dir) cmd._run(args) os.chdir(cwd) check_split_files() # clean before the next test test_utils.clean_tmp_dir(target_def_dir) # reverse order test prepare_target_def_file() args = parser.parse_args([ '-f', 'target-definition.yaml', '-e', 'target-definition.metadata,target-definition.targets.*' ]) os.chdir(target_def_dir) cmd._run(args) os.chdir(cwd) check_split_files()
def test_split_merge(testdata_dir: pathlib.Path, tmp_trestle_dir: pathlib.Path) -> None: """Test merging data that has been split using the split command- to ensure symmetry.""" # trestle split -f catalog.json -e catalog.groups.*.controls.* # prepare trestle project dir with the file test_utils.ensure_trestle_config_dir(tmp_trestle_dir) test_data_source = testdata_dir / 'split_merge/step0-merged_catalog/catalogs' catalogs_dir = Path('catalogs/') mycatalog_dir = catalogs_dir / 'mycatalog' # Copy files from test/data/split_merge/step4 shutil.rmtree(catalogs_dir) shutil.copytree(test_data_source, catalogs_dir) os.chdir(mycatalog_dir) catalog_file = Path('catalog.json') # Read and store the catalog before split stripped_catalog_type, _ = ModelUtils.get_stripped_model_type( catalog_file.resolve(), tmp_trestle_dir) pre_split_catalog = stripped_catalog_type.oscal_read(catalog_file) assert 'groups' in pre_split_catalog.__fields__.keys() # Split the catalog args = argparse.Namespace(name='split', file='catalog.json', verbose=1, element='catalog.groups.*.controls.*', trestle_root=tmp_trestle_dir) split = SplitCmd()._run(args) assert split == 0 interim_catalog_type, _ = ModelUtils.get_stripped_model_type( catalog_file.resolve(), tmp_trestle_dir) interim_catalog = interim_catalog_type.oscal_read(catalog_file.resolve()) assert 'groups' not in interim_catalog.__fields__.keys() # Merge everything back into the catalog # Equivalent to trestle merge -e catalog.* args = argparse.Namespace(name='merge', element='catalog.*', verbose=2, trestle_root=tmp_trestle_dir) rc = MergeCmd()._run(args) assert rc == 0 # Check both the catalogs are the same. post_catalog_type, _ = ModelUtils.get_stripped_model_type( catalog_file.resolve(), tmp_trestle_dir) post_merge_catalog = post_catalog_type.oscal_read(catalog_file) assert post_merge_catalog == pre_split_catalog
def test_split_stop_at_string(tmp_path, keep_cwd: pathlib.Path, simplified_nist_catalog: oscatalog.Catalog, monkeypatch: MonkeyPatch) -> None: """Test prevention of split at string level.""" # prepare trestle project dir with the file cat_name = 'mycat' trestle_root = test_utils.create_trestle_project_with_model( tmp_path, simplified_nist_catalog, cat_name, monkeypatch) catalog_dir = trestle_root / 'catalogs' / cat_name os.chdir(catalog_dir) args = argparse.Namespace( file='catalog.json', element='catalog.groups.*.controls.*.controls.*.id', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 1 args = argparse.Namespace(file='catalog.json', element='catalog.metadata.version', verbose=1, trestle_root=trestle_root) assert SplitCmd()._run(args) == 1
def test_validate_distributed(testdata_dir: pathlib.Path, tmp_trestle_dir: pathlib.Path, monkeypatch: MonkeyPatch) -> None: """Check that validate will run correctly when exploiting load distributed.""" test_utils.ensure_trestle_config_dir(tmp_trestle_dir) # Clean up. test_data_source = testdata_dir / 'split_merge/step0-merged_catalog/catalogs' catalogs_dir = tmp_trestle_dir / 'catalogs' shutil.rmtree(catalogs_dir) shutil.copytree(test_data_source, catalogs_dir) args = argparse.Namespace(name='split', file='catalogs/mycatalog/catalog.json', verbose=1, element='catalog.groups.*.controls.*', trestle_root=tmp_trestle_dir) _ = SplitCmd()._run(args) test_args = 'trestle validate -a'.split(' ') monkeypatch.setattr(sys, 'argv', test_args) with pytest.raises(SystemExit) as pytest_wrapped_e: cli.run() assert pytest_wrapped_e.type == SystemExit assert pytest_wrapped_e.value.code == 0
def test_split_merge_out_of_context(testdata_dir, tmp_trestle_dir, rel_context_dir: str, use_absolutes: bool, split_elem: str, merge_elem: str, use_effective_cwd: bool): """Test merging data that has been split using the split command- to ensure symmetry.""" # trestle split -f catalog.json -e catalog.groups.*.controls.* # prepare trestle project dir with the file - could e cleaned up. test_utils.ensure_trestle_config_dir(tmp_trestle_dir) test_data_source = testdata_dir / 'split_merge/step0-merged_catalog/catalogs/' # Pontentially change to NIST DIR catalogs_dir = Path('catalogs/') shutil.rmtree(catalogs_dir) shutil.copytree(test_data_source, catalogs_dir) full_path_to_model_dir = tmp_trestle_dir / 'catalogs' / 'mycatalog' full_path_to_model = full_path_to_model_dir / 'catalog.json' full_context_dir = tmp_trestle_dir / rel_context_dir if use_absolutes: model_file = full_path_to_model else: model_file = full_path_to_model.relative_to(full_context_dir) # Always use full context dir for safety os.chdir(full_context_dir) # Read and store the catalog before split stripped_catalog_type, _ = ModelUtils.get_stripped_model_type( full_path_to_model.resolve(), tmp_trestle_dir) pre_split_catalog = stripped_catalog_type.oscal_read(full_path_to_model) assert 'groups' in pre_split_catalog.__fields__.keys() # Split the catalog args = argparse.Namespace(name='split', file=model_file, verbose=0, element=split_elem, trestle_root=tmp_trestle_dir) split = SplitCmd()._run(args) assert split == 0 interim_catalog_type, _ = ModelUtils.get_stripped_model_type( full_path_to_model.resolve(), tmp_trestle_dir) interim_catalog = interim_catalog_type.oscal_read( full_path_to_model.resolve()) assert 'groups' not in interim_catalog.__fields__.keys() # Merge everything back into the catalog # Equivalent to trestle merge -e catalog.* if use_effective_cwd: plan = MergeCmd.merge(full_path_to_model_dir, ElementPath(merge_elem), trestle_root=tmp_trestle_dir) else: os.chdir(full_path_to_model_dir) plan = MergeCmd.merge(pathlib.Path.cwd(), ElementPath(merge_elem), trestle_root=tmp_trestle_dir) plan.execute() # Check both the catalogs are the same. post_catalog_type, _ = ModelUtils.get_stripped_model_type( full_path_to_model.resolve(), tmp_trestle_dir) post_merge_catalog = post_catalog_type.oscal_read(full_path_to_model) assert post_merge_catalog == pre_split_catalog
def test_split_run( keep_cwd: pathlib.Path, tmp_path: pathlib.Path, sample_nist_component_def: component.ComponentDefinition) -> None: """Test split run.""" # common variables owd = keep_cwd component_def_dir: pathlib.Path = tmp_path / 'component-definitions' / 'mytarget' component_def_file: pathlib.Path = component_def_dir / 'component-definition.yaml' args = {} cmd = SplitCmd() # inner function for checking split files def check_split_files(): assert component_def_dir.joinpath( 'component-definition/metadata.yaml').exists() assert component_def_dir.joinpath('component-definition.yaml').exists() assert component_def_dir.joinpath( 'component-definition/components').exists() assert component_def_dir.joinpath( 'component-definition/components').is_dir() # Confirm that the list items are written with the expected numbered names components: list = Element(sample_nist_component_def).get_at( ElementPath('component-definition.components.*')) for index in range(len(components)): comp_fname = f'{str(index).zfill(const.FILE_DIGIT_PREFIX_LENGTH)}{const.IDX_SEP}defined-component.yaml' component_file = component_def_dir / 'component-definition' / 'components' / comp_fname assert component_file.exists() assert trash.to_trash_file_path(component_def_file).exists() # prepare trestle project dir with the file def prepare_component_def_file() -> None: test_utils.ensure_trestle_config_dir(tmp_path) component_def_dir.mkdir(exist_ok=True, parents=True) sample_nist_component_def.oscal_write(component_def_file) # test prepare_component_def_file() args = argparse.Namespace( file='component-definition.yaml', element= 'component-definition.components.*,component-definition.metadata', verbose=0, trestle_root=tmp_path) os.chdir(component_def_dir) assert cmd._run(args) == 0 os.chdir(owd) check_split_files() # clean before the next test test_utils.clean_tmp_path(component_def_dir) # reverse order test prepare_component_def_file() args = argparse.Namespace( file='component-definition.yaml', element= 'component-definition.metadata,component-definition.components.*', verbose=0, trestle_root=tmp_path) os.chdir(component_def_dir) assert cmd._run(args) == 0 os.chdir(owd) check_split_files()