Esempio n. 1
0
def test_https_with_verification():
    with requests_mock.mock() as m:
        m.get("https://example.com/experiment.yaml",
              exc=requests.exceptions.SSLError)
        with pytest.raises(requests.exceptions.SSLError):
            load_experiment("https://example.com/experiment.yaml",
                            verify_tls=True)
Esempio n. 2
0
def test_yaml_safe_load_from_http():
    with requests_mock.mock() as m:
        m.get('http://example.com/experiment.yaml',
              status_code=200,
              headers={"Content-Type": "application/x-yaml"},
              text=experiments.UnsafeYamlExperiment)
        with pytest.raises(InvalidSource):
            load_experiment('http://example.com/experiment.yaml')
Esempio n. 3
0
def test_http_loads_fails_when_known_type():
    with requests_mock.mock() as m:
        m.get('http://example.com/experiment.yaml',
              status_code=200,
              headers={"Content-Type": "text/css"},
              text="body {}")
        with pytest.raises(InvalidExperiment):
            load_experiment('http://example.com/experiment.yaml')
Esempio n. 4
0
def test_load_from_http_without_auth(generic_experiment: str):
    with requests_mock.mock() as m:
        m.get('http://example.com/experiment.json',
              status_code=200,
              headers={"Content-Type": "application/json"},
              json=json.dumps(generic_experiment))
        try:
            load_experiment('http://example.com/experiment.json')
        except InvalidSource as x:
            pytest.fail(str(x))
Esempio n. 5
0
def test_can_load_yaml_from_plain_text_http(generic_experiment: str):
    with requests_mock.mock() as m:
        m.get('http://example.com/experiment.json',
              status_code=200,
              headers={"Content-Type": "text/plain; charset=utf-8"},
              text=json.dumps(generic_experiment))
        try:
            load_experiment('http://example.com/experiment.json')
        except InvalidExperiment as x:
            pytest.fail(str(x))
Esempio n. 6
0
def test_can_load_json_from_plain_text_http():
    with requests_mock.mock() as m:
        m.get('http://example.com/experiment.yaml',
              status_code=200,
              headers={"Content-Type": "text/plain; charset=utf-8"},
              text=experiments.YamlExperiment)
        try:
            load_experiment('http://example.com/experiment.yaml')
        except InvalidExperiment as x:
            pytest.fail(str(x))
Esempio n. 7
0
def test_https_no_verification():
    with requests_mock.mock() as m:
        m.get(
            "https://example.com/experiment.yaml",
            status_code=200,
            headers={"Content-Type": "text/css"},
            text="body {}",
        )
        with pytest.raises(InvalidExperiment):
            load_experiment("https://example.com/experiment.yaml", verify_tls=False)
Esempio n. 8
0
def test_load_from_http_with_auth(settings: Settings, generic_experiment: str):
    with requests_mock.mock() as m:
        settings['auths'] = {'example.com': {'type': 'bearer', 'value': 'XYZ'}}
        m.get('http://example.com/experiment.json',
              status_code=200,
              request_headers={
                  "Authorization": "bearer XYZ",
                  "Accept": "application/json, application/x-yaml"
              },
              headers={"Content-Type": "application/json"},
              json=json.dumps(generic_experiment))
        try:
            load_experiment('http://example.com/experiment.json', settings)
        except InvalidSource as x:
            pytest.fail(str(x))
Esempio n. 9
0
 def run_chaos_engine(self, file, env_params: dict, report: str,
                      report_endpoint: str) -> bool:
     """
     Runs chaos engine programmatically instead of using chaos binary
     :param file:
     :param env_params:
     :param report:
     :param report_endpoint:
     :return:
     """
     settings = ({}, os.environ.get("settings_path")
                 )[os.environ.get("settings_path") is not None]
     has_deviated = False
     has_failed = False
     load_global_controls(settings)
     jornal_file_suffix = file
     try:
         try:
             with open(file, "r"):
                 logger.info("File exists in local")
         except FileNotFoundError:
             logger.info(
                 "File is not available in the current directory, looking inside site packages"
             )
             location = site.getsitepackages().__getitem__(0)
             file_found = False
             for root, dirs, files in os.walk(location):
                 if file in files:
                     file_found = True
                     file = os.path.join(root, file)
                     break
             if not file_found:
                 logger.error("File " + file +
                              " not found in site packages too, quitting")
                 raise FileNotFoundError("Chaos file is not found")
         experiment = load_experiment(click.format_filename(file), settings)
     except InvalidSource as x:
         logger.error(str(x))
         logger.debug(x)
         sys.exit(1)
     logger.info("chaos json file found, proceeding with test")
     journal = run_experiment(experiment, settings=settings)
     has_deviated = journal.get("deviated", False)
     has_failed = journal["status"] != "completed"
     json_file_name = "journal" + "-" + jornal_file_suffix
     with open(json_file_name, "w") as r:
         json.dump(journal,
                   r,
                   indent=2,
                   ensure_ascii=False,
                   default=encoder)
     r.close()
     if report == 'true':
         self.create_report(os.environ, journal, report_endpoint)
     if has_failed or has_deviated:
         logger.error("Test Failed")
         return has_failed and has_deviated
     else:
         logger.info("Test Passed")
         return True
