Example #1
0
    def _verify_request(
        self,
        *,
        variables: VariableMap,
        lsp_id: Json,
        entry: TranscriptEntry,
        request: "_RequestSpec",
    ) -> Optional["_ErrorDescription"]:
        actual_result = entry.received.get("result")
        actual_powered_by = entry.received.get("powered_by")
        if request.comment is not None:
            request_description = (
                f"Request with ID {lsp_id!r} (comment: {request.comment!r})"
            )
        else:
            request_description = f"Request with ID {lsp_id!r}"

        # Because of the way hack allocates a different HHI folder for each running
        # process, let's replace the standard HHI foldername
        actual_result = fixup_hhi_json(actual_result)
        expected_result = interpolate_variables(
            payload=request.result, variables=variables
        )
        expected_result = fixup_hhi_json(expected_result)

        if actual_result != expected_result:
            error_description = self._pretty_print_diff(
                actual=actual_result, expected=expected_result
            )
            description = f"""\
{request_description} got an incorrect result:

{error_description}"""
            request_context = self._get_context_for_traceback(request.traceback)
            context = f"""\
This was the associated request:

{request_context}"""
            remediation = self._describe_response_for_remediation(
                variables=variables, request=request, actual_response=entry.received
            )
            return _ErrorDescription(
                description=description, context=context, remediation=remediation
            )
        elif entry.received.get("powered_by") != request.powered_by:
            description = f"""\
{request_description} had an incorrect value for the `powered_by` field
(expected {request.powered_by!r}; got {actual_powered_by!r})
"""
            request_context = self._get_context_for_traceback(request.traceback)
            context = f"""\
This was the associated request:

{request_context}"""
            remediation = self._describe_response_for_remediation(
                variables=variables, request=request, actual_response=entry.received
            )
            return _ErrorDescription(
                description=description, context=context, remediation=remediation
            )
Example #2
0
 def test_interpolate_variables_multiple(self) -> None:
     variables = {"foo": "bar", "baz": "qux"}
     payload = {
         "hello": "${foo} ${baz}",
         "nested": {
             "foo": "${foo}"
         },
         "in key: ${baz}": True,
     }
     expected = {
         "hello": "bar qux",
         "nested": {
             "foo": "bar"
         },
         "in key: qux": True
     }
     self.assertEqual(interpolate_variables(payload, variables), expected)
     self.assertEqual(uninterpolate_variables(expected, variables), payload)
Example #3
0
    def _flag_unhandled_messages(
        self,
        handled_entries: AbstractSet[str],
        variables: VariableMap,
        transcript: Transcript,
        # pyre-fixme[11]: Annotation `_LspIdMap` is not defined as a type.
        lsp_id_map: _LspIdMap,
    ) -> Iterable["_ErrorDescription"]:
        for transcript_id, entry in transcript.items():
            if transcript_id in handled_entries:
                continue

            received = entry.received
            if received is None:
                continue

            if entry.sent is not None:
                # We received a request and responded to it.
                continue

            method = received["method"]
            params = received["params"]
            payload = self._pretty_print_snippet(received)
            if "id" in received:
                description = f"""\
An unexpected request of type {method!r} was sent by the language server.
Here is the request payload:

{payload}
"""
                at_nocommit = "@" + "nocommit"
                remediation = f"""\
1) If this was unexpected, then the language server is buggy and should be
fixed.

2) If all requests of type {method!r} with theses params should be ignored,
add this directive anywhere in your test:

    .{self.ignore_requests.__name__}(method={method!r}, params={params!r})

3) To handle this request, add this directive to your test to wait for it and
respond to it before proceeding:

    .{self.wait_for_server_request.__name__}(
        method={method!r},
        params={params!r},
        result={{
            "{at_nocommit}": "fill in request data here",
        }},
    )
"""
            else:
                if any(
                        isinstance(message, _WaitForNotificationSpec)
                        and message.method == method and
                        interpolate_variables(payload=message.params,
                                              variables=variables) == params
                        for message in self._messages):
                    # This was a notification we we explicitly waiting for, so skip
                    # it.
                    continue

                uninterpolated_params = uninterpolate_variables(
                    payload=params, variables=variables)
                description = f"""\
An unexpected notification of type {method!r} was sent by the language server.
Here is the notification payload:

{payload}
"""
                remediation = f"""\
1) If this was unexpected, then the language server is buggy and should be
fixed.

2) If all notifications of type {method!r} should be ignored, add this directive
anywhere in your test:

    .{self.ignore_notifications.__name__}(method={method!r})

3) If this single instance of the notification was expected, add this directive
to your test to wait for it before proceeding:

    .{self.wait_for_notification.__name__}(
        method={method!r},
        params={uninterpolated_params!r},
    )
"""

            previous_request = self._find_previous_request(
                transcript, lsp_id_map, current_id=transcript_id)
            if previous_request is not None:
                request_context = self._get_context_for_call_site_info(
                    previous_request.call_site_info)
            else:
                request_context = "<no previous request was found>"
            context = f"""\
This was the most recent request issued from the language client before it
received the notification:

{request_context}"""

            yield _ErrorDescription(description=description,
                                    context=context,
                                    remediation=remediation)
