コード例 #1
0
 def __init__(self, opp):
     """Initialize the dashboards collection."""
     super().__init__(
         storage.Store(opp, DASHBOARDS_STORAGE_VERSION,
                       DASHBOARDS_STORAGE_KEY),
         _LOGGER,
     )
コード例 #2
0
async def test_removing_while_delay_in_progress(tmpdir):
    """Test removing while delay in progress."""

    loop = asyncio.get_event_loop()
    opp = await async_test_open_peer_power(loop)

    test_dir = await opp.async_add_executor_job(tmpdir.mkdir, "storage")

    with patch.object(storage, "STORAGE_DIR", test_dir):
        real_store = storage.Store(opp, 1, "remove_me")

        await real_store.async_save({"delay": "no"})

        assert await opp.async_add_executor_job(os.path.exists,
                                                real_store.path)

        real_store.async_delay_save(lambda: {"delay": "yes"}, 1)

        await real_store.async_remove()
        assert not await opp.async_add_executor_job(os.path.exists,
                                                    real_store.path)

        async_fire_time_changed(opp, dt.utcnow() + timedelta(seconds=1))
        await opp.async_block_till_done()
        assert not await opp.async_add_executor_job(os.path.exists,
                                                    real_store.path)
        await opp.async_stop()
コード例 #3
0
ファイル: resources.py プロジェクト: OpenPeerPower/core
 def __init__(self, opp: OpenPeerPower, ll_config: LovelaceConfig) -> None:
     """Initialize the storage collection."""
     super().__init__(
         storage.Store(opp, RESOURCES_STORAGE_VERSION,
                       RESOURCE_STORAGE_KEY),
         _LOGGER,
     )
     self.ll_config = ll_config
コード例 #4
0
ファイル: __init__.py プロジェクト: OpenPeerPower/core
async def async_setup(opp: OpenPeerPower, config: dict) -> bool:
    """Set up configured zones as well as Open Peer Power zone if necessary."""
    component = entity_component.EntityComponent(_LOGGER, DOMAIN, opp)
    id_manager = collection.IDManager()

    yaml_collection = collection.IDLessCollection(
        logging.getLogger(f"{__name__}.yaml_collection"), id_manager)
    collection.sync_entity_lifecycle(opp, DOMAIN, DOMAIN, component,
                                     yaml_collection, Zone.from_yaml)

    storage_collection = ZoneStorageCollection(
        storage.Store(opp, STORAGE_VERSION, STORAGE_KEY),
        logging.getLogger(f"{__name__}.storage_collection"),
        id_manager,
    )
    collection.sync_entity_lifecycle(opp, DOMAIN, DOMAIN, component,
                                     storage_collection, Zone)

    if config[DOMAIN]:
        await yaml_collection.async_load(config[DOMAIN])

    await storage_collection.async_load()

    collection.StorageCollectionWebsocket(storage_collection, DOMAIN, DOMAIN,
                                          CREATE_FIELDS,
                                          UPDATE_FIELDS).async_setup(opp)

    async def reload_service_handler(service_call: ServiceCall) -> None:
        """Remove all zones and load new ones from config."""
        conf = await component.async_prepare_reload(skip_reset=True)
        if conf is None:
            return
        await yaml_collection.async_load(conf[DOMAIN])

    service.async_register_admin_service(
        opp,
        DOMAIN,
        SERVICE_RELOAD,
        reload_service_handler,
        schema=RELOAD_SERVICE_SCHEMA,
    )

    if component.get_entity("zone.home"):
        return True

    home_zone = Zone(_home_conf(opp))
    home_zone.entity_id = ENTITY_ID_HOME
    await component.async_add_entities([home_zone])

    async def core_config_updated(_: Event) -> None:
        """Handle core config updated."""
        await home_zone.async_update_config(_home_conf(opp))

    opp.bus.async_listen(EVENT_CORE_CONFIG_UPDATE, core_config_updated)

    opp.data[DOMAIN] = storage_collection

    return True
