async def test_pending_snapshot_timeout(time: FakeTime, ha: HaSource,
                                        config: Config,
                                        interceptor: RequestInterceptor):
    interceptor.setSleep(URL_MATCH_SNAPSHOT_FULL, sleep=5)
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 1)
    config.override(Setting.FAILED_SNAPSHOT_TIMEOUT_SECONDS, 1)
    config.override(Setting.PENDING_SNAPSHOT_TIMEOUT_SECONDS, 1)

    snapshot_immediate: PendingSnapshot = await ha.create(
        CreateOptions(time.now(), "Test Name"))
    assert isinstance(snapshot_immediate, PendingSnapshot)
    assert snapshot_immediate.name() == "Test Name"
    assert not ha.check()
    assert ha.pending_snapshot is snapshot_immediate

    await asyncio.wait({ha._pending_snapshot_task})
    assert ha.pending_snapshot is snapshot_immediate
    assert ha.check()
    assert not ha.check()

    time.advance(minutes=1)
    assert ha.check()
    assert len(await ha.get()) == 0
    assert not ha.check()
    assert ha.pending_snapshot is None
    assert snapshot_immediate.isStale()
async def test_failed_snapshot_retry(ha: HaSource, time: FakeTime,
                                     config: Config,
                                     supervisor: SimulatedSupervisor,
                                     interceptor: RequestInterceptor):
    # create a blocking snapshot
    interceptor.setError(URL_MATCH_SNAPSHOT_FULL, 524)
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 0)
    await supervisor.toggleBlockSnapshot()
    snapshot_immediate = await ha.create(CreateOptions(time.now(),
                                                       "Some Name"))
    assert isinstance(snapshot_immediate, PendingSnapshot)
    assert snapshot_immediate.name() == "Some Name"
    assert not ha.check()
    assert not snapshot_immediate.isFailed()
    await supervisor.toggleBlockSnapshot()

    # let the snapshot attempt to complete
    await asyncio.wait({ha._pending_snapshot_task})

    # verify it failed with the expected http error
    assert snapshot_immediate.isFailed()
    assert snapshot_immediate._exception.status == 524

    assert ha.check()
    assert not ha.check()
    time.advance(seconds=config.get(Setting.FAILED_SNAPSHOT_TIMEOUT_SECONDS))

    # should trigger a sync after the failed snapshot timeout
    assert ha.check()
    await ha.get()
    assert not ha.check()
async def test_failed_snapshot(time, ha: HaSource,
                               supervisor: SimulatedSupervisor, config: Config,
                               interceptor: RequestInterceptor):
    # create a blocking snapshot
    interceptor.setError(URL_MATCH_SNAPSHOT_FULL, 524)
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 0)
    await supervisor.toggleBlockSnapshot()
    snapshot_immediate = await ha.create(CreateOptions(time.now(),
                                                       "Some Name"))
    assert isinstance(snapshot_immediate, PendingSnapshot)
    assert snapshot_immediate.name() == "Some Name"
    assert not ha.check()
    assert not snapshot_immediate.isFailed()
    await supervisor.toggleBlockSnapshot()

    # let the snapshot attempt to complete
    await asyncio.wait({ha._pending_snapshot_task})

    # verify it failed with the expected http error
    assert snapshot_immediate.isFailed()
    assert snapshot_immediate._exception.status == 524

    snapshots = list((await ha.get()).values())
    assert len(snapshots) == 1
    assert snapshots[0] is snapshot_immediate

    # verify we can create a new snapshot immediately
    interceptor.clear()
    await ha.create(CreateOptions(time.now(), "Some Name"))
    assert len(await ha.get()) == 1
async def test_pending_snapshot_replaces_original(
        time, ha: HaSource, config: Config, supervisor: SimulatedSupervisor):
    # now configure a snapshto to start outside of the addon
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 100)
    await supervisor.toggleBlockSnapshot()
    with pytest.raises(SnapshotInProgress):
        await ha.create(CreateOptions(time.now(), "Ignored"))
    snapshot_immediate = (await ha.get())['pending']
    await supervisor.toggleBlockSnapshot()
    assert isinstance(snapshot_immediate, PendingSnapshot)
    assert snapshot_immediate.name() == "Pending Snapshot"
    assert ha.check()
    assert ha.pending_snapshot is snapshot_immediate
    assert await ha.get() == {snapshot_immediate.slug(): snapshot_immediate}

    # create a new snapshot behind the scenes, the pending snapshot should get replaced with the new one
    slug = (await ha.harequests.createSnapshot({
        'name': "Suddenly Appears",
        "hardlock": True
    }))['slug']
    results = await ha.get()
    assert len(results) == 1
    assert slug in results
    assert results[slug].name() == "Suddenly Appears"
    assert not results[slug].retained()
