コード例 #1
0
def test_database_init_version_too_high():
    """
    Database will raise DatabaseException if loaded database version is too high
    """
    json_data = b"""{
  "version": VERSION,
  "hash_algorithm": "sha256",
  "timezone_default": "-0400",
  "photo_db": {},
  "command_history": {}
}""".replace(b"VERSION", f"{Database.VERSION + 1}".encode())
    with pytest.raises(DatabaseException):
        Database.from_json(json_data)
コード例 #2
0
def test_database_add_photo_same_source_new_checksum(caplog):
    """
    When adding a photo with a source_path in the database but a different checksum
    the photo is added to the database but a warning is issued.
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data2)
    uid = db.add_photo(
        PhotoFile(
            chk="not_a_match",
            src="/a/b/c.jpg",
            dt="2015:08:27 04:09:36.50",
            ts=1440662976.5,
            fsz=1024,
            sto="",
            prio=10,
        ),
        uid="uid1",
    )
    print([(r.levelname, r) for r in caplog.records])
    print(uid)
    assert uid == "uid1"
    assert db.hash_to_uid["not_a_match"] == "uid1"
    assert db.hash_to_uid["deadbeef"] == "uid1"
    print(db.photo_db["uid1"])
    assert len(db.photo_db["uid1"]) == 2
    print([(r.levelname, r) for r in caplog.records])
    assert any(record.levelname == "WARNING" for record in caplog.records)
    assert any(
        "Checksum of previously-indexed source photo has changed" in record.msg
        for record in caplog.records)
コード例 #3
0
def test_database_save_not_modified(tmpdir, caplog):
    """
    Database.save() will not save if the database is unchanged from loading
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data3)
    db_path = tmpdir / "photos.json"
    db.save(db_path, ["photomanager", "test"])
    assert "The database was not modified and will not be saved" in caplog.messages
    assert not db_path.exists()
コード例 #4
0
def test_database_list_sources(caplog):
    """
    The Database.sources property yields all src paths in the database
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data3)
    assert set(db.sources) == {
        "/a/b/c.jpg",
        "/o/b/c.jpg",
        "/a/c/e.jpg",
    }
コード例 #5
0
def test_database_clean_verify_absolute_subdir(tmpdir, caplog):
    """
    An exception is raised if subdir is an absolute path
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data2)
    with pytest.raises(DatabaseException):
        db.get_photos_to_remove(tmpdir / "a", subdirectory=tmpdir / "b")
    with pytest.raises(DatabaseException):
        db.get_stored_photos(subdirectory=tmpdir / "b")
    with pytest.raises(NotImplementedError):
        db.verify_indexed_photos()
コード例 #6
0
def test_database_is_modified(caplog):
    """
    Database.is_modified() is True if Database.db has been modified
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data3)
    assert not db.is_modified()
    db.add_command("test")
    assert db.is_modified()
    db.reset_saved()
    assert not db.is_modified()
    db.photo_db["uid1"][1].sto = "/path/to/sto.jpg"
    assert db.is_modified()
コード例 #7
0
def test_database_save_modified(tmpdir, caplog):
    """
    Database.save() will save if the database has been modified
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data3)
    db.photo_db["uid1"][1].sto = "/path/to/sto.jpg"
    db_path = tmpdir / "photos.json"
    db.save(db_path, ["photomanager", "test"])
    assert "The database was not modified and will not be saved" not in caplog.messages
    assert db_path.exists()
    with open(db_path, "rb") as f:
        assert len(orjson.loads(f.read())["command_history"]) == 2
