update repository references and improve script handling
This commit is contained in:
442
hassio-google-drive-backup/tests/test_scheme.py
Normal file
442
hassio-google-drive-backup/tests/test_scheme.py
Normal file
@@ -0,0 +1,442 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from dateutil.tz import tzutc
|
||||
from pytest import fail
|
||||
|
||||
from backup.model import GenConfig, GenerationalScheme, DummyBackup, Backup
|
||||
from backup.time import Time
|
||||
|
||||
|
||||
def test_timezone(time) -> None:
|
||||
assert time.local_tz is not None
|
||||
|
||||
|
||||
def test_trivial(time) -> None:
|
||||
config = GenConfig(days=1)
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=0)
|
||||
|
||||
backups = [
|
||||
makeBackup("single", time.local(1928, 12, 6))
|
||||
]
|
||||
|
||||
assert scheme.getOldest(backups)[1].date() == time.local(1928, 12, 6)
|
||||
|
||||
|
||||
def test_trivial_empty(time):
|
||||
config = GenConfig(days=1)
|
||||
scheme = GenerationalScheme(time, config, count=0)
|
||||
assert scheme.getOldest([])[1] is None
|
||||
|
||||
|
||||
def test_trivial_oldest(time: Time) -> None:
|
||||
config = GenConfig(days=1)
|
||||
scheme = GenerationalScheme(time, config, count=0)
|
||||
|
||||
backups = [
|
||||
makeBackup("test", time.local(1985, 12, 6, 10)),
|
||||
makeBackup("test", time.local(1985, 12, 6, 12)),
|
||||
makeBackup("test", time.local(1985, 12, 6, 13))
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(1985, 12, 6, 10),
|
||||
time.local(1985, 12, 6, 12),
|
||||
time.local(1985, 12, 6, 13)
|
||||
])
|
||||
|
||||
|
||||
def test_duplicate_weeks(time):
|
||||
config = GenConfig(weeks=1, day_of_week='wed')
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=0)
|
||||
|
||||
backups = [
|
||||
makeBackup("test", time.local(1985, 12, 5)),
|
||||
makeBackup("test", time.local(1985, 12, 4)),
|
||||
makeBackup("test", time.local(1985, 12, 1)),
|
||||
makeBackup("test", time.local(1985, 12, 2))
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(1985, 12, 1),
|
||||
time.local(1985, 12, 2),
|
||||
time.local(1985, 12, 5),
|
||||
time.local(1985, 12, 4)
|
||||
])
|
||||
|
||||
|
||||
def test_duplicate_months(time) -> None:
|
||||
config = GenConfig(months=2, day_of_month=15)
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=0)
|
||||
|
||||
backups = [
|
||||
makeBackup("test", time.local(1985, 12, 6)),
|
||||
makeBackup("test", time.local(1985, 12, 15)),
|
||||
makeBackup("test", time.local(1985, 11, 20)),
|
||||
makeBackup("test", time.local(1985, 11, 15))
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(1985, 11, 20),
|
||||
time.local(1985, 12, 6),
|
||||
time.local(1985, 11, 15),
|
||||
time.local(1985, 12, 15)
|
||||
])
|
||||
|
||||
|
||||
def test_duplicate_years(time):
|
||||
config = GenConfig(years=2, day_of_year=1)
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=0)
|
||||
|
||||
backups = [
|
||||
makeBackup("test", time.local(1985, 12, 31)),
|
||||
makeBackup("test", time.local(1985, 1, 1)),
|
||||
makeBackup("test", time.local(1984, 12, 31)),
|
||||
makeBackup("test", time.local(1984, 1, 1))
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(1984, 12, 31),
|
||||
time.local(1985, 12, 31),
|
||||
time.local(1984, 1, 1),
|
||||
time.local(1985, 1, 1)
|
||||
])
|
||||
|
||||
|
||||
def test_removal_order(time) -> None:
|
||||
config = GenConfig(days=5, weeks=2, months=2, years=2,
|
||||
day_of_week='mon', day_of_month=15, day_of_year=1)
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=0)
|
||||
|
||||
backups = [
|
||||
# 5 days, week 1
|
||||
makeBackup("test", time.local(1985, 12, 7)), # day 1
|
||||
makeBackup("test", time.local(1985, 12, 6)), # day 2
|
||||
makeBackup("test", time.local(1985, 12, 5)), # day 3
|
||||
makeBackup("test", time.local(1985, 12, 4)), # day 4
|
||||
makeBackup("test", time.local(1985, 12, 3)), # day 5
|
||||
|
||||
makeBackup("test", time.local(1985, 12, 1)), # 1st week pref
|
||||
|
||||
# week 2
|
||||
makeBackup("test", time.local(1985, 11, 25)), # 1st month pref
|
||||
|
||||
# month2
|
||||
makeBackup("test", time.local(1985, 11, 15)), # 2nd month pref
|
||||
|
||||
# year 1
|
||||
makeBackup("test", time.local(1985, 1, 1)), # 1st year preference
|
||||
makeBackup("test", time.local(1985, 1, 2)),
|
||||
|
||||
# year 2
|
||||
makeBackup("test", time.local(1984, 6, 1)), # 2nd year pref
|
||||
makeBackup("test", time.local(1984, 7, 1)),
|
||||
|
||||
# year 3
|
||||
makeBackup("test", time.local(1983, 1, 1)),
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(1983, 1, 1),
|
||||
time.local(1984, 7, 1),
|
||||
time.local(1985, 1, 2),
|
||||
|
||||
time.local(1984, 6, 1),
|
||||
time.local(1985, 1, 1),
|
||||
time.local(1985, 11, 15),
|
||||
time.local(1985, 11, 25),
|
||||
time.local(1985, 12, 1),
|
||||
time.local(1985, 12, 3),
|
||||
time.local(1985, 12, 4),
|
||||
time.local(1985, 12, 5),
|
||||
time.local(1985, 12, 6),
|
||||
time.local(1985, 12, 7)
|
||||
])
|
||||
|
||||
|
||||
@pytest.mark.timeout(60)
|
||||
def test_simulate_daily_backup_for_4_years(time):
|
||||
config = GenConfig(days=4, weeks=4, months=4, years=4,
|
||||
day_of_week='mon', day_of_month=1, day_of_year=1)
|
||||
scheme = GenerationalScheme(time, config, count=16)
|
||||
backups = simulate(time.local(2019, 1, 1),
|
||||
time.local(2022, 12, 31),
|
||||
scheme)
|
||||
assertRemovalOrder(GenerationalScheme(time, config, count=0), backups, [
|
||||
# 4 years
|
||||
time.local(2019, 1, 1),
|
||||
time.local(2020, 1, 1),
|
||||
time.local(2021, 1, 1),
|
||||
time.local(2022, 1, 1),
|
||||
|
||||
# 4 months
|
||||
time.local(2022, 9, 1),
|
||||
time.local(2022, 10, 1),
|
||||
time.local(2022, 11, 1),
|
||||
time.local(2022, 12, 1),
|
||||
|
||||
# 4 weeks
|
||||
time.local(2022, 12, 5),
|
||||
time.local(2022, 12, 12),
|
||||
time.local(2022, 12, 19),
|
||||
time.local(2022, 12, 26),
|
||||
|
||||
# 4 days
|
||||
time.local(2022, 12, 28),
|
||||
time.local(2022, 12, 29),
|
||||
time.local(2022, 12, 30),
|
||||
time.local(2022, 12, 31)
|
||||
])
|
||||
|
||||
|
||||
@pytest.mark.timeout(60)
|
||||
def test_simulate_agressive_daily_backup_for_4_years(time):
|
||||
config = GenConfig(days=4, weeks=4, months=4, years=4,
|
||||
day_of_week='mon', day_of_month=1, day_of_year=1, aggressive=True)
|
||||
scheme = GenerationalScheme(time, config, count=16)
|
||||
backups = simulate(time.local(2019, 1, 1),
|
||||
time.local(2022, 12, 31),
|
||||
scheme)
|
||||
|
||||
assertRemovalOrder(GenerationalScheme(time, config, count=0), backups, [
|
||||
# 4 years
|
||||
time.local(2019, 1, 1),
|
||||
time.local(2020, 1, 1),
|
||||
time.local(2021, 1, 1),
|
||||
time.local(2022, 1, 1),
|
||||
|
||||
# 4 months
|
||||
time.local(2022, 9, 1),
|
||||
time.local(2022, 10, 1),
|
||||
time.local(2022, 11, 1),
|
||||
time.local(2022, 12, 1),
|
||||
|
||||
# 4 weeks
|
||||
time.local(2022, 12, 5),
|
||||
time.local(2022, 12, 12),
|
||||
time.local(2022, 12, 19),
|
||||
time.local(2022, 12, 26),
|
||||
|
||||
# 4 days
|
||||
time.local(2022, 12, 28),
|
||||
time.local(2022, 12, 29),
|
||||
time.local(2022, 12, 30),
|
||||
time.local(2022, 12, 31),
|
||||
])
|
||||
|
||||
|
||||
def test_count_limit(time):
|
||||
config = GenConfig(years=2, day_of_year=1)
|
||||
scheme = GenerationalScheme(time, config, count=1)
|
||||
backups = [
|
||||
makeBackup("test", time.local(1985, 1, 1)),
|
||||
makeBackup("test", time.local(1984, 1, 1))
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(1984, 1, 1)
|
||||
])
|
||||
|
||||
|
||||
def test_aggressive_removal_below_limit(time):
|
||||
config = GenConfig(years=2, day_of_year=1, aggressive=True)
|
||||
scheme = GenerationalScheme(time, config, count=5)
|
||||
backups = [
|
||||
makeBackup("test", time.local(1985, 1, 1)),
|
||||
makeBackup("test", time.local(1985, 1, 2))
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(1985, 1, 2)
|
||||
])
|
||||
|
||||
|
||||
def test_aggressive_removal_at_limit_ok(time):
|
||||
config = GenConfig(years=2, day_of_year=1, aggressive=True)
|
||||
scheme = GenerationalScheme(time, config, count=2)
|
||||
backups = [
|
||||
makeBackup("test", time.local(1985, 1, 1)),
|
||||
makeBackup("test", time.local(1984, 1, 1))
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [])
|
||||
|
||||
|
||||
def test_aggressive_removal_over_limit(time):
|
||||
config = GenConfig(years=2, day_of_year=1, aggressive=True)
|
||||
scheme = GenerationalScheme(time, config, count=2)
|
||||
backups = [
|
||||
makeBackup("test", time.local(1985, 1, 1)),
|
||||
makeBackup("test", time.local(1984, 1, 1)),
|
||||
makeBackup("test", time.local(1983, 1, 1)),
|
||||
makeBackup("test", time.local(1983, 1, 2))
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(1983, 1, 1),
|
||||
time.local(1983, 1, 2)
|
||||
])
|
||||
|
||||
|
||||
def test_removal_order_week(time: Time):
|
||||
config = GenConfig(weeks=1, day_of_week='wed', aggressive=True)
|
||||
scheme = GenerationalScheme(time, config, count=1)
|
||||
backups = [
|
||||
makeBackup("test", time.local(2019, 10, 28)),
|
||||
makeBackup("test", time.local(2019, 10, 29)),
|
||||
makeBackup("test", time.local(2019, 10, 30, 1)),
|
||||
makeBackup("test", time.local(2019, 10, 30, 2)),
|
||||
makeBackup("test", time.local(2019, 10, 31)),
|
||||
makeBackup("test", time.local(2019, 11, 1)),
|
||||
makeBackup("test", time.local(2019, 11, 2)),
|
||||
makeBackup("test", time.local(2019, 11, 3)),
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(2019, 10, 28),
|
||||
time.local(2019, 10, 29),
|
||||
time.local(2019, 10, 30, 1),
|
||||
time.local(2019, 10, 31),
|
||||
time.local(2019, 11, 1),
|
||||
time.local(2019, 11, 2),
|
||||
time.local(2019, 11, 3)
|
||||
])
|
||||
|
||||
|
||||
def test_removal_order_month(time):
|
||||
config = GenConfig(months=1, day_of_month=20, aggressive=True)
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=1)
|
||||
|
||||
backups = [
|
||||
makeBackup("test", time.local(2019, 1, 1)),
|
||||
makeBackup("test", time.local(2019, 1, 2)),
|
||||
makeBackup("test", time.local(2019, 1, 20, 1)),
|
||||
makeBackup("test", time.local(2019, 1, 20, 2)),
|
||||
makeBackup("test", time.local(2019, 1, 21)),
|
||||
makeBackup("test", time.local(2019, 1, 25)),
|
||||
makeBackup("test", time.local(2019, 1, 26)),
|
||||
makeBackup("test", time.local(2019, 1, 27)),
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(2019, 1, 1),
|
||||
time.local(2019, 1, 2),
|
||||
time.local(2019, 1, 20, 1),
|
||||
time.local(2019, 1, 21),
|
||||
time.local(2019, 1, 25),
|
||||
time.local(2019, 1, 26),
|
||||
time.local(2019, 1, 27)
|
||||
])
|
||||
|
||||
|
||||
def test_removal_order_many_months(time):
|
||||
config = GenConfig(months=70, day_of_month=20, aggressive=True)
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=10)
|
||||
|
||||
backups = [
|
||||
makeBackup("test", time.local(2019, 7, 20)), # preferred
|
||||
makeBackup("test", time.local(2018, 7, 18)), # preferred
|
||||
makeBackup("test", time.local(2018, 7, 21)),
|
||||
makeBackup("test", time.local(2017, 1, 19)),
|
||||
makeBackup("test", time.local(2017, 1, 20)), # preferred
|
||||
makeBackup("test", time.local(2017, 1, 31)),
|
||||
makeBackup("test", time.local(2016, 12, 1)), # preferred
|
||||
makeBackup("test", time.local(2014, 1, 31)),
|
||||
makeBackup("test", time.local(2014, 1, 1)), # preferred
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(2014, 1, 31),
|
||||
time.local(2017, 1, 19),
|
||||
time.local(2017, 1, 31),
|
||||
time.local(2018, 7, 21),
|
||||
])
|
||||
|
||||
|
||||
def test_removal_order_years(time):
|
||||
config = GenConfig(years=2, day_of_year=15, aggressive=True)
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=10)
|
||||
|
||||
backups = [
|
||||
makeBackup("test", time.local(2019, 2, 15)),
|
||||
makeBackup("test", time.local(2019, 1, 15)), # keep
|
||||
makeBackup("test", time.local(2018, 1, 14)),
|
||||
makeBackup("test", time.local(2018, 1, 15)), # keep
|
||||
makeBackup("test", time.local(2018, 1, 16)),
|
||||
makeBackup("test", time.local(2017, 1, 15)),
|
||||
]
|
||||
assertRemovalOrder(scheme, backups, [
|
||||
time.local(2017, 1, 15),
|
||||
time.local(2018, 1, 14),
|
||||
time.local(2018, 1, 16),
|
||||
time.local(2019, 2, 15),
|
||||
])
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ignored_generational_labels(time):
|
||||
config = GenConfig(days=2)
|
||||
|
||||
scheme = GenerationalScheme(time, config, count=10)
|
||||
backup1 = makeBackup("test", time.local(2019, 2, 15))
|
||||
backup2 = makeBackup("test", time.local(2019, 2, 14))
|
||||
backup3 = makeBackup("test", time.local(2019, 2, 13), ignore=True)
|
||||
backups = [backup1, backup2, backup3]
|
||||
scheme.handleNaming(backups)
|
||||
assert backup1.getStatusDetail() == ['Day 1 of 2']
|
||||
assert backup2.getStatusDetail() == ['Day 2 of 2']
|
||||
assert backup3.getStatusDetail() is None
|
||||
|
||||
|
||||
def getRemovalOrder(scheme, toCheck):
|
||||
backups = list(toCheck)
|
||||
removed = []
|
||||
while True:
|
||||
oldest = scheme.getOldest(backups)
|
||||
if not oldest:
|
||||
break
|
||||
removed.append(oldest.date())
|
||||
backups.remove(oldest)
|
||||
return removed
|
||||
|
||||
|
||||
def assertRemovalOrder(scheme, toCheck, expected):
|
||||
backups = list(toCheck)
|
||||
removed = []
|
||||
index = 0
|
||||
time = scheme.time
|
||||
while True:
|
||||
reason, oldest = scheme.getOldest(backups)
|
||||
if index >= len(expected):
|
||||
if oldest is not None:
|
||||
fail("at index {0}, expected 'None' but got {1}".format(
|
||||
index, time.toLocal(oldest.date())))
|
||||
break
|
||||
if oldest.date() != expected[index]:
|
||||
fail("at index {0}, expected {1} but got {2}".format(
|
||||
index, time.toLocal(expected[index]), time.toLocal(oldest.date())))
|
||||
removed.append(oldest.date())
|
||||
backups.remove(oldest)
|
||||
index += 1
|
||||
return removed
|
||||
|
||||
|
||||
def makeBackup(slug, date, name=None, ignore=False) -> Backup:
|
||||
if not name:
|
||||
name = slug
|
||||
return DummyBackup(name, date.astimezone(tzutc()), "src", slug, ignore=ignore)
|
||||
|
||||
|
||||
def simulate(start: datetime, end: datetime, scheme: GenerationalScheme, backups=[]):
|
||||
today = start
|
||||
while today <= end:
|
||||
backups.append(makeBackup("test", today))
|
||||
test = scheme.getOldest(backups)
|
||||
if test is None:
|
||||
pass
|
||||
reason, oldest = test
|
||||
while oldest is not None:
|
||||
backups.remove(oldest)
|
||||
test = scheme.getOldest(backups)
|
||||
if test is None:
|
||||
pass
|
||||
reason, oldest = test
|
||||
today = today + timedelta(hours=27)
|
||||
today = scheme.time.local(today.year, today.month, today.day)
|
||||
return backups
|
||||
Reference in New Issue
Block a user