From dffade6552436ba57a09560996cf80d1ef73425a Mon Sep 17 00:00:00 2001 From: Charlie Egan Date: Mon, 15 Apr 2024 10:56:47 +0100 Subject: [PATCH] WIP --- internal/lsp/server.go | 3 +- internal/lsp/server_test.go | 313 ++++++++++++++++++++++-------------- 2 files changed, 190 insertions(+), 126 deletions(-) diff --git a/internal/lsp/server.go b/internal/lsp/server.go index c8fe36186..8b1513c35 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -182,7 +182,8 @@ func (l *LanguageServer) StartDiagnosticsWorker(ctx context.Context) { if ok && len(aggDiags) > 0 { l.diagnosticRequestWorkspace <- fmt.Sprintf("file %q with aggregate violation changed", evt.URI) } - case <-l.diagnosticRequestWorkspace: + case r := <-l.diagnosticRequestWorkspace: + l.logError(fmt.Errorf("diagnostic request workspace: %s", r)) // results will be sent in response to the next workspace/diagnostics request err := updateAllDiagnostics(ctx, l.cache, l.loadedConfig, l.clientRootURI) if err != nil { diff --git a/internal/lsp/server_test.go b/internal/lsp/server_test.go index 2e86499bd..c92411232 100644 --- a/internal/lsp/server_test.go +++ b/internal/lsp/server_test.go @@ -152,44 +152,53 @@ allow = true } // validate that the client received a diagnostics notification for the file - select { - case request := <-receivedMessages: - if request.Method != methodTextDocumentPublishDiagnostics { - t.Fatalf("expected diagnostics to be sent, got %v", request) - } + for { + var success bool + select { + case request := <-receivedMessages: + // validate that the diagnostics are correct + var requestData FileDiagnostics - // validate that the diagnostics are correct - var requestData FileDiagnostics + err = json.Unmarshal(*request.Params, &requestData) + if err != nil { + t.Logf("failed to unmarshal diagnostics: %s", err) + break + } - err = json.Unmarshal(*request.Params, &requestData) - if err != nil { - t.Fatalf("failed to unmarshal diagnostics: %s", err) - } + if requestData.URI != mainRegoURI { + t.Logf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) + break + } - if requestData.URI != mainRegoURI { - t.Fatalf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) - } + if len(requestData.Items) != 2 { + t.Logf("expected 2 diagnostics, got %d, %v", len(requestData.Items), requestData) + break + } - if len(requestData.Items) != 2 { - t.Fatalf("expected 2 diagnostics, got %d, %v", len(requestData.Items), requestData) - } + expectedItems := map[string]bool{ + "opa-fmt": false, + "use-assignment-operator": false, + } - expectedItems := map[string]bool{ - "opa-fmt": false, - "use-assignment-operator": false, - } + for _, item := range requestData.Items { + expectedItems[item.Code] = true + } + + for item, found := range expectedItems { + if !found { + t.Logf("expected diagnostic %s to be found", item) + break + } + } - for _, item := range requestData.Items { - expectedItems[item.Code] = true + success = true + case <-time.After(3 * time.Second): + t.Fatalf("timed out waiting for file diagnostics to be sent") } - for item, found := range expectedItems { - if !found { - t.Fatalf("expected diagnostic %s to be found", item) - } + if success { + break } - case <-time.After(3 * time.Second): - t.Fatalf("timed out waiting for file diagnostics to be sent") } // 3. Client sends textDocument/didChange notification with new contents for main.rego @@ -212,33 +221,41 @@ allow := true } // validate that the client received a new diagnostics notification for the file - select { - case request := <-receivedMessages: - if request.Method != methodTextDocumentPublishDiagnostics { - t.Fatalf("expected diagnostics to be sent, got %v", request) - } + for { + var success bool + select { + case request := <-receivedMessages: + var requestData FileDiagnostics - // validate that the diagnostics are correct - var requestData FileDiagnostics + err = json.Unmarshal(*request.Params, &requestData) + if err != nil { + t.Logf("failed to unmarshal diagnostics: %s", err) + break + } - err = json.Unmarshal(*request.Params, &requestData) - if err != nil { - t.Fatalf("failed to unmarshal diagnostics: %s", err) - } + if requestData.URI != mainRegoURI { + t.Logf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) + break + } - if requestData.URI != mainRegoURI { - t.Fatalf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) - } + if len(requestData.Items) != 1 { + t.Logf("expected 1 diagnostic, got %d", len(requestData.Items)) + break + } - if len(requestData.Items) != 1 { - t.Fatalf("expected 1 diagnostic, got %d", len(requestData.Items)) + if requestData.Items[0].Code != "opa-fmt" { + t.Logf("expected diagnostic to be opa-fmt, got %s", requestData.Items[0].Code) + break + } + + success = true + case <-time.After(3 * time.Second): + t.Fatalf("timed out waiting for file diagnostics to be sent") } - if requestData.Items[0].Code != "opa-fmt" { - t.Fatalf("expected diagnostic to be opa-fmt, got %s", requestData.Items[0].Code) + if success { + break } - case <-time.After(3 * time.Second): - t.Fatalf("timed out waiting for file diagnostics to be sent") } // 4. Client sends workspace/didChangeWatchedFiles notification with new config @@ -255,29 +272,36 @@ rules: } // validate that the client received a new, empty diagnostics notification for the file - select { - case request := <-receivedMessages: - if request.Method != methodTextDocumentPublishDiagnostics { - t.Fatalf("expected diagnostics to be sent, got %v", request) - } + for { + var success bool + select { + case request := <-receivedMessages: + var requestData FileDiagnostics - // validate that the diagnostics are correct - var requestData FileDiagnostics + err = json.Unmarshal(*request.Params, &requestData) + if err != nil { + t.Logf("failed to unmarshal diagnostics: %s", err) + break + } - err = json.Unmarshal(*request.Params, &requestData) - if err != nil { - t.Fatalf("failed to unmarshal diagnostics: %s", err) - } + if requestData.URI != mainRegoURI { + t.Logf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) + break + } + + if len(requestData.Items) != 0 { + t.Logf("expected 0 diagnostic, got %d", len(requestData.Items)) + break + } - if requestData.URI != mainRegoURI { - t.Fatalf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) + success = true + case <-time.After(3 * time.Second): + t.Fatalf("timed out waiting for file diagnostics to be sent") } - if len(requestData.Items) != 0 { - t.Fatalf("expected 0 diagnostic, got %d", len(requestData.Items)) + if success { + break } - case <-time.After(3 * time.Second): - t.Fatalf("timed out waiting for file diagnostics to be sent") } } @@ -490,45 +514,48 @@ allow if input.user in admins.users // here we wait to receive a diagnostics notification for authz.rego with no diagnostics items, the file diagnostics // can arrive first which can still contain the old diagnostics items - ok := make(chan bool, 1) - - go func() { - for { - requestData := <-authzFileMessages - if requestData.URI != authzRegoURI { - t.Logf("expected diagnostics to be sent for authz.rego, got %s", requestData.URI) - } - - if len(requestData.Items) != 0 { - continue + for { + var success bool + select { + case diags := <-authzFileMessages: + if len(diags.Items) != 0 { + t.Logf("expected 0 diagnostic, got %d", len(diags.Items)) + break } - ok <- true - - return + success = true + case <-time.After(3 * time.Second): + t.Fatalf("timed out waiting for file diagnostics to be sent") } - }() - select { - case <-ok: - case <-time.After(3 * time.Second): - t.Fatalf("timed out waiting for authz.rego diagnostics to be sent") + if success { + break + } } // we should also receive a diagnostics notification for admins.rego, since it is in the workspace, but it has not // been changed, so the violations should be the same - select { - case requestData := <-adminsFileMessages: - if requestData.URI != adminsRegoURI { - t.Fatalf("expected diagnostics to be sent for admins.rego, got %s", requestData.URI) + for { + var success bool + select { + case requestData := <-adminsFileMessages: + if requestData.URI != adminsRegoURI { + t.Fatalf("expected diagnostics to be sent for admins.rego, got %s", requestData.URI) + } + + // this file is unchanged + if len(requestData.Items) != 1 { + t.Logf("expected 1 diagnostics, got %d", len(requestData.Items)) + break + } + success = true + case <-time.After(3 * time.Second): + t.Fatalf("timed out waiting for file diagnostics to be sent") } - // this file is unchanged - if len(requestData.Items) != 1 { - t.Fatalf("expected 1 diagnostics, got %d", len(requestData.Items)) + if success { + break } - case <-time.After(3 * time.Second): - t.Fatalf("timed out waiting for admins.rego diagnostics to be sent") } } @@ -583,6 +610,8 @@ allow := true ctx, cancel := context.WithCancel(context.Background()) defer cancel() + fmt.Fprintf(os.Stderr, "start \n") + ls := NewLanguageServer(&LanguageServerOptions{ ErrorLog: os.Stderr, }) @@ -592,8 +621,16 @@ allow := true receivedMessages := make(chan jsonrpc2.Request, 1) clientHandler := func(_ context.Context, _ *jsonrpc2.Conn, req *jsonrpc2.Request) (result any, err error) { if req.Method == methodTextDocumentPublishDiagnostics { + fmt.Fprintf(os.Stderr, "received diagnostics: %v\n", req.Method) receivedMessages <- *req + var requestData FileDiagnostics + err = json.Unmarshal(*req.Params, &requestData) + if err != nil { + t.Fatalf("failed to unmarshal diagnostics: %s", err) + } + fmt.Fprintf(os.Stderr, "received diagnostics: %v items\n", len(requestData.Items)) + return struct{}{}, nil } @@ -632,29 +669,42 @@ allow := true } // validate that the client received a diagnostics notification for the file - select { - case request := <-receivedMessages: - // validate that the diagnostics are correct - var requestData FileDiagnostics + for { + var success bool + select { + case request := <-receivedMessages: + // validate that the diagnostics are correct + var requestData FileDiagnostics - err = json.Unmarshal(*request.Params, &requestData) - if err != nil { - t.Fatalf("failed to unmarshal diagnostics: %s", err) - } + err = json.Unmarshal(*request.Params, &requestData) + if err != nil { + t.Logf("failed to unmarshal diagnostics: %s", err) + break + } - if requestData.URI != mainRegoFileURI { - t.Fatalf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) - } + if requestData.URI != mainRegoFileURI { + t.Logf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) + break + } - if len(requestData.Items) != 1 { - t.Fatalf("expected 1 diagnostics, got %d, %v", len(requestData.Items), requestData) + if len(requestData.Items) != 1 { + t.Logf("expected 1 diagnostics, got %d, %v", len(requestData.Items), requestData) + break + } + + if requestData.Items[0].Code != "opa-fmt" { + t.Logf("expected diagnostic to be opa-fmt, got %s", requestData.Items[0].Code) + break + } + + success = true + case <-time.After(3 * time.Second): + t.Fatalf("timed out waiting for file diagnostics to be sent") } - if requestData.Items[0].Code != "opa-fmt" { - t.Fatalf("expected diagnostic to be opa-fmt, got %s", requestData.Items[0].Code) + if success { + break } - case <-time.After(3 * time.Second): - t.Fatalf("timed out waiting for file diagnostics to be sent") } // User updates config file contents in parent directory that is not @@ -671,26 +721,39 @@ allow := true } // validate that the client received a new, empty diagnostics notification for the file - select { - case request := <-receivedMessages: - // validate that the diagnostics are correct - var requestData FileDiagnostics + for { + var success bool + select { + case request := <-receivedMessages: + // validate that the diagnostics are correct + var requestData FileDiagnostics - err = json.Unmarshal(*request.Params, &requestData) - if err != nil { - t.Fatalf("failed to unmarshal diagnostics: %s", err) - } + err = json.Unmarshal(*request.Params, &requestData) + if err != nil { + t.Logf("failed to unmarshal diagnostics: %s", err) + break + } + + if requestData.URI != mainRegoFileURI { + t.Logf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) + break + } - if requestData.URI != mainRegoFileURI { - t.Fatalf("expected diagnostics to be sent for main.rego, got %s", requestData.URI) + if len(requestData.Items) != 0 { + t.Logf("expected 0 diagnostic, got %d", len(requestData.Items)) + break + } + + success = true + case <-time.After(3 * time.Second): + t.Fatalf("timed out waiting for file diagnostics to be sent") } - if len(requestData.Items) != 0 { - t.Fatalf("expected 0 diagnostic, got %d", len(requestData.Items)) + if success { + break } - case <-time.After(3 * time.Second): - t.Fatalf("timed out waiting for file diagnostics to be sent") } + } func createConnections(