Exemplo n.º 1
0
async def test_upload_session_expired(drive, time, snapshot_helper,
                                      interceptor: RequestInterceptor):
    from_snapshot, data = await snapshot_helper.createFile()
    interceptor.setError(URL_MATCH_UPLOAD_PROGRESS, status=404)
    with pytest.raises(GoogleSessionError):
        await drive.save(from_snapshot, data)
    assert time.sleeps == []
Exemplo n.º 2
0
async def test_resume_session_abandoned_on_http4XX(
        time, drive: DriveSource, config: Config, server, snapshot_helper,
        interceptor: RequestInterceptor):
    from_snapshot, data = await snapshot_helper.createFile()

    # Configure the upload to fail after the first upload chunk
    interceptor.setError(URL_MATCH_UPLOAD_PROGRESS, 402, 1)
    with pytest.raises(ClientResponseError):
        await drive.save(from_snapshot, data)

    # Verify a requst was made to start the upload but not cached
    assert server.wasUrlRequested(
        "/upload/drive/v3/files/?uploadType=resumable&supportsAllDrives=true")
    assert drive.drivebackend.last_attempt_count == 1
    assert drive.drivebackend.last_attempt_location is None
    assert drive.drivebackend.last_attempt_metadata is None

    # upload again, which should retry
    server.urls.clear()
    interceptor.clear()
    data.position(0)
    snapshot = await drive.save(from_snapshot, data)
    assert server.wasUrlRequested(URL_START_UPLOAD)

    # Verify the uploaded bytes are identical
    from_snapshot.addSource(snapshot)
    download = await drive.read(from_snapshot)
    data.position(0)
    await compareStreams(data, download)
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(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()
Exemplo n.º 5
0
async def test_start_on_boot(ha: HaSource, time,
                             interceptor: RequestInterceptor, config: Config,
                             supervisor: SimulatedSupervisor) -> None:
    boot_slug = "boot_slug"
    supervisor.installAddon(boot_slug,
                            "Start on boot",
                            boot=True,
                            started=False)

    no_boot_slug = "no_boot_slug"
    supervisor.installAddon(no_boot_slug,
                            "Don't start on boot",
                            boot=False,
                            started=False)
    config.override(Setting.STOP_ADDONS, ",".join([boot_slug, no_boot_slug]))
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 0.001)

    assert supervisor.addon(boot_slug)["state"] == "stopped"
    assert supervisor.addon(no_boot_slug)["state"] == "stopped"
    async with supervisor._snapshot_inner_lock:
        await ha.create(CreateOptions(time.now(), "Test Name"))
        assert supervisor.addon(boot_slug)["state"] == "stopped"
    assert supervisor.addon(no_boot_slug)["state"] == "stopped"
    await ha._pending_snapshot_task
    assert supervisor.addon(boot_slug)["state"] == "started"
    assert supervisor.addon(no_boot_slug)["state"] == "stopped"
    assert len(await ha.get()) == 1
    assert not interceptor.urlWasCalled(URL_MATCH_START_ADDON)
    assert not interceptor.urlWasCalled(URL_MATCH_STOP_ADDON)
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_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()
Exemplo n.º 8
0
async def test_upload_resume(drive: DriveSource, time,
                             snapshot_helper: SnapshotHelper,
                             google: SimulatedGoogle,
                             interceptor: RequestInterceptor):
    from_snapshot, data = await snapshot_helper.createFile()
    interceptor.setError(URL_MATCH_UPLOAD_PROGRESS, attempts=1, status=500)

    # Upload, which will fail
    with pytest.raises(GoogleInternalError):
        await drive.save(from_snapshot, data)

    # Verify we uploaded one chunk
    assert google.chunks == [BASE_CHUNK_SIZE]

    # Retry the upload, which shoudl now pass
    interceptor.clear()
    data.position(0)
    drive_snapshot = await drive.save(from_snapshot, data)
    from_snapshot.addSource(drive_snapshot)
    assert google.chunks == [
        BASE_CHUNK_SIZE, BASE_CHUNK_SIZE, (data.size()) - BASE_CHUNK_SIZE * 2
    ]

    # Verify the data is correct
    data.position(0)
    await compareStreams(data, await drive.read(from_snapshot))