Example #4
0
    def _get_json_commands(
        self, variables: VariableMap
        # pyre-fixme[11]: Annotation `_LspIdMap` is not defined as a type.
    ) -> Tuple[Sequence[Json], "_LspIdMap"]:
        """Transforms this test spec into something the LSP command processor
        can interpret."""
        json_commands = []
        lsp_id_map = {}
        current_id = 0
        for message in self._messages:
            current_id += 1
            lsp_id_map[message] = current_id

            if isinstance(message, _RequestSpec):
                json_commands.append({
                    "jsonrpc":
                    "2.0",
                    "comment":
                    message.comment,
                    "id":
                    current_id,
                    "method":
                    message.method,
                    "params":
                    interpolate_variables(message.params, variables=variables),
                })

                if message.wait_id is None:
                    # Assume that if no wait ID was explicitly passed, we want
                    # to wait on the response before sending the next message.
                    json_commands.append({
                        "jsonrpc": "2.0",
                        "method": "$test/waitForResponse",
                        "params": {
                            "id": current_id
                        },
                    })
            elif isinstance(message, _DebugRequestSpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "id": current_id,
                    "method": "telemetry/rage",
                    "params": {},
                })
            elif isinstance(message, _NotificationSpec):
                json_commands.append({
                    "jsonrpc":
                    "2.0",
                    "comment":
                    message.comment,
                    "method":
                    message.method,
                    "params":
                    interpolate_variables(message.params, variables=variables),
                })
            elif isinstance(message, _WaitForRequestSpec):
                params = {
                    "method":
                    message.method,
                    "params":
                    interpolate_variables(message.params, variables=variables),
                }
                if not isinstance(message.result, NoResponse):
                    params["result"] = message.result
                json_commands.append({
                    "jsonrpc": "2.0",
                    "comment": message.comment,
                    "method": "$test/waitForRequest",
                    "params": params,
                })
            elif isinstance(message, _WaitForNotificationSpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "comment": message.comment,
                    "method": "$test/waitForNotification",
                    "params": {
                        "method":
                        message.method,
                        "params":
                        interpolate_variables(message.params,
                                              variables=variables),
                    },
                })
            elif isinstance(message, _WaitForResponseSpec):
                lsp_ids = [
                    lsp_id for previous_message, lsp_id in lsp_id_map.items()
                    if isinstance(previous_message, _RequestSpec)
                    and previous_message.wait_id == message.wait_id
                ]
                assert len(lsp_ids) == 1, (
                    f"Should have had exactly one previous message with wait ID {message.wait_id!r}, "
                    + "but got {len(lsp_ids)}")
                [lsp_id] = lsp_ids

                json_commands.append({
                    "jsonrpc": "2.0",
                    "method": "$test/waitForResponse",
                    "params": {
                        "id": lsp_id
                    },
                })
            elif isinstance(message, _WaitForHhServerReadySpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "method": "$test/waitForHhServerReady",
                    "params": {},
                })
            else:
                raise ValueError(
                    f"unhandled message type {message.__class__.__name__}")
        return (json_commands, lsp_id_map)
Example #5
0
 def parse_test_data(self, file: str, variables: Mapping[str, str]) -> Json:
     text = self.read_repo_file(file)
     data: Json = json.loads(text)
     data = interpolate_variables(data, variables)
     return data