コード例 #8
0
def test_database_init_update_version_1():
    """
    Database will upgrade loaded database files to current version
    """
    json_data = b"""{
  "version": 1,
  "hash_algorithm": "sha256",
  "timezone_default": "-0400",
  "photo_db": {
    "d239210f00534b76a2b215e073f75832": [
      {
        "checksum": "deadbeef",
        "source_path": "/a/b/c.jpg",
        "datetime": "2015:08:27 04:09:36.50",
        "timestamp": 1440662976.5,
        "file_size": 1024,
        "store_path": "/d/e/f.jpg",
        "priority": 11,
        "tz_offset": null
      },
      {
        "checksum": "deadbeef",
        "source_path": "/g/b/c.jpg",
        "datetime": "2015:08:27 04:09:36.50",
        "timestamp": 1440662976.5,
        "file_size": 1024,
        "store_path": "",
        "priority": 20,
        "tz_offset": -14400
      }
    ]
  },
  "command_history": {
    "2021-03-08_23-56-00Z": "photomanager create --db test.json",
    "2021-03-08_23-57-00Z": "photomanager import --db test.json test.jpg"
  }
}"""
    new_json_data = json_data.replace(
        b'"version": 1', f'"version": {Database.VERSION}'.encode())
    for k, v in NAME_MAP_ENC.items():
        new_json_data = new_json_data.replace(
            b'"' + k.encode() + b'"',
            b'"' + v.encode() + b'"',
        )
    db = Database.from_json(json_data)
    print(db.db)
    assert db.db["timezone_default"] == "-0400"
    assert db.timezone_default == timezone(timedelta(days=-1, seconds=72000))
    assert orjson.loads(db.json) == orjson.loads(new_json_data)
    assert db.to_json(pretty=True) == new_json_data
コード例 #9
0
def test_database_save(tmpdir, caplog):
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data)
    db.to_file(tmpdir / "test.json")
    db2 = db.from_file(tmpdir / "test.json")
    print(db.db, db2.db, sep="\n")
    assert db == db2
    db.to_file(tmpdir / "test.json.gz")
    db2 = db.from_file(tmpdir / "test.json.gz")
    print(db2.db)
    assert db == db2
    db.to_file(tmpdir / "test.json.zst")
    db2 = db.from_file(tmpdir / "test.json.zst")
    print(db2.db)
    assert db == db2
コード例 #10
0
def test_database_add_photo_sort(caplog):
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data)
    uid = db.add_photo(
        PhotoFile(
            chk="deadbeef",
            src="/x/y/c.jpg",
            dt="2015:08:27 04:09:36.50",
            ts=1440662976.5,
            fsz=1024,
            sto="",
            prio=20,
        ),
        uid=None,
    )
    db.add_photo(
        PhotoFile(
            chk="deadbeef",
            src="/z/y/c.jpg",
            dt="2015:08:27 04:09:36.50",
            ts=1440662976.5,
            fsz=1024,
            sto="",
            prio=11,
        ),
        uid=None,
    )
    db.add_photo(
        PhotoFile(
            chk="deadbeef",
            src="/0/1/c.jpg",
            dt="2015:08:27 04:09:36.50",
            ts=1440662976.5,
            fsz=1024,
            sto="",
            prio=10,
        ),
        uid=None,
    )
    assert list(p.src for p in db.photo_db[uid]) == [
        "/0/1/c.jpg",
        "/a/b/c.jpg",
        "/z/y/c.jpg",
        "/x/y/c.jpg",
    ]
コード例 #11
0
def test_database_load_zstd_checksum_error(tmpdir, monkeypatch, caplog):
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data)
    db.to_file(tmpdir / "test.json.zst")
    with open(tmpdir / "test.json.zst", "r+b") as f:
        f.seek(4)
        c = f.read(1)
        f.seek(4)
        f.write(bytes([ord(c) ^ 0b1]))
    with pytest.raises(zstandard.ZstdError):
        db.from_file(tmpdir / "test.json.zst")
    monkeypatch.setattr(
        zstandard,
        "decompress",
        lambda _: db.to_json(pretty=True).replace(c, bytes([ord(c) ^ 0b1])),
    )
    with pytest.raises(DatabaseException):
        db.from_file(tmpdir / "test.json.zst")