コード例 #5
0
async def test_not_delayed_saving_while_stopping(opp, opp_storage):
    """Test delayed saves don't write after the stop event has fired."""
    store = storage.Store(opp, MOCK_VERSION, MOCK_KEY)
    opp.bus.async_fire(EVENT_OPENPEERPOWER_STOP)
    await opp.async_block_till_done()
    opp.state = CoreState.stopping

    store.async_delay_save(lambda: MOCK_DATA, 1)
    async_fire_time_changed(opp, dt.utcnow() + timedelta(seconds=2))
    await opp.async_block_till_done()
    assert store.key not in opp_storage
コード例 #6
0
async def test_custom_encoder(opp):
    """Test we can save and load data."""
    class JSONEncoder(json.JSONEncoder):
        """Mock JSON encoder."""
        def default(self, o):
            """Mock JSON encode method."""
            return "9"

    store = storage.Store(opp, MOCK_VERSION, MOCK_KEY, encoder=JSONEncoder)
    await store.async_save(Mock())
    data = await store.async_load()
    assert data == "9"
コード例 #7
0
    def __init__(self, opp, config):
        """Initialize Lovelace config based on storage helper."""
        if config is None:
            url_path = None
            storage_key = CONFIG_STORAGE_KEY_DEFAULT
        else:
            url_path = config[CONF_URL_PATH]
            storage_key = CONFIG_STORAGE_KEY.format(config["id"])

        super().__init__(opp, url_path, config)

        self._store = storage.Store(opp, CONFIG_STORAGE_VERSION, storage_key)
        self._data = None
コード例 #8
0
async def test_not_delayed_saving_after_stopping(opp, opp_storage):
    """Test delayed saves don't write after stop if issued before stopping Open Peer Power."""
    store = storage.Store(opp, MOCK_VERSION, MOCK_KEY)
    store.async_delay_save(lambda: MOCK_DATA, 10)
    assert store.key not in opp_storage

    opp.bus.async_fire(EVENT_OPENPEERPOWER_STOP)
    opp.state = CoreState.stopping
    await opp.async_block_till_done()
    assert store.key not in opp_storage

    async_fire_time_changed(opp, dt.utcnow() + timedelta(seconds=15))
    await opp.async_block_till_done()
    assert store.key not in opp_storage
コード例 #9
0
ファイル: __init__.py プロジェクト: OpenPeerPower/core
async def start_http_server_and_save_config(opp: OpenPeerPower, conf: dict,
                                            server: OpenPeerPowerHTTP) -> None:
    """Startup the http server and save the config."""
    await server.start()

    # If we are set up successful, we store the HTTP settings for safe mode.
    store = storage.Store(opp, STORAGE_VERSION, STORAGE_KEY)

    if CONF_TRUSTED_PROXIES in conf:
        conf[CONF_TRUSTED_PROXIES] = [
            str(ip.network_address) for ip in conf[CONF_TRUSTED_PROXIES]
        ]

    store.async_delay_save(lambda: conf, SAVE_DELAY)
コード例 #10
0
    async def start_server(event):
        """Start the server."""
        opp.bus.async_listen_once(EVENT_OPENPEERPOWER_STOP, stop_server)
        await server.start()

        # If we are set up successful, we store the HTTP settings for safe mode.
        store = storage.Store(opp, STORAGE_VERSION, STORAGE_KEY)

        if CONF_TRUSTED_PROXIES in conf:
            conf_to_save = dict(conf)
            conf_to_save[CONF_TRUSTED_PROXIES] = [
                str(ip.network_address) for ip in conf_to_save[CONF_TRUSTED_PROXIES]
            ]
        else:
            conf_to_save = conf

        await store.async_save(conf_to_save)
コード例 #11
0
async def test_saving_on_final_write(opp, opp_storage):
    """Test delayed saves trigger when we quit Open Peer Power."""
    store = storage.Store(opp, MOCK_VERSION, MOCK_KEY)
    store.async_delay_save(lambda: MOCK_DATA, 5)
    assert store.key not in opp_storage

    opp.bus.async_fire(EVENT_OPENPEERPOWER_STOP)
    opp.state = CoreState.stopping
    await opp.async_block_till_done()

    async_fire_time_changed(opp, dt.utcnow() + timedelta(seconds=10))
    await opp.async_block_till_done()
    assert store.key not in opp_storage

    opp.bus.async_fire(EVENT_OPENPEERPOWER_FINAL_WRITE)
    await opp.async_block_till_done()
    assert opp_storage[store.key] == {
        "version": MOCK_VERSION,
        "key": MOCK_KEY,
        "data": MOCK_DATA,
    }