async def test_failure_logging(updater: HaUpdater, server, time: FakeTime,
                               interceptor: RequestInterceptor):
    interceptor.setError(URL_MATCH_CORE_API, 501)
    assert getLast() is None
    await updater.update()
    assert getLast() is None

    time.advance(minutes=1)
    await updater.update()
    assert getLast() is None

    time.advance(minutes=5)
    await updater.update()
    assert getLast().msg == REASSURING_MESSAGE.format(501)

    last_log = getLast()
    time.advance(minutes=5)
    await updater.update()
    assert getLast() is not last_log
    assert getLast().msg == REASSURING_MESSAGE.format(501)

    last_log = getLast()
    interceptor.clear()
    await updater.update()
    assert getLast() is last_log
async def test_backup_supervisor_path(ha: HaSource,
                                      supervisor: SimulatedSupervisor,
                                      interceptor: RequestInterceptor):
    supervisor._super_version = Version(2021, 7)
    await ha.get()
    assert not interceptor.urlWasCalled(URL_MATCH_BACKUPS)
    assert interceptor.urlWasCalled(URL_MATCH_SNAPSHOT)
Exemplo n.º 11
0
async def test_refresh_problem_with_google(drive: DriveSource, interceptor: RequestInterceptor, config: Config, time):
    time.advanceDay()
    interceptor.setError(".*/oauth2/v4/token.*", status=510)
    drive.drivebackend.creds._secret = None
    with pytest.raises(CredRefreshGoogleError) as error:
        await drive.get()
    assert error.value.data() == {"from_google": "Google returned HTTP 510"}
Exemplo n.º 12
0
async def test_failure_backoff_other(updater: HaUpdater, server, time: FakeTime, interceptor: RequestInterceptor):
    interceptor.setError(URL_MATCH_CORE_API, 400)
    for x in range(9):
        await updater.update()
    assert time.sleeps == [60, 120, 240, 300, 300, 300, 300, 300, 300]
    interceptor.clear()
    await updater.update()
    assert time.sleeps == [60, 120, 240, 300, 300, 300, 300, 300, 300]
async def test_delete_error(time, ha: HaSource,
                            interceptor: RequestInterceptor):
    snapshot = await ha.create(CreateOptions(time.now(), "Some Name"))
    full = DummySnapshot(snapshot.name(), snapshot.date(), snapshot.size(),
                         snapshot.slug(), "dummy")
    full.addSource(snapshot)
    interceptor.setError(URL_MATCH_SNAPSHOT_DELETE, 400)
    with pytest.raises(HomeAssistantDeleteError):
        await ha.delete(full)

    interceptor.clear()
    await ha.delete(full)
async def test_delete_error(time, ha: HaSource,
                            interceptor: RequestInterceptor):
    backup = await ha.create(CreateOptions(time.now(), "Some Name"))
    full = DummyBackup(backup.name(), backup.date(), backup.size(),
                       backup.slug(), "dummy")
    full.addSource(backup)
    interceptor.setError(URL_MATCH_BACKUP_DELETE, 400)
    with pytest.raises(HomeAssistantDeleteError):
        await ha.delete(full)

    interceptor.clear()
    await ha.delete(full)
async def test_pending_snapshot_nowait(ha: HaSource, time,
                                       supervisor: SimulatedSupervisor,
                                       interceptor: RequestInterceptor,
                                       config: Config):
    interceptor.setSleep(URL_MATCH_SNAPSHOT_FULL, sleep=5)
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 0.1)
    snapshot_immediate: PendingSnapshot = await ha.create(
        CreateOptions(time.now(), "Test Name"))
    assert isinstance(snapshot_immediate, PendingSnapshot)
    snapshot_pending: HASnapshot = (await ha.get())['pending']

    assert isinstance(snapshot_immediate, PendingSnapshot)
    assert isinstance(snapshot_pending, PendingSnapshot)
    assert snapshot_immediate is snapshot_pending
    assert snapshot_immediate.name() == "Test Name"
    assert snapshot_immediate.slug() == "pending"
    assert not snapshot_immediate.uploadable()
    assert snapshot_immediate.snapshotType() == "Full"
    assert snapshot_immediate.source() == SOURCE_HA
    assert snapshot_immediate.date() == time.now()
    assert not snapshot_immediate.protected()

    # Might be a little flaky but...whatever
    await asyncio.wait({ha._pending_snapshot_task})

    snapshots = await ha.get()
    assert 'pending' not in snapshots
    assert isinstance(next(iter(snapshots.values())), HASnapshot)

    return
    # ignroe events for now
    assert supervisor.getEvents() == [(EVENT_SNAPSHOT_START, {
        'snapshot_name':
        snapshot_immediate.name(),
        'snapshot_time':
        str(snapshot_immediate.date())
    })]
    ha.snapshot_thread.join()
    assert supervisor.getEvents() == [(EVENT_SNAPSHOT_START, {
        'snapshot_name':
        snapshot_immediate.name(),
        'snapshot_time':
        str(snapshot_immediate.date())
    }),
                                      (EVENT_SNAPSHOT_END, {
                                          'completed':
                                          True,
                                          'snapshot_name':
                                          snapshot_immediate.name(),
                                          'snapshot_time':
                                          str(snapshot_immediate.date())
                                      })]
