Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some info for testing(in general) the extensions built on tower-lsp #229

Open
Hyperion101010 opened this issue Sep 28, 2020 · 7 comments
Labels
documentation Improvements or additions to documentation enhancement New feature or request

Comments

@Hyperion101010
Copy link

Hi there, at hyperledger we are developing vscode server for solidity language and tower-lsp has proved as a great server implementation to built our server on. Thanks for writing this server and for keeping it up to date.
So I was working on my version of the server and finished implementing the hover feature for same. Now my server is in Rust(tower-lsp) and the client is in Js. I searched on the vscode API but I couldn't find any way to invoke hover while running tests(like running test from client side and getting the hover message in the test from the server using some function).
I implemented diagnostics as well but at that time vscode API had getdiagnostics function which did the trick. This time I can't find any such method for hover.
Any suggestions on how should the hover tests be implemented?
my repo: https://github.com/hyperledger-labs/solang-vscode

@silvanshade
Copy link
Contributor

Any suggestions on how should the hover tests be implemented?

@Hyperion101010 One possibility would be to test textDocument/hover in a similar way to how I do for wasm-lsp/wasm-language-server. See here. Specifically, the actual responses from the server are checked here.

@ebkalderon ebkalderon added enhancement New feature or request documentation Improvements or additions to documentation labels Sep 29, 2020
@ebkalderon
Copy link
Owner

@Hyperion101010 Hello! Thank you for the kind words; I'm glad to hear that tower-lsp has been useful to you. LspService implements the tower::Service trait and is therefore compatible with the broader Tower ecosystem, including tower-test which is used to test Tower-based libraries. In essence, LspService can be conceptually modeled as the function below (see the actual Service implementation on docs.rs):

async fn call(&mut self, req: Incoming) -> Result<Option<Outgoing>, ExitedError>

One can leverage tower-test to spin up an instance of the language server in tests, send requests, and assert the content of responses like this:

tower-lsp/src/service.rs

Lines 177 to 233 in 58457ad

#[tokio::test]
async fn initializes_only_once() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
let initialize: Incoming = serde_json::from_str(INITIALIZE_REQUEST).unwrap();
let raw = r#"{"jsonrpc":"2.0","result":{"capabilities":{}},"id":1}"#;
let ok = serde_json::from_str(raw).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(initialize.clone()).await, Ok(Some(ok)));
let raw = r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":1}"#;
let err = serde_json::from_str(raw).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(initialize).await, Ok(Some(err)));
}
#[tokio::test]
async fn refuses_requests_after_shutdown() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
let initialize: Incoming = serde_json::from_str(INITIALIZE_REQUEST).unwrap();
let raw = r#"{"jsonrpc":"2.0","result":{"capabilities":{}},"id":1}"#;
let ok = serde_json::from_str(raw).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(initialize.clone()).await, Ok(Some(ok)));
let shutdown: Incoming = serde_json::from_str(SHUTDOWN_REQUEST).unwrap();
let raw = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
let ok = serde_json::from_str(raw).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(shutdown.clone()).await, Ok(Some(ok)));
let raw = r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":1}"#;
let err = serde_json::from_str(raw).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(shutdown).await, Ok(Some(err)));
}
#[tokio::test]
async fn exit_notification() {
let (service, _) = LspService::new(|_| Mock::default());
let mut service = Spawn::new(service);
let initialized: Incoming = serde_json::from_str(INITIALIZED_NOTIF).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(initialized.clone()).await, Ok(None));
let exit: Incoming = serde_json::from_str(EXIT_NOTIF).unwrap();
assert_eq!(service.poll_ready(), Poll::Ready(Ok(())));
assert_eq!(service.call(exit).await, Ok(None));
assert_eq!(service.poll_ready(), Poll::Ready(Err(ExitedError)));
assert_eq!(service.call(initialized).await, Err(ExitedError));
}
}

Note that a less-than-pretty caveat of the current design is that server-to-client requests (initiated by calls to Client) are sent through a separate channel (the MessageStream returned by LspService::new()) and will have to be asserted separately.

This may change in the future with #177, where LspService is remodeled to avoid this problem, which will undoubtedly be a breaking change to any downstream testing code. Feel free to contribute further there if you have something to share!

@ebkalderon
Copy link
Owner

I think this issue should be safe to close if it can be confirmed that tower-test satisfies the needs of your language server project. But if enough users are asking the same question, though, perhaps we could clarify things further and add a helpful section to the README explicitly pointing users to the tower-test documentation. 😄

@Hyperion101010
Copy link
Author

Sure, I will checkout the details. Closing this issue.

@ebkalderon
Copy link
Owner

Feel free to reopen if you run into troubles with tower-test, @Hyperion101010. Thanks for reporting this issue!

@lpil
Copy link

lpil commented Nov 1, 2020

Could we open this issue to track adding testing documentation? Thank you

@ebkalderon
Copy link
Owner

Sure, @lpil! I can amend the README to include a link to tower-test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants