Пример #1
0
async def test_inspect_job_bad_context(client: Client) -> None:
    expr = StrExpr(POS, POS, "${{ inspect_job(22) }}")
    with pytest.raises(
            EvalError,
            match=r"inspect_job\(\) is only available inside a job definition"
    ):
        await expr.eval(Root({}, client))
Пример #2
0
async def test_inspect_job_bad_second_arg(
        client: Client, live_context_factory: LiveContextFactory) -> None:
    expr = StrExpr(POS, POS, "${{ inspect_job('foo', 22) }}")
    ctx = live_context_factory(client, set())
    with pytest.raises(
            EvalError,
            match=r"inspect_job\(\) suffix argument should be a str, got 22"):
        await expr.eval(ctx)
Пример #3
0
def test_expr_validation_set_indexing() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ tags['flow_id'] }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors[0].args[0] == "'TagsCtx' is not subscriptable"
Пример #4
0
def test_expr_validation_list_comp_ok() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ [x * x for x in range(5) ] }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors == []
Пример #5
0
def test_expr_validation_ok() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ flow.flow_id }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors == []
Пример #6
0
def test_expr_validation_unknown_context() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ something_new }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors[0].args[0] == "Unknown context 'something_new'"
Пример #7
0
def test_expr_validation_ok_for_property_access() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ volumes.volume.ref_rw }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors == []
Пример #8
0
def test_expr_validation_not_context_field() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ flow.foo }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors[0].args[0] == "'BatchFlowCtx' has no attribute 'foo'"
Пример #9
0
def test_expr_validation_bad_set_attr() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ tags.anything }}",
    )
    errors = validate_expr(expr, BatchContext)
    assert errors[0].args[0] == "'TagsCtx' has no attribute 'anything'"
Пример #10
0
def test_expr_validation_bad_subcontext_lookup() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ needs.task.foo }}",
    )
    errors = validate_expr(expr, BatchTaskContext, known_needs={"task"})
    assert errors[0].args[0] == "'DepCtx' has no attribute 'foo'"
Пример #11
0
def test_expr_validation_invalid_need() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ needs.fff }}",
    )
    errors = validate_expr(expr, BatchTaskContext, known_needs=set())
    assert errors[0].args[
        0] == "Task 'fff' is not available under needs context"
Пример #12
0
def test_expr_validation_invalid_input() -> None:
    expr = StrExpr(
        Pos(0, 0, LocalPath("<default>")),
        Pos(0, 0, LocalPath("<default>")),
        pattern="${{ inputs.fff }}",
    )
    errors = validate_expr(expr,
                           BatchActionContext[EmptyRoot],
                           known_inputs=set())
    assert errors[0].args[0] == "Input 'fff' is undefined"
Пример #13
0
async def test_inspect_job_no_jobs_errors(
        client: Client, live_context_factory: LiveContextFactory) -> None:
    async def fake_list(*args: Any, **kwargs: Any) -> AsyncIterator[Any]:
        # make it async iterator:
        for _ in range(0):
            yield None

    client.jobs.list = fake_list  # type: ignore

    expr = StrExpr(POS, POS, "${{ inspect_job('foo') }}")
    expr_with_suffix = StrExpr(POS, POS, "${{ inspect_job('foo', 'bar') }}")

    ctx = live_context_factory(client, set())
    with pytest.raises(
            EvalError,
            match=r"inspect_job\(\) did not found running job with name foo"):
        await expr.eval(ctx)

    with pytest.raises(
            EvalError,
            match=r"inspect_job\(\) did not found running job with name foo"
            r" and suffix bar",
    ):
        await expr_with_suffix.eval(ctx)
Пример #14
0
async def test_inspect_job_correct_set_of_tags_multi(
        client: Client, live_context_factory: LiveContextFactory) -> None:
    called = False

    async def fake_list(*args: Any, tags: AbstractSet[str],
                        **kwargs: Any) -> AsyncIterator[Any]:
        nonlocal called
        called = True
        assert tags == {"test_tag", "job:foo", "multi:bar"}
        yield {"id": "test_id"}

    client.jobs.list = fake_list  # type: ignore

    expr = StrExpr(POS, POS, "${{ inspect_job('foo', 'bar').id }}")

    ctx = live_context_factory(client, {"test_tag"})
    result = await expr.eval(ctx)
    assert result == "test_id"
    assert called
