Beispiel #1
0
class UserLogInVesyncAuthorizationServer(HttpRunner):
    """
    Vesync user log in to vesync authorization server.

    Config Variables:
        - email (str): required
        - password (str): required
        - client_id (str): OAuth client id
        - platform_type (Literal["Alexa", "GoogleHome"]): required
        - scope (str): required
        - redirect_url (str): OAuth redirect URL

    Export Variables:
        - authorization_code (bytes): note the type is 'bytes', not 'str'
    """

    config = (
        Config("VeSync 用户登录,登录成功后重定向回第三方 app 并附带 authorization code").export(
            *["authorization_code"]))

    teststeps = [
        Step(
            RunRequest("VeSync 用户登录,登录成功后重定向回第三方 app 并附带 authorization code").
            with_variables(
                **{
                    "api":
                    "${get_api_from_orm_by_name(userLogInVesyncAuthorizationServer)}"
                }).post("${getattr($api, url)}").with_data({
                    "email":
                    "$email",
                    "password":
                    "******",
                    "traceId":
                    generate_trace_id(),
                    "clientId":
                    "$client_id",
                    "platformType":
                    "$platform_type",
                    "state":
                    generate_trace_id(),
                    "scope":
                    "$scope",
                    "redirectUrl":
                    "$redirect_url",
                    "userLocale":
                    "",
                    "responseType":
                    "code"
                }).extract().with_jmespath(
                    "body",
                    "authorization_code")  # note: the type is bytes, not str.
            .validate().assert_equal("status_code", 200).assert_type_match(
                "body", "bytes", "返回的 authorization code 应该是一个字符串")),
    ]
Beispiel #2
0
def accept_grant(request: dict, user: User, oauth_client_id: str,
                 authentication_code: str) -> None:
    """
    Set parameters for Alexa directive 'AcceptGrant'.
    """
    oauth_token = crud.oauth_token.get_not_expired_by_user_id_and_client_id(
        db, user.id, oauth_client_id)
    if not oauth_token:
        raise ValueError(
            "No valid oauth token found, make sure oauth token exist, and it's access token not expired. "
            "Refresh access token if expired.")

    set_alexa_directive_parent_dict(request)
    request["req_json"]["data"]["directive"] = {
        "header": {
            "namespace": "Alexa.Authorization",
            "name": "AcceptGrant",
            "messageId": generate_trace_id("UUID4"),
            "payloadVersion": alexa_settings.authorization_payload_version
        },
        "payload": {
            "grant": {
                "type": "OAuth2.AuthorizationCode",
                "code": authentication_code
            },
            "grantee": {
                "type": "BearerToken",
                "token": oauth_token.access_token
            }
        }
    }
Beispiel #3
0
class AssertAdjustRangeValueAlexaResponseCorrect(HttpRunner):
    """
    Send Alexa directive AdjustRangeValue and assert the response is correct.

    Config Variables:
        - instance (str): required (set to None if not exist), e.g. AirPurifier.Mode
        - access_token (str): required
        - payload (dict): required (set to {} if not exist), e.g. {"mode": "mode.sleep"}
        - final_value (int): required, the expected value in response
        - sku (Sku): required
        - cid (str): required
    """
    config = (Config("AdjustRangeValue 命令中各个参数均正确,event AlexaResponse 正确"))

    teststeps = [
        Step(RunApiInterfaceSpecificDirective().with_variables(
            **{
                "namespace": AlexaInterfaceEnum.RangeController.value,
                "name": "AdjustRangeValue",
                "config_model": "${getattr($sku, config_model)}",
                "endpoint_id": "$cid;$config_model",
                "message_id": generate_trace_id("UUID4")
            }
        ).request().teardown_hook(
            "${check_alexa_directive_params($namespace, $instance, $name, $payload)}"
        ).validate().assert_equal("body.code", 0).assert_equal(
            "body.result.statusCode", 200
        ).assert_json_contains(
            "body.result.data", "${get_adjust_range_value_alexa_response("
            "$message_id, $access_token, $sku, $cid, $instance, $final_value)}"
        ))
    ]
