github.com/terraform-linters/tflint@v0.51.2-0.20240520175844-3750771571b6/integrationtest/langserver/langserver_test.go (about) 1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "log" 8 "os" 9 "path/filepath" 10 "strings" 11 "testing" 12 13 "github.com/hashicorp/logutils" 14 lsp "github.com/sourcegraph/go-lsp" 15 "github.com/sourcegraph/jsonrpc2" 16 "github.com/terraform-linters/tflint/langserver" 17 "github.com/terraform-linters/tflint/plugin" 18 "github.com/terraform-linters/tflint/tflint" 19 ) 20 21 type jsonrpcMessage struct { 22 JSONRPC string `json:"jsonrpc"` 23 ID int `json:"id,omitempty"` 24 Method string `json:"method"` 25 Params interface{} `json:"params"` 26 } 27 28 func TestMain(m *testing.M) { 29 // Disable the bundled plugin because the `os.Executable()` is go(1) in the tests 30 tflint.DisableBundledPlugin = true 31 defer func() { 32 tflint.DisableBundledPlugin = false 33 }() 34 35 filter := &logutils.LevelFilter{ 36 Levels: []logutils.LogLevel{"TRACE", "DEBUG", "INFO", "WARN", "ERROR"}, 37 MinLevel: logutils.LogLevel(""), 38 Writer: os.Stderr, 39 } 40 log.SetOutput(filter) 41 os.Exit(m.Run()) 42 } 43 44 func startServer(t *testing.T, configPath string) (io.Writer, io.Reader, *plugin.Plugin) { 45 handler, plugin, err := langserver.NewHandler(configPath, tflint.EmptyConfig()) 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 stdin, stdinWriter := io.Pipe() 51 stdoutReader, stdout := io.Pipe() 52 53 var connOpt []jsonrpc2.ConnOpt 54 jsonrpc2.NewConn( 55 context.Background(), 56 jsonrpc2.NewBufferedStream(langserver.NewConn(stdin, stdout), jsonrpc2.VSCodeObjectCodec{}), 57 handler, 58 connOpt..., 59 ) 60 61 return stdinWriter, stdoutReader, plugin 62 } 63 64 func pathToURI(path string) lsp.DocumentURI { 65 path = filepath.ToSlash(path) 66 parts := strings.SplitN(path, "/", 2) 67 68 head := parts[0] 69 if head != "" { 70 head = "/" + head 71 } 72 73 rest := "" 74 if len(parts) > 1 { 75 rest = "/" + parts[1] 76 } 77 78 return lsp.DocumentURI("file://" + head + rest) 79 } 80 81 func shutdownRequest() string { 82 return toJSONRPC2(`{"id":0,"method":"shutdown","params":{},"jsonrpc":"2.0"}`) 83 } 84 85 func exitRequest() string { 86 return toJSONRPC2(`{"id":0,"method":"exit","params":{},"jsonrpc":"2.0"}`) 87 } 88 89 func emptyResponse() string { 90 return toJSONRPC2(`{"id":0,"result":null,"jsonrpc":"2.0"}`) 91 } 92 93 func toJSONRPC2(json string) string { 94 return fmt.Sprintf("Content-Length: %d\r\n\r\n%s", len(json), json) 95 } 96 97 func withinFixtureDir(t *testing.T, dir string, test func(dir string)) { 98 current, err := os.Getwd() 99 if err != nil { 100 t.Fatal(err) 101 } 102 defer func() { 103 if err = os.Chdir(current); err != nil { 104 t.Fatal(err) 105 } 106 }() 107 108 dir, err = filepath.Abs("test-fixtures/" + dir) 109 if err != nil { 110 t.Fatal(err) 111 } 112 test(dir) 113 } 114 115 func withinTempDir(t *testing.T, test func(dir string)) { 116 current, err := os.Getwd() 117 if err != nil { 118 t.Fatal(err) 119 } 120 defer func() { 121 if err = os.Chdir(current); err != nil { 122 t.Fatal(err) 123 } 124 }() 125 126 dir, err := os.MkdirTemp("", "withinTempDir") 127 if err != nil { 128 t.Fatal(err) 129 } 130 defer os.RemoveAll(dir) 131 132 // on macOS MkdirTemp returns a /var/folders/... path 133 // In other contexts these paths are returned with their full /private/var/folders/... path 134 // EvalSymlinks will resolve the /var/folders/... path to the full path 135 dir, err = filepath.EvalSymlinks(dir) 136 if err != nil { 137 t.Fatal(err) 138 } 139 140 test(dir) 141 }