github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/vcweb/vcstest/vcstest.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package vcstest serves the repository scripts in cmd/go/testdata/vcstest 6 // using the [vcweb] script engine. 7 package vcstest 8 9 import ( 10 "crypto/tls" 11 "crypto/x509" 12 "encoding/pem" 13 "fmt" 14 "io" 15 "log" 16 "net/http" 17 "net/http/httptest" 18 "net/url" 19 "os" 20 "path/filepath" 21 "testing" 22 23 "github.com/go-asm/go/cmd/go/vcs" 24 "github.com/go-asm/go/cmd/go/vcweb" 25 "github.com/go-asm/go/cmd/go/web" 26 "github.com/go-asm/go/testenv" 27 ) 28 29 var Hosts = []string{ 30 "vcs-test.golang.org", 31 } 32 33 type Server struct { 34 vcweb *vcweb.Server 35 workDir string 36 HTTP *httptest.Server 37 HTTPS *httptest.Server 38 } 39 40 // NewServer returns a new test-local vcweb server that serves VCS requests 41 // for modules with paths that begin with "vcs-test.golang.org" using the 42 // scripts in cmd/go/testdata/vcstest. 43 func NewServer() (srv *Server, err error) { 44 if vcs.VCSTestRepoURL != "" { 45 panic("vcs URL hooks already set") 46 } 47 48 scriptDir := filepath.Join(testenv.GOROOT(nil), "src/cmd/go/testdata/vcstest") 49 50 workDir, err := os.MkdirTemp("", "vcstest") 51 if err != nil { 52 return nil, err 53 } 54 defer func() { 55 if err != nil { 56 os.RemoveAll(workDir) 57 } 58 }() 59 60 logger := log.Default() 61 if !testing.Verbose() { 62 logger = log.New(io.Discard, "", log.LstdFlags) 63 } 64 handler, err := vcweb.NewServer(scriptDir, workDir, logger) 65 if err != nil { 66 return nil, err 67 } 68 defer func() { 69 if err != nil { 70 handler.Close() 71 } 72 }() 73 74 srvHTTP := httptest.NewServer(handler) 75 httpURL, err := url.Parse(srvHTTP.URL) 76 if err != nil { 77 return nil, err 78 } 79 defer func() { 80 if err != nil { 81 srvHTTP.Close() 82 } 83 }() 84 85 srvHTTPS := httptest.NewTLSServer(handler) 86 httpsURL, err := url.Parse(srvHTTPS.URL) 87 if err != nil { 88 return nil, err 89 } 90 defer func() { 91 if err != nil { 92 srvHTTPS.Close() 93 } 94 }() 95 96 srv = &Server{ 97 vcweb: handler, 98 workDir: workDir, 99 HTTP: srvHTTP, 100 HTTPS: srvHTTPS, 101 } 102 vcs.VCSTestRepoURL = srv.HTTP.URL 103 vcs.VCSTestHosts = Hosts 104 105 var interceptors []web.Interceptor 106 for _, host := range Hosts { 107 interceptors = append(interceptors, 108 web.Interceptor{Scheme: "http", FromHost: host, ToHost: httpURL.Host, Client: srv.HTTP.Client()}, 109 web.Interceptor{Scheme: "https", FromHost: host, ToHost: httpsURL.Host, Client: srv.HTTPS.Client()}) 110 } 111 web.EnableTestHooks(interceptors) 112 113 fmt.Fprintln(os.Stderr, "vcs-test.golang.org rerouted to "+srv.HTTP.URL) 114 fmt.Fprintln(os.Stderr, "https://vcs-test.golang.org rerouted to "+srv.HTTPS.URL) 115 116 return srv, nil 117 } 118 119 func (srv *Server) Close() error { 120 if vcs.VCSTestRepoURL != srv.HTTP.URL { 121 panic("vcs URL hooks modified before Close") 122 } 123 vcs.VCSTestRepoURL = "" 124 vcs.VCSTestHosts = nil 125 web.DisableTestHooks() 126 127 srv.HTTP.Close() 128 srv.HTTPS.Close() 129 err := srv.vcweb.Close() 130 if rmErr := os.RemoveAll(srv.workDir); err == nil { 131 err = rmErr 132 } 133 return err 134 } 135 136 func (srv *Server) WriteCertificateFile() (string, error) { 137 b := pem.EncodeToMemory(&pem.Block{ 138 Type: "CERTIFICATE", 139 Bytes: srv.HTTPS.Certificate().Raw, 140 }) 141 142 filename := filepath.Join(srv.workDir, "cert.pem") 143 if err := os.WriteFile(filename, b, 0644); err != nil { 144 return "", err 145 } 146 return filename, nil 147 } 148 149 // TLSClient returns an http.Client that can talk to the httptest.Server 150 // whose certificate is written to the given file path. 151 func TLSClient(certFile string) (*http.Client, error) { 152 client := &http.Client{ 153 Transport: http.DefaultTransport.(*http.Transport).Clone(), 154 } 155 156 pemBytes, err := os.ReadFile(certFile) 157 if err != nil { 158 return nil, err 159 } 160 161 certpool := x509.NewCertPool() 162 if !certpool.AppendCertsFromPEM(pemBytes) { 163 return nil, fmt.Errorf("no certificates found in %s", certFile) 164 } 165 client.Transport.(*http.Transport).TLSClientConfig = &tls.Config{ 166 RootCAs: certpool, 167 } 168 169 return client, nil 170 }