Example #6
0
    def _get_json_commands(
            self,
            variables: Mapping[str,
                               str]) -> Tuple[Sequence[Json], "_LspIdMap"]:
        """Transforms this test spec into something the LSP command processor
        can interpret."""
        json_commands = []
        lsp_id_map = {}
        current_id = 0
        for message in self._messages:
            current_id += 1
            lsp_id_map[message] = current_id

            if isinstance(message, _RequestSpec):
                json_commands.append({
                    "jsonrpc":
                    "2.0",
                    "comment":
                    message.comment,
                    "id":
                    current_id,
                    "method":
                    message.method,
                    "params":
                    interpolate_variables(message.params, variables=variables),
                })

                if message.wait:
                    json_commands.append({
                        "jsonrpc": "2.0",
                        "method": "$test/waitForResponse",
                        "params": {
                            "id": current_id
                        },
                    })
            elif isinstance(message, _NotificationSpec):
                json_commands.append({
                    "jsonrpc":
                    "2.0",
                    "comment":
                    message.comment,
                    "method":
                    message.method,
                    "params":
                    interpolate_variables(message.params, variables=variables),
                })
            elif isinstance(message, _WaitForRequestSpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "comment": message.comment,
                    "method": "$test/waitForRequest",
                    "params": {
                        "method": message.method,
                        "params": message.params,
                        "result": message.result,
                    },
                })
            elif isinstance(message, _WaitForNotificationSpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "comment": message.comment,
                    "method": "$test/waitForNotification",
                    "params": {
                        "method": message.method,
                        "params": message.params
                    },
                })
            else:
                raise ValueError(
                    f"unhandled message type {message.__class__.__name__}")
        return (json_commands, lsp_id_map)
Example #7
0
    def _get_json_commands(
            self,
            variables: VariableMap) -> Tuple[Sequence[Json], "_LspIdMap"]:
        """Transforms this test spec into something the LSP command processor
        can interpret."""
        json_commands = []
        lsp_id_map = {}
        current_id = 0
        for message in self._messages:
            current_id += 1
            lsp_id_map[message] = current_id

            if isinstance(message, _RequestSpec):
                json_commands.append({
                    "jsonrpc":
                    "2.0",
                    "comment":
                    message.comment,
                    "id":
                    current_id,
                    "method":
                    message.method,
                    "params":
                    interpolate_variables(message.params, variables=variables),
                })

                if message.wait_id is None:
                    # Assume that if no wait ID was explicitly passed, we want
                    # to wait on the response before sending the next message.
                    json_commands.append({
                        "jsonrpc": "2.0",
                        "method": "$test/waitForResponse",
                        "params": {
                            "id": current_id
                        },
                    })
            elif isinstance(message, _DebugRequestSpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "id": current_id,
                    "method": "telemetry/rage",
                    "params": {},
                })
            elif isinstance(message, _NotificationSpec):
                json_commands.append({
                    "jsonrpc":
                    "2.0",
                    "comment":
                    message.comment,
                    "method":
                    message.method,
                    "params":
                    interpolate_variables(message.params, variables=variables),
                })
            elif isinstance(message, _WaitForRequestSpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "comment": message.comment,
                    "method": "$test/waitForRequest",
                    "params": {
                        "method": message.method,
                        "params": message.params,
                        "result": message.result,
                    },
                })
            elif isinstance(message, _WaitForNotificationSpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "comment": message.comment,
                    "method": "$test/waitForNotification",
                    "params": {
                        "method": message.method,
                        "params": message.params
                    },
                })
            elif isinstance(message, _WaitForResponseSpec):
                [lsp_id] = [
                    lsp_id for previous_message, lsp_id in lsp_id_map.items()
                    if isinstance(previous_message, _RequestSpec)
                    and previous_message.wait_id == message.wait_id
                ]
                json_commands.append({
                    "jsonrpc": "2.0",
                    "method": "$test/waitForResponse",
                    "params": {
                        "id": lsp_id
                    },
                })
            elif isinstance(message, _WaitForHhServerReadySpec):
                json_commands.append({
                    "jsonrpc": "2.0",
                    "method": "$test/waitForHhServerReady",
                    "params": {},
                })
            else:
                raise ValueError(
                    f"unhandled message type {message.__class__.__name__}")
        return (json_commands, lsp_id_map)
Example #8
0
 def test_interpolate_variables_simple(self) -> None:
     variables = {"foo": "bar"}
     payload = {"hello": "hi ${foo} hi"}
     expected = {"hello": "hi bar hi"}
     self.assertEqual(interpolate_variables(payload, variables), expected)
     self.assertEqual(uninterpolate_variables(expected, variables), payload)
Example #9
0
 def test_undefined_variable_raises_exception(self) -> None:
     variables = {}
     payload = {"hello": "bar ${foo} bar"}
     with self.assertRaises(ValueError):
         interpolate_variables(payload, variables)