Exemplo n.º 16
0
async def test_download_timeout(time, drive: DriveSource, config: Config, interceptor: RequestInterceptor, backup_helper):
    config.override(Setting.DOWNLOAD_TIMEOUT_SECONDS, 0.1)
    from_backup, data = await backup_helper.createFile()
    backup = await drive.save(from_backup, data)

    # Verify the uploaded bytes are identical
    from_backup.addSource(backup)
    interceptor.setSleep(URL_MATCH_FILE, sleep=100)
    download = await drive.read(from_backup)
    data.position(0)

    with pytest.raises(GoogleTimeoutError):
        await compareStreams(data, download)
async def test_upgrade_all_config(ha: HaSource,
                                  supervisor: SimulatedSupervisor,
                                  interceptor: RequestInterceptor,
                                  config: Config, server_url):
    """Verify that converting all upgradeable config optiosn works as expected"""

    # overwrite the addon options with old values
    supervisor._options = {
        Setting.DEPRECTAED_MAX_BACKUPS_IN_HA.value: 1,
        Setting.DEPRECTAED_MAX_BACKUPS_IN_GOOGLE_DRIVE.value: 2,
        Setting.DEPRECATED_DAYS_BETWEEN_BACKUPS.value: 5,
        Setting.DEPRECTAED_IGNORE_OTHER_BACKUPS.value: True,
        Setting.DEPRECTAED_IGNORE_UPGRADE_BACKUPS.value: True,
        Setting.DEPRECTAED_BACKUP_TIME_OF_DAY.value: "01:11",
        Setting.DEPRECTAED_DELETE_BEFORE_NEW_BACKUP.value: True,
        Setting.DEPRECTAED_BACKUP_NAME.value: "test",
        Setting.DEPRECTAED_SPECIFY_BACKUP_FOLDER.value: True,
        Setting.DEPRECTAED_NOTIFY_FOR_STALE_BACKUPS.value: False,
        Setting.DEPRECTAED_ENABLE_BACKUP_STALE_SENSOR.value: False,
        Setting.DEPRECTAED_ENABLE_BACKUP_STATE_SENSOR.value: False,
        Setting.DEPRECATED_BACKUP_PASSWORD.value: "test password",
    }

    await ha.init()
    assert not config.mustSaveUpgradeChanges()
    assert interceptor.urlWasCalled(URL_MATCH_SELF_OPTIONS)

    # Verify the config was upgraded
    assert supervisor._options == {
        Setting.MAX_BACKUPS_IN_HA.value: 1,
        Setting.MAX_BACKUPS_IN_GOOGLE_DRIVE.value: 2,
        Setting.DAYS_BETWEEN_BACKUPS.value: 5,
        Setting.IGNORE_OTHER_BACKUPS.value: True,
        Setting.IGNORE_UPGRADE_BACKUPS.value: True,
        Setting.BACKUP_TIME_OF_DAY.value: "01:11",
        Setting.DELETE_BEFORE_NEW_BACKUP.value: True,
        Setting.BACKUP_NAME.value: "test",
        Setting.SPECIFY_BACKUP_FOLDER.value: True,
        Setting.NOTIFY_FOR_STALE_BACKUPS.value: False,
        Setting.ENABLE_BACKUP_STALE_SENSOR.value: False,
        Setting.ENABLE_BACKUP_STATE_SENSOR.value: False,
        Setting.BACKUP_PASSWORD.value: "test password",
        Setting.CALL_BACKUP_SNAPSHOT.value: True,
    }

    interceptor.clear()

    await ha.init()
    assert not interceptor.urlWasCalled(URL_MATCH_SELF_OPTIONS)
