Skip to content
Snippets Groups Projects
Commit de449107 authored by Carl Mastrangelo's avatar Carl Mastrangelo
Browse files

Add HTTP/2 Interop tests to be run

parent 5cd55dd4
No related branches found
No related tags found
No related merge requests found
File added
...@@ -2,15 +2,38 @@ package http2interop ...@@ -2,15 +2,38 @@ package http2interop
import ( import (
"crypto/tls" "crypto/tls"
"crypto/x509"
"fmt" "fmt"
"io" "io"
"log" "net"
"testing"
"time"
) )
const ( const (
Preface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" Preface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
) )
var (
defaultTimeout = 1 * time.Second
)
type HTTP2InteropCtx struct {
// Inputs
ServerHost string
ServerPort int
UseTLS bool
UseTestCa bool
ServerHostnameOverride string
T *testing.T
// Derived
serverSpec string
authority string
rootCAs *x509.CertPool
}
func parseFrame(r io.Reader) (Frame, error) { func parseFrame(r io.Reader) (Frame, error) {
fh := FrameHeader{} fh := FrameHeader{}
if err := fh.Parse(r); err != nil { if err := fh.Parse(r); err != nil {
...@@ -49,22 +72,8 @@ func streamFrame(w io.Writer, f Frame) error { ...@@ -49,22 +72,8 @@ func streamFrame(w io.Writer, f Frame) error {
return nil return nil
} }
func getHttp2Conn(addr string) (*tls.Conn, error) { func testClientShortSettings(ctx *HTTP2InteropCtx, length int) error {
config := &tls.Config{ c, err := connect(ctx)
InsecureSkipVerify: true,
NextProtos: []string{"h2"},
}
conn, err := tls.Dial("tcp", addr, config)
if err != nil {
return nil, err
}
return conn, nil
}
func testClientShortSettings(addr string, length int) error {
c, err := getHttp2Conn(addr)
if err != nil { if err != nil {
return err return err
} }
...@@ -82,22 +91,22 @@ func testClientShortSettings(addr string, length int) error { ...@@ -82,22 +91,22 @@ func testClientShortSettings(addr string, length int) error {
Data: make([]byte, length), Data: make([]byte, length),
} }
if err := streamFrame(c, sf); err != nil { if err := streamFrame(c, sf); err != nil {
ctx.T.Log("Unable to stream frame", sf)
return err return err
} }
for { for {
frame, err := parseFrame(c) if _, err := parseFrame(c); err != nil {
if err != nil { ctx.T.Log("Unable to parse frame")
return err return err
} }
log.Println(frame)
} }
return nil return nil
} }
func testClientPrefaceWithStreamId(addr string) error { func testClientPrefaceWithStreamId(ctx *HTTP2InteropCtx) error {
c, err := getHttp2Conn(addr) c, err := connect(ctx)
if err != nil { if err != nil {
return err return err
} }
...@@ -119,18 +128,16 @@ func testClientPrefaceWithStreamId(addr string) error { ...@@ -119,18 +128,16 @@ func testClientPrefaceWithStreamId(addr string) error {
} }
for { for {
frame, err := parseFrame(c) if _, err := parseFrame(c); err != nil {
if err != nil {
return err return err
} }
log.Println(frame)
} }
return nil return nil
} }
func testUnknownFrameType(addr string) error { func testUnknownFrameType(ctx *HTTP2InteropCtx) error {
c, err := getHttp2Conn(addr) c, err := connect(ctx)
if err != nil { if err != nil {
return err return err
} }
...@@ -143,6 +150,7 @@ func testUnknownFrameType(addr string) error { ...@@ -143,6 +150,7 @@ func testUnknownFrameType(addr string) error {
// Send some settings, which are part of the client preface // Send some settings, which are part of the client preface
sf := &SettingsFrame{} sf := &SettingsFrame{}
if err := streamFrame(c, sf); err != nil { if err := streamFrame(c, sf); err != nil {
ctx.T.Log("Unable to stream frame", sf)
return err return err
} }
...@@ -154,6 +162,7 @@ func testUnknownFrameType(addr string) error { ...@@ -154,6 +162,7 @@ func testUnknownFrameType(addr string) error {
}, },
} }
if err := streamFrame(c, fh); err != nil { if err := streamFrame(c, fh); err != nil {
ctx.T.Log("Unable to stream frame", fh)
return err return err
} }
} }
...@@ -162,12 +171,14 @@ func testUnknownFrameType(addr string) error { ...@@ -162,12 +171,14 @@ func testUnknownFrameType(addr string) error {
Data: []byte("01234567"), Data: []byte("01234567"),
} }
if err := streamFrame(c, pf); err != nil { if err := streamFrame(c, pf); err != nil {
ctx.T.Log("Unable to stream frame", sf)
return err return err
} }
for { for {
frame, err := parseFrame(c) frame, err := parseFrame(c)
if err != nil { if err != nil {
ctx.T.Log("Unable to parse frame")
return err return err
} }
if npf, ok := frame.(*PingFrame); !ok { if npf, ok := frame.(*PingFrame); !ok {
...@@ -183,8 +194,8 @@ func testUnknownFrameType(addr string) error { ...@@ -183,8 +194,8 @@ func testUnknownFrameType(addr string) error {
return nil return nil
} }
func testShortPreface(addr string, prefacePrefix string) error { func testShortPreface(ctx *HTTP2InteropCtx, prefacePrefix string) error {
c, err := getHttp2Conn(addr) c, err := connect(ctx)
if err != nil { if err != nil {
return err return err
} }
...@@ -201,17 +212,15 @@ func testShortPreface(addr string, prefacePrefix string) error { ...@@ -201,17 +212,15 @@ func testShortPreface(addr string, prefacePrefix string) error {
return err return err
} }
func testTLSMaxVersion(addr string, version uint16) error { func testTLSMaxVersion(ctx *HTTP2InteropCtx, version uint16) error {
config := &tls.Config{ config := buildTlsConfig(ctx)
InsecureSkipVerify: true, config.MaxVersion = version
NextProtos: []string{"h2"}, conn, err := connectWithTls(ctx, config)
MaxVersion: version,
}
conn, err := tls.Dial("tcp", addr, config)
if err != nil { if err != nil {
return err return err
} }
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(defaultTimeout))
buf := make([]byte, 256) buf := make([]byte, 256)
if n, err := conn.Read(buf); err != nil { if n, err := conn.Read(buf); err != nil {
...@@ -223,16 +232,15 @@ func testTLSMaxVersion(addr string, version uint16) error { ...@@ -223,16 +232,15 @@ func testTLSMaxVersion(addr string, version uint16) error {
return nil return nil
} }
func testTLSApplicationProtocol(addr string) error { func testTLSApplicationProtocol(ctx *HTTP2InteropCtx) error {
config := &tls.Config{ config := buildTlsConfig(ctx)
InsecureSkipVerify: true, config.NextProtos = []string{"h2c"}
NextProtos: []string{"h2c"}, conn, err := connectWithTls(ctx, config)
}
conn, err := tls.Dial("tcp", addr, config)
if err != nil { if err != nil {
return err return err
} }
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(defaultTimeout))
buf := make([]byte, 256) buf := make([]byte, 256)
if n, err := conn.Read(buf); err != nil { if n, err := conn.Read(buf); err != nil {
...@@ -243,3 +251,48 @@ func testTLSApplicationProtocol(addr string) error { ...@@ -243,3 +251,48 @@ func testTLSApplicationProtocol(addr string) error {
} }
return nil return nil
} }
func connect(ctx *HTTP2InteropCtx) (net.Conn, error) {
var conn net.Conn
var err error
if !ctx.UseTLS {
conn, err = connectWithoutTls(ctx)
} else {
config := buildTlsConfig(ctx)
conn, err = connectWithTls(ctx, config)
}
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(defaultTimeout))
return conn, nil
}
func buildTlsConfig(ctx *HTTP2InteropCtx) *tls.Config {
return &tls.Config{
RootCAs: ctx.rootCAs,
NextProtos: []string{"h2"},
ServerName: ctx.authority,
MinVersion: tls.VersionTLS12,
// TODO(carl-mastrangelo): remove this once all test certificates have been updated.
InsecureSkipVerify: true,
}
}
func connectWithoutTls(ctx *HTTP2InteropCtx) (net.Conn, error) {
conn, err := net.DialTimeout("tcp", ctx.serverSpec, defaultTimeout)
if err != nil {
return nil, err
}
return conn, nil
}
func connectWithTls(ctx *HTTP2InteropCtx, config *tls.Config) (*tls.Conn, error) {
conn, err := connectWithoutTls(ctx)
if err != nil {
return nil, err
}
return tls.Client(conn, config), nil
}
...@@ -2,46 +2,117 @@ package http2interop ...@@ -2,46 +2,117 @@ package http2interop
import ( import (
"crypto/tls" "crypto/tls"
"crypto/x509"
"strings"
"flag" "flag"
"fmt"
"io" "io"
"io/ioutil"
"os" "os"
"strconv"
"testing" "testing"
) )
var ( var (
serverSpec = flag.String("spec", ":50051", "The server spec to test") serverHost = flag.String("server_host", "", "The host to test")
serverPort = flag.Int("server_port", 443, "The port to test")
useTls = flag.Bool("use_tls", true, "Should TLS tests be run")
// TODO: implement
testCase = flag.String("test_case", "", "What test cases to run")
// The rest of these are unused, but present to fulfill the client interface
serverHostOverride = flag.String("server_host_override", "", "Unused")
useTestCa = flag.Bool("use_test_ca", false, "Unused")
defaultServiceAccount = flag.String("default_service_account", "", "Unused")
oauthScope = flag.String("oauth_scope", "", "Unused")
serviceAccountKeyFile = flag.String("service_account_key_file", "", "Unused")
) )
func InteropCtx(t *testing.T) *HTTP2InteropCtx {
ctx := &HTTP2InteropCtx{
ServerHost: *serverHost,
ServerPort: *serverPort,
ServerHostnameOverride: *serverHostOverride,
UseTLS: *useTls,
UseTestCa: *useTestCa,
T: t,
}
ctx.serverSpec = ctx.ServerHost
if ctx.ServerPort != -1 {
ctx.serverSpec += ":" + strconv.Itoa(ctx.ServerPort)
}
if ctx.ServerHostnameOverride == "" {
ctx.authority = ctx.ServerHost
} else {
ctx.authority = ctx.ServerHostnameOverride
}
if ctx.UseTestCa {
// It would be odd if useTestCa was true, but not useTls. meh
certData, err := ioutil.ReadFile("src/core/tsi/test_creds/ca.pem")
if err != nil {
t.Fatal(err)
}
ctx.rootCAs = x509.NewCertPool()
if !ctx.rootCAs.AppendCertsFromPEM(certData) {
t.Fatal(fmt.Errorf("Unable to parse pem data"))
}
}
return ctx
}
func (ctx *HTTP2InteropCtx) Close() error {
// currently a noop
return nil
}
func TestShortPreface(t *testing.T) { func TestShortPreface(t *testing.T) {
ctx := InteropCtx(t)
for i := 0; i < len(Preface)-1; i++ { for i := 0; i < len(Preface)-1; i++ {
if err := testShortPreface(*serverSpec, Preface[:i]+"X"); err != io.EOF { if err := testShortPreface(ctx, Preface[:i]+"X"); err != io.EOF {
t.Error("Expected an EOF but was", err) t.Error("Expected an EOF but was", err)
} }
} }
} }
func TestUnknownFrameType(t *testing.T) { func TestUnknownFrameType(t *testing.T) {
if err := testUnknownFrameType(*serverSpec); err != nil { ctx := InteropCtx(t)
if err := testUnknownFrameType(ctx); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestTLSApplicationProtocol(t *testing.T) { func TestTLSApplicationProtocol(t *testing.T) {
if err := testTLSApplicationProtocol(*serverSpec); err != io.EOF { ctx := InteropCtx(t)
t.Fatal("Expected an EOF but was", err) err := testTLSApplicationProtocol(ctx);
} matchError(t, err, "EOF")
} }
func TestTLSMaxVersion(t *testing.T) { func TestTLSMaxVersion(t *testing.T) {
if err := testTLSMaxVersion(*serverSpec, tls.VersionTLS11); err != io.EOF { ctx := InteropCtx(t)
t.Fatal("Expected an EOF but was", err) err := testTLSMaxVersion(ctx, tls.VersionTLS11);
} matchError(t, err, "EOF", "server selected unsupported protocol")
} }
func TestClientPrefaceWithStreamId(t *testing.T) { func TestClientPrefaceWithStreamId(t *testing.T) {
if err := testClientPrefaceWithStreamId(*serverSpec); err != io.EOF { ctx := InteropCtx(t)
t.Fatal("Expected an EOF but was", err) err := testClientPrefaceWithStreamId(ctx)
} matchError(t, err, "EOF")
}
func matchError(t *testing.T, err error, matches ... string) {
if err == nil {
t.Fatal("Expected an error")
}
for _, s := range matches {
if strings.Contains(err.Error(), s) {
return
}
}
t.Fatalf("Error %v not in %+v", err, matches)
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
......
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
FROM golang:1.4
# Using login shell removes Go from path, so we add it.
RUN ln -s /usr/src/go/bin/go /usr/local/bin
# Define the default command.
CMD ["bash"]
#!/bin/bash
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Builds http2 interop client in a base image.
set -e
mkdir -p /var/local/git
git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
# copy service account keys if available
cp -r /var/local/jenkins/service_account $HOME || true
# compile the tests
(cd /var/local/git/grpc/tools/http2_interop && go test -c)
...@@ -108,10 +108,12 @@ def fill_one_test_result(shortname, resultset, html_str): ...@@ -108,10 +108,12 @@ def fill_one_test_result(shortname, resultset, html_str):
def render_html_report(client_langs, server_langs, test_cases, auth_test_cases, def render_html_report(client_langs, server_langs, test_cases, auth_test_cases,
resultset, num_failures, cloud_to_prod): http2_cases, resultset, num_failures, cloud_to_prod,
http2_interop):
"""Generate html report.""" """Generate html report."""
sorted_test_cases = sorted(test_cases) sorted_test_cases = sorted(test_cases)
sorted_auth_test_cases = sorted(auth_test_cases) sorted_auth_test_cases = sorted(auth_test_cases)
sorted_http2_cases = sorted(http2_cases)
sorted_client_langs = sorted(client_langs) sorted_client_langs = sorted(client_langs)
sorted_server_langs = sorted(server_langs) sorted_server_langs = sorted(server_langs)
html_str = ('<!DOCTYPE html>\n' html_str = ('<!DOCTYPE html>\n'
...@@ -170,6 +172,30 @@ def render_html_report(client_langs, server_langs, test_cases, auth_test_cases, ...@@ -170,6 +172,30 @@ def render_html_report(client_langs, server_langs, test_cases, auth_test_cases,
html_str = fill_one_test_result(shortname, resultset, html_str) html_str = fill_one_test_result(shortname, resultset, html_str)
html_str = '%s</tr>\n' % html_str html_str = '%s</tr>\n' % html_str
html_str = '%s</table>\n' % html_str html_str = '%s</table>\n' % html_str
if http2_interop:
# Each column header is the server language.
html_str = ('%s<h2>HTTP/2 Interop</h2>\n'
'<table style=\"width:100%%\" border=\"1\">\n'
'<tr bgcolor=\"#00BFFF\">\n'
'<th>Servers &#9658;<br/>'
'Test Cases &#9660;</th>\n') % html_str
for server_lang in sorted_server_langs:
html_str = '%s<th>%s\n' % (html_str, server_lang)
if cloud_to_prod:
html_str = '%s<th>%s\n' % (html_str, "prod")
html_str = '%s</tr>\n' % html_str
for test_case in sorted_http2_cases:
html_str = '%s<tr><td><b>%s</b></td>\n' % (html_str, test_case)
# Fill up the cells with test result.
for server_lang in sorted_server_langs:
shortname = 'cloud_to_cloud:%s:%s_server:%s' % (
"http2", server_lang, test_case)
html_str = fill_one_test_result(shortname, resultset, html_str)
if cloud_to_prod:
shortname = 'cloud_to_prod:%s:%s' % ("http2", test_case)
html_str = fill_one_test_result(shortname, resultset, html_str)
html_str = '%s</tr>\n' % html_str
html_str = '%s</table>\n' % html_str
html_str = ('%s\n' html_str = ('%s\n'
'<script>\n' '<script>\n'
......
...@@ -159,6 +159,31 @@ class GoLanguage: ...@@ -159,6 +159,31 @@ class GoLanguage:
return 'go' return 'go'
class Http2Client:
"""Represents the HTTP/2 Interop Test
This pretends to be a language in order to be built and run, but really it
isn't.
"""
def __init__(self):
self.client_cwd = None
self.safename = str(self)
def client_args(self):
return ['tools/http2_interop/http2_interop.test']
def cloud_to_prod_env(self):
return {}
def global_env(self):
return {}
def unimplemented_test_cases(self):
return _TEST_CASES
def __str__(self):
return 'http2'
class NodeLanguage: class NodeLanguage:
def __init__(self): def __init__(self):
...@@ -281,6 +306,7 @@ _TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong', ...@@ -281,6 +306,7 @@ _TEST_CASES = ['large_unary', 'empty_unary', 'ping_pong',
_AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds', _AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
'oauth2_auth_token', 'per_rpc_creds'] 'oauth2_auth_token', 'per_rpc_creds']
_HTTP2_TEST_CASES = ["tls"]
def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None): def docker_run_cmdline(cmdline, image, docker_args=[], cwd=None, environ=None):
"""Wraps given cmdline array to create 'docker run' cmdline from it.""" """Wraps given cmdline array to create 'docker run' cmdline from it."""
...@@ -439,6 +465,7 @@ def server_jobspec(language, docker_image): ...@@ -439,6 +465,7 @@ def server_jobspec(language, docker_image):
environ=environ, environ=environ,
docker_args=['-p', str(_DEFAULT_SERVER_PORT), docker_args=['-p', str(_DEFAULT_SERVER_PORT),
'--name', container_name]) '--name', container_name])
server_job = jobset.JobSpec( server_job = jobset.JobSpec(
cmdline=docker_cmdline, cmdline=docker_cmdline,
environ=environ, environ=environ,
...@@ -516,6 +543,12 @@ argp.add_argument('--allow_flakes', ...@@ -516,6 +543,12 @@ argp.add_argument('--allow_flakes',
action='store_const', action='store_const',
const=True, const=True,
help='Allow flaky tests to show as passing (re-runs failed tests up to five times)') help='Allow flaky tests to show as passing (re-runs failed tests up to five times)')
argp.add_argument('--http2_interop',
default=False,
action='store_const',
const=True,
help='Enable HTTP/2 interop tests')
args = argp.parse_args() args = argp.parse_args()
servers = set(s for s in itertools.chain.from_iterable(_SERVERS servers = set(s for s in itertools.chain.from_iterable(_SERVERS
...@@ -539,12 +572,16 @@ languages = set(_LANGUAGES[l] ...@@ -539,12 +572,16 @@ languages = set(_LANGUAGES[l]
for l in itertools.chain.from_iterable( for l in itertools.chain.from_iterable(
_LANGUAGES.iterkeys() if x == 'all' else [x] _LANGUAGES.iterkeys() if x == 'all' else [x]
for x in args.language)) for x in args.language))
http2Interop = Http2Client() if args.http2_interop else None
docker_images={} docker_images={}
if args.use_docker: if args.use_docker:
# languages for which to build docker images # languages for which to build docker images
languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] + languages_to_build = set(_LANGUAGES[k] for k in set([str(l) for l in languages] +
[s for s in servers])) [s for s in servers]))
if args.http2_interop:
languages_to_build.add(http2Interop)
build_jobs = [] build_jobs = []
for l in languages_to_build: for l in languages_to_build:
...@@ -586,6 +623,13 @@ try: ...@@ -586,6 +623,13 @@ try:
test_job = cloud_to_prod_jobspec(language, test_case, test_job = cloud_to_prod_jobspec(language, test_case,
docker_image=docker_images.get(str(language))) docker_image=docker_images.get(str(language)))
jobs.append(test_job) jobs.append(test_job)
if args.http2_interop:
for test_case in _HTTP2_TEST_CASES:
test_job = cloud_to_prod_jobspec(http2Interop, test_case,
docker_image=docker_images.get(str(http2Interop)))
jobs.append(test_job)
if args.cloud_to_prod_auth: if args.cloud_to_prod_auth:
for language in languages: for language in languages:
...@@ -613,6 +657,16 @@ try: ...@@ -613,6 +657,16 @@ try:
server_port, server_port,
docker_image=docker_images.get(str(language))) docker_image=docker_images.get(str(language)))
jobs.append(test_job) jobs.append(test_job)
if args.http2_interop:
for test_case in _HTTP2_TEST_CASES:
test_job = cloud_to_cloud_jobspec(http2Interop,
test_case,
server_name,
server_host,
server_port,
docker_image=docker_images.get(str(http2Interop)))
jobs.append(test_job)
if not jobs: if not jobs:
print 'No jobs to run.' print 'No jobs to run.'
...@@ -631,7 +685,8 @@ try: ...@@ -631,7 +685,8 @@ try:
report_utils.render_html_report( report_utils.render_html_report(
set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES, set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
resultset, num_failures, args.cloud_to_prod_auth or args.cloud_to_prod) _HTTP2_TEST_CASES, resultset, num_failures,
args.cloud_to_prod_auth or args.cloud_to_prod, args.http2_interop)
finally: finally:
# Check if servers are still running. # Check if servers are still running.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment