async def test_freshness(coord: Coordinator, source: HelperTestSource, dest: HelperTestSource, snapshot: Snapshot, time: FakeTime): source.setMax(2) dest.setMax(2) await coord.sync() assert snapshot.getPurges() == {source.name(): False, dest.name(): False} source.setMax(1) dest.setMax(1) await coord.sync() assert snapshot.getPurges() == {source.name(): True, dest.name(): True} dest.setMax(0) await coord.sync() assert snapshot.getPurges() == {source.name(): True, dest.name(): False} source.setMax(0) await coord.sync() assert snapshot.getPurges() == {source.name(): False, dest.name(): False} source.setMax(2) dest.setMax(2) time.advance(days=7) await coord.sync() assert len(coord.snapshots()) == 2 assert snapshot.getPurges() == {source.name(): True, dest.name(): True} assert coord.snapshots()[1].getPurges() == { source.name(): False, dest.name(): False } # should refresh on delete source.setMax(1) dest.setMax(1) await coord.delete([source.name()], snapshot.slug()) assert coord.snapshots()[0].getPurges() == {dest.name(): True} assert coord.snapshots()[1].getPurges() == { source.name(): True, dest.name(): False } # should update on retain await coord.retain({dest.name(): True}, snapshot.slug()) assert coord.snapshots()[0].getPurges() == {dest.name(): False} assert coord.snapshots()[1].getPurges() == { source.name(): True, dest.name(): True } # should update on upload await coord.uploadSnapshot(coord.snapshots()[0].slug()) assert coord.snapshots()[0].getPurges() == { dest.name(): False, source.name(): True } assert coord.snapshots()[1].getPurges() == { source.name(): False, dest.name(): True }
async def test_retain(reader: ReaderHelper, config: Config, snapshot: Snapshot, coord: Coordinator, time: FakeTime): slug = snapshot.slug() assert await reader.getjson("retain", json={'slug': slug, 'sources': ["GoogleDrive", "HomeAssistant"]}) == { 'message': "Updated the snapshot's settings" } status = await reader.getjson("getstatus") assert status['sources'][SOURCE_GOOGLE_DRIVE] == { 'deletable': 0, 'name': SOURCE_GOOGLE_DRIVE, 'retained': 1, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_GOOGLE_DRIVE]['size'], 'enabled': True, 'max': config.get(Setting.MAX_SNAPSHOTS_IN_GOOGLE_DRIVE), 'title': "Google Drive" } assert status['sources'][SOURCE_HA] == { 'deletable': 0, 'name': SOURCE_HA, 'retained': 1, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_HA]['size'], 'enabled': True, 'max': config.get(Setting.MAX_SNAPSHOTS_IN_HASSIO), 'title': "Home Assistant", 'free_space': "0.0 B" } await reader.getjson("retain", json={'slug': slug, 'sources': []}) status = await reader.getjson("getstatus") assert status['sources'][SOURCE_GOOGLE_DRIVE] == { 'deletable': 1, 'name': SOURCE_GOOGLE_DRIVE, 'retained': 0, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_GOOGLE_DRIVE]['size'], 'enabled': True, 'max': config.get(Setting.MAX_SNAPSHOTS_IN_GOOGLE_DRIVE), 'title': "Google Drive" } assert status['sources'][SOURCE_HA] == { 'deletable': 1, 'name': SOURCE_HA, 'retained': 0, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_HA]['size'], 'enabled': True, 'max': config.get(Setting.MAX_SNAPSHOTS_IN_HASSIO), 'title': "Home Assistant", 'free_space': "0.0 B" } delete_req = { "slug": slug, "sources": ["GoogleDrive"] } await reader.getjson("deleteSnapshot", json=delete_req) await reader.getjson("retain", json={'slug': slug, 'sources': ["HomeAssistant"]}) status = await reader.getjson("getstatus") assert status['sources'][SOURCE_GOOGLE_DRIVE] == { 'deletable': 0, 'name': SOURCE_GOOGLE_DRIVE, 'retained': 0, 'snapshots': 0, 'latest': None, 'size': status['sources'][SOURCE_GOOGLE_DRIVE]['size'], 'enabled': True, 'max': config.get(Setting.MAX_SNAPSHOTS_IN_GOOGLE_DRIVE), 'title': "Google Drive" } assert status['sources'][SOURCE_HA] == { 'deletable': 0, 'name': SOURCE_HA, 'retained': 1, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_HA]['size'], 'enabled': True, 'max': config.get(Setting.MAX_SNAPSHOTS_IN_HASSIO), 'title': "Home Assistant", 'free_space': "0.0 B" } # sync again, which should upoload the snapshot to Drive await coord.sync() status = await reader.getjson("getstatus") assert status['sources'][SOURCE_GOOGLE_DRIVE]['snapshots'] == 1 assert status['sources'][SOURCE_GOOGLE_DRIVE]['retained'] == 0 assert status['sources'][SOURCE_GOOGLE_DRIVE]['snapshots'] == 1
async def test_retain(reader, config: Config, snapshot: Snapshot, coord: Coordinator, time: FakeTime): slug = snapshot.slug() assert await reader.getjson("retain?slug={0}&drive=true&ha=true".format(slug)) == { 'message': "Updated the snapshot's settings" } status = await reader.getjson("getstatus") assert status['sources'][SOURCE_GOOGLE_DRIVE] == { 'deletable': 0, 'name': SOURCE_GOOGLE_DRIVE, 'retained': 1, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_GOOGLE_DRIVE]['size'] } assert status['sources'][SOURCE_HA] == { 'deletable': 0, 'name': SOURCE_HA, 'retained': 1, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_HA]['size'] } await reader.getjson("retain?slug={0}&drive=false&ha=false".format(slug)) status = await reader.getjson("getstatus") assert status['sources'][SOURCE_GOOGLE_DRIVE] == { 'deletable': 1, 'name': SOURCE_GOOGLE_DRIVE, 'retained': 0, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_GOOGLE_DRIVE]['size'] } assert status['sources'][SOURCE_HA] == { 'deletable': 1, 'name': SOURCE_HA, 'retained': 0, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_HA]['size'] } await reader.getjson("deleteSnapshot?slug={0}&drive=true&ha=false".format(slug)) await reader.getjson("retain?slug={0}&drive=true&ha=true".format(slug)) status = await reader.getjson("getstatus") assert status['sources'][SOURCE_GOOGLE_DRIVE] == { 'deletable': 0, 'name': SOURCE_GOOGLE_DRIVE, 'retained': 0, 'snapshots': 0, 'latest': None, 'size': status['sources'][SOURCE_GOOGLE_DRIVE]['size'] } assert status['sources'][SOURCE_HA] == { 'deletable': 0, 'name': SOURCE_HA, 'retained': 1, 'snapshots': 1, 'latest': time.asRfc3339String(snapshot.date()), 'size': status['sources'][SOURCE_HA]['size'] } # sync again, which should upoload the snapshot to Drive await coord.sync() status = await reader.getjson("getstatus") assert status['sources'][SOURCE_GOOGLE_DRIVE]['snapshots'] == 1 assert status['sources'][SOURCE_GOOGLE_DRIVE]['retained'] == 1 # it shoudl be retained, since we indicated it should be retained in the last call with drive=true assert status['snapshots'][0]['driveRetain']
def getSnapshotDetails(self, snapshot: Snapshot): drive = snapshot.getSource(SOURCE_GOOGLE_DRIVE) ha = snapshot.getSource(SOURCE_HA) return { 'name': snapshot.name(), 'slug': snapshot.slug(), 'size': snapshot.sizeString(), 'status': snapshot.status(), 'date': self._time.toLocal(snapshot.date()).strftime("%c"), 'inDrive': drive is not None, 'inHA': ha is not None, 'isPending': ha is not None and type(ha) is PendingSnapshot, 'protected': snapshot.protected(), 'type': snapshot.snapshotType(), 'details': snapshot.details(), 'deleteNextDrive': snapshot.getPurges().get(SOURCE_GOOGLE_DRIVE) or False, 'deleteNextHa': snapshot.getPurges().get(SOURCE_HA) or False, 'driveRetain': drive.retained() if drive else False, 'haRetain': ha.retained() if ha else False }
def getSnapshotDetails(self, snapshot: Snapshot): ha = snapshot.getSource(SOURCE_HA) sources = [] for source_key in snapshot.sources: source: AbstractSnapshot = snapshot.sources[source_key] sources.append({ 'name': source.name(), 'key': source_key, 'size': source.size(), 'retained': source.retained(), 'delete_next': snapshot.getPurges().get(source_key) or False }) return { 'name': snapshot.name(), 'slug': snapshot.slug(), 'size': snapshot.sizeString(), 'status': snapshot.status(), 'date': self._time.toLocal(snapshot.date()).strftime("%c"), 'isPending': ha is not None and type(ha) is PendingSnapshot, 'protected': snapshot.protected(), 'type': snapshot.snapshotType(), 'details': snapshot.details(), 'sources': sources, 'uploadable': snapshot.getSource(SOURCE_HA) is None and len(snapshot.sources) > 0, 'restorable': snapshot.getSource(SOURCE_HA) is not None, }
def getSnapshotDetails(self, snapshot: Snapshot): ha = snapshot.getSource(SOURCE_HA) sources = [] for source_key in snapshot.sources: source: AbstractSnapshot = snapshot.sources[source_key] sources.append({ 'name': source.name(), 'key': source_key, 'size': source.size(), 'retained': source.retained(), 'delete_next': snapshot.getPurges().get(source_key) or False, 'slug': snapshot.slug(), 'ignored': source.ignore(), }) return { 'name': snapshot.name(), 'slug': snapshot.slug(), 'size': snapshot.sizeString(), 'status': snapshot.status(), 'date': self._time.toLocal(snapshot.date()).strftime("%c"), 'createdAt': self._time.formatDelta(snapshot.date()), 'isPending': ha is not None and type(ha) is PendingSnapshot, 'protected': snapshot.protected(), 'type': snapshot.snapshotType(), 'folders': snapshot.details().get("folders", []), 'addons': self.formatAddons(snapshot.details()), 'sources': sources, 'haVersion': snapshot.version(), 'uploadable': snapshot.getSource(SOURCE_HA) is None and len(snapshot.sources) > 0, 'restorable': snapshot.getSource(SOURCE_HA) is not None, 'status_detail': snapshot.getStatusDetail(), 'upload_info': snapshot.getUploadInfo(self._time), 'ignored': snapshot.ignore(), 'timestamp': snapshot.date().timestamp(), }