async def test_upgrade_some_config(ha: HaSource,
                                   supervisor: SimulatedSupervisor,
                                   interceptor: RequestInterceptor,
                                   config: Config, server_url):
    """Verify that converting a mix of upgradeable and not upgradeable config works"""

    # overwrite the addon options with old values
    supervisor._options = {
        Setting.DEPRECTAED_MAX_BACKUPS_IN_HA.value: 4,
        Setting.DEPRECTAED_MAX_BACKUPS_IN_GOOGLE_DRIVE.value: 4,
        Setting.DEPRECATED_DAYS_BETWEEN_BACKUPS.value: 3,
        Setting.DEPRECTAED_BACKUP_TIME_OF_DAY.value: "01:11",
        Setting.EXCLUDE_ADDONS.value: "test",
        Setting.USE_SSL.value: False,
    }

    await ha.init()

    assert not config.mustSaveUpgradeChanges()
    assert interceptor.urlWasCalled(URL_MATCH_SELF_OPTIONS)

    # Verify the config was upgraded
    assert supervisor._options == {
        Setting.MAX_BACKUPS_IN_HA.value: 4,
        Setting.MAX_BACKUPS_IN_GOOGLE_DRIVE.value: 4,
        Setting.DAYS_BETWEEN_BACKUPS.value: 3,
        Setting.EXCLUDE_ADDONS.value: "test",
        Setting.BACKUP_TIME_OF_DAY.value: "01:11",
        Setting.CALL_BACKUP_SNAPSHOT.value: True,
    }
async def test_upgrade_default_config(ha: HaSource,
                                      supervisor: SimulatedSupervisor,
                                      interceptor: RequestInterceptor,
                                      config: Config, server_url):
    """Verify that converting the original default config optiosn works as expected"""

    # overwrite the addon options with old values
    supervisor._options = {
        Setting.DEPRECTAED_MAX_BACKUPS_IN_HA.value: 4,
        Setting.DEPRECTAED_MAX_BACKUPS_IN_GOOGLE_DRIVE.value: 4,
        Setting.DEPRECATED_DAYS_BETWEEN_BACKUPS.value: 3,
        Setting.USE_SSL.value: False,
    }

    await ha.init()

    assert not config.mustSaveUpgradeChanges()
    assert interceptor.urlWasCalled(URL_MATCH_SELF_OPTIONS)

    # Verify the config was upgraded
    assert supervisor._options == {
        Setting.MAX_BACKUPS_IN_HA.value: 4,
        Setting.MAX_BACKUPS_IN_GOOGLE_DRIVE.value: 4,
        Setting.DAYS_BETWEEN_BACKUPS.value: 3,
        Setting.CALL_BACKUP_SNAPSHOT.value: True,
    }
async def test_upgrade_no_config(ha: HaSource, supervisor: SimulatedSupervisor,
                                 interceptor: RequestInterceptor,
                                 config: Config, server_url):
    """Verifies that config not in need of an upgrade doesn't get upgraded"""

    # overwrite the addon options with old values
    supervisor._options = {
        Setting.MAX_BACKUPS_IN_HA.value: 4,
        Setting.MAX_BACKUPS_IN_GOOGLE_DRIVE.value: 4,
        Setting.DAYS_BETWEEN_BACKUPS.value: 3,
        Setting.BACKUP_TIME_OF_DAY.value: "01:11",
        Setting.EXCLUDE_ADDONS.value: "test"
    }

    await ha.init()

    assert not config.mustSaveUpgradeChanges()
    assert not interceptor.urlWasCalled(URL_MATCH_SELF_OPTIONS)

    # Verify the config was upgraded
    assert supervisor._options == {
        Setting.MAX_BACKUPS_IN_HA.value: 4,
        Setting.MAX_BACKUPS_IN_GOOGLE_DRIVE.value: 4,
        Setting.DAYS_BETWEEN_BACKUPS.value: 3,
        Setting.BACKUP_TIME_OF_DAY.value: "01:11",
        Setting.EXCLUDE_ADDONS.value: "test",
    }
Exemplo n.º 21
0
async def test_ingore_self_when_stopping(
        ha: HaSource, time, interceptor: RequestInterceptor, config: Config,
        supervisor: SimulatedSupervisor) -> None:
    slug = supervisor._addon_slug
    config.override(Setting.STOP_ADDONS, slug)
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 0.001)
    interceptor.setError(URL_MATCH_START_ADDON, 400)

    assert supervisor.addon(slug)["state"] == "started"
    async with supervisor._snapshot_inner_lock:
        await ha.create(CreateOptions(time.now(), "Test Name"))
        assert supervisor.addon(slug)["state"] == "started"
    await ha._pending_snapshot_task
    assert supervisor.addon(slug)["state"] == "started"
    assert not interceptor.urlWasCalled(URL_MATCH_START_ADDON)
    assert not interceptor.urlWasCalled(URL_MATCH_STOP_ADDON)
    assert len(await ha.get()) == 1
