From: Matus Fabian Date: Thu, 10 Apr 2025 14:17:30 +0000 (-0400) Subject: hs-test: http/2 testing with h2spec X-Git-Tag: v25.10-rc0~103 X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F83%2F42783%2F3;p=vpp.git hs-test: http/2 testing with h2spec suite is marked as pending since http plugin is not build with http/2 enabled by default Type: test Change-Id: If13f2add1f418060dae6d493f2cd800f9f734449 Signed-off-by: Matus Fabian --- diff --git a/extras/hs-test/go.mod b/extras/hs-test/go.mod index 4cc24d510cc..db0f7a2ee6f 100644 --- a/extras/hs-test/go.mod +++ b/extras/hs-test/go.mod @@ -11,6 +11,7 @@ require ( github.com/onsi/gomega v1.33.1 github.com/quic-go/quic-go v0.48.2 github.com/sirupsen/logrus v1.9.3 + github.com/summerwind/h2spec v2.2.1+incompatible go.fd.io/govpp v0.10.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -20,6 +21,7 @@ require ( github.com/containerd/log v0.1.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-connections v0.4.0 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -35,6 +37,8 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect github.com/lunixbochs/struc v0.0.0-20200521075829-a4cb8d33dbbe // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect diff --git a/extras/hs-test/go.sum b/extras/hs-test/go.sum index 19a120b3007..11270283d4d 100644 --- a/extras/hs-test/go.sum +++ b/extras/hs-test/go.sum @@ -29,6 +29,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/edwarnicke/exechelper v1.0.3 h1:OY2ocGAITTqnEDvZk0dRQSeMIQvyH0SyL/4ncz+5GeQ= github.com/edwarnicke/exechelper v1.0.3/go.mod h1:R65OUPKns4bgeHkCmfSHbmqLBU8aHZxTgLmEyUBUk4U= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -98,6 +100,11 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -164,6 +171,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/summerwind/h2spec v2.2.1+incompatible h1:Ex8kpG4LjIeudEtfbM892Os2PawIZBsEvukHJcvZHho= +github.com/summerwind/h2spec v2.2.1+incompatible/go.mod h1:eP7IHGVDEe9cbCxRNtmGfII77lBvLgJLNfJjTaKa9sI= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= @@ -230,6 +239,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/extras/hs-test/infra/suite_h2.go b/extras/hs-test/infra/suite_h2.go index 54a373e315b..f05d4510e77 100644 --- a/extras/hs-test/infra/suite_h2.go +++ b/extras/hs-test/infra/suite_h2.go @@ -1,11 +1,21 @@ package hst import ( + "bytes" + "io" + "os" "reflect" "runtime" "strings" + "time" + + "github.com/summerwind/h2spec/spec" . "github.com/onsi/ginkgo/v2" + "github.com/summerwind/h2spec/config" + "github.com/summerwind/h2spec/generic" + "github.com/summerwind/h2spec/hpack" + "github.com/summerwind/h2spec/http2" ) var h2Tests = map[string][]func(s *H2Suite){} @@ -60,7 +70,8 @@ func (s *H2Suite) VppAddr() string { return s.Interfaces.Tap.Peer.Ip4AddressString() } -var _ = PDescribe("Http2Suite", Ordered, ContinueOnFailure, func() { +// Marked as pending since http plugin is not build with http/2 enabled by default +var _ = Describe("Http2Suite", Pending, Ordered, ContinueOnFailure, func() { var s H2Suite BeforeAll(func() { s.SetupSuite() @@ -88,3 +99,250 @@ var _ = PDescribe("Http2Suite", Ordered, ContinueOnFailure, func() { } } }) + +type h2specTest struct { + desc string +} + +var genericTests = []h2specTest{ + {desc: "generic/1/1"}, + {desc: "generic/2/1"}, + {desc: "generic/2/2"}, + {desc: "generic/2/3"}, + {desc: "generic/2/4"}, + {desc: "generic/2/5"}, + // TODO: message framing without content length using END_STREAM flag + // {desc: "generic/3.1/1"}, + // {desc: "generic/3.1/2"}, + // {desc: "generic/3.1/3"}, + {desc: "generic/3.2/1"}, + {desc: "generic/3.2/2"}, + {desc: "generic/3.2/3"}, + // generic/3.3/* PRIORITY is deprecated + // TODO: message framing without content length using END_STREAM flag + // {desc: "generic/3.4/1"}, + {desc: "generic/3.5/1"}, + {desc: "generic/3.7/1"}, + {desc: "generic/3.8/1"}, + // TODO: flow control + //{desc: "generic/3.9/1"}, + //{desc: "generic/3.9/2"}, + // TODO: CONTINUATION + //{desc: "generic/3.10/1"}, + //{desc: "generic/3.10/2"}, + {desc: "generic/4/1"}, + // HEAD method not supported + // {desc: "generic/4/2"}, + // TODO: message framing without content length using END_STREAM flag + // {desc: "generic/4/3"}, + // message framing using trailer section not supported + // {desc: "generic/4/4"}, + {desc: "generic/5/1"}, + {desc: "generic/5/2"}, + {desc: "generic/5/3"}, + {desc: "generic/5/4"}, + {desc: "generic/5/5"}, + {desc: "generic/5/6"}, + {desc: "generic/5/7"}, + {desc: "generic/5/8"}, + {desc: "generic/5/9"}, + {desc: "generic/5/10"}, + {desc: "generic/5/11"}, + {desc: "generic/5/12"}, + {desc: "generic/5/13"}, + {desc: "generic/5/14"}, + {desc: "generic/5/15"}, +} + +var hpackTests = []h2specTest{ + {desc: "hpack/2.3.3/1"}, + {desc: "hpack/4.2/1"}, + {desc: "hpack/5.2/1"}, + {desc: "hpack/5.2/2"}, + {desc: "hpack/5.2/3"}, + {desc: "hpack/6.1/1"}, + {desc: "hpack/6.3/1"}, +} + +var http2Tests = []h2specTest{ + {desc: "http2/3.5/1"}, + // TODO: need to be tested with TLS, otherwise we consider invalid preface as bogus HTTP/1 request + // {desc: "http2/3.5/2"}, + {desc: "http2/4.1/1"}, + {desc: "http2/4.1/2"}, + {desc: "http2/4.1/3"}, + // TODO: message framing without content length using END_STREAM flag + // {desc: "http2/4.2/1"}, + {desc: "http2/4.2/2"}, + {desc: "http2/4.2/3"}, + {desc: "http2/4.3/1"}, + {desc: "http2/4.3/2"}, + {desc: "http2/4.3/3"}, + {desc: "http2/5.1.1/1"}, + {desc: "http2/5.1.1/2"}, + // TODO: flow control + // {desc: "http2/5.1.2/1"}, + {desc: "http2/5.1/1"}, + {desc: "http2/5.1/2"}, + // TODO: flow control + // {desc: "http2/5.1/3"}, + // TODO: CONTINUATION + // {desc: "http2/5.1/4"}, + {desc: "http2/5.1/5"}, + {desc: "http2/5.1/6"}, + // TODO: CONTINUATION + // {desc: "http2/5.1/7"}, + {desc: "http2/5.1/8"}, + {desc: "http2/5.1/9"}, + // TODO: CONTINUATION + // {desc: "http2/5.1/10"}, + {desc: "http2/5.1/11"}, + {desc: "http2/5.1/12"}, + // TODO: CONTINUATION + // {desc: "http2/5.1/13"}, + // http2/5.3.1/* PRIORITY is deprecated + {desc: "http2/5.4.1/1"}, + {desc: "http2/5.4.1/2"}, + {desc: "http2/5.5/1"}, + // TODO: CONTINUATION + // {desc: "http2/5.5/2"}, + {desc: "http2/6.1/1"}, + {desc: "http2/6.1/2"}, + // TODO: http_static url handler POST expect data immediately + // {desc: "http2/6.1/3"}, + {desc: "http2/6.2/1"}, + {desc: "http2/6.2/2"}, + {desc: "http2/6.2/3"}, + {desc: "http2/6.2/4"}, + // http2/6.3/* PRIORITY is deprecated + {desc: "http2/6.4/1"}, + {desc: "http2/6.4/2"}, + {desc: "http2/6.4/3"}, + {desc: "http2/6.5.2/1"}, + {desc: "http2/6.5.2/2"}, + {desc: "http2/6.5.2/3"}, + {desc: "http2/6.5.2/4"}, + {desc: "http2/6.5.2/5"}, + // TODO: flow control + // {desc: "http2/6.5.3/1"}, + {desc: "http2/6.5.3/2"}, + {desc: "http2/6.5/1"}, + {desc: "http2/6.5/2"}, + {desc: "http2/6.5/3"}, + {desc: "http2/6.7/1"}, + {desc: "http2/6.7/2"}, + {desc: "http2/6.7/3"}, + {desc: "http2/6.7/4"}, + {desc: "http2/6.8/1"}, + // TODO: flow control + // {desc: "http2/6.9.1/1"}, + // {desc: "http2/6.9.1/2"}, + // {desc: "http2/6.9.1/3"}, + // {desc: "http2/6.9.2/1"}, + // {desc: "http2/6.9.2/2"}, + // {desc: "http2/6.9.2/3"}, + // {desc: "http2/6.9/1"}, + // {desc: "http2/6.9/2"}, + // {desc: "http2/6.9/3"}, + // TODO: CONTINUATION + // {desc: "http2/6.10/1"}, + // {desc: "http2/6.10/2"}, + // {desc: "http2/6.10/3"}, + // {desc: "http2/6.10/4"}, + // {desc: "http2/6.10/5"}, + // {desc: "http2/6.10/6"}, + {desc: "http2/7/1"}, + // TODO: message framing without content length using END_STREAM flag + // {desc: "http2/7/2"}, + {desc: "http2/8.1.2.1/1"}, + {desc: "http2/8.1.2.1/2"}, + {desc: "http2/8.1.2.1/3"}, + {desc: "http2/8.1.2.1/4"}, + {desc: "http2/8.1.2.2/1"}, + {desc: "http2/8.1.2.2/2"}, + {desc: "http2/8.1.2.3/1"}, + {desc: "http2/8.1.2.3/2"}, + {desc: "http2/8.1.2.3/3"}, + {desc: "http2/8.1.2.3/4"}, + {desc: "http2/8.1.2.3/5"}, + {desc: "http2/8.1.2.3/6"}, + {desc: "http2/8.1.2.3/7"}, + // TODO: http_static url handler POST expect data immediately + // {desc: "http2/8.1.2.6/1"}, + {desc: "http2/8.1.2.6/2"}, + {desc: "http2/8.1.2/1"}, + {desc: "http2/8.1/1"}, + {desc: "http2/8.2/1"}, +} + +var specs = []struct { + tg *spec.TestGroup + tests []h2specTest +}{ + {generic.Spec(), genericTests}, + {hpack.Spec(), hpackTests}, + {http2.Spec(), http2Tests}, +} + +// Marked as pending since http plugin is not build with http/2 enabled by default +var _ = Describe("H2SpecSuite", Pending, Ordered, ContinueOnFailure, func() { + var s H2Suite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for _, spec := range specs { + for _, test := range spec.tests { + test := test + testName := "http2_test.go/h2spec_" + strings.ReplaceAll(test.desc, "/", "_") + It(testName, func(ctx SpecContext) { + s.Log(testName + ": BEGIN") + vpp := s.Containers.Vpp.VppInstance + serverAddress := s.VppAddr() + s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug 2")) + s.Log(vpp.Vppctl("test-url-handler enable")) + conf := &config.Config{ + Host: serverAddress, + Port: 80, + Path: "/test1", + Timeout: time.Second * 5, + MaxHeaderLen: 1024, + TLS: false, + Insecure: true, + Sections: []string{test.desc}, + Verbose: true, + } + + // capture h2spec output so it will be in log + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + spec.tg.Test(conf) + + oChan := make(chan string) + go func() { + var buf bytes.Buffer + io.Copy(&buf, r) + oChan <- buf.String() + }() + + // restore to normal state + w.Close() + os.Stdout = oldStdout + o := <-oChan + s.Log(o) + s.AssertEqual(0, spec.tg.FailedCount) + }) + } + } +})