コード例 #12
0
async def _configure_almond_for_ha(opp: OpenPeerPower,
                                   entry: config_entries.ConfigEntry,
                                   api: WebAlmondAPI):
    """Configure Almond to connect to HA."""

    if entry.data["type"] == TYPE_OAUTH2:
        # If we're connecting over OAuth2, we will only set up connection
        # with Open Peer Power if we're remotely accessible.
        opp_url = network.async_get_external_url(opp)
    else:
        opp_url = opp.config.api.base_url

    # If opp_url is None, we're not going to configure Almond to connect to HA.
    if opp_url is None:
        return

    _LOGGER.debug("Configuring Almond to connect to Open Peer Power at %s",
                  opp_url)
    store = storage.Store(opp, STORAGE_VERSION, STORAGE_KEY)
    data = await store.async_load()

    if data is None:
        data = {}

    user = None
    if "almond_user" in data:
        user = await opp.auth.async_get_user(data["almond_user"])

    if user is None:
        user = await opp.auth.async_create_system_user("Almond",
                                                       [GROUP_ID_ADMIN])
        data["almond_user"] = user.id
        await store.async_save(data)

    refresh_token = await opp.auth.async_create_refresh_token(
        user,
        # Almond will be fine as long as we restart once every 5 years
        access_token_expiration=timedelta(days=365 * 5),
    )

    # Create long lived access token
    access_token = opp.auth.async_create_access_token(refresh_token)

    # Store token in Almond
    try:
        with async_timeout.timeout(30):
            await api.async_create_device({
                "kind":
                "io.open-peer-power",
                "oppUrl":
                opp_url,
                "accessToken":
                access_token,
                "refreshToken":
                "",
                # 5 years from now in ms.
                "accessTokenExpires":
                (time.time() + 60 * 60 * 24 * 365 * 5) * 1000,
            })
    except (asyncio.TimeoutError, ClientError) as err:
        if isinstance(err, asyncio.TimeoutError):
            msg = "Request timeout"
        else:
            msg = err
        _LOGGER.warning("Unable to configure Almond: %s", msg)
        await opp.auth.async_remove_refresh_token(refresh_token)
        raise ConfigEntryNotReady

    # Clear all other refresh tokens
    for token in list(user.refresh_tokens.values()):
        if token.id != refresh_token.id:
            await opp.auth.async_remove_refresh_token(token)
コード例 #13
0
def store(opp):
    """Fixture of a store that prevents writing on Open Peer Power stop."""
    yield storage.Store(opp, MOCK_VERSION, MOCK_KEY)