async def test_failed_backup(time, ha: HaSource,
                             supervisor: SimulatedSupervisor, config: Config,
                             interceptor: RequestInterceptor):
    # create a blocking backup
    interceptor.setError(URL_MATCH_BACKUP_FULL, 524)
    config.override(Setting.NEW_BACKUP_TIMEOUT_SECONDS, 0)
    await supervisor.toggleBlockBackup()
    backup_immediate = await ha.create(CreateOptions(time.now(), "Some Name"))
    assert isinstance(backup_immediate, PendingBackup)
    assert backup_immediate.name() == "Some Name"
    assert not ha.check()
    assert not backup_immediate.isFailed()
    await supervisor.toggleBlockBackup()

    # let the backup attempt to complete
    await asyncio.wait({ha._pending_backup_task})

    # verify it failed with the expected http error
    assert backup_immediate.isFailed()
    assert backup_immediate._exception.status == 524

    backups = list((await ha.get()).values())
    assert len(backups) == 1
    assert backups[0] is backup_immediate

    # verify we can create a new backup immediately
    interceptor.clear()
    await ha.create(CreateOptions(time.now(), "Some Name"))
    assert len(await ha.get()) == 1
async def test_pending_snapshot_timeout_external(
        time, config, ha: HaSource, supervisor: SimulatedSupervisor):
    # now configure a snapshto to start outside of the addon
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 100)
    await supervisor.toggleBlockSnapshot()
    with pytest.raises(SnapshotInProgress):
        await ha.create(CreateOptions(time.now(), "Ignored"))
    snapshot_immediate = (await ha.get())['pending']
    await supervisor.toggleBlockSnapshot()
    assert isinstance(snapshot_immediate, PendingSnapshot)
    assert snapshot_immediate.name() == "Pending Snapshot"
    assert ha.check()
    assert not ha.check()
    assert ha.pending_snapshot is snapshot_immediate

    # should clean up after a day, since we're still waiting on the snapshot thread.
    time.advanceDay()
    assert ha.check()
    assert len(await ha.get()) == 0
예제 #7
0
async def test_CRUD(ha: HaSource, time, interceptor: RequestInterceptor,
                    data_cache: DataCache) -> None:
    snapshot: HASnapshot = await ha.create(
        CreateOptions(time.now(), "Test Name"))

    assert snapshot.name() == "Test Name"
    assert type(snapshot) is HASnapshot
    assert not snapshot.retained()
    assert snapshot.snapshotType() == "full"
    assert not snapshot.protected()
    assert snapshot.name() == "Test Name"
    assert snapshot.source() == SOURCE_HA
    assert not snapshot.ignore()
    assert snapshot.madeByTheAddon()
    assert "pending" not in data_cache.snapshots

    # read the item directly, its metadata should match
    from_ha = await ha.harequests.snapshot(snapshot.slug())
    assert from_ha.size() == snapshot.size()
    assert from_ha.slug() == snapshot.slug()
    assert from_ha.source() == SOURCE_HA

    snapshots = await ha.get()
    assert len(snapshots) == 1
    assert snapshot.slug() in snapshots

    full = DummySnapshot(from_ha.name(), from_ha.date(), from_ha.size(),
                         from_ha.slug(), "dummy")
    full.addSource(snapshot)

    # download the item, its bytes should match up
    download = await ha.read(full)
    await download.setup()
    direct_download = await ha.harequests.download(snapshot.slug())
    await direct_download.setup()
    while True:
        from_file = await direct_download.read(1024 * 1024)
        from_download = await download.read(1024 * 1024)
        if len(from_file.getbuffer()) == 0:
            assert len(from_download.getbuffer()) == 0
            break
        assert from_file.getbuffer() == from_download.getbuffer()

    # update retention
    assert not snapshot.retained()
    await ha.retain(full, True)
    assert (await ha.get())[full.slug()].retained()
    await ha.retain(full, False)
    assert not (await ha.get())[full.slug()].retained()

    # Delete the item, make sure its gone
    await ha.delete(full)
    assert full.getSource(ha.name()) is None
    snapshots = await ha.get()
    assert len(snapshots) == 0
async def test_immediate_backup_failure(time: FakeTime, ha: HaSource,
                                        config: Config,
                                        interceptor: RequestInterceptor):
    interceptor.setError(URL_MATCH_BACKUP_FULL, 524)
    with pytest.raises(ClientResponseError) as thrown:
        await ha.create(CreateOptions(time.now(), "Some Name"))
    assert thrown.value.status == 524

    assert ha.pending_backup is not None
    backups = list((await ha.get()).values())
    assert len(backups) == 1
    assert backups[0].isFailed()

    # Failed backup should go away after it times out
    assert ha.check()
    assert not ha.check()
    time.advance(seconds=config.get(Setting.FAILED_BACKUP_TIMEOUT_SECONDS) + 1)
    assert ha.check()

    assert len(await ha.get()) == 0
    assert not ha.check()
async def test_retained_on_finish(ha: HaSource, server, time, config: Config,
                                  supervisor: SimulatedSupervisor):
    async with supervisor._snapshot_inner_lock:
        retention = {ha.name(): True}
        config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 0.0001)
        pending = await ha.create(
            CreateOptions(time.now(), "Test Name", retention))
        results = await ha.get()
        assert pending.name() == "Test Name"
        assert results == {pending.slug(): pending}
        assert type(pending) == PendingSnapshot
        assert not ha._pending_snapshot_task.done()

    await asyncio.wait({ha._pending_snapshot_task})
    results = list((await ha.get()).values())
    assert len(results) == 1
    assert results[0].name() == "Test Name"
    assert type(results[0]) == HASnapshot
    assert results[0].retained()
    assert config.isRetained(results[0].slug())