hs-test: http/2 testing with h2spec 83/42783/3
authorMatus Fabian <matfabia@cisco.com>
Thu, 10 Apr 2025 14:17:30 +0000 (10:17 -0400)
committerFlorin Coras <florin.coras@gmail.com>
Fri, 11 Apr 2025 18:58:15 +0000 (18:58 +0000)
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 <matfabia@cisco.com>
extras/hs-test/go.mod
extras/hs-test/go.sum
extras/hs-test/infra/suite_h2.go

index 4cc24d5..db0f7a2 100644 (file)
@@ -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
index 19a120b..1127028 100644 (file)
@@ -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=
index 54a373e..f05d451 100644 (file)
@@ -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)
+                       })
+               }
+       }
+})