Ejemplo n.º 1
0
    def test_put_overwrite_and_get(self):
        service_manager = ServiceManager()
        service_manager.get_states = mock.MagicMock(
            return_value={"foo": ServiceState.AVAILABLE})

        resource = HealthResource(service_manager)

        resource.on_put(
            Request(
                "PUT",
                "/",
                body=
                b'{"features:initScripts": "initializing","features:persistence": "disabled"}',
            ))

        resource.on_put(
            Request("PUT",
                    "/",
                    body=b'{"features:initScripts": "initialized"}'))

        state = resource.on_get(Request("GET", "/", body=b"None"))

        assert state == {
            "features": {
                "initScripts": "initialized",
                "persistence": "disabled",
            },
            "services": {
                "foo": "available",
            },
            "version": VERSION,
        }
Ejemplo n.º 2
0
    def test_add_route_endpoint_with_object(self):
        class MySuperApi:
            @route("/users")
            def user(self, _: Request, args):
                # should be inherited
                assert not args
                return Response("user")

        class MyApi(MySuperApi):
            @route("/users/<int:user_id>")
            def user_id(self, _: Request, args):
                assert args
                return Response(f"{args['user_id']}")

            def foo(self, _: Request, args):
                # should be ignored
                raise NotImplementedError

        api = MyApi()
        router = Router()
        rules = router.add_route_endpoints(api)
        assert len(rules) == 2

        assert router.dispatch(Request("GET", "/users")).data == b"user"
        assert router.dispatch(Request("GET", "/users/123")).data == b"123"
Ejemplo n.º 3
0
    def test_dispatch_to_correct_function(self):
        router = Router(dispatcher=resource_dispatcher(pass_response=False))

        requests = []

        class TestResource:
            def on_get(self, req):
                requests.append(req)
                return "GET/OK"

            def on_post(self, req):
                requests.append(req)
                return {"ok": "POST"}

        router.add("/health", TestResource())

        request1 = Request("GET", "/health")
        request2 = Request("POST", "/health")
        assert router.dispatch(request1).get_data(True) == "GET/OK"
        assert router.dispatch(request1).get_data(True) == "GET/OK"
        assert router.dispatch(request2).json == {"ok": "POST"}
        assert len(requests) == 3
        assert requests[0] is request1
        assert requests[1] is request1
        assert requests[2] is request2
Ejemplo n.º 4
0
def test_s3_head_request():
    router = RestServiceOperationRouter(load_service("s3"))

    op, _ = router.match(Request("GET", "/my-bucket/my-key/"))
    assert op.name == "GetObject"

    op, _ = router.match(Request("HEAD", "/my-bucket/my-key/"))
    assert op.name == "HeadObject"
Ejemplo n.º 5
0
 def test_regex_path_dispatcher(self):
     router = Router()
     router.url_map.converters["regex"] = RegexConverter
     rgx = r"([^.]+)endpoint(.*)"
     regex = f"/<regex('{rgx}'):dist>/"
     router.add(path=regex, endpoint=noop)
     assert router.dispatch(Request(method="GET", path="/test-endpoint"))
     with pytest.raises(NotFound):
         router.dispatch(Request(method="GET", path="/test-not-point"))
Ejemplo n.º 6
0
    def test_dispatch_to_non_existing_method_raises_exception(self):
        router = Router(dispatcher=resource_dispatcher(pass_response=False))

        class TestResource:
            def on_post(self, request):
                return "POST/OK"

        router.add("/health", TestResource())

        with pytest.raises(MethodNotAllowed):
            assert router.dispatch(Request("GET", "/health"))
        assert router.dispatch(Request("POST",
                                       "/health")).get_data(True) == "POST/OK"
Ejemplo n.º 7
0
def test_endpoint_prefix_based_routing():
    # TODO could be generalized using endpoint resolvers and replacing "amazonaws.com" with "localhost.localstack.cloud"
    detected_service_name = determine_aws_service_name(
        Request(method="GET", path="/", headers={"Host": "sqs.localhost.localstack.cloud"})
    )
    assert detected_service_name == "sqs"

    detected_service_name = determine_aws_service_name(
        Request(
            method="POST",
            path="/app-instances",
            headers={"Host": "identity-chime.localhost.localstack.cloud"},
        )
    )
    assert detected_service_name == "chime-sdk-identity"
Ejemplo n.º 8
0
    def test_router_route_decorator(self):
        router = Router()

        @router.route("/users")
        def user(_: Request, args):
            assert not args
            return Response("user")

        @router.route("/users/<int:user_id>")
        def user_id(_: Request, args):
            assert args
            return Response(f"{args['user_id']}")

        assert router.dispatch(Request("GET", "/users")).data == b"user"
        assert router.dispatch(Request("GET", "/users/123")).data == b"123"