Пример #15
0
async def test_upload_dry_run_mode_prints_commands(
    client: Client,
    live_context_factory: LiveContextFactory,
    capsys: CaptureFixture[str],
) -> None:
    expr = StrExpr(
        POS,
        POS,
        "${{ upload(volumes.test) }}",
    )
    ctx = live_context_factory(
        client,
        set(),
        dry_run=True,
        volumes={
            "test":
            VolumeCtx(
                id="test",
                full_local_path=LocalPath("/test/local"),
                local=LocalPath("local"),
                remote=URL("storage://cluster/user/somedir"),
                read_only=False,
                mount=RemotePath("/mnt"),
            )
        },
    )
    await expr.eval(ctx)
    capture = capsys.readouterr()
    assert "neuro mkdir --parents storage://cluster/user\n" in capture.out
    if sys.platform == "win32":
        assert ("neuro cp --recursive --update --no-target-directory"
                " '\\test\\local' storage://cluster/user/somedir\n"
                in capture.out)
    else:
        assert ("neuro cp --recursive --update --no-target-directory"
                " /test/local storage://cluster/user/somedir\n" in capture.out)
Пример #16
0
async def test_fmt(client: Client) -> None:
    expr = StrExpr(POS, POS, "${{ fmt('{} {}', 1, 'a') }}")
    ret = await expr.eval(Root({}, client))
    assert ret == "1 a"
Пример #17
0
async def test_hash_files(client: Client) -> None:
    expr = StrExpr(POS, POS,
                   "${{ hash_files('Dockerfile', 'requirements/*.txt') }}")
    folder = LocalPath(__file__).parent / "hash_files"
    ret = await expr.eval(Root({"flow": {"workspace": folder}}, client))
    assert ret == "081fde04651e1184890a0470501bff3db8e0014260224e07acf5688e70e0edbe"
Пример #18
0
async def test_lower(client: Client) -> None:
    expr = StrExpr(POS, POS, "${{ lower('aBcDeF') }}")
    ret = await expr.eval(Root({}, client))
    assert ret == "abcdef"
Пример #19
0
async def test_upper(client: Client) -> None:
    expr = StrExpr(POS, POS, "${{ upper('aBcDeF') }}")
    ret = await expr.eval(Root({}, client))
    assert ret == "ABCDEF"
Пример #20
0
async def test_parse_volume_remote(client: Client) -> None:
    expr = StrExpr(
        POS, POS, "${{ parse_volume('storage:path/to:/mnt/path:rw').remote }}")
    ret = await expr.eval(Root({}, client))
    assert Matches("storage:[^:]+/path/to") == ret
Пример #21
0
async def test_parse_volume_mount(client: Client) -> None:
    expr = StrExpr(
        POS, POS, "${{ parse_volume('storage:path/to:/mnt/path:rw').mount }}")
    ret = await expr.eval(Root({}, client))
    assert ret == "/mnt/path"
Пример #22
0
async def test_parse_volume_read_only(client: Client) -> None:
    expr = StrExpr(
        POS, POS,
        "${{ parse_volume('storage:path/to:/mnt/path:rw').read_only }}")
    ret = await expr.eval(Root({}, client))
    assert ret == "False"
Пример #23
0
async def test_parse_volume_local_full(client: Client) -> None:
    expr = StrExpr(
        POS, POS,
        "${{ parse_volume('storage:path/to:/mnt/path:rw').full_local_path }}")
    ret = await expr.eval(Root({}, client))
    assert ret == "None"
Пример #24
0
async def test_str(client: Client, pattern: str, result: str) -> None:
    expr = StrExpr(POS, POS, "${{ str(" + pattern + ") }}")
    ret = await expr.eval(Root({}, client))
    assert ret == result
Пример #25
0
async def test_values(client: Client) -> None:
    expr = StrExpr(POS, POS, "${{ values(dct) }}")
    ret = await expr.eval(Root({"dct": {"a": 1, "b": 2}}, client))
    assert ret == "[1, 2]"