コード例 #12
0
def test_database_overwrite_error(tmpdir, caplog):
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data)
    path = Path(tmpdir / "test.json")
    db.to_file(path)
    base_path = path
    for _ in path.suffixes:
        base_path = base_path.with_suffix("")
    timestamp_str = datetime.fromtimestamp(
        path.stat().st_mtime).strftime("%Y-%m-%d_%H-%M-%S")
    new_path = base_path.with_name(
        f"{base_path.name}_{timestamp_str}").with_suffix("".join(
            path.suffixes))
    os.makedirs(new_path)
    (new_path / "file.txt").touch()
    db.to_file(path)
    print(tmpdir.listdir())
    assert (tmpdir / "test_1.json").exists()

    Path(tmpdir / "test_0.json").touch()
    Path(tmpdir / "test_a.json").touch()
    db.to_file(path)
    print(tmpdir.listdir())
    assert (tmpdir / "test_2.json").exists()

    path = Path(tmpdir / "test_2.json")
    base_path = path
    for _ in path.suffixes:
        base_path = base_path.with_suffix("")
    timestamp_str = datetime.fromtimestamp(
        path.stat().st_mtime).strftime("%Y-%m-%d_%H-%M-%S")
    new_path = base_path.with_name(
        f"{base_path.name}_{timestamp_str}").with_suffix("".join(
            path.suffixes))
    os.makedirs(new_path)
    (new_path / "file.txt").touch()
    db.to_file(path)
    print(tmpdir.listdir())
    assert (tmpdir / "test_3.json").exists()
コード例 #13
0
def test_database_add_photo_already_present(caplog):
    """
    When adding a photo that is already in the database,
    the photo is not added and add_photo returns None.
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data2)
    uid = db.add_photo(
        PhotoFile(
            chk="deadbeef",
            src="/a/b/c.jpg",
            dt="2015:08:27 04:09:36.50",
            ts=1440662976.5,
            fsz=1024,
            sto="",
            prio=10,
        ),
        uid="uid1",
    )
    print([(r.levelname, r) for r in caplog.records])
    print(uid)
    assert uid is None
コード例 #14
0
def test_database_add_photo_wrong_uid(caplog):
    """
    When adding a photo with a matching checksum for a different uid,
    the photo is not added and add_photo returns None.
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data2)
    uid = db.add_photo(
        PhotoFile(
            chk="deadbeef",
            src="/x/y/c.jpg",
            dt="2015:08:27 04:09:36.50",
            ts=1440662976.5,
            fsz=1024,
            sto="",
            prio=10,
        ),
        uid="uid2",
    )
    print([(r.levelname, r) for r in caplog.records])
    print(uid)
    assert uid is None
コード例 #15
0
def test_database_find_photo_ambiguous(caplog):
    """
    When there is no checksum match and an ambiguous timestamp+source match,
    find_photo returns the first match.
    """
    caplog.set_level(logging.DEBUG)
    db = Database.from_json(example_database_json_data2)
    uid = db.find_photo(
        PhotoFile(
            chk="not_a_match",
            src="/x/y/c.jpg",
            dt="2015:08:27 04:09:36.50",
            ts=1440662976.5,
            fsz=1024,
            sto="",
            prio=10,
        ))
    print([(r.levelname, r) for r in caplog.records])
    print(uid)
    assert any(record.levelname == "WARNING" for record in caplog.records)
    assert any("ambiguous timestamp+name match" in record.msg
               for record in caplog.records)
    assert uid == "uid1"