Exemplo n.º 22
0
async def test_stop_addon_failure(ha: HaSource, time,
                                  interceptor: RequestInterceptor,
                                  config: Config,
                                  supervisor: SimulatedSupervisor) -> None:
    slug = "test_slug"
    supervisor.installAddon(slug, "Test decription")
    config.override(Setting.STOP_ADDONS, slug)
    config.override(Setting.NEW_SNAPSHOT_TIMEOUT_SECONDS, 0.001)
    interceptor.setError(URL_MATCH_STOP_ADDON, 400)

    assert supervisor.addon(slug)["state"] == "started"
    async with supervisor._snapshot_inner_lock:
        await ha.create(CreateOptions(time.now(), "Test Name"))
        assert supervisor.addon(slug)["state"] == "started"
    await ha._pending_snapshot_task
    assert supervisor.addon(slug)["state"] == "started"
    assert len(await ha.get()) == 1
async def test_download_timeout(ha: HaSource, time,
                                interceptor: RequestInterceptor,
                                config: Config) -> None:
    config.override(Setting.NEW_BACKUP_TIMEOUT_SECONDS, 100)
    backup: HABackup = await ha.create(CreateOptions(time.now(), "Test Name"))
    from_ha = await ha.harequests.backup(backup.slug())
    full = DummyBackup(from_ha.name(), from_ha.date(), from_ha.size(),
                       from_ha.slug(), "dummy")
    full.addSource(backup)

    interceptor.setSleep(URL_MATCH_BACKUP_DOWNLOAD, sleep=100)
    config.override(Setting.DOWNLOAD_TIMEOUT_SECONDS, 1)
    direct_download = await ha.harequests.download(backup.slug())

    with pytest.raises(SupervisorTimeoutError):
        await direct_download.setup()
        await direct_download.read(1)
async def verify_upload_resumed(time,
                                drive: DriveSource,
                                config: Config,
                                server: SimulationServer,
                                interceptor: RequestInterceptor,
                                status,
                                snapshot_helper,
                                expected=ClientResponseError):
    from_snapshot, data = await snapshot_helper.createFile()

    # Configure the upload to fail after the first upload chunk
    interceptor.setError(URL_MATCH_UPLOAD_PROGRESS, status, 1)
    with pytest.raises(expected):
        await drive.save(from_snapshot, data)

    # Verify a requst was made to start the upload
    assert server.wasUrlRequested(
        "/upload/drive/v3/files/?uploadType=resumable&supportsAllDrives=true")
    assert drive.drivebackend.last_attempt_location is not None
    assert drive.drivebackend.last_attempt_metadata is not None
    last_location = drive.drivebackend.last_attempt_location

    # Retry the upload and let is succeed
    server.urls.clear()
    interceptor.clear()
    data.position(0)
    snapshot = await drive.save(from_snapshot, data)

    # We shoudl nto see the upload "initialize" url
    assert not server.wasUrlRequested(
        "/upload/drive/v3/files/?uploadType=resumable&supportsAllDrives=true")

    # We should see the last location url (which has a unique token) reused to resume the upload
    assert server.wasUrlRequested(last_location)

    # The saved metadata should be cleared out.
    assert drive.drivebackend.last_attempt_count == 1
    assert drive.drivebackend.last_attempt_location is None
    assert drive.drivebackend.last_attempt_metadata is None

    # Verify the uploaded bytes are identical
    from_snapshot.addSource(snapshot)
    download = await drive.read(from_snapshot)
    data.position(0)
    await compareStreams(data, download)
async def test_do_nothing_while_snapshotting(
        supervisor: SimulatedSupervisor, addon_stopper: AddonStopper,
        config: Config, interceptor: RequestInterceptor) -> None:
    slug1 = "test_slug_1"
    supervisor.installAddon(slug1, "Test decription")
    slug2 = "test_slug_2"
    supervisor.installAddon(slug2, "Test decription")
    config.override(Setting.STOP_ADDONS, ",".join([slug1, slug2]))

    await addon_stopper.start(False)
    addon_stopper.allowRun()
    addon_stopper.isSnapshotting(True)
    assert addon_stopper.must_start == {slug1, slug2}

    await addon_stopper.check()

    assert not interceptor.urlWasCalled(URL_MATCH_START_ADDON)
    assert not interceptor.urlWasCalled(URL_MATCH_STOP_ADDON)
