mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
Clear logs before assertions so that logs from other tests do not interfere with the test. Some destructors may also run in between due to GC, so hopefully this will fix that issue too, or reduce the chances of it happening. See https://github.com/iterative/dvc/actions/runs/14873217814/job/41775314725#step:6:97. ```console > assert first(caplog.messages) == expected_message E assert 'RC: discarding all clients' == "Output 'path... 'stage.dvc'." E E + RC: discarding all clients E - Output 'path'(stage: 'stage.dvc') is missing version info. Cache for it will not be collected. Use `dvc repro` to get your pipeline up to date. E - You can also use `dvc commit stage.dvc` to associate existing 'path' with stage: 'stage.dvc'. ```
204 lines
6.5 KiB
Python
204 lines
6.5 KiB
Python
import logging
|
|
import os
|
|
|
|
import pytest
|
|
from funcy import first
|
|
from voluptuous import MultipleInvalid, Schema
|
|
|
|
from dvc.fs import RemoteMissingDepsError
|
|
from dvc.ignore import _no_match
|
|
from dvc.output import CHECKSUM_SCHEMA, Output
|
|
from dvc.stage import Stage
|
|
from dvc.utils.fs import remove
|
|
|
|
|
|
def test_save_missing(dvc, mocker):
|
|
stage = Stage(dvc)
|
|
out = Output(stage, "path", cache=False)
|
|
mocker.patch.object(out.fs, "exists", return_value=False)
|
|
with pytest.raises(out.DoesNotExistError):
|
|
out.save()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"value,expected",
|
|
[
|
|
("", None),
|
|
(None, None),
|
|
(11111, "11111"),
|
|
("11111", "11111"),
|
|
("aAaBa", "aaaba"),
|
|
(
|
|
"3cc286c534a71504476da009ed174423",
|
|
"3cc286c534a71504476da009ed174423",
|
|
), # md5
|
|
(
|
|
"d41d8cd98f00b204e9800998ecf8427e-38",
|
|
"d41d8cd98f00b204e9800998ecf8427e-38",
|
|
), # etag
|
|
(
|
|
"000002000000000000000000c16859d1d071c6b1ffc9c8557d4909f1",
|
|
"000002000000000000000000c16859d1d071c6b1ffc9c8557d4909f1",
|
|
), # hdfs checksum
|
|
# Not much we can do about hex and oct values without writing our own
|
|
# parser. So listing these test cases just to acknowledge this.
|
|
# See https://github.com/iterative/dvc/issues/3331.
|
|
(0x3451, "13393"),
|
|
(0o1244, "676"),
|
|
],
|
|
)
|
|
def test_checksum_schema(value, expected):
|
|
assert Schema(CHECKSUM_SCHEMA)(value) == expected
|
|
|
|
|
|
@pytest.mark.parametrize("value", ["1", "11", {}, {"a": "b"}, [], [1, 2]])
|
|
def test_checksum_schema_fail(value):
|
|
with pytest.raises(MultipleInvalid):
|
|
assert Schema(CHECKSUM_SCHEMA)(value)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"exists, expected_message",
|
|
[
|
|
(
|
|
False,
|
|
(
|
|
"Output 'path'(stage: 'stage.dvc') is missing version info. "
|
|
"Cache for it will not be collected. "
|
|
"Use `dvc repro` to get your pipeline up to date."
|
|
),
|
|
),
|
|
(
|
|
True,
|
|
(
|
|
"Output 'path'(stage: 'stage.dvc') is missing version info. "
|
|
"Cache for it will not be collected. "
|
|
"Use `dvc repro` to get your pipeline up to date.\n"
|
|
"You can also use `dvc commit stage.dvc` to associate "
|
|
"existing 'path' with stage: 'stage.dvc'."
|
|
),
|
|
),
|
|
],
|
|
)
|
|
def test_get_used_objs(exists, expected_message, mocker, caplog):
|
|
stage = mocker.MagicMock()
|
|
mocker.patch.object(stage, "__str__", return_value="stage: 'stage.dvc'")
|
|
mocker.patch.object(stage, "addressing", "stage.dvc")
|
|
mocker.patch.object(stage, "wdir", os.getcwd())
|
|
mocker.patch.object(stage.repo, "root_dir", os.getcwd())
|
|
mocker.patch.object(stage.repo.dvcignore, "is_ignored", return_value=False)
|
|
mocker.patch.object(
|
|
stage.repo.dvcignore, "check_ignore", return_value=_no_match("path")
|
|
)
|
|
stage.repo.fs.version_aware = False
|
|
stage.repo.fs.PARAM_CHECKSUM = "md5"
|
|
|
|
output = Output(stage, "path")
|
|
|
|
mocker.patch.object(output, "use_cache", True)
|
|
mocker.patch.object(stage, "is_repo_import", False)
|
|
mocker.patch.object(
|
|
Output, "exists", new_callable=mocker.PropertyMock
|
|
).return_value = exists
|
|
|
|
caplog.clear()
|
|
with caplog.at_level(logging.WARNING, logger="dvc"):
|
|
assert output.get_used_objs() == {}
|
|
assert first(caplog.messages) == expected_message
|
|
|
|
|
|
def test_remote_missing_dependency_on_dir_pull(tmp_dir, scm, dvc, mocker):
|
|
tmp_dir.dvc_gen({"dir": {"subfile": "file2 content"}}, commit="add dir")
|
|
with dvc.config.edit() as conf:
|
|
conf["remote"]["s3"] = {"url": "s3://bucket/name"}
|
|
conf["core"] = {"remote": "s3"}
|
|
|
|
remove("dir")
|
|
remove(dvc.cache.local.path)
|
|
|
|
mocker.patch(
|
|
"dvc.data_cloud.DataCloud.get_remote",
|
|
side_effect=RemoteMissingDepsError(dvc.fs, "azure", "azure://", []),
|
|
)
|
|
with pytest.raises(RemoteMissingDepsError):
|
|
dvc.pull()
|
|
|
|
|
|
def test_hash_info_cloud_versioning_dir(mocker):
|
|
stage = mocker.MagicMock()
|
|
stage.repo.fs.version_aware = False
|
|
stage.repo.fs.PARAM_CHECKSUM = "etag"
|
|
files = [
|
|
{
|
|
"size": 3,
|
|
"version_id": "WYRG4BglP7pD.gEoJP6a4AqOhl.FRA.h",
|
|
"etag": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"md5": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"relpath": "bar",
|
|
},
|
|
{
|
|
"size": 3,
|
|
"version_id": "0vL53tFVY5vVAoJ4HG2jCS1mEcohDPE0",
|
|
"etag": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"md5": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"relpath": "foo",
|
|
},
|
|
]
|
|
out = Output(stage, "path", files=files)
|
|
# `hash_info`` and `meta`` constructed from `files``
|
|
assert out.hash_info.name == "md5"
|
|
assert out.hash_info.value == "77e8000f532886eef8ee1feba82e9bad.dir"
|
|
assert out.meta.isdir
|
|
assert out.meta.nfiles == 2
|
|
assert out.meta.size == 6
|
|
|
|
|
|
def test_dumpd_cloud_versioning_dir(mocker):
|
|
stage = mocker.MagicMock()
|
|
stage.repo.fs.version_aware = False
|
|
stage.repo.fs.PARAM_CHECKSUM = "md5"
|
|
files = [
|
|
{
|
|
"size": 3,
|
|
"version_id": "WYRG4BglP7pD.gEoJP6a4AqOhl.FRA.h",
|
|
"etag": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"md5": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"relpath": "bar",
|
|
},
|
|
{
|
|
"size": 3,
|
|
"version_id": "0vL53tFVY5vVAoJ4HG2jCS1mEcohDPE0",
|
|
"etag": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"md5": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"relpath": "foo",
|
|
},
|
|
]
|
|
out = Output(stage, "path", files=files)
|
|
|
|
dumpd = out.dumpd()
|
|
assert dumpd == {"path": "path", "hash": "md5", "files": files}
|
|
|
|
|
|
def test_version_aware_is_set_based_on_files(mocker):
|
|
import dvc.fs as dvc_fs
|
|
|
|
get_fs_config = mocker.spy(dvc_fs, "get_fs_config")
|
|
|
|
stage = mocker.MagicMock()
|
|
stage.repo.fs.version_aware = False
|
|
stage.repo.fs.PARAM_CHECKSUM = "etag"
|
|
files = [
|
|
{
|
|
"size": 3,
|
|
"version_id": "WYRG4BglP7pD.gEoJP6a4AqOhl.FRA.h",
|
|
"etag": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"md5": "acbd18db4cc2f85cedef654fccc4a4d8",
|
|
"relpath": "bar",
|
|
}
|
|
]
|
|
Output(stage, "path", files=files)
|
|
# version_aware is passed as `True` if `files` is present`.
|
|
# This will be intentionally ignored in filesystems that don't handle it
|
|
# in `_prepare_credentials`.
|
|
assert get_fs_config.call_args_list[0][1] == {"url": "path", "version_aware": True}
|