Esempio n. 10
0
def validate(
    ctx: click.Context, source: str, no_verify_tls: bool = False
) -> Experiment:
    """Validate the experiment at SOURCE."""
    settings = load_settings(ctx.obj["settings_path"])

    try:
        experiment = load_experiment(source, settings, verify_tls=not no_verify_tls)
    except InvalidSource as x:
        logger.error(str(x))
        logger.debug(x)
        ctx.exit(1)

    try:
        notify(settings, ValidateFlowEvent.ValidateStarted, experiment)
        ensure_experiment_is_valid(experiment)
        notify(settings, ValidateFlowEvent.ValidateCompleted, experiment)
        logger.info("experiment syntax and semantic look valid")
    except ChaosException as x:
        notify(settings, ValidateFlowEvent.ValidateFailed, experiment, x)
        logger.error(str(x))
        logger.debug(x)
        ctx.exit(1)

    return experiment
def test_controls_on_loaded_experiment():
    settings = {
        "controls": {
            "dummy": {
                "provider": {
                    "type":
                    "python",
                    "module":
                    "fixtures.controls.dummy_retitle_experiment_on_loading"
                }
            }
        }
    }
    load_global_controls(settings)
    initialize_global_controls({}, {}, {}, settings)

    with tempfile.NamedTemporaryFile(suffix=".json") as f:
        try:
            f.write(
                json.dumps(experiments.ExperimentNoControls).encode('utf-8'))
            f.seek(0)
            experiment = load_experiment(f.name)
            assert experiment["title"] == "BOOM I changed it"
        finally:
            cleanup_global_controls()
Esempio n. 12
0
def run(ctx: click.Context,
        source: str,
        journal_path: str = "./journal.json",
        dry: bool = False,
        no_validation: bool = False,
        no_exit: bool = False,
        no_verify_tls: bool = False,
        rollback_strategy: str = "default") -> Journal:
    """Run the experiment loaded from SOURCE, either a local file or a
       HTTP resource. SOURCE can be formatted as JSON or YAML."""
    settings = load_settings(ctx.obj["settings_path"]) or {}
    has_deviated = False
    has_failed = False

    load_global_controls(settings)

    try:
        experiment = load_experiment(source,
                                     settings,
                                     verify_tls=not no_verify_tls)
    except InvalidSource as x:
        logger.error(str(x))
        logger.debug(x)
        ctx.exit(1)

    notify(settings, RunFlowEvent.RunStarted, experiment)

    if not no_validation:
        try:
            ensure_experiment_is_valid(experiment)
        except ChaosException as x:
            logger.error(str(x))
            logger.debug(x)
            ctx.exit(1)

    experiment["dry"] = dry
    settings.setdefault("runtime",
                        {}).setdefault("rollbacks",
                                       {}).setdefault("strategy",
                                                      rollback_strategy)

    journal = run_experiment(experiment, settings=settings)
    has_deviated = journal.get("deviated", False)
    has_failed = journal["status"] != "completed"

    with io.open(journal_path, "w") as r:
        json.dump(journal, r, indent=2, ensure_ascii=False, default=encoder)

    if journal["status"] == "completed":
        notify(settings, RunFlowEvent.RunCompleted, journal)
    elif has_failed:
        notify(settings, RunFlowEvent.RunFailed, journal)

        if has_deviated:
            notify(settings, RunFlowEvent.RunDeviated, journal)

    if (has_failed or has_deviated) and not no_exit:
        ctx.exit(1)

    return journal
Esempio n. 13
0
def test_load_from_http_with_auth(settings: Settings, generic_experiment: str):
    with requests_mock.mock() as m:
        settings["auths"] = {"example.com": {"type": "bearer", "value": "XYZ"}}
        m.get(
            "http://example.com/experiment.json",
            status_code=200,
            request_headers={
                "Authorization": "bearer XYZ",
                "Accept": "application/json, application/x-yaml",
            },
            headers={"Content-Type": "application/json"},
            json=json.dumps(generic_experiment),
        )
        try:
            load_experiment("http://example.com/experiment.json", settings)
        except InvalidSource as x:
            pytest.fail(str(x))