コード例 #14
0
ファイル: test_collection.py プロジェクト: OpenPeerPower/core
async def test_storage_collection_websocket(opp, opp_ws_client):
    """Test exposing a storage collection via websockets."""
    store = storage.Store(opp, 1, "test-data")
    coll = MockStorageCollection(store, _LOGGER)
    changes = track_changes(coll)
    collection.StorageCollectionWebsocket(
        coll,
        "test_item/collection",
        "test_item",
        {
            vol.Required("name"): str,
            vol.Required("immutable_string"): str
        },
        {
            vol.Optional("name"): str
        },
    ).async_setup(opp)

    client = await opp_ws_client(opp)

    # Create invalid
    await client.send_json({
        "id": 1,
        "type": "test_item/collection/create",
        "name": 1,
        # Forgot to add immutable_string
    })
    response = await client.receive_json()
    assert not response["success"]
    assert response["error"]["code"] == "invalid_format"
    assert len(changes) == 0

    # Create
    await client.send_json({
        "id": 2,
        "type": "test_item/collection/create",
        "name": "Initial Name",
        "immutable_string": "no-changes",
    })
    response = await client.receive_json()
    assert response["success"]
    assert response["result"] == {
        "id": "initial_name",
        "name": "Initial Name",
        "immutable_string": "no-changes",
    }
    assert len(changes) == 1
    assert changes[0] == (collection.CHANGE_ADDED, "initial_name",
                          response["result"])

    # List
    await client.send_json({"id": 3, "type": "test_item/collection/list"})
    response = await client.receive_json()
    assert response["success"]
    assert response["result"] == [{
        "id": "initial_name",
        "name": "Initial Name",
        "immutable_string": "no-changes",
    }]
    assert len(changes) == 1

    # Update invalid data
    await client.send_json({
        "id": 4,
        "type": "test_item/collection/update",
        "test_item_id": "initial_name",
        "immutable_string": "no-changes",
    })
    response = await client.receive_json()
    assert not response["success"]
    assert response["error"]["code"] == "invalid_format"
    assert len(changes) == 1

    # Update invalid item
    await client.send_json({
        "id": 5,
        "type": "test_item/collection/update",
        "test_item_id": "non-existing",
        "name": "Updated name",
    })
    response = await client.receive_json()
    assert not response["success"]
    assert response["error"]["code"] == "not_found"
    assert len(changes) == 1

    # Update
    await client.send_json({
        "id": 6,
        "type": "test_item/collection/update",
        "test_item_id": "initial_name",
        "name": "Updated name",
    })
    response = await client.receive_json()
    assert response["success"]
    assert response["result"] == {
        "id": "initial_name",
        "name": "Updated name",
        "immutable_string": "no-changes",
    }
    assert len(changes) == 2
    assert changes[1] == (collection.CHANGE_UPDATED, "initial_name",
                          response["result"])

    # Delete invalid ID
    await client.send_json({
        "id": 7,
        "type": "test_item/collection/update",
        "test_item_id": "non-existing"
    })
    response = await client.receive_json()
    assert not response["success"]
    assert response["error"]["code"] == "not_found"
    assert len(changes) == 2

    # Delete
    await client.send_json({
        "id": 8,
        "type": "test_item/collection/delete",
        "test_item_id": "initial_name"
    })
    response = await client.receive_json()
    assert response["success"]

    assert len(changes) == 3
    assert changes[2] == (
        collection.CHANGE_REMOVED,
        "initial_name",
        {
            "id": "initial_name",
            "immutable_string": "no-changes",
            "name": "Updated name",
        },
    )
コード例 #15
0
async def test_not_saving_while_stopping(opp, opp_storage):
    """Test saves don't write when stopping Open Peer Power."""
    store = storage.Store(opp, MOCK_VERSION, MOCK_KEY)
    opp.state = CoreState.stopping
    await store.async_save(MOCK_DATA)
    assert store.key not in opp_storage
コード例 #16
0
async def async_setup(opp: OpenPeerPower, config: Dict) -> bool:
    """Set up configured zones as well as Open Peer Power zone if necessary."""
    component = entity_component.EntityComponent(_LOGGER, DOMAIN, opp)
    id_manager = collection.IDManager()

    yaml_collection = IDLessCollection(
        logging.getLogger(f"{__name__}.yaml_collection"), id_manager)
    collection.attach_entity_component_collection(
        component, yaml_collection, lambda conf: Zone(conf, False))

    storage_collection = ZoneStorageCollection(
        storage.Store(opp, STORAGE_VERSION, STORAGE_KEY),
        logging.getLogger(f"{__name__}_storage_collection"),
        id_manager,
    )
    collection.attach_entity_component_collection(
        component, storage_collection, lambda conf: Zone(conf, True))

    if DOMAIN in config:
        await yaml_collection.async_load(config[DOMAIN])

    await storage_collection.async_load()

    collection.StorageCollectionWebsocket(storage_collection, DOMAIN, DOMAIN,
                                          CREATE_FIELDS,
                                          UPDATE_FIELDS).async_setup(opp)

    async def _collection_changed(change_type: str, item_id: str,
                                  config: Optional[Dict]) -> None:
        """Handle a collection change: clean up entity registry on removals."""
        if change_type != collection.CHANGE_REMOVED:
            return

        ent_reg = await entity_registry.async_get_registry(opp)
        ent_reg.async_remove(
            cast(str, ent_reg.async_get_entity_id(DOMAIN, DOMAIN, item_id)))

    storage_collection.async_add_listener(_collection_changed)

    async def reload_service_handler(service_call: ServiceCall) -> None:
        """Remove all zones and load new ones from config."""
        conf = await component.async_prepare_reload(skip_reset=True)
        if conf is None:
            return
        await yaml_collection.async_load(conf.get(DOMAIN, []))

    service.async_register_admin_service(
        opp,
        DOMAIN,
        SERVICE_RELOAD,
        reload_service_handler,
        schema=RELOAD_SERVICE_SCHEMA,
    )

    if component.get_entity("zone.home"):
        return True

    home_zone = Zone(
        _home_conf(opp),
        True,
    )
    home_zone.entity_id = ENTITY_ID_HOME
    await component.async_add_entities([home_zone])  # type: ignore

    async def core_config_updated(_: Event) -> None:
        """Handle core config updated."""
        await home_zone.async_update_config(_home_conf(opp))

    opp.bus.async_listen(EVENT_CORE_CONFIG_UPDATE, core_config_updated)

    opp.data[DOMAIN] = storage_collection

    return True
