💾 Archived View for source.community › ckaznocha › gemini › raw › main › geminitest › server.go captured on 2024-05-26 at 15:09:52.
⬅️ Previous capture (2021-12-17)
-=-=-=-=-=-=-
package geminitest import ( "crypto/tls" "crypto/x509" "fmt" "net" "sync" "testing" "source.community/ckaznocha/gemini" ) // Server is gemini server listing on a randomly chosen open port. type Server struct { Listener net.Listener TLS *tls.Config Config *gemini.Server certificate *x509.Certificate URL string Addr string wg sync.WaitGroup mu sync.Mutex closed bool } func newLocalListener() net.Listener { l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { if l, err = net.Listen("tcp6", "[::1]:0"); err != nil { panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err)) } } return l } // NewUnstartedServer returns a server which has not been started. func NewUnstartedServer(t *testing.T, handler gemini.Handler) *Server { t.Helper() return &Server{ Listener: newLocalListener(), Config: &gemini.Server{ Handler: handler, LogHandler: func(message string, isError bool) { t.Log(message) }, }, } } // Start starts an unstarted server. func (s *Server) Start() { if s.URL != "" { panic("Server already started") } cert, err := tls.LoadX509KeyPair("testdata/cert.pem", "testdata/key.pem") if err != nil { panic(fmt.Sprintf("httptest: NewTLSServer: %v", err)) } if existingConfig := s.TLS; existingConfig != nil { s.TLS = existingConfig.Clone() } else { s.TLS = new(tls.Config) } if len(s.TLS.Certificates) == 0 { s.TLS.Certificates = []tls.Certificate{cert} } s.certificate, err = x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0]) if err != nil { panic(fmt.Sprintf("httptest: NewTLSServer: %v", err)) } certpool := x509.NewCertPool() certpool.AddCert(s.certificate) s.Listener = tls.NewListener(s.Listener, s.TLS) s.URL = "gemini://" + s.Listener.Addr().String() s.Addr = s.Listener.Addr().String() s.goServe() } func (s *Server) goServe() { s.wg.Add(1) go func() { defer s.wg.Done() if err := s.Config.Serve(s.Listener); err != nil && s.Config.LogHandler != nil { s.Config.LogHandler(err.Error(), true) } }() } // NewServer returns a test server which has been started and is ready to use. func NewServer(t *testing.T, handler gemini.Handler) *Server { t.Helper() ts := NewUnstartedServer(t, handler) ts.Start() return ts } // Close closes the server. func (s *Server) Close() { s.mu.Lock() if !s.closed { s.closed = true if err := s.Listener.Close(); err != nil && s.Config.LogHandler != nil { s.Config.LogHandler(err.Error(), true) } } s.mu.Unlock() s.wg.Wait() }