h2spec/spec/server.go

127 строки
2.4 KiB
Go

package spec
import (
"crypto/tls"
"fmt"
"net"
"time"
"github.com/summerwind/h2spec/config"
"github.com/summerwind/h2spec/log"
"golang.org/x/net/http2"
)
type Server struct {
listeners []net.Listener
config *config.Config
spec *ClientTestGroup
}
func Listen(c *config.Config, tg *ClientTestGroup) (*Server, error) {
testCases := make(map[int]*ClientTestCase)
tg.ClientTestCases(testCases, c, c.FromPort)
server := &Server{
listeners: make([]net.Listener, 0),
config: c,
}
for port, tc := range testCases {
var err error
var listener net.Listener
addr := fmt.Sprintf("%s:%d", c.Host, port)
if c.TLS {
tlsConfig, err := c.TLSConfig()
if err != nil {
return nil, err
}
listener, err = tls.Listen("tcp", addr, tlsConfig)
if err != nil {
return nil, err
}
} else {
listener, err = net.Listen("tcp", addr)
if err != nil {
return nil, err
}
}
server.listeners = append(server.listeners, listener)
go server.RunListener(listener, tc)
}
return server, nil
}
func (server *Server) RunListener(listener net.Listener, tc *ClientTestCase) {
for {
baseConn, err := listener.Accept()
if err != nil {
log.Println(err)
continue
}
conn, err := Accept(server.config, baseConn)
if err != nil {
log.Println(err)
continue
}
go server.handleConn(conn, tc)
}
}
func (server *Server) Close() {
for _, listener := range server.listeners {
listener.Close()
}
}
func (server *Server) handleConn(conn *Conn, tc *ClientTestCase) {
if server.config.IsBrowserMode() {
// Only log here when browser mode
log.Println(groupNames(tc.Parent))
}
start := time.Now()
err := tc.Run(server.config, conn)
end := time.Now()
// Ensure that connection had been closed
go closeConn(conn)
tr := NewClientTestResult(tc, err, end.Sub(start))
if server.config.IsBrowserMode() {
// Only log here when browser mode
tr.Print()
}
if tc.Result != nil {
tc.Parent.IncRecursive(tc.Result.Failed, tc.Result.Skipped, -1)
}
tc.Result = tr
tc.Parent.IncRecursive(tc.Result.Failed, tc.Result.Skipped, 1)
}
func groupNames(tg *ClientTestGroup) string {
if tg.IsRoot() {
return tg.Title()
}
parentGroupNames := groupNames(tg.Parent)
return fmt.Sprintf("%s -> %s", parentGroupNames, tg.Title())
}
func closeConn(conn *Conn) {
if !conn.Closed {
conn.WriteGoAway(0, http2.ErrCodeNo, make([]byte, 0))
time.Sleep(1 * time.Second)
}
conn.Close()
}