Пример #26
0
def test_parse_full_exprs(assets: pathlib.Path) -> None:
    workspace = assets
    config_file = workspace / "live-full-exprs.yml"
    flow = parse_live(workspace, config_file)
    assert flow == ast.LiveFlow(
        Pos(0, 0, config_file),
        Pos(48, 0, config_file),
        id=SimpleOptIdExpr(
            Pos(0, 0, config_file),
            Pos(0, 0, config_file),
            None,
        ),
        kind=ast.FlowKind.LIVE,
        title=SimpleOptStrExpr(
            Pos(0, 0, config_file),
            Pos(0, 0, config_file),
            "Global title",
        ),
        images={
            "image_a": ast.Image(
                Pos(4, 4, config_file),
                Pos(11, 0, config_file),
                ref=StrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "image:banana"
                ),
                context=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "dir"
                ),
                dockerfile=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "dir/Dockerfile"
                ),
                build_args=SequenceExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ ['--arg1', 'val1', '--arg2=val2'] }}",
                    type2str,
                ),
                env=MappingExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ {'SECRET_ENV': 'secret:key' } }}",
                    type2str,
                ),
                volumes=SequenceExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ ['secret:key:/var/secret/key.txt'] }}",
                    type2str,
                ),
                build_preset=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "gpu-small"
                ),
                force_rebuild=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
            )
        },
        volumes={
            "volume_a": ast.Volume(
                Pos(13, 4, config_file),
                Pos(17, 2, config_file),
                remote=URIExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "storage:dir"
                ),
                mount=RemotePathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "/var/dir"
                ),
                read_only=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), True
                ),
                local=OptLocalPathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "dir"
                ),
            ),
            "volume_b": ast.Volume(
                Pos(18, 4, config_file),
                Pos(20, 0, config_file),
                remote=URIExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "storage:other"
                ),
                mount=RemotePathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "/var/other"
                ),
                read_only=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                local=OptLocalPathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
            ),
        },
        defaults=ast.FlowDefaults(
            Pos(21, 2, config_file),
            Pos(28, 0, config_file),
            _specified_fields={
                "env",
                "volumes",
                "life_span",
                "schedule_timeout",
                "preset",
                "workdir",
                "tags",
            },
            tags=SequenceExpr(
                Pos(0, 0, config_file),
                Pos(0, 0, config_file),
                "${{ ['tag-a', 'tag-b'] }}",
                type2str,
            ),
            env=MappingExpr(
                Pos(0, 0, config_file),
                Pos(0, 0, config_file),
                "${{ {'global_a': 'val-a', 'global_b': 'val-b'} }}",
                type2str,
            ),
            volumes=SequenceExpr(
                Pos(0, 0, config_file),
                Pos(0, 0, config_file),
                "${{ ['storage:common:/mnt/common:rw'] }}",
                type2str,
            ),
            workdir=OptRemotePathExpr(
                Pos(0, 0, config_file), Pos(0, 0, config_file), "/global/dir"
            ),
            life_span=OptTimeDeltaExpr(
                Pos(0, 0, config_file), Pos(0, 0, config_file), "1d4h"
            ),
            preset=OptStrExpr(
                Pos(0, 0, config_file), Pos(0, 0, config_file), "cpu-large"
            ),
            schedule_timeout=OptTimeDeltaExpr(
                Pos(0, 0, config_file), Pos(0, 0, config_file), "24d23h22m21s"
            ),
        ),
        mixins=None,
        jobs={
            "test_a": ast.Job(
                Pos(30, 4, config_file),
                Pos(48, 0, config_file),
                _specified_fields={
                    "pass_config",
                    "image",
                    "life_span",
                    "http_port",
                    "title",
                    "cmd",
                    "schedule_timeout",
                    "tags",
                    "preset",
                    "http_auth",
                    "env",
                    "browse",
                    "workdir",
                    "name",
                    "entrypoint",
                    "port_forward",
                    "volumes",
                    "detach",
                },
                mixins=None,
                name=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "job-name"
                ),
                image=OptStrExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ images.image_a.ref }}",
                ),
                preset=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "cpu-micro"
                ),
                schedule_timeout=OptTimeDeltaExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "1d2h3m4s"
                ),
                entrypoint=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "bash"
                ),
                cmd=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "echo abc"
                ),
                workdir=OptRemotePathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "/local/dir"
                ),
                env=MappingExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ {'local_a': 'val-1', 'local_b': 'val-2'} }}",
                    type2str,
                ),
                volumes=SequenceExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ [volumes.volume_a.ref, 'storage:dir:/var/dir:ro'] }}",
                    type2str,
                ),
                tags=SequenceExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ ['tag-1', 'tag-2'] }}",
                    type2str,
                ),
                life_span=OptTimeDeltaExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "2h55m"
                ),
                title=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "Job title"
                ),
                detach=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), True
                ),
                browse=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), True
                ),
                http_port=OptIntExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), 8080
                ),
                http_auth=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), False
                ),
                pass_config=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), True
                ),
                port_forward=SequenceExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    '${{ ["2211:22"] }}',
                    port_pair_item,
                ),
                multi=SimpleOptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                params=None,
            )
        },
    )
