def test_invalid_spec(self): """Ensure that loading an invalid spec result in a SandboxError.""" spec_repo = AnodSpecRepository(self.spec_dir) with pytest.raises(SandBoxError) as err: spec_repo.load('invalid_spec') assert 'invalid spec code' in str(err.value)
def test_spec_loader1(self): spec_dir = os.path.join( os.path.dirname(__file__), 'data') spec_repo = AnodSpecRepository(spec_dir) s = spec_repo.load('loader1') assert s.name == 'loader1'
def test_load_config_api_1_5(self): sync_tree(self.spec_dir, "new_spec_dir") Run(["e3-sandbox", "migrate", "1.5", "new_spec_dir"], output=None) spec_repo = AnodSpecRepository("new_spec_dir") spec_repo.api_version = "1.5" anod_class = spec_repo.load("withconfig") anod_instance = anod_class("", "build") assert anod_instance.test1() == 9 assert anod_instance.test_suffix() == 42
def test_spec_loader_prolog(self): spec_repo = AnodSpecRepository(self.spec_dir, spec_config=True) anod_class = spec_repo.load('prolog_test') # We should be able to load a spec twice anod_class = spec_repo.load('prolog_test') anod_instance = anod_class('prolog_test', '', 'build') assert anod_instance.prolog_test, 'prolog not executed properly'
def test_spec_loader_prolog(self): spec_repo = AnodSpecRepository(self.spec_dir) anod_class = spec_repo.load("prolog_test") # We should be able to load a spec twice anod_class = spec_repo.load("prolog_test") anod_instance = anod_class("prolog_test", "", "build") assert anod_instance.prolog_test, "prolog not executed properly"
def test_load_config_api_1_5(self): sync_tree(self.spec_dir, 'new_spec_dir') Run(['e3-sandbox', 'migrate', '1.5', 'new_spec_dir'], output=None) spec_repo = AnodSpecRepository('new_spec_dir') spec_repo.api_version = '1.5' anod_class = spec_repo.load('withconfig') anod_instance = anod_class('', 'build') assert anod_instance.test1() == 9 assert anod_instance.test_suffix() == 42
def create_context(self): # Create a context for a x86-linux machine asr = AnodSpecRepository(self.spec_dir) asr.repos['spec1-git'] = 'spec1-git' asr.repos['spec8-git'] = 'spec8-git' asr.repos['spec2-git'] = 'spec2-git' env = BaseEnv() env.set_build('x86-linux', 'rhes6', 'mylinux') ac = AnodContext(asr, default_env=env) return ac
def test_spec_loader2(self): spec_dir = os.path.join( os.path.dirname(__file__), 'data') spec_repo = AnodSpecRepository(spec_dir) with pytest.raises(SandBoxError) as err: spec_repo.load('loader2') assert str(err.value).startswith( 'load: cannot find Anod subclass in')
def test_load_config(self): spec_repo = AnodSpecRepository(self.spec_dir) anod_class = spec_repo.load('withconfig') anod_instance = anod_class('', 'build') # See comments in tests/tests_e3/anod/data/withconfig.anod assert anod_instance.test1() == 9 with pytest.raises(KeyError) as err: anod_instance.test2() assert 'foo' in str(err.value) assert list(anod_instance.test3()) == ['case_foo']
def test_load_config(self): spec_repo = AnodSpecRepository(self.spec_dir) spec_repo.api_version = "1.4" anod_class = spec_repo.load("withconfig") anod_instance = anod_class("", "build") # See comments in tests/tests_e3/anod/data/withconfig.anod assert anod_instance.test1() == 9 with pytest.raises(KeyError) as err: anod_instance.test2() assert "foo" in str(err.value) assert list(anod_instance.test3()) == ["case_foo"]
def test_force_download_after_install(self): """Test two deps on the same spec with installation and download. Here we have two specs having an "installation" and a "download" depdendency on the same spec (spec_build). When the two are set together the scheduler find the proper solution: download. """ env = BaseEnv() env.set_build("x86_64-linux", "rhes8", "mylinux") asr = AnodSpecRepository(self.spec_dir) ac = AnodContext(asr, default_env=env) ac.add_anod_action("spec_install_dep", env=ac.default_env, primitive="build") with pytest.raises(SchedulingError) as err: ac.schedule(ac.always_create_source_resolver) assert "This plan resolver cannot decide" in str(err) ac.add_anod_action("spec_download_dep", env=ac.default_env, primitive="build") result = ac.schedule(ac.always_create_source_resolver) assert set(result.vertex_data.keys()) == { "root", "mylinux.x86_64-linux.spec_install_dep.build", "mylinux.x86_64-linux.spec_download_dep.build", "mylinux.x86_64-linux.spec_build.install", "mylinux.x86_64-linux.spec_build.download_bin", }
def test_force_download_before_install(self): """Test two deps on the same spec with installation and download. Same as test_force_download_after_install but in a different order. The end result should be the same. """ env = BaseEnv() env.set_build("x86_64-linux", "rhes8", "mylinux") asr = AnodSpecRepository(self.spec_dir) ac = AnodContext(asr, default_env=env) ac.add_anod_action("spec_download_dep", env=ac.default_env, primitive="build") result = ac.schedule(ac.always_create_source_resolver) assert set(result.vertex_data.keys()) == { "root", "mylinux.x86_64-linux.spec_download_dep.build", "mylinux.x86_64-linux.spec_build.install", "mylinux.x86_64-linux.spec_build.download_bin", } ac.add_anod_action("spec_install_dep", env=ac.default_env, primitive="build") ac.schedule(ac.always_create_source_resolver) result = ac.schedule(ac.always_create_source_resolver) assert set(result.vertex_data.keys()) == { "root", "mylinux.x86_64-linux.spec_install_dep.build", "mylinux.x86_64-linux.spec_download_dep.build", "mylinux.x86_64-linux.spec_build.install", "mylinux.x86_64-linux.spec_build.download_bin", }
def test_force_download_after_build(self): """Test two deps on the same spec with build and download. Here we have two specs having an "build_tree" and a "download" depdendency on the same spec (spec_build). When the two are set together the scheduler cannot find a solution. """ env = BaseEnv() env.set_build("x86_64-linux", "rhes8", "mylinux") asr = AnodSpecRepository(self.spec_dir) ac = AnodContext(asr, default_env=env) ac.add_anod_action("spec_build_dep", env=ac.default_env, primitive="build") # Verify that, when scheduling this plan, the scheduler ask for # having an explicit build with pytest.raises(SchedulingError) as err: ac.schedule(ac.always_create_source_resolver) assert "A spec in the plan has a build_tree dependency on spec_build" in str( err) # Verify that after adding a download dep, the scheduler now # warns that he cannot resolve the plan ac.add_anod_action("spec_download_dep", env=ac.default_env, primitive="build") with pytest.raises(SchedulingError) as err: ac.schedule(ac.always_create_source_resolver) assert "explicit DownloadBinary decision made" in str(err)
def test_load_all(self): spec_repo = AnodSpecRepository(self.spec_dir) with pytest.raises(SandBoxError): spec_repo.load_all() spec_repo = AnodSpecRepository(self.spec2_dir) spec_repo.load_all() assert 'parent' in spec_repo assert 'child' in spec_repo assert 'unknown' not in spec_repo
def create_context(self, reject_duplicates=True): """Create a spec repository and anod context. :param reject_duplicates: whether to reject duplicates in plan :type reject_duplicates: bool :rtype: AnodContext """ # Create a context for a x86-linux machine asr = AnodSpecRepository(self.spec_dir) asr.repos['spec1-git'] = 'spec1-git' asr.repos['spec8-git'] = 'spec8-git' asr.repos['spec2-git'] = 'spec2-git' env = BaseEnv() env.set_build('x86-linux', 'rhes6', 'mylinux') ac = AnodContext(asr, default_env=env, reject_duplicates=reject_duplicates) return ac
def test_context_init(self): # Create a context using: # 1. the local default configuration # 2. forcing a x86-linux configuration asr = AnodSpecRepository(self.spec_dir) ac = AnodContext(asr) assert ac.default_env.build == BaseEnv().build assert ac.default_env.host == BaseEnv().host assert ac.default_env.target == BaseEnv().target self.create_context()
def get_source_closure(self, name, expand_packages=True, other_builds=None): asr = AnodSpecRepository(self.spec_dir) ac = AnodContext(asr) anod_instance = ac.add_anod_action(name, primitive="build").data anod_instance = get_build_node(anod_instance, ac, anod_instance) if other_builds is not None: for b in other_builds: ac.add_anod_action(b, primitive="build") return SourceClosure(anod_instance=anod_instance, context=ac, expand_packages=expand_packages)
def activate(self, sandbox: SandBox, spec_repository: AnodSpecRepository) -> None: self.anod_instance.bind_to_sandbox(sandbox) self.anod_instance.log = e3.log.getLogger("spec." + self.anod_instance.uid) for e in getattr(self.anod_instance, "%s_deps" % self.anod_instance.kind, ()): if isinstance(e, self.anod_instance.Dependency): dep_class = spec_repository.load(e.name) dep_instance = dep_class( qualifier=e.qualifier, kind=e.kind, env=e.env(self.anod_instance, BaseEnv.from_env()), ) self.anod_instance.deps[e.local_name] = dep_instance e3.log.debug("activating spec %s", self.anod_instance.uid)
def test_multiple_spec_repository(self): """Ensure that spec function is context dependent.""" spec_repo = AnodSpecRepository(self.spec_dir) spec2_repo = AnodSpecRepository(self.spec2_dir) anod_class = spec_repo.load('child') anod_instance = anod_class('load', '', 'build') assert anod_instance.parent_info == 'from_parent' anod_class2 = spec2_repo.load('child') anod_instance2 = anod_class2('load', '', 'build') assert anod_instance2.parent_info == 'from_parent2'
def test_multiple_spec_repository(self): """Ensure that spec function is context dependent.""" spec_repo = AnodSpecRepository(self.spec_dir) spec2_repo = AnodSpecRepository(self.spec2_dir) anod_class = spec_repo.load("child") anod_instance = anod_class("load", "", "build") assert anod_instance.parent_info == "from_parent" anod_class2 = spec2_repo.load("child") anod_instance2 = anod_class2("load", "", "build") assert anod_instance2.parent_info == "from_parent2"
def test_force_download_before_build(self): """Test two deps on the same spec with build and download. Same as test_force_download_after_build but in a different order. The expected result is the same: an error should be raised. """ env = BaseEnv() env.set_build("x86_64-linux", "rhes8", "mylinux") asr = AnodSpecRepository(self.spec_dir) ac = AnodContext(asr, default_env=env) ac.add_anod_action("spec_download_dep", env=ac.default_env, primitive="build") ac.add_anod_action("spec_build_dep", env=ac.default_env, primitive="build") with pytest.raises(SchedulingError) as err: ac.schedule(ac.always_create_source_resolver) assert "explicit DownloadBinary decision made" in str(err)
def test_force_download_without_require_condition(self): """Test that the force download can be done thanks to require=xxx. A require condition can be added to the build primitive to disable the build primitive for some qualifiers. """ env = BaseEnv() env.set_build("x86_64-linux", "rhes8", "mylinux") asr = AnodSpecRepository(self.spec_dir) # We start with a dependency on spec_nobuild where build primitive # require condition is True ac = AnodContext(asr, default_env=env) ac.add_anod_action( "spec_nobuild_dep", env=ac.default_env, primitive="build", ) # If both build and install are allowed the resolver will # complain and ask for an explicit choice with pytest.raises(SchedulingError) as err: ac.schedule(ac.always_create_source_resolver) assert "what to do for resolving" in str(err) # Now with a dependency making require return False, and so # disable the build primitive, the resolver will not have any # conflict: the only allowed action will be download. ac2 = AnodContext(asr, default_env=env) ac2.add_anod_action( "spec_nobuild_stable_dep", env=ac.default_env, primitive="build", ) result = ac2.schedule(ac.always_create_source_resolver) assert set(result.vertex_data.keys()) == { "root", "mylinux.x86_64-linux.spec_nobuild.download_bin", "mylinux.x86_64-linux.spec_nobuild_stable_dep.build", "mylinux.x86_64-linux.spec_nobuild.install", }
def test_force_download_without_download_primitive(self): """Test that the force download do not require the download primitive. Having a download() primitive or not should not impact this feature. """ env = BaseEnv() env.set_build("x86_64-linux", "rhes8", "mylinux") asr = AnodSpecRepository(self.spec_dir) ac = AnodContext(asr, default_env=env) ac.add_anod_action( "spec_download_dep_for_nodownloadprimitive", env=ac.default_env, primitive="build", ) result = ac.schedule(ac.always_create_source_resolver) assert set(result.vertex_data.keys()) == { "root", "mylinux.x86_64-linux.spec_download_dep_for_nodownloadprimitive.build", "mylinux.x86_64-linux.spec_nodownloadprimitive.install", "mylinux.x86_64-linux.spec_nodownloadprimitive.download_bin", }
def create_context(self, reject_duplicates: bool = True) -> AnodContext: """Create a spec repository and anod context. :param reject_duplicates: whether to reject duplicates in plan """ def repo_conf(name: str) -> dict[str, str]: return {"vcs": "git", "url": name, "branch": "master"} # Create a context for a x86-linux machine asr = AnodSpecRepository(self.spec_dir) asr.repos["spec1-git"] = repo_conf("spec1") asr.repos["spec8-git"] = repo_conf("spec8") asr.repos["spec2-git"] = repo_conf("spec2") asr.repos["a-git"] = repo_conf("a") env = BaseEnv() env.set_build("x86-linux", "rhes6", "mylinux") ac = AnodContext(asr, default_env=env, reject_duplicates=reject_duplicates) return ac
def test_spec_loader_prolog_with_repos(self): sync_tree(self.spec_dir, "specs_dir") repositories_yaml = os.path.join("specs_dir", "config", "repositories.yaml") cp(repositories_yaml + ".tmpl", repositories_yaml) spec_repo = AnodSpecRepository("specs_dir") anod_class = spec_repo.load("prolog_test") assert anod_class.e3_version == "20.1" assert anod_class.has_foo is False assert anod_class.e3_extra_version is None override_conf = { "e3-core": { "revision": 21.0 }, "e3-extra": { "vcs": "git", "url": "unknown", "revision": "master" }, } spec_config = SpecConfig() spec_config.foo = 2 spec_repo2 = AnodSpecRepository( "specs_dir", spec_config=spec_config, extra_repositories_config=override_conf, ) anod_class2 = spec_repo2.load("prolog_test") assert anod_class2.e3_version == "21.0" assert anod_class2.e3_extra_version == "master" assert anod_class2.has_foo is True
def test_spec_inheritance(self): """Load a spec that inherit from another spec.""" spec_repo = AnodSpecRepository(self.spec_dir) anod_class = spec_repo.load("child") anod_instance = anod_class("load", "", "build") assert anod_instance.parent_info == "from_parent"
def test_spec_does_not_exist(self): with pytest.raises(SandBoxError) as err: AnodSpecRepository('/foo/bar') assert str( err.value).startswith('spec directory /foo/bar does not exist')
def run(self, args): sandbox = SandBox() sandbox.root_dir = args.sandbox if args.specs_dir: sandbox.specs_dir = args.specs_dir if args.create_sandbox: sandbox.create_dirs() if args.create_sandbox and args.spec_git_url: mkdir(sandbox.specs_dir) g = GitRepository(sandbox.specs_dir) if e3.log.default_output_stream is not None: g.log_stream = e3.log.default_output_stream g.init() g.update(args.spec_git_url, args.spec_git_branch, force=True) sandbox.dump_configuration() sandbox.write_scripts() asr = AnodSpecRepository(sandbox.specs_dir) check_api_version(asr.api_version) # Load plan content if needed if args.plan: if not os.path.isfile(args.plan): raise SandBoxError("plan file %s does not exist" % args.plan, origin="SandBoxExec.run") with open(args.plan, "r") as plan_fd: plan_content = ["def main_entry_point():"] plan_content += [ " %s" % line for line in plan_fd.read().splitlines() ] plan_content = "\n".join(plan_content) env = BaseEnv() cm = PlanContext(server=env) store = None resolver = getattr( AnodContext, str(args.resolver), AnodContext.always_create_source_resolver, ) logger.debug("Using resolver %s", resolver.__name__) # Declare available actions and their signature def anod_action(module, build=None, host=None, target=None, qualifier=None): pass # all: no cover for a in ("anod_install", "anod_build", "anod_test"): cm.register_action(a, anod_action) # Load the plan and execute plan = Plan(data={}) plan.load_chunk(plan_content) actions = cm.execute(plan, "main_entry_point") ac = AnodContext(asr, default_env=env) for action in actions: ac.add_anod_action( action.module, action, action.action.replace("anod_", "", 1), action.qualifier, ) # Check if machine plan is locally schedulable action_list = ac.schedule(resolver) e = ElectrolytJobFactory(sandbox, asr, store, dry_run=args.dry_run) e.run(action_list)
def test_spec_inheritance(self): """Load a spec that inherit from another spec.""" spec_repo = AnodSpecRepository(self.spec_dir) anod_class = spec_repo.load('child') anod_instance = anod_class('load', '', 'build') assert anod_instance.parent_info == 'from_parent'
def test_getitem_without_buildspace(self): """Without a build space PKG_DIR returns 'unknown'.""" spec_repo = AnodSpecRepository(self.spec_dir) anod_class = spec_repo.load('parent') anod_instance = anod_class('', 'build') assert anod_instance['PKG_DIR'] == 'unknown'
def test_spec_loader1(self): spec_repo = AnodSpecRepository(self.spec_dir) s = spec_repo.load('loader1') assert s.name == 'loader1'
def test_spec_loader2(self): spec_repo = AnodSpecRepository(self.spec_dir) with pytest.raises(SandBoxError) as err: spec_repo.load('loader2') assert str(err.value).startswith('load: cannot find Anod subclass in')