Skip to content

Commit c0348af

Browse files
authoredJul 23, 2024··
lsp: Address bug in multi file test case (#933)
Fixes #931 Signed-off-by: Charlie Egan <charlie@styra.com>
1 parent 2a29cd2 commit c0348af

File tree

1 file changed

+61
-50
lines changed

1 file changed

+61
-50
lines changed
 

‎internal/lsp/server_test.go

+61-50
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@ import (
55
"context"
66
"encoding/json"
77
"fmt"
8+
"io"
89
"net"
910
"os"
1011
"path/filepath"
12+
"slices"
13+
"sort"
14+
"strings"
1115
"testing"
1216
"time"
1317

1418
"github.com/sourcegraph/jsonrpc2"
1519

16-
"github.com/styrainc/regal/internal/lsp/cache"
1720
"github.com/styrainc/regal/internal/lsp/types"
1821
)
1922

2023
const mainRegoFileName = "/main.rego"
2124

22-
const defaultTimeout = 3 * time.Second
25+
// defaultTimeout is set based on the investigation done as part of
26+
// https://github.com/StyraInc/regal/issues/931. 20 seconds is 10x the
27+
// maximum time observed for an operation to complete.
28+
const defaultTimeout = 20 * time.Second
2329

2430
const defaultBufferedChannelSize = 5
2531

@@ -87,7 +93,7 @@ allow = true
8793
defer cancel()
8894

8995
ls := NewLanguageServer(&LanguageServerOptions{
90-
ErrorLog: os.Stderr,
96+
ErrorLog: newTestLogger(t),
9197
})
9298
go ls.StartDiagnosticsWorker(ctx)
9399
go ls.StartConfigWorker(ctx)
@@ -331,7 +337,7 @@ ignore:
331337
defer cancel()
332338

333339
ls := NewLanguageServer(&LanguageServerOptions{
334-
ErrorLog: os.Stderr,
340+
ErrorLog: newTestLogger(t),
335341
})
336342
go ls.StartDiagnosticsWorker(ctx)
337343
go ls.StartConfigWorker(ctx)
@@ -340,30 +346,29 @@ ignore:
340346
adminsFileMessages := make(chan types.FileDiagnostics, defaultBufferedChannelSize)
341347
ignoredFileMessages := make(chan types.FileDiagnostics, defaultBufferedChannelSize)
342348
clientHandler := func(_ context.Context, _ *jsonrpc2.Conn, req *jsonrpc2.Request) (result any, err error) {
343-
if req.Method == "textDocument/publishDiagnostics" {
344-
var requestData types.FileDiagnostics
345-
346-
err = json.Unmarshal(*req.Params, &requestData)
347-
if err != nil {
348-
t.Fatalf("failed to unmarshal diagnostics: %s", err)
349-
}
349+
if req.Method != "textDocument/publishDiagnostics" {
350+
t.Log("unexpected request method:", req.Method)
350351

351-
if requestData.URI == authzRegoURI {
352-
authzFileMessages <- requestData
353-
}
352+
return struct{}{}, nil
353+
}
354354

355-
if requestData.URI == adminsRegoURI {
356-
adminsFileMessages <- requestData
357-
}
355+
var requestData types.FileDiagnostics
358356

359-
if requestData.URI == ignoredRegoURI {
360-
ignoredFileMessages <- requestData
361-
}
362-
363-
return struct{}{}, nil
357+
err = json.Unmarshal(*req.Params, &requestData)
358+
if err != nil {
359+
t.Fatalf("failed to unmarshal diagnostics: %s", err)
364360
}
365361

366-
t.Fatalf("unexpected request: %v", req)
362+
switch requestData.URI {
363+
case authzRegoURI:
364+
authzFileMessages <- requestData
365+
case adminsRegoURI:
366+
adminsFileMessages <- requestData
367+
case ignoredRegoURI:
368+
ignoredFileMessages <- requestData
369+
default:
370+
t.Logf("unexpected diagnostics for file: %s", requestData.URI)
371+
}
367372

368373
return struct{}{}, nil
369374
}
@@ -464,7 +469,7 @@ allow if input.user in admins.users
464469
case diags := <-authzFileMessages:
465470
success = testRequestDataCodes(t, diags, authzRegoURI, []string{})
466471
case <-timeout.C:
467-
t.Fatalf("timed out waiting for file diagnostics to be sent")
472+
t.Fatalf("timed out waiting for authz.rego diagnostics to be sent")
468473
}
469474

470475
if success {
@@ -483,7 +488,7 @@ allow if input.user in admins.users
483488
case requestData := <-adminsFileMessages:
484489
success = testRequestDataCodes(t, requestData, adminsRegoURI, []string{"use-assignment-operator"})
485490
case <-timeout.C:
486-
t.Fatalf("timed out waiting for file diagnostics to be sent")
491+
t.Fatalf("timed out waiting for admins.rego diagnostics to be sent")
487492
}
488493

489494
if success {
@@ -496,9 +501,9 @@ allow if input.user in admins.users
496501
func TestProcessBuiltinUpdateExitsOnMissingFile(t *testing.T) {
497502
t.Parallel()
498503

499-
ls := LanguageServer{
500-
cache: cache.NewCache(),
501-
}
504+
ls := NewLanguageServer(&LanguageServerOptions{
505+
ErrorLog: newTestLogger(t),
506+
})
502507

503508
err := ls.processHoverContentUpdate(context.Background(), "file://missing.rego", "foo")
504509
if err != nil {
@@ -571,7 +576,7 @@ allow := true
571576
defer cancel()
572577

573578
ls := NewLanguageServer(&LanguageServerOptions{
574-
ErrorLog: os.Stderr,
579+
ErrorLog: newTestLogger(t),
575580
})
576581
go ls.StartDiagnosticsWorker(ctx)
577582
go ls.StartConfigWorker(ctx)
@@ -683,31 +688,20 @@ func testRequestDataCodes(t *testing.T, requestData types.FileDiagnostics, fileU
683688
return false
684689
}
685690

686-
if len(requestData.Items) != len(codes) {
687-
t.Log("expected", len(codes), "diagnostics, got", len(requestData.Items))
688-
689-
return false
691+
// Extract the codes from requestData.Items
692+
requestCodes := make([]string, len(requestData.Items))
693+
for i, item := range requestData.Items {
694+
requestCodes[i] = item.Code
690695
}
691696

692-
for _, v := range codes {
693-
found := false
694-
foundItems := make([]string, 0, len(requestData.Items))
695-
696-
for _, i := range requestData.Items {
697-
foundItems = append(foundItems, i.Code)
697+
// Sort both slices
698+
sort.Strings(requestCodes)
699+
sort.Strings(codes)
698700

699-
if i.Code == v {
700-
found = true
701+
if !slices.Equal(requestCodes, codes) {
702+
t.Logf("expected items: %v, got: %v", codes, requestCodes)
701703

702-
break
703-
}
704-
}
705-
706-
if !found {
707-
t.Log("expected diagnostic", v, "not found in", foundItems)
708-
709-
return false
710-
}
704+
return false
711705
}
712706

713707
return true
@@ -740,3 +734,20 @@ func createConnections(
740734

741735
return connServer, connClient, cleanup
742736
}
737+
738+
// NewTestLogger returns an io.Writer that logs to the given testing.T.
739+
func newTestLogger(t *testing.T) io.Writer {
740+
t.Helper()
741+
742+
return &testLogger{t: t}
743+
}
744+
745+
type testLogger struct {
746+
t *testing.T
747+
}
748+
749+
func (tl *testLogger) Write(p []byte) (n int, err error) {
750+
tl.t.Log(strings.TrimSpace(string(p)))
751+
752+
return len(p), nil
753+
}

0 commit comments

Comments
 (0)
Please sign in to comment.