def test_controls_on_loading_experiment():
    settings = {
        "controls": {
            "dummy": {
                "provider": {
                    "type": "python",
                    "module": "fixtures.controls.dummy_fail_loading_experiment"
                }
            }
        }
    }
    load_global_controls(settings)
    initialize_global_controls({}, {}, {}, settings)

    with tempfile.NamedTemporaryFile(suffix=".json") as f:
        try:
            with pytest.raises(InterruptExecution):
                load_experiment(f.name)
        finally:
            cleanup_global_controls()
Esempio n. 15
0
def run(ctx: click.Context, source: str, journal_path: str = "./journal.json",
        dry: bool = False, no_validation: bool = False,
        no_exit: bool = False) -> Journal:
    """Run the experiment loaded from SOURCE, either a local file or a
       HTTP resource."""
    settings = load_settings(ctx.obj["settings_path"]) or {}
    initialize_global_controls(settings)
    has_deviated = False
    has_failed = False

    try:
        try:
            experiment = load_experiment(
                click.format_filename(source), settings)
        except InvalidSource as x:
            logger.error(str(x))
            logger.debug(x)
            ctx.exit(1)

        notify(settings, RunFlowEvent.RunStarted, experiment)

        if not no_validation:
            try:
                ensure_experiment_is_valid(experiment)
            except ChaosException as x:
                logger.error(str(x))
                logger.debug(x)
                ctx.exit(1)

        experiment["dry"] = dry

        journal = run_experiment(experiment)
        has_deviated = journal.get("deviated", False)
        has_failed = journal["status"] != "completed"

        with io.open(journal_path, "w") as r:
            json.dump(
                journal, r, indent=2, ensure_ascii=False, default=encoder)

        if journal["status"] == "completed":
            notify(settings, RunFlowEvent.RunCompleted, journal)
        elif has_failed:
            notify(settings, RunFlowEvent.RunFailed, journal)

            if has_deviated:
                notify(settings, RunFlowEvent.RunDeviated, journal)
    finally:
        cleanup_global_controls()

    if (has_failed or has_deviated) and not no_exit:
        ctx.exit(1)

    return journal
Esempio n. 16
0
def run(ctx: click.Context,
        source: str,
        journal_path: str = "./journal.json",
        dry: bool = False,
        no_validation: bool = False,
        fail_fast: bool = True) -> Journal:
    """Run the experiment loaded from SOURCE, either a local file or a
       HTTP resource."""
    settings = load_settings(ctx.obj["settings_path"])
    try:
        experiment = load_experiment(click.format_filename(source), settings)
    except InvalidSource as x:
        logger.error(str(x))
        logger.debug(x)
        sys.exit(1)

    notify(settings, RunFlowEvent.RunStarted, experiment)

    if not no_validation:
        try:
            ensure_experiment_is_valid(experiment)
        except ChaosException as x:
            logger.error(str(x))
            logger.debug(x)
            sys.exit(1)

    experiment["dry"] = dry

    journal = run_experiment(experiment)

    with io.open(journal_path, "w") as r:
        json.dump(journal, r, indent=2, ensure_ascii=False, default=encoder)

    if journal["status"] == "completed":
        notify(settings, RunFlowEvent.RunCompleted, journal)
    else:
        notify(settings, RunFlowEvent.RunFailed, journal)

        if journal.get("deviated", False):
            notify(settings, RunFlowEvent.RunDeviated, journal)

        # when set (default) we exit this command immediatly if the execution
        # failed, was aborted or interrupted
        # when unset, plugins can continue the processing. In that case, they
        # are responsible to set the process exit code accordingly.
        if fail_fast:
            sys.exit(1)

    return journal
Esempio n. 17
0
def validate(ctx: click.Context, path: str) -> Experiment:
    """Validate the experiment at PATH."""
    settings = load_settings(ctx.obj["settings_path"])
    experiment = load_experiment(click.format_filename(path))
    try:
        notify(settings, ValidateFlowEvent.ValidateStarted, experiment)
        ensure_experiment_is_valid(experiment)
        notify(settings, ValidateFlowEvent.ValidateCompleted, experiment)
        logger.info("experiment syntax and semantic look valid")
    except ChaosException as x:
        notify(settings, ValidateFlowEvent.ValidateFailed, experiment, x)
        logger.error(str(x))
        logger.debug(x)
        ctx.exit(1)

    return experiment
