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
    }
Example #2
0
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
Example #3
0
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,
        }
Example #6
0
    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(),
        }