Пример #27
0
def test_parse_full(assets: pathlib.Path) -> None:
    workspace = assets
    config_file = workspace / "live-full.yml"
    flow = parse_live(workspace, config_file)
    assert flow == ast.LiveFlow(
        Pos(0, 0, config_file),
        Pos(69, 0, config_file),
        id=SimpleOptIdExpr(
            Pos(0, 0, config_file),
            Pos(0, 0, config_file),
            None,
        ),
        kind=ast.FlowKind.LIVE,
        title=SimpleOptStrExpr(
            Pos(0, 0, config_file),
            Pos(0, 0, config_file),
            "Global title",
        ),
        images={
            "image_a": ast.Image(
                Pos(4, 4, config_file),
                Pos(16, 0, config_file),
                ref=StrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "image:banana"
                ),
                context=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "dir"
                ),
                dockerfile=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "dir/Dockerfile"
                ),
                build_args=SequenceItemsExpr(
                    [
                        StrExpr(
                            Pos(0, 0, config_file), Pos(0, 0, config_file), "--arg1"
                        ),
                        StrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file), "val1"),
                        StrExpr(
                            Pos(0, 0, config_file),
                            Pos(0, 0, config_file),
                            "--arg2=val2",
                        ),
                    ]
                ),
                env=MappingItemsExpr(
                    {
                        "SECRET_ENV": StrExpr(
                            Pos(0, 0, config_file), Pos(0, 0, config_file), "secret:key"
                        ),
                    }
                ),
                volumes=SequenceItemsExpr(
                    [
                        OptStrExpr(
                            Pos(0, 0, config_file),
                            Pos(0, 0, config_file),
                            "secret:key:/var/secret/key.txt",
                        ),
                    ]
                ),
                build_preset=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "gpu-small"
                ),
                force_rebuild=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
            )
        },
        volumes={
            "volume_a": ast.Volume(
                Pos(18, 4, config_file),
                Pos(22, 2, config_file),
                remote=URIExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "storage:dir"
                ),
                mount=RemotePathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "/var/dir"
                ),
                read_only=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), True
                ),
                local=OptLocalPathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "dir"
                ),
            ),
            "volume_b": ast.Volume(
                Pos(23, 4, config_file),
                Pos(25, 0, config_file),
                remote=URIExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "storage:other"
                ),
                mount=RemotePathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "/var/other"
                ),
                read_only=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                local=OptLocalPathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
            ),
        },
        defaults=ast.FlowDefaults(
            Pos(26, 2, config_file),
            Pos(36, 0, config_file),
            _specified_fields={
                "env",
                "volumes",
                "life_span",
                "schedule_timeout",
                "preset",
                "workdir",
                "tags",
            },
            tags=SequenceItemsExpr(
                [
                    StrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file), "tag-a"),
                    StrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file), "tag-b"),
                ]
            ),
            env=MappingItemsExpr(
                {
                    "global_a": StrExpr(
                        Pos(0, 0, config_file), Pos(0, 0, config_file), "val-a"
                    ),
                    "global_b": StrExpr(
                        Pos(0, 0, config_file), Pos(0, 0, config_file), "val-b"
                    ),
                }
            ),
            volumes=SequenceItemsExpr(
                [
                    OptStrExpr(
                        Pos(0, 0, config_file),
                        Pos(0, 0, config_file),
                        "storage:common:/mnt/common:rw",
                    ),
                ]
            ),
            workdir=OptRemotePathExpr(
                Pos(0, 0, config_file), Pos(0, 0, config_file), "/global/dir"
            ),
            life_span=OptTimeDeltaExpr(
                Pos(0, 0, config_file), Pos(0, 0, config_file), "1d4h"
            ),
            preset=OptStrExpr(
                Pos(0, 0, config_file), Pos(0, 0, config_file), "cpu-large"
            ),
            schedule_timeout=OptTimeDeltaExpr(
                Pos(0, 0, config_file), Pos(0, 0, config_file), "24d23h22m21s"
            ),
        ),
        mixins={
            "envs": ast.JobMixin(
                Pos(38, 4, config_file),
                Pos(41, 0, config_file),
                _specified_fields={"env"},
                mixins=None,
                name=OptStrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file), None),
                image=OptStrExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    None,
                ),
                preset=OptStrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file), None),
                schedule_timeout=OptTimeDeltaExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                entrypoint=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                cmd=OptStrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file), None),
                workdir=OptRemotePathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                env=MappingItemsExpr(
                    {
                        "local_b": StrExpr(
                            Pos(0, 0, config_file),
                            Pos(0, 0, config_file),
                            "val-mixin-2",
                        ),
                        "local_c": StrExpr(
                            Pos(0, 0, config_file),
                            Pos(0, 0, config_file),
                            "val-mixin-3",
                        ),
                    }
                ),
                volumes=None,
                tags=None,
                life_span=OptTimeDeltaExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                title=OptStrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file), None),
                detach=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                browse=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                http_port=OptIntExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                http_auth=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                pass_config=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                port_forward=None,
                multi=SimpleOptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                params=None,
            )
        },
        jobs={
            "test_a": ast.Job(
                Pos(43, 4, config_file),
                Pos(69, 0, config_file),
                _specified_fields={
                    "workdir",
                    "http_auth",
                    "preset",
                    "port_forward",
                    "life_span",
                    "title",
                    "http_port",
                    "cmd",
                    "schedule_timeout",
                    "env",
                    "pass_config",
                    "detach",
                    "name",
                    "tags",
                    "image",
                    "mixins",
                    "browse",
                    "volumes",
                    "entrypoint",
                },
                mixins=[
                    StrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file), "envs")
                ],
                name=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "job-name"
                ),
                image=OptStrExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ images.image_a.ref }}",
                ),
                preset=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "cpu-micro"
                ),
                schedule_timeout=OptTimeDeltaExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "1d2h3m4s"
                ),
                entrypoint=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "bash"
                ),
                cmd=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "echo abc"
                ),
                workdir=OptRemotePathExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "/local/dir"
                ),
                env=MappingItemsExpr(
                    {
                        "local_a": StrExpr(
                            Pos(0, 0, config_file), Pos(0, 0, config_file), "val-1"
                        ),
                        "local_b": StrExpr(
                            Pos(0, 0, config_file), Pos(0, 0, config_file), "val-2"
                        ),
                    }
                ),
                volumes=SequenceItemsExpr(
                    [
                        OptStrExpr(
                            Pos(0, 0, config_file),
                            Pos(0, 0, config_file),
                            "${{ volumes.volume_a.ref }}",
                        ),
                        OptStrExpr(
                            Pos(0, 0, config_file),
                            Pos(0, 0, config_file),
                            "storage:dir:/var/dir:ro",
                        ),
                        OptStrExpr(
                            Pos(0, 0, config_file),
                            Pos(0, 0, config_file),
                            "",
                        ),
                        OptStrExpr(
                            Pos(0, 0, config_file),
                            Pos(0, 0, config_file),
                            None,
                        ),
                    ]
                ),
                tags=SequenceItemsExpr(
                    [
                        StrExpr(
                            Pos(0, 0, config_file), Pos(0, 0, config_file), "tag-1"
                        ),
                        StrExpr(
                            Pos(0, 0, config_file), Pos(0, 0, config_file), "tag-2"
                        ),
                    ]
                ),
                life_span=OptTimeDeltaExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "2h55m"
                ),
                title=OptStrExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), "Job title"
                ),
                detach=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), True
                ),
                browse=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), True
                ),
                http_port=OptIntExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), 8080
                ),
                http_auth=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), False
                ),
                pass_config=OptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), True
                ),
                port_forward=SequenceItemsExpr(
                    [
                        PortPairExpr(
                            Pos(0, 0, config_file), Pos(0, 0, config_file), "2211:22"
                        )
                    ]
                ),
                multi=SimpleOptBoolExpr(
                    Pos(0, 0, config_file), Pos(0, 0, config_file), None
                ),
                params=None,
            )
        },
    )