Beispiel #4
0
def set_fw_shared_params(request: dict, cid: str, sku: Sku, api_name: str, main_firmware_version: str = None) -> None:
    """
    Set shared parameters for firmware API.

    Note:
        1. argument api_name will be assigned to parameter 'method',
            so make sure use api method as name when inserting row into table api.
        2. argument 'main_firmware_version' must not be None when setup mode of sku is 'WIFI_V21'.
    """
    shared_params = {
        "context": {
            "traceId": generate_trace_id(),
            "method": api_name,
            "cid": cid,
            "deviceRegion": sku.device_region
        }
    }

    if sku.setup_mode == SetupModeEnum.WIFI_V20:
        shared_params["context"]["pid"] = sku.pid
    elif sku.setup_mode == SetupModeEnum.WIFI_V21:
        if not main_firmware_version:
            raise ValueError("argument 'main_firmware_version' must not be None when setup mode of sku is 'WIFI_V21'")
        shared_params["context"]["configModel"] = sku.config_model
        shared_params["context"]["mainFwVersion"] = main_firmware_version
        shared_params["context"]["cause"] = "onConn"

    request["req_json"].update(shared_params)
Beispiel #5
0
 def request(self):
     return (super().request().with_json({
         "data": {
             "directive": {
                 "header": {
                     "namespace": "$namespace",
                     "instance": "$instance",
                     "name": "$name",
                     "messageId": "$message_id",
                     "correlationToken": generate_trace_id("UUID4"),
                     "payloadVersion":
                     alexa_settings.interface_payload_version
                 },
                 "endpoint": {
                     "scope": {
                         "type": "BearerToken",
                         "token": "$access_token"
                     },
                     "endpointId": "$endpoint_id",
                     "cookie": {}
                 },
                 "payload": "$payload"
             }
         }
     }))
Beispiel #6
0
def get_access_log(request: dict, user: User, event: Event, platform: PlatformEnum) -> None:
    """
    Set parameters for api 'getAccessLog'.
    """
    device = event.device
    cookie = user.cookie

    if platform == PlatformEnum.ALEXA:
        third_party_name = "Alexa"
        agent_user_id = None
    elif platform == PlatformEnum.GOOGLE_HOME:
        third_party_name = "GoogleHome"
        agent_user_id = cookie.vesync_main_account_id
    else:
        raise ValueError("not supported third party platform")

    request_json = {
        "traceId": generate_trace_id(),
        "method": "getAccessLog",
        "thirdPartyName": third_party_name,
        "accountId": cookie.vesync_main_account_id,
        "cid": device.cid,
        "configModule": device.sku.config_model,
        "subDeviceNo": 0,
        "agentUserId": agent_user_id,
        "triggerId": None
    }

    request["req_json"] = request_json
Beispiel #7
0
class AssertDiscoverResponseCorrect(HttpRunner):
    """
    Call alexa directive Discover and make assertion on the response.

    Config Variables:
        - access_token (str): required, access token given by vesync
        - expected (list[dict]): required, expected endpoints
        - jmespath (str): optional, default to "body.result.data.event.payload.endpoints"
    """
    config = (Config("Discover").variables(
        **{
            "jmespath": "body.result.data.event.payload.endpoints",
        }))

    teststeps = [
        Step(RunApiDiscover().with_variables(
            **{
                "message_id": generate_trace_id("UUID4")
            }).request().validate().assert_equal("body.code", 0).assert_equal(
                "body.result.statusCode", 200).assert_json_contains(
                    "body.result.data.event.header", {
                        "namespace": "Alexa.Discovery",
                        "name": "Discover.Response",
                        "payloadVersion":
                        alexa_settings.discovery_payload_version,
                        "messageId": "$message_id",
                    }).assert_json_contains("$jmespath", "$expected")),
    ]
Beispiel #8
0
def set_alexa_directive_shared_params(request: dict) -> None:
    """Set shared parameters for Alexa directives sent to skill (hosted on LWS Lambda)."""
    request["req_json"].update({
        "traceId": generate_trace_id(),
        "method": "invokeLambda",
        "projectName": "alexaSmartHome",
        "alexaRegion": "NorthAmerica",
    })