Ejemplo n.º 9
0
def try_call_sqs(request: Request, region: str) -> Tuple[Dict, OperationModel]:
    action = request.values.get("Action")
    if not action:
        raise UnknownOperationException()

    if action in ["ListQueues", "CreateQueue"]:
        raise InvalidAction(action)

    # prepare aws request for the SQS query protocol (POST request with action url-encoded in the body)
    params = {"QueueUrl": request.base_url}
    # if a QueueUrl is already set in the body, it should overwrite the one in the URL. this behavior is validated
    # against AWS (see TestSqsQueryApi)
    params.update(request.values)
    body = urlencode(params)

    try:
        headers = Headers(request.headers)
        headers["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8"
        operation, service_request = parser.parse(Request("POST", "/", headers=headers, body=body))
        validate_request(operation, service_request).raise_first()
    except OperationNotFoundParserError:
        raise InvalidAction(action)
    except MissingRequiredField as e:
        raise MissingParameter(f"The request must contain the parameter {e.required_name}.")

    # TODO: permissions encoded in URL as AUTHPARAMS cannot be accounted for in this method, which is not a big
    #  problem yet since we generally don't enforce permissions.
    client = aws_stack.connect_to_service("sqs", region_name=region)
    try:
        # using the layer below boto3.client("sqs").<operation>(...) to make the call
        boto_response = client._make_api_call(operation.name, service_request)
    except ClientError as e:
        raise BotoException(e.response) from e

    return boto_response, operation
Ejemplo n.º 10
0
def test_trailing_slashes_are_not_strict():
    # this is tested against AWS. AWS is not strict about trailing slashes when routing operations.

    router = RestServiceOperationRouter(load_service("lambda"))

    op, _ = router.match(Request("GET", "/2015-03-31/functions"))
    assert op.name == "ListFunctions"

    op, _ = router.match(Request("GET", "/2015-03-31/functions/"))
    assert op.name == "ListFunctions"

    op, _ = router.match(Request("POST", "/2015-03-31/functions"))
    assert op.name == "CreateFunction"

    op, _ = router.match(Request("POST", "/2015-03-31/functions/"))
    assert op.name == "CreateFunction"
Ejemplo n.º 11
0
def test_create_op_router_works_for_every_service(service):
    router = RestServiceOperationRouter(load_service(service))

    try:
        router.match(Request("GET", "/"))
    except NotFound:
        pass
Ejemplo n.º 12
0
    def test_dispatcher_with_pass_response(self):
        router = Router(dispatcher=resource_dispatcher(pass_response=True))

        class TestResource:
            def on_get(self, req, resp: Response):
                resp.set_json({"message": "GET/OK"})

            def on_post(self, req, resp):
                resp.set_data("POST/OK")

        router.add("/health", TestResource())
        assert router.dispatch(Request("GET", "/health")).json == {
            "message": "GET/OK"
        }
        assert router.dispatch(Request("POST",
                                       "/health")).get_data(True) == "POST/OK"
Ejemplo n.º 13
0
    def test_handler_dispatcher_with_none_return(self):
        router = Router(dispatcher=handler_dispatcher())

        def handler(_request: Request):
            return None

        router.add("/", handler)
        assert router.dispatch(Request("GET", "/")).status_code == 200
Ejemplo n.º 14
0
    def test_custom_dispatcher(self):
        collector = RequestCollector()
        router = Router(dispatcher=collector)

        router.add("/", "index")
        router.add("/users/<int:id>", "users")

        router.dispatch(Request("GET", "/"))
        router.dispatch(Request("GET", "/users/12"))

        _, endpoint, args = collector.requests[0]
        assert endpoint == "index"
        assert args == {}

        _, endpoint, args = collector.requests[1]
        assert endpoint == "users"
        assert args == {"id": 12}
Ejemplo n.º 15
0
    def test_handler_dispatcher_with_text_return(self):
        router = Router(dispatcher=handler_dispatcher())

        def handler(_request: Request, arg1) -> str:
            return f"hello: {arg1}"

        router.add("/<arg1>", handler)
        assert router.dispatch(Request("GET",
                                       "/world")).data == b"hello: world"
Ejemplo n.º 16
0
    def test_default_dispatcher_invokes_correct_endpoint(self):
        router = Router()

        def index(_: Request, args) -> Response:
            response = Response()
            response.set_json(args)
            return response

        def users(_: Request, args) -> Response:
            response = Response()
            response.set_json(args)
            return response

        router.add("/", index)
        router.add("/users/<int:user_id>", users)

        assert router.dispatch(Request("GET", "/")).json == {}
        assert router.dispatch(Request("GET", "/users/12")).json == {"user_id": 12}
Ejemplo n.º 17
0
 def test_regex_host_dispatcher(self):
     router = Router()
     router.url_map.converters["regex"] = RegexConverter
     rgx = r"\.cloudfront.(net|localhost\.localstack\.cloud)"
     router.add(path="/", endpoint=noop, host=f"<dist_id><regex('{rgx}'):host>:<port>")
     assert router.dispatch(
         Request(
             method="GET",
             headers={"Host": "ad91f538.cloudfront.localhost.localstack.cloud:5446"},
         )
     )
     with pytest.raises(NotFound):
         router.dispatch(
             Request(
                 method="GET",
                 headers={"Host": "ad91f538.cloudfront.amazon.aws.com:5446"},
             )
         )
Ejemplo n.º 18
0
    def test_handler_dispatcher_invalid_signature(self):
        router = Router(dispatcher=handler_dispatcher())

        def handler(_request: Request, arg1) -> Response:  # invalid signature
            return Response("ok")

        router.add("/foo/<arg1>/<arg2>", handler)

        with pytest.raises(TypeError):
            router.dispatch(Request("GET", "/foo/a/b"))
Ejemplo n.º 19
0
    def test_handler_dispatcher_with_dict_return(self):
        router = Router(dispatcher=handler_dispatcher())

        def handler(_request: Request, arg1) -> Dict[str, Any]:
            return {"arg1": arg1, "hello": "there"}

        router.add("/foo/<arg1>", handler)
        assert router.dispatch(Request("GET", "/foo/a")).json == {
            "arg1": "a",
            "hello": "there"
        }
Ejemplo n.º 20
0
    def on_post(self, request: Request):
        data = request.get_json(True, True)
        if not data:
            return Response("invalid request", 400)

        # backdoor API to support restarting the instance
        if data.get("action") in ["kill", "restart"]:
            terminate_all_processes_in_docker()
            SHUTDOWN_INFRA.set()

        return Response("ok", 200)
Ejemplo n.º 21
0
def test_diagnose_resource():
    # simple smoke test diagnose resource
    resource = DiagnoseResource()
    result = resource.on_get(Request(path="/_localstack/diagnose"))

    assert "/tmp" in result["file-tree"]
    assert "/var/lib/localstack" in result["file-tree"]
    assert result["config"]["EDGE_PORT"] == config.EDGE_PORT
    assert result["config"]["DATA_DIR"] == config.DATA_DIR
    assert result["important-endpoints"][
        "localhost.localstack.cloud"].startswith("127.0.")
    assert result["logs"]["docker"]
Ejemplo n.º 22
0
    def test_remove_rule(self):
        router = Router()

        def index(_: Request, args) -> Response:
            return Response(b"index")

        def users(_: Request, args) -> Response:
            return Response(b"users")

        rule0 = router.add("/", index)
        rule1 = router.add("/users/<int:user_id>", users)

        assert router.dispatch(Request("GET", "/")).data == b"index"
        assert router.dispatch(Request("GET", "/users/12")).data == b"users"

        router.remove_rule(rule1)

        assert router.dispatch(Request("GET", "/")).data == b"index"
        with pytest.raises(NotFound):
            assert router.dispatch(Request("GET", "/users/12"))

        router.remove_rule(rule0)
        with pytest.raises(NotFound):
            assert router.dispatch(Request("GET", "/"))
        with pytest.raises(NotFound):
            assert router.dispatch(Request("GET", "/users/12"))
Ejemplo n.º 23
0
    def test_handler_dispatcher(self):
        router = Router(dispatcher=handler_dispatcher())

        def handler_foo(_request: Request) -> Response:
            return Response("ok")

        def handler_bar(_request: Request, bar, baz) -> Dict[str, any]:
            response = Response()
            response.set_json({"bar": bar, "baz": baz})
            return response

        router.add("/foo", handler_foo)
        router.add("/bar/<int:bar>/<baz>", handler_bar)

        assert router.dispatch(Request("GET", "/foo")).data == b"ok"
        assert router.dispatch(Request("GET", "/bar/420/ed")).json == {
            "bar": 420,
            "baz": "ed"
        }

        with pytest.raises(NotFound):
            assert router.dispatch(Request("GET", "/bar/asfg/ed"))
Ejemplo n.º 24
0
def _botocore_request_to_localstack_request(request_object: AWSRequest) -> Request:
    """Converts a botocore request (AWSRequest) to our HTTP framework's Request object based on Werkzeug."""
    split_url = urlsplit(request_object.url)
    path = split_url.path
    query_string = split_url.query
    body = request_object.body
    headers = request_object.headers
    return Request(
        method=request_object.method or "GET",
        path=path,
        query_string=to_str(query_string),
        headers=dict(headers),
        body=body,
        raw_path=path,
    )
Ejemplo n.º 25
0
    def on_put(self, request: Request):
        data = request.get_json(True, True) or {}

        # keys like "features:initScripts" should be interpreted as ['features']['initScripts']
        state = defaultdict(dict)
        for k, v in data.items():
            if ":" in k:
                path = k.split(":")
            else:
                path = [k]

            d = state
            for p in path[:-1]:
                d = state[p]
            d[path[-1]] = v

        self.state = merge_recursive(state, self.state, overwrite=True)
        return {"status": "OK"}
Ejemplo n.º 26
0
 def test_dispatch_raises_not_found(self):
     router = Router()
     router.add("/foobar", noop)
     with pytest.raises(NotFound):
         assert router.dispatch(Request("GET", "/foo"))
Ejemplo n.º 27
0
 def invoke(path, server, port):
     return router.dispatch(Request("GET", path,
                                    server=(server, port))).json