async def test_get_info_failure_on_stop(
        supervisor: SimulatedSupervisor, addon_stopper: AddonStopper,
        config: Config, interceptor: RequestInterceptor) -> None:
    slug1 = "test_slug_1"
    supervisor.installAddon(slug1, "Test decription")
    config.override(Setting.STOP_ADDONS, slug1)
    addon_stopper.allowRun()
    addon_stopper.must_start = set()
    assert supervisor.addon(slug1)["state"] == "started"
    interceptor.setError(URL_MATCH_ADDON_INFO, 400)

    await addon_stopper.stopAddons("ignore")
    assert interceptor.urlWasCalled(URL_MATCH_ADDON_INFO)
    assert getSaved(config) == (set(), set())
    assert supervisor.addon(slug1)["state"] == "started"
    await addon_stopper.check()
    await addon_stopper.startAddons()
    assert supervisor.addon(slug1)["state"] == "started"
    assert getSaved(config) == (set(), set())
Exemplo n.º 27
0
async def test_resume_session_reused_on_http408(time, drive: DriveSource, config: Config, server: SimulationServer, backup_helper: BackupHelper, interceptor: RequestInterceptor):
    from_backup, data = await backup_helper.createFile()

    # Configure the upload to fail
    interceptor.setError(URL_MATCH_UPLOAD_PROGRESS, 408)
    with pytest.raises(GoogleTimeoutError):
        await drive.save(from_backup, data)

    # Verify a requst was made to start the upload
    assert server.wasUrlRequested(URL_START_UPLOAD)
    location = drive.drivebackend.last_attempt_location
    assert location is not None

    server.urls.clear()
    interceptor.clear()
    data.position(0)

    await drive.save(from_backup, data)
    assert interceptor.urlWasCalled(URL(location).path)
Exemplo n.º 28
0
async def test_resume_upload_attempts_exhausted(
        drive: DriveSource, time, snapshot_helper,
        interceptor: RequestInterceptor, google: SimulatedGoogle):
    # Allow an upload to update one chunk and then fail.
    from_snapshot, data = await snapshot_helper.createFile()
    interceptor.setError(URL_MATCH_UPLOAD_PROGRESS, attempts=1, status=500)
    with pytest.raises(GoogleInternalError):
        await drive.save(from_snapshot, data)
    assert google.chunks == [BASE_CHUNK_SIZE]

    # Verify we have a cached location
    assert drive.drivebackend.last_attempt_location is not None
    assert drive.drivebackend.last_attempt_count == 1
    last_location = drive.drivebackend.last_attempt_location

    for x in range(1, RETRY_SESSION_ATTEMPTS):
        data.position(0)
        with pytest.raises(GoogleInternalError):
            await drive.save(from_snapshot, data)
        assert drive.drivebackend.last_attempt_count == x + 1

    # We should still be using the same location url
    assert drive.drivebackend.last_attempt_location == last_location

    # Another attempt should use another location url
    with pytest.raises(GoogleInternalError):
        data.position(0)
        await drive.save(from_snapshot, data)
    assert drive.drivebackend.last_attempt_count == 0
    assert drive.drivebackend.last_attempt_location is not None
    assert drive.drivebackend.last_attempt_location != last_location

    # Now let it succeed
    interceptor.clear()
    data.position(0)
    drive_snapshot = await drive.save(from_snapshot, data)
    from_snapshot.addSource(drive_snapshot)

    # And verify the bytes are correct
    data.position(0)
    await compareStreams(data, await drive.read(from_snapshot))
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_old_delete_path(ha: HaSource, supervisor: SimulatedSupervisor,
                               interceptor: RequestInterceptor,
                               time: FakeTime):
    supervisor._super_version = Version(2020, 8)
    await ha.get()
    backup: HABackup = await ha.create(CreateOptions(time.now(), "Test Name"))
    full = DummyBackup(backup.name(), backup.date(), backup.size(),
                       backup.slug(), "dummy")
    full.addSource(backup)
    await ha.delete(full)
    assert interceptor.urlWasCalled("/snapshots/{0}/remove".format(
        backup.slug()))