Esempio n. 18
0
def verify(ctx: click.Context,
           source: str,
           journal_path: str = "./journal.json",
           dry: bool = False,
           no_validation: bool = False,
           no_exit: bool = False,
           no_verify_tls: bool = False):
    """Run the verification loaded from SOURCE, either a local file or a
       HTTP resource. SOURCE can be formatted as JSON or YAML."""

    settings = load_settings(ctx.obj["settings_path"]) or {}
    load_global_controls(settings)

    try:
        if not switch_team_during_verification_run(source, settings):
            ctx.exit(1)

        verification = load_experiment(source,
                                       settings,
                                       verify_tls=not no_verify_tls)
    except InvalidSource as x:
        logger.error(str(x))
        logger.debug(x)
        ctx.exit(1)

    if not no_validation:
        try:
            ensure_verification_is_valid(verification)
        except ChaosException as v:
            logger.error(str(v))
            logger.debug(v)
            ctx.exit(1)

    verification["dry"] = dry

    journal = run_verification(verification,
                               settings=settings,
                               strategy=Strategy.CONTINOUS)

    with io.open(journal_path, "w") as r:
        json.dump(journal, r, indent=2, ensure_ascii=False, default=encoder)

    return journal
Esempio n. 19
0
def run(
    ctx: click.Context,
    source: str,
    journal_path: str = "./journal.json",
    dry: Optional[str] = None,
    no_validation: bool = False,
    no_exit: bool = False,
    no_verify_tls: bool = False,
    rollback_strategy: str = "default",
    var: Dict[str, Any] = None,
    var_file: List[str] = None,
    hypothesis_strategy: str = "default",
    hypothesis_frequency: float = 1.0,
    fail_fast: bool = False,
) -> Journal:
    """Run the experiment loaded from SOURCE, either a local file or a
    HTTP resource. SOURCE can be formatted as JSON or YAML."""
    settings = load_settings(ctx.obj["settings_path"]) or {}
    has_deviated = False
    has_failed = False

    experiment_vars = merge_vars(var, var_file)

    load_global_controls(settings)

    try:
        experiment = load_experiment(source, settings, verify_tls=not no_verify_tls)
    except InvalidSource as x:
        logger.error(str(x))
        logger.debug(x)
        ctx.exit(1)

    notify(settings, RunFlowEvent.RunStarted, experiment)

    if not no_validation:
        try:
            ensure_experiment_is_valid(experiment)
        except ChaosException as x:
            logger.error(str(x))
            logger.debug(x)
            ctx.exit(1)

    experiment["dry"] = Dry.from_string(dry)
    settings.setdefault("runtime", {}).setdefault("rollbacks", {}).setdefault(
        "strategy", rollback_strategy
    )
    hypothesis_strategy = check_hypothesis_strategy_spelling(hypothesis_strategy)
    schedule = Schedule(
        continuous_hypothesis_frequency=hypothesis_frequency, fail_fast=fail_fast
    )

    journal = run_experiment(
        experiment,
        settings=settings,
        strategy=hypothesis_strategy,
        schedule=schedule,
        experiment_vars=experiment_vars,
    )
    has_deviated = journal.get("deviated", False)
    has_failed = journal["status"] != "completed"
    if "dry" in journal["experiment"]:
        journal["experiment"]["dry"] = dry
    with open(journal_path, "w") as r:
        json.dump(journal, r, indent=2, ensure_ascii=False, default=encoder)

    if journal["status"] == "completed":
        notify(settings, RunFlowEvent.RunCompleted, journal)
    elif has_failed:
        notify(settings, RunFlowEvent.RunFailed, journal)

        if has_deviated:
            notify(settings, RunFlowEvent.RunDeviated, journal)

    if (has_failed or has_deviated) and not no_exit:
        ctx.exit(1)

    return journal
Esempio n. 20
0
 def run(self, path):
     experiment = load_experiment(path)
     journal = run_experiment(experiment)
     return journal
Esempio n. 21
0
def test_load_from_http_with_missing_auth(generic_experiment: str):
    with requests_mock.mock() as m:
        m.get("http://example.com/experiment.json", status_code=401)
        with pytest.raises(InvalidSource):
            load_experiment("http://example.com/experiment.json")
Esempio n. 22
0
def test_load_invalid_filepath(generic_experiment: str):
    with pytest.raises(InvalidSource) as x:
        load_experiment("/tmp/xyuzye.txt")
    assert 'Path "/tmp/xyuzye.txt" does not exist.' in str(x.value)
Esempio n. 23
0
 def run(self, path):
     experiment = load_experiment(path)
     return experiment
Esempio n. 24
0
def test_load_from_file(generic_experiment: str):
    try:
        load_experiment(generic_experiment)
    except InvalidSource as x:
        pytest.fail(str(x))