コード例 #17
0
async def async_get_last_config(opp: OpenPeerPower) -> Optional[dict]:
    """Return the last known working config."""
    store = storage.Store(opp, STORAGE_VERSION, STORAGE_KEY)
    return cast(Optional[dict], await store.async_load())
コード例 #18
0
ファイル: __init__.py プロジェクト: OpenPeerPower/core
 async def async_setup(self):
     """Set up and migrate to storage."""
     self.store = storage.Store(self.opp, DATA_VERSION, DATA_KEY)
     self.numbers = (await storage.async_migrator(
         self.opp, self.opp.config.path(NUMBERS_FILE), self.store) or {})
コード例 #19
0
ファイル: test_collection.py プロジェクト: OpenPeerPower/core
async def test_storage_collection(opp):
    """Test storage collection."""
    store = storage.Store(opp, 1, "test-data")
    await store.async_save({
        "items": [
            {
                "id": "mock-1",
                "name": "Mock 1",
                "data": 1
            },
            {
                "id": "mock-2",
                "name": "Mock 2",
                "data": 2
            },
        ]
    })
    id_manager = collection.IDManager()
    coll = MockStorageCollection(store, _LOGGER, id_manager)
    changes = track_changes(coll)

    await coll.async_load()
    assert id_manager.has_id("mock-1")
    assert id_manager.has_id("mock-2")
    assert len(changes) == 2
    assert changes[0] == (
        collection.CHANGE_ADDED,
        "mock-1",
        {
            "id": "mock-1",
            "name": "Mock 1",
            "data": 1
        },
    )
    assert changes[1] == (
        collection.CHANGE_ADDED,
        "mock-2",
        {
            "id": "mock-2",
            "name": "Mock 2",
            "data": 2
        },
    )

    item = await coll.async_create_item({"name": "Mock 3"})
    assert item["id"] == "mock_3"
    assert len(changes) == 3
    assert changes[2] == (
        collection.CHANGE_ADDED,
        "mock_3",
        {
            "id": "mock_3",
            "name": "Mock 3"
        },
    )

    updated_item = await coll.async_update_item("mock-2",
                                                {"name": "Mock 2 updated"})
    assert id_manager.has_id("mock-2")
    assert updated_item == {
        "id": "mock-2",
        "name": "Mock 2 updated",
        "data": 2
    }
    assert len(changes) == 4
    assert changes[3] == (collection.CHANGE_UPDATED, "mock-2", updated_item)

    with pytest.raises(ValueError):
        await coll.async_update_item("mock-2", {"id": "mock-2-updated"})

    assert id_manager.has_id("mock-2")
    assert not id_manager.has_id("mock-2-updated")
    assert len(changes) == 4

    await flush_store(store)

    assert await storage.Store(opp, 1, "test-data").async_load() == {
        "items": [
            {
                "id": "mock-1",
                "name": "Mock 1",
                "data": 1
            },
            {
                "id": "mock-2",
                "name": "Mock 2 updated",
                "data": 2
            },
            {
                "id": "mock_3",
                "name": "Mock 3"
            },
        ]
    }