Пример #28
0
async def test_len(client: Client) -> None:
    expr = StrExpr(POS, POS, "${{ len('abc') }}")
    ret = await expr.eval(Root({}, client))
    assert ret == "3"
Пример #29
0
def test_parse_batch_action(assets: LocalPath) -> None:
    config_file = assets / "batch-action-with-image.yml"
    action = parse_action(config_file)
    assert action == ast.BatchAction(
        Pos(0, 0, config_file),
        Pos(43, 0, config_file),
        kind=ast.ActionKind.BATCH,
        name=SimpleOptStrExpr(
            Pos(0, 0, config_file),
            Pos(0, 0, config_file),
            "Test batch Action",
        ),
        author=SimpleOptStrExpr(
            Pos(0, 0, config_file),
            Pos(0, 0, config_file),
            "Andrew Svetlov",
        ),
        descr=SimpleOptStrExpr(
            Pos(0, 0, config_file),
            Pos(0, 0, config_file),
            "description of test action",
        ),
        inputs={
            "arg1":
            ast.Input(
                Pos(6, 4, config_file),
                Pos(7, 2, config_file),
                descr=SimpleOptStrExpr(Pos(0, 0, config_file),
                                       Pos(0, 0, config_file), "param 1"),
                default=SimpleOptPrimitiveExpr(Pos(0, 0, config_file),
                                               Pos(0, 0, config_file), None),
            ),
            "arg2":
            ast.Input(
                Pos(8, 4, config_file),
                Pos(10, 0, config_file),
                descr=SimpleOptStrExpr(Pos(0, 0, config_file),
                                       Pos(0, 0, config_file), "param 2"),
                default=SimpleOptPrimitiveExpr(Pos(0, 0, config_file),
                                               Pos(0, 0, config_file),
                                               "value 2"),
            ),
        },
        outputs=BatchActionOutputs(
            Pos(ANY, ANY, config_file),
            Pos(ANY, ANY, config_file),
            values={
                "res1":
                ast.Output(
                    Pos(ANY, ANY, config_file),
                    Pos(ANY, ANY, config_file),
                    descr=SimpleOptStrExpr(
                        Pos(0, 0, config_file),
                        Pos(0, 0, config_file),
                        "action result 1",
                    ),
                    value=OptStrExpr(
                        Pos(0, 0, config_file),
                        Pos(0, 0, config_file),
                        "${{ needs.task_1.outputs.task1 }}",
                    ),
                ),
                "res2":
                ast.Output(
                    Pos(ANY, ANY, config_file),
                    Pos(ANY, ANY, config_file),
                    descr=SimpleOptStrExpr(
                        Pos(0, 0, config_file),
                        Pos(0, 0, config_file),
                        "action result 2",
                    ),
                    value=OptStrExpr(
                        Pos(0, 0, config_file),
                        Pos(0, 0, config_file),
                        "${{ needs.task_2.outputs.task2 }}",
                    ),
                ),
            },
        ),
        cache=ast.Cache(
            Pos(19, 2, config_file),
            Pos(21, 0, config_file),
            strategy=ast.CacheStrategy.INHERIT,
            life_span=OptTimeDeltaExpr(Pos(0, 0, config_file),
                                       Pos(0, 0, config_file), "30m"),
        ),
        images={
            "image_a":
            ast.Image(
                _start=Pos(23, 4, config_file),
                _end=Pos(35, 0, config_file),
                ref=StrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file),
                            "image:banana"),
                context=OptStrExpr(Pos(0, 0, config_file),
                                   Pos(0, 0, config_file), "dir"),
                dockerfile=OptStrExpr(Pos(0, 0, config_file),
                                      Pos(0, 0, config_file),
                                      "dir/Dockerfile"),
                build_args=SequenceItemsExpr([
                    StrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file),
                            "--arg1"),
                    StrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file),
                            "val1"),
                    StrExpr(
                        Pos(0, 0, config_file),
                        Pos(0, 0, config_file),
                        "--arg2=val2",
                    ),
                ]),
                env=MappingItemsExpr({
                    "SECRET_ENV":
                    StrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file),
                            "secret:key"),
                }),
                volumes=SequenceItemsExpr([
                    OptStrExpr(
                        Pos(0, 0, config_file),
                        Pos(0, 0, config_file),
                        "secret:key:/var/secret/key.txt",
                    ),
                ]),
                build_preset=OptStrExpr(Pos(0, 0, config_file),
                                        Pos(0, 0, config_file), "gpu-small"),
                force_rebuild=OptBoolExpr(Pos(0, 0, config_file),
                                          Pos(0, 0, config_file), None),
            )
        },
        tasks=[
            ast.Task(
                Pos(36, 2, config_file),
                Pos(40, 0, config_file),
                _specified_fields={"needs", "image", "cmd", "id"},
                mixins=None,
                title=OptStrExpr(Pos(0, 0, config_file),
                                 Pos(0, 0, config_file), None),
                name=OptStrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file),
                                None),
                image=OptStrExpr(Pos(0, 0, config_file),
                                 Pos(0, 0, config_file), "image:banana"),
                preset=OptStrExpr(Pos(0, 0, config_file),
                                  Pos(0, 0, config_file), None),
                schedule_timeout=OptTimeDeltaExpr(Pos(0, 0, config_file),
                                                  Pos(0, 0, config_file),
                                                  None),
                entrypoint=OptStrExpr(Pos(0, 0, config_file),
                                      Pos(0, 0, config_file), None),
                cmd=OptBashExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "echo ::set-output name=task1::Task 1 ${{ inputs.arg1 }}",
                ),
                workdir=OptRemotePathExpr(Pos(0, 0, config_file),
                                          Pos(0, 0, config_file), None),
                env=None,
                volumes=None,
                tags=None,
                life_span=OptTimeDeltaExpr(Pos(0, 0, config_file),
                                           Pos(0, 0, config_file), None),
                http_port=OptIntExpr(Pos(0, 0, config_file),
                                     Pos(0, 0, config_file), None),
                http_auth=OptBoolExpr(Pos(0, 0, config_file),
                                      Pos(0, 0, config_file), None),
                pass_config=OptBoolExpr(Pos(0, 0, config_file),
                                        Pos(0, 0, config_file), None),
                id=OptIdExpr(Pos(0, 0, config_file), Pos(0, 0, config_file),
                             "task_1"),
                needs={},
                strategy=None,
                cache=None,
                enable=EnableExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ success() }}",
                ),
            ),
            ast.Task(
                Pos(40, 2, config_file),
                Pos(43, 0, config_file),
                _specified_fields={"image", "cmd", "id"},
                mixins=None,
                title=OptStrExpr(Pos(0, 0, config_file),
                                 Pos(0, 0, config_file), None),
                name=OptStrExpr(Pos(0, 0, config_file), Pos(0, 0, config_file),
                                None),
                image=OptStrExpr(Pos(0, 0, config_file),
                                 Pos(0, 0, config_file), "ubuntu"),
                preset=OptStrExpr(Pos(0, 0, config_file),
                                  Pos(0, 0, config_file), None),
                schedule_timeout=OptTimeDeltaExpr(Pos(0, 0, config_file),
                                                  Pos(0, 0, config_file),
                                                  None),
                entrypoint=OptStrExpr(Pos(0, 0, config_file),
                                      Pos(0, 0, config_file), None),
                cmd=OptBashExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "echo ::set-output name=task2::Task 2 ${{ inputs.arg2 }}",
                ),
                workdir=OptRemotePathExpr(Pos(0, 0, config_file),
                                          Pos(0, 0, config_file), None),
                env=None,
                volumes=None,
                tags=None,
                life_span=OptTimeDeltaExpr(Pos(0, 0, config_file),
                                           Pos(0, 0, config_file), None),
                http_port=OptIntExpr(Pos(0, 0, config_file),
                                     Pos(0, 0, config_file), None),
                http_auth=OptBoolExpr(Pos(0, 0, config_file),
                                      Pos(0, 0, config_file), None),
                pass_config=OptBoolExpr(Pos(0, 0, config_file),
                                        Pos(0, 0, config_file), None),
                id=OptIdExpr(Pos(0, 0, config_file), Pos(0, 0, config_file),
                             "task_2"),
                needs=None,
                strategy=None,
                cache=None,
                enable=EnableExpr(
                    Pos(0, 0, config_file),
                    Pos(0, 0, config_file),
                    "${{ success() }}",
                ),
            ),
        ],
    )
Пример #30
0
async def test_join(client: Client) -> None:
    expr = StrExpr(POS, POS, "${{ join('_', ['x', 'y', 'z']) }}")
    ret = await expr.eval(Root({}, client))
    assert ret == "x_y_z"