forked from quic-go/quic-go
add integration tests with the quic_server
This commit is contained in:
committed by
Lucas Clemente
parent
8b351a9b7e
commit
fb127ecfd5
@@ -42,7 +42,8 @@ var (
|
||||
dataMan dataManager
|
||||
port string
|
||||
uploadDir string
|
||||
clientPath string
|
||||
clientPath string // path of the quic_client
|
||||
serverPath string // path of the quic_server
|
||||
|
||||
docker *gexec.Session
|
||||
)
|
||||
@@ -78,6 +79,7 @@ var _ = BeforeEach(func() {
|
||||
Fail("Failed to get current path")
|
||||
}
|
||||
clientPath = filepath.Join(thisfile, fmt.Sprintf("../../../quic-clients/client-%s-debug", runtime.GOOS))
|
||||
serverPath = filepath.Join(thisfile, fmt.Sprintf("../../../quic-clients/server-%s-debug", runtime.GOOS))
|
||||
})
|
||||
|
||||
var _ = AfterEach(func() {
|
||||
|
||||
213
integrationtests/server_test.go
Normal file
213
integrationtests/server_test.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package integrationtests
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
mrand "math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/h2quic"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/onsi/gomega/gexec"
|
||||
)
|
||||
|
||||
var _ = Describe("Server tests", func() {
|
||||
mrand.Seed(time.Now().UnixNano())
|
||||
|
||||
var (
|
||||
serverPort string
|
||||
tmpDir string
|
||||
session *Session
|
||||
client *http.Client
|
||||
)
|
||||
|
||||
generateCA := func() (*rsa.PrivateKey, *x509.Certificate) {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
t := time.Now().Add(-time.Minute)
|
||||
templateRoot := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: t,
|
||||
NotAfter: t.Add(time.Hour),
|
||||
IsCA: true,
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, templateRoot, templateRoot, &key.PublicKey, key)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cert, err := x509.ParseCertificate(certDER)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
return key, cert
|
||||
}
|
||||
|
||||
// prepare the file such that it can be by the quic_server
|
||||
// some HTTP headers neeed to be prepended, see https://www.chromium.org/quic/playing-with-quic
|
||||
createDownloadFile := func(filename string, data []byte) {
|
||||
dataDir := filepath.Join(tmpDir, "quic.clemente.io")
|
||||
err := os.Mkdir(dataDir, 0777)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
f, err := os.Create(filepath.Join(dataDir, filename))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer f.Close()
|
||||
_, err = f.Write([]byte("HTTP/1.1 200 OK\n"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = f.Write([]byte("Content-Type: text/html\n"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = f.Write([]byte("X-Original-Url: https://quic.clemente.io:" + serverPort + "/" + filename + "\n"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = f.Write([]byte("Content-Length: " + strconv.Itoa(len(data)) + "\n\n"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = f.Write(data)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
// download files must be create *before* the quic_server is started
|
||||
// the quic_server reads its data dir on startup, and only serves those files that were already present then
|
||||
startServer := func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
var err error
|
||||
command := exec.Command(
|
||||
serverPath,
|
||||
"--quic_response_cache_dir="+filepath.Join(tmpDir, "quic.clemente.io"),
|
||||
"--key_file="+filepath.Join(tmpDir, "key.pkcs8"),
|
||||
"--certificate_file="+filepath.Join(tmpDir, "cert.pem"),
|
||||
"--port="+serverPort,
|
||||
)
|
||||
session, err = Start(command, GinkgoWriter, GinkgoWriter)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}()
|
||||
}
|
||||
|
||||
stopServer := func() {
|
||||
session.Kill()
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
serverPort = strconv.Itoa(20000 + int(mrand.Int31n(10000)))
|
||||
|
||||
var err error
|
||||
tmpDir, err = ioutil.TempDir("", "quic-server-certs")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// generate an RSA key pair for the server
|
||||
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// save the private key in PKCS8 format to disk (required by quic_server)
|
||||
pkcs8key, err := asn1.Marshal(struct { // copied from the x509 package
|
||||
Version int
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
PrivateKey []byte
|
||||
}{
|
||||
PrivateKey: x509.MarshalPKCS1PrivateKey(key),
|
||||
Algo: pkix.AlgorithmIdentifier{
|
||||
Algorithm: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1},
|
||||
Parameters: asn1.RawValue{Tag: 5},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
f, err := os.Create(filepath.Join(tmpDir, "key.pkcs8"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = f.Write(pkcs8key)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
f.Close()
|
||||
|
||||
// generate a Certificate Authority
|
||||
// this CA is used to sign the server's key
|
||||
// it is set as a valid CA in the QUIC client
|
||||
rootKey, CACert := generateCA()
|
||||
template := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(time.Hour),
|
||||
Subject: pkix.Name{CommonName: "quic.clemente.io"},
|
||||
}
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, template, CACert, &key.PublicKey, rootKey)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// save the certificate to disk
|
||||
certOut, err := os.Create(filepath.Join(tmpDir, "cert.pem"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
||||
certOut.Close()
|
||||
|
||||
// prepare the h2quic.client
|
||||
certPool := x509.NewCertPool()
|
||||
certPool.AddCert(CACert)
|
||||
client = &http.Client{
|
||||
Transport: &h2quic.QuicRoundTripper{
|
||||
TLSClientConfig: &tls.Config{RootCAs: certPool},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(tmpDir).ToNot(BeEmpty())
|
||||
err := os.RemoveAll(tmpDir)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
tmpDir = ""
|
||||
})
|
||||
|
||||
It("downloads a hello", func(done Done) {
|
||||
data := []byte("Hello world!\n")
|
||||
createDownloadFile("hello", data)
|
||||
|
||||
startServer()
|
||||
defer stopServer()
|
||||
|
||||
rsp, err := client.Get("https://quic.clemente.io:" + serverPort + "/hello")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rsp.StatusCode).To(Equal(200))
|
||||
body, err := ioutil.ReadAll(rsp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(body).To(Equal(data))
|
||||
close(done)
|
||||
}, 5)
|
||||
|
||||
It("downloads a small file", func(done Done) {
|
||||
dataMan.GenerateData(dataLen)
|
||||
data := dataMan.GetData()
|
||||
createDownloadFile("file.dat", data)
|
||||
|
||||
startServer()
|
||||
defer stopServer()
|
||||
|
||||
rsp, err := client.Get("https://quic.clemente.io:" + serverPort + "/file.dat")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rsp.StatusCode).To(Equal(200))
|
||||
body, err := ioutil.ReadAll(rsp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(body).To(Equal(data))
|
||||
close(done)
|
||||
}, 5)
|
||||
|
||||
It("downloads a large file", func(done Done) {
|
||||
dataMan.GenerateData(dataLongLen)
|
||||
data := dataMan.GetData()
|
||||
createDownloadFile("file.dat", data)
|
||||
|
||||
startServer()
|
||||
defer stopServer()
|
||||
|
||||
rsp, err := client.Get("https://quic.clemente.io:" + serverPort + "/file.dat")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rsp.StatusCode).To(Equal(200))
|
||||
body, err := ioutil.ReadAll(rsp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(body).To(Equal(data))
|
||||
close(done)
|
||||
}, 20)
|
||||
})
|
||||
Reference in New Issue
Block a user