Beispiel #9
0
def _get_vesync_app_unauthenticated_shared_params(
        api: Api,
        client: Client,
        debug: bool = True,
        method: str = None) -> dict:
    """
    Get unauthenticated shared parameters for vesync app apis.

    5 parameters will always be set:
        * method
        * acceptLanguage
        * debugMode
        * timeZone
        * traceId

    if request format is VESYNC-APP-V1.0, 3 extra parameters will be set
        * phoneOS
        * phoneBrand
        * appVersion

    if request format is VESYNC-APP-V2.0, 5 extra parameters will be set
        * osInfo
        * clientInfo
        * clientVersion
        * clientType
        * terminalId

    if request format is VESYNC-APP-V2.1 (for arize), 3 extra parameters will be set
        * osInfo
        * clientVersion
        * clientType
    """
    # use the basename of api path as method
    if not method:
        method = api.method

    shared_params = {
        "acceptLanguage": client.accept_language,
        "debugMode": debug,
        "method": method,
        "timeZone": client.time_zone,
        "traceId": generate_trace_id()
    }

    if (request_format := api.service.request_format) == "VESYNC-APP-V1.0":
        shared_params.update({
            "phoneOS": client.os_info,
            "phoneBrand": client.client_info,
            "appVersion": client.client_version
        })
        return shared_params
Beispiel #10
0
def report_state(request: dict, access_token: str, device: Device) -> None:
    """
    Set parameters for Alexa directive 'ReportState'.
    """
    set_alexa_directive_parent_dict(request)
    request["req_json"]["data"]["directive"] = {
        "header": {
            "namespace": "Alexa",
            "name": "ReportState",
            "messageId": generate_trace_id("UUID4"),
            "correlationToken": generate_trace_id("UUID4"),
            "payloadVersion": alexa_settings.alexa_payload_version
        },
        "endpoint": {
            "scope": {
                "type": "BearerToken",
                "token": access_token
            },
            "endpointId": f"{device.cid};{device.sku.config_model}",
            "cookie": {}
        },
        "payload": {}
    }
Beispiel #11
0
class AssertOneEndpointCorrectInDiscoverResponse(HttpRunner):
    """
    Call alexa directive Discover and assert the information of specific endpoint is correct.

    Config Variables:
        - access_token (str): required, access token given by vesync
        - sku (Sku): required
        - cid (str): required
        - device_name (str): required
        - main_firmware_version (str): required
    """
    config = (Config("Discover"))

    teststeps = [
        Step(RunApiDiscover().with_variables(
            **{
                "config_model": "${getattr($sku, config_model)}",
                "endpoint_id": "$cid;$config_model",
                "message_id": generate_trace_id("UUID4"),
            }
        ).request().validate().assert_equal("body.code", 0).assert_equal(
            "body.result.statusCode", 200
        ).assert_json_contains(
            "body.result.data.event.header", {
                "namespace":
                "Alexa.Discovery",
                "name":
                "Discover.Response",
                "payloadVersion":
                alexa_settings.discovery_payload_version,
                "messageId":
                "$message_id",
            }
        ).assert_json_contains(
            "body.result.data.event.payload.endpoints[?endpointId=='$endpoint_id'] | [0]",
            "${get_endpoint_info($sku, $cid, $device_name, $main_firmware_version)}"
        )),
    ]
Beispiel #12
0
    }

    if (request_format := api.service.request_format) == "VESYNC-APP-V1.0":
        shared_params.update({
            "phoneOS": client.os_info,
            "phoneBrand": client.client_info,
            "appVersion": client.client_version
        })
        return shared_params
    elif request_format == "VESYNC-APP-V2.0":
        shared_params.update({
            "osInfo": client.os_info,
            "clientInfo": client.client_info,
            "clientVersion": client.client_version,
            "clientType": client.client_type,
            "terminalId": generate_trace_id("UUID4")
        })
        return {"context": shared_params}
    elif request_format == "VESYNC-APP-V2.1":
        shared_params.update({
            "osInfo": client.os_info,
            "clientVersion": client.client_version,
            "clientType": client.client_type,
        })
        return {"context": shared_params}
    else:
        raise ValueError(f"request format '{request_format}' was not supported yet.")


def set_vesync_app_shared_params(
        request: dict,