コード例 #16
0
def test_database_load_version_1():
    json_data = b"""{
"version": 1,
"hash_algorithm": "sha256",
"photo_db": {
    "d239210f00534b76a2b215e073f75832": [
        {
            "checksum": "deadbeef",
            "source_path": "/a/b/c.jpg",
            "datetime": "2015:08:27 04:09:36.50",
            "timestamp": 1440662976.5,
            "file_size": 1024,
            "store_path": "/d/e/f.jpg",
            "priority": 11
        },
        {
            "checksum": "deadbeef",
            "source_path": "/g/b/c.jpg",
            "datetime": "2015:08:27 04:09:36.50",
            "timestamp": 1440662976.5,
            "file_size": 1024,
            "store_path": "",
            "priority": 20,
            "tz_offset": -14400
        }
    ]
},
"command_history": {
    "2021-03-08_23-56-00Z": "photomanager create --db test.json",
    "2021-03-08_23-57-00Z": "photomanager import --db test.json test.jpg"
}
}"""
    db = Database.from_json(json_data)
    print(db.db)
    assert db.version == Database.VERSION
    assert db.hash_algorithm == HashAlgorithm.SHA256
    assert db.db["timezone_default"] == "local"
    assert db.timezone_default is None
    photo_db_expected = {
        "d239210f00534b76a2b215e073f75832": [
            PhotoFile.from_dict({
                "chk": "deadbeef",
                "src": "/a/b/c.jpg",
                "dt": "2015:08:27 04:09:36.50",
                "ts": 1440662976.5,
                "fsz": 1024,
                "sto": "/d/e/f.jpg",
                "prio": 11,
            }),
            PhotoFile.from_dict({
                "chk": "deadbeef",
                "src": "/g/b/c.jpg",
                "dt": "2015:08:27 04:09:36.50",
                "ts": 1440662976.5,
                "fsz": 1024,
                "sto": "",
                "prio": 20,
                "tzo": -14400,
            }),
        ]
    }
    command_history_expected = {
        "2021-03-08_23-56-00Z": "photomanager create --db test.json",
        "2021-03-08_23-57-00Z": "photomanager import --db test.json test.jpg",
    }
    db_expected = {
        "version": Database.VERSION,
        "hash_algorithm": HashAlgorithm.SHA256,
        "timezone_default": "local",
        "photo_db": photo_db_expected,
        "command_history": command_history_expected,
    }
    assert db.photo_db == photo_db_expected
    assert db.command_history == command_history_expected
    assert orjson.loads(db.json) != orjson.loads(json_data)
    assert db.db == db_expected
    assert db == Database.from_dict(orjson.loads(json_data))
    assert db.get_stats() == (1, 2, 1, 1024)
コード例 #17
0
def test_database_load_version_3():
    json_data = b"""{
"version": 3,
"hash_algorithm": "sha256",
"photo_db": {
    "QKEsTn2X": [
        {
            "chk": "deadbeef",
            "src": "/a/b/c.jpg",
            "dt": "2015:08:27 04:09:36.50",
            "ts": 1440662976.5,
            "fsz": 1024,
            "sto": "/d/e/f.jpg",
            "prio": 11,
            "tzo": null
        },
        {
            "chk": "deadbeef",
            "src": "/g/b/c.jpg",
            "dt": "2015:08:27 04:09:36.50",
            "ts": 1440662976.5,
            "fsz": 1024,
            "sto": "",
            "prio": 20,
            "tzo": -14400
        }
    ]
},
"command_history": {
    "2021-03-08_23-56-00Z": "photomanager create --db test.json",
    "2021-03-08_23-57-00Z": "photomanager import --db test.json test.jpg"
}
}""".replace(b"VERSION", f"{Database.VERSION}".encode())
    db = Database.from_json(json_data)
    print(db.db)
    assert db.version == Database.VERSION
    assert db.hash_algorithm == HashAlgorithm.SHA256
    assert db.db["timezone_default"] == "local"
    assert db.timezone_default is None
    photo_db_expected = {
        "QKEsTn2X": [
            PhotoFile.from_dict({
                "chk": "deadbeef",
                "src": "/a/b/c.jpg",
                "dt": "2015:08:27 04:09:36.50",
                "ts": 1440662976.5,
                "fsz": 1024,
                "sto": "/d/e/f.jpg",
                "prio": 11,
            }),
            PhotoFile.from_dict({
                "chk": "deadbeef",
                "src": "/g/b/c.jpg",
                "dt": "2015:08:27 04:09:36.50",
                "ts": 1440662976.5,
                "fsz": 1024,
                "sto": "",
                "prio": 20,
                "tzo": -14400,
            }),
        ]
    }
    command_history_expected = {
        "2021-03-08_23-56-00Z": "photomanager create --db test.json",
        "2021-03-08_23-57-00Z": "photomanager import --db test.json test.jpg",
    }
    db_expected = {
        "version": Database.VERSION,
        "hash_algorithm": HashAlgorithm.SHA256,
        "timezone_default": "local",
        "photo_db": photo_db_expected,
        "command_history": command_history_expected,
    }
    assert db.photo_db == photo_db_expected
    assert db.command_history == command_history_expected
    assert orjson.loads(db.json) != orjson.loads(json_data)
    assert db.db == db_expected
    assert db == Database.from_dict(orjson.loads(json_data))
    assert db.get_stats() == (1, 2, 1, 1024)