mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
1044
vendor/google.golang.org/grpc/internal/binarylog/binarylog_end2end_test.go
generated
vendored
1044
vendor/google.golang.org/grpc/internal/binarylog/binarylog_end2end_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
147
vendor/google.golang.org/grpc/internal/binarylog/binarylog_test.go
generated
vendored
147
vendor/google.golang.org/grpc/internal/binarylog/binarylog_test.go
generated
vendored
@ -1,147 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package binarylog
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test that get method logger returns the one with the most exact match.
|
||||
func TestGetMethodLogger(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
method string
|
||||
hdr, msg uint64
|
||||
}{
|
||||
// Global.
|
||||
{
|
||||
in: "*{h:12;m:23}",
|
||||
method: "/s/m",
|
||||
hdr: 12, msg: 23,
|
||||
},
|
||||
// service/*.
|
||||
{
|
||||
in: "*,s/*{h:12;m:23}",
|
||||
method: "/s/m",
|
||||
hdr: 12, msg: 23,
|
||||
},
|
||||
// Service/method.
|
||||
{
|
||||
in: "*{h;m},s/m{h:12;m:23}",
|
||||
method: "/s/m",
|
||||
hdr: 12, msg: 23,
|
||||
},
|
||||
{
|
||||
in: "*{h;m},s/*{h:314;m},s/m{h:12;m:23}",
|
||||
method: "/s/m",
|
||||
hdr: 12, msg: 23,
|
||||
},
|
||||
{
|
||||
in: "*{h;m},s/*{h:12;m:23},s/m",
|
||||
method: "/s/m",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
|
||||
// service/*.
|
||||
{
|
||||
in: "*{h;m},s/*{h:12;m:23},s/m1",
|
||||
method: "/s/m",
|
||||
hdr: 12, msg: 23,
|
||||
},
|
||||
{
|
||||
in: "*{h;m},s1/*,s/m{h:12;m:23}",
|
||||
method: "/s/m",
|
||||
hdr: 12, msg: 23,
|
||||
},
|
||||
|
||||
// With black list.
|
||||
{
|
||||
in: "*{h:12;m:23},-s/m1",
|
||||
method: "/s/m",
|
||||
hdr: 12, msg: 23,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
l := NewLoggerFromConfigString(tc.in)
|
||||
if l == nil {
|
||||
t.Errorf("in: %q, failed to create logger from config string", tc.in)
|
||||
continue
|
||||
}
|
||||
ml := l.getMethodLogger(tc.method)
|
||||
if ml == nil {
|
||||
t.Errorf("in: %q, method logger is nil, want non-nil", tc.in)
|
||||
continue
|
||||
}
|
||||
|
||||
if ml.headerMaxLen != tc.hdr || ml.messageMaxLen != tc.msg {
|
||||
t.Errorf("in: %q, want header: %v, message: %v, got header: %v, message: %v", tc.in, tc.hdr, tc.msg, ml.headerMaxLen, ml.messageMaxLen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expect method logger to be nil
|
||||
func TestGetMethodLoggerOff(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
method string
|
||||
}{
|
||||
// method not specified.
|
||||
{
|
||||
in: "s1/m",
|
||||
method: "/s/m",
|
||||
},
|
||||
{
|
||||
in: "s/m1",
|
||||
method: "/s/m",
|
||||
},
|
||||
{
|
||||
in: "s1/*",
|
||||
method: "/s/m",
|
||||
},
|
||||
{
|
||||
in: "s1/*,s/m1",
|
||||
method: "/s/m",
|
||||
},
|
||||
|
||||
// blacklisted.
|
||||
{
|
||||
in: "*,-s/m",
|
||||
method: "/s/m",
|
||||
},
|
||||
{
|
||||
in: "s/*,-s/m",
|
||||
method: "/s/m",
|
||||
},
|
||||
{
|
||||
in: "-s/m,s/*",
|
||||
method: "/s/m",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
l := NewLoggerFromConfigString(tc.in)
|
||||
if l == nil {
|
||||
t.Errorf("in: %q, failed to create logger from config string", tc.in)
|
||||
continue
|
||||
}
|
||||
ml := l.getMethodLogger(tc.method)
|
||||
if ml != nil {
|
||||
t.Errorf("in: %q, method logger is non-nil, want nil", tc.in)
|
||||
}
|
||||
}
|
||||
}
|
478
vendor/google.golang.org/grpc/internal/binarylog/env_config_test.go
generated
vendored
478
vendor/google.golang.org/grpc/internal/binarylog/env_config_test.go
generated
vendored
@ -1,478 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package binarylog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// This tests that when multiple configs are specified, all methods loggers will
|
||||
// be set correctly. Correctness of each logger is covered by other unit tests.
|
||||
func TestNewLoggerFromConfigString(t *testing.T) {
|
||||
const (
|
||||
s1 = "s1"
|
||||
m1 = "m1"
|
||||
m2 = "m2"
|
||||
fullM1 = s1 + "/" + m1
|
||||
fullM2 = s1 + "/" + m2
|
||||
)
|
||||
c := fmt.Sprintf("*{h:1;m:2},%s{h},%s{m},%s{h;m}", s1+"/*", fullM1, fullM2)
|
||||
l := NewLoggerFromConfigString(c).(*logger)
|
||||
|
||||
if l.all.hdr != 1 || l.all.msg != 2 {
|
||||
t.Errorf("l.all = %#v, want headerLen: 1, messageLen: 2", l.all)
|
||||
}
|
||||
|
||||
if ml, ok := l.services[s1]; ok {
|
||||
if ml.hdr != maxUInt || ml.msg != 0 {
|
||||
t.Errorf("want maxUInt header, 0 message, got header: %v, message: %v", ml.hdr, ml.msg)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("service/* is not set")
|
||||
}
|
||||
|
||||
if ml, ok := l.methods[fullM1]; ok {
|
||||
if ml.hdr != 0 || ml.msg != maxUInt {
|
||||
t.Errorf("want 0 header, maxUInt message, got header: %v, message: %v", ml.hdr, ml.msg)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("service/method{h} is not set")
|
||||
}
|
||||
|
||||
if ml, ok := l.methods[fullM2]; ok {
|
||||
if ml.hdr != maxUInt || ml.msg != maxUInt {
|
||||
t.Errorf("want maxUInt header, maxUInt message, got header: %v, message: %v", ml.hdr, ml.msg)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("service/method{h;m} is not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewLoggerFromConfigStringInvalid(t *testing.T) {
|
||||
testCases := []string{
|
||||
"",
|
||||
"*{}",
|
||||
"s/m,*{}",
|
||||
"s/m,s/m{a}",
|
||||
|
||||
// Duplciate rules.
|
||||
"s/m,-s/m",
|
||||
"-s/m,s/m",
|
||||
"s/m,s/m",
|
||||
"s/m,s/m{h:1;m:1}",
|
||||
"s/m{h:1;m:1},s/m",
|
||||
"-s/m,-s/m",
|
||||
"s/*,s/*{h:1;m:1}",
|
||||
"*,*{h:1;m:1}",
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
l := NewLoggerFromConfigString(tc)
|
||||
if l != nil {
|
||||
t.Errorf("With config %q, want logger %v, got %v", tc, nil, l)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMethodConfigAndSuffix(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in, service, method, suffix string
|
||||
}{
|
||||
{
|
||||
in: "p.s/m",
|
||||
service: "p.s", method: "m", suffix: "",
|
||||
},
|
||||
{
|
||||
in: "p.s/m{h,m}",
|
||||
service: "p.s", method: "m", suffix: "{h,m}",
|
||||
},
|
||||
{
|
||||
in: "p.s/*",
|
||||
service: "p.s", method: "*", suffix: "",
|
||||
},
|
||||
{
|
||||
in: "p.s/*{h,m}",
|
||||
service: "p.s", method: "*", suffix: "{h,m}",
|
||||
},
|
||||
|
||||
// invalid suffix will be detected by another function.
|
||||
{
|
||||
in: "p.s/m{invalidsuffix}",
|
||||
service: "p.s", method: "m", suffix: "{invalidsuffix}",
|
||||
},
|
||||
{
|
||||
in: "p.s/*{invalidsuffix}",
|
||||
service: "p.s", method: "*", suffix: "{invalidsuffix}",
|
||||
},
|
||||
{
|
||||
in: "s/m*",
|
||||
service: "s", method: "m", suffix: "*",
|
||||
},
|
||||
{
|
||||
in: "s/*m",
|
||||
service: "s", method: "*", suffix: "m",
|
||||
},
|
||||
{
|
||||
in: "s/**",
|
||||
service: "s", method: "*", suffix: "*",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Logf("testing parseMethodConfigAndSuffix(%q)", tc.in)
|
||||
s, m, suffix, err := parseMethodConfigAndSuffix(tc.in)
|
||||
if err != nil {
|
||||
t.Errorf("returned error %v, want nil", err)
|
||||
continue
|
||||
}
|
||||
if s != tc.service {
|
||||
t.Errorf("service = %q, want %q", s, tc.service)
|
||||
}
|
||||
if m != tc.method {
|
||||
t.Errorf("method = %q, want %q", m, tc.method)
|
||||
}
|
||||
if suffix != tc.suffix {
|
||||
t.Errorf("suffix = %q, want %q", suffix, tc.suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMethodConfigAndSuffixInvalid(t *testing.T) {
|
||||
testCases := []string{
|
||||
"*/m",
|
||||
"*/m{}",
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s, m, suffix, err := parseMethodConfigAndSuffix(tc)
|
||||
if err == nil {
|
||||
t.Errorf("Parsing %q got nil error with %q, %q, %q, want non-nil error", tc, s, m, suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseHeaderMessageLengthConfig(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
hdr, msg uint64
|
||||
}{
|
||||
{
|
||||
in: "",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h}",
|
||||
hdr: maxUInt, msg: 0,
|
||||
},
|
||||
{
|
||||
in: "{h:314}",
|
||||
hdr: 314, msg: 0,
|
||||
},
|
||||
{
|
||||
in: "{m}",
|
||||
hdr: 0, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{m:213}",
|
||||
hdr: 0, msg: 213,
|
||||
},
|
||||
{
|
||||
in: "{h;m}",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h:314;m}",
|
||||
hdr: 314, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h;m:213}",
|
||||
hdr: maxUInt, msg: 213,
|
||||
},
|
||||
{
|
||||
in: "{h:314;m:213}",
|
||||
hdr: 314, msg: 213,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Logf("testing parseHeaderMessageLengthConfig(%q)", tc.in)
|
||||
hdr, msg, err := parseHeaderMessageLengthConfig(tc.in)
|
||||
if err != nil {
|
||||
t.Errorf("returned error %v, want nil", err)
|
||||
continue
|
||||
}
|
||||
if hdr != tc.hdr {
|
||||
t.Errorf("header length = %v, want %v", hdr, tc.hdr)
|
||||
}
|
||||
if msg != tc.msg {
|
||||
t.Errorf("message length = %v, want %v", msg, tc.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestParseHeaderMessageLengthConfigInvalid(t *testing.T) {
|
||||
testCases := []string{
|
||||
"{}",
|
||||
"{h;a}",
|
||||
"{h;m;b}",
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
_, _, err := parseHeaderMessageLengthConfig(tc)
|
||||
if err == nil {
|
||||
t.Errorf("Parsing %q got nil error, want non-nil error", tc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFillMethodLoggerWithConfigStringBlacklist(t *testing.T) {
|
||||
testCases := []string{
|
||||
"p.s/m",
|
||||
"service/method",
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
c := "-" + tc
|
||||
t.Logf("testing fillMethodLoggerWithConfigString(%q)", c)
|
||||
l := newEmptyLogger()
|
||||
if err := l.fillMethodLoggerWithConfigString(c); err != nil {
|
||||
t.Errorf("returned err %v, want nil", err)
|
||||
continue
|
||||
}
|
||||
_, ok := l.blacklist[tc]
|
||||
if !ok {
|
||||
t.Errorf("blacklist[%q] is not set", tc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFillMethodLoggerWithConfigStringGlobal(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
hdr, msg uint64
|
||||
}{
|
||||
{
|
||||
in: "",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h}",
|
||||
hdr: maxUInt, msg: 0,
|
||||
},
|
||||
{
|
||||
in: "{h:314}",
|
||||
hdr: 314, msg: 0,
|
||||
},
|
||||
{
|
||||
in: "{m}",
|
||||
hdr: 0, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{m:213}",
|
||||
hdr: 0, msg: 213,
|
||||
},
|
||||
{
|
||||
in: "{h;m}",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h:314;m}",
|
||||
hdr: 314, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h;m:213}",
|
||||
hdr: maxUInt, msg: 213,
|
||||
},
|
||||
{
|
||||
in: "{h:314;m:213}",
|
||||
hdr: 314, msg: 213,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
c := "*" + tc.in
|
||||
t.Logf("testing fillMethodLoggerWithConfigString(%q)", c)
|
||||
l := newEmptyLogger()
|
||||
if err := l.fillMethodLoggerWithConfigString(c); err != nil {
|
||||
t.Errorf("returned err %v, want nil", err)
|
||||
continue
|
||||
}
|
||||
if l.all == nil {
|
||||
t.Errorf("l.all is not set")
|
||||
continue
|
||||
}
|
||||
if hdr := l.all.hdr; hdr != tc.hdr {
|
||||
t.Errorf("header length = %v, want %v", hdr, tc.hdr)
|
||||
|
||||
}
|
||||
if msg := l.all.msg; msg != tc.msg {
|
||||
t.Errorf("message length = %v, want %v", msg, tc.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFillMethodLoggerWithConfigStringPerService(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
hdr, msg uint64
|
||||
}{
|
||||
{
|
||||
in: "",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h}",
|
||||
hdr: maxUInt, msg: 0,
|
||||
},
|
||||
{
|
||||
in: "{h:314}",
|
||||
hdr: 314, msg: 0,
|
||||
},
|
||||
{
|
||||
in: "{m}",
|
||||
hdr: 0, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{m:213}",
|
||||
hdr: 0, msg: 213,
|
||||
},
|
||||
{
|
||||
in: "{h;m}",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h:314;m}",
|
||||
hdr: 314, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h;m:213}",
|
||||
hdr: maxUInt, msg: 213,
|
||||
},
|
||||
{
|
||||
in: "{h:314;m:213}",
|
||||
hdr: 314, msg: 213,
|
||||
},
|
||||
}
|
||||
const serviceName = "service"
|
||||
for _, tc := range testCases {
|
||||
c := serviceName + "/*" + tc.in
|
||||
t.Logf("testing fillMethodLoggerWithConfigString(%q)", c)
|
||||
l := newEmptyLogger()
|
||||
if err := l.fillMethodLoggerWithConfigString(c); err != nil {
|
||||
t.Errorf("returned err %v, want nil", err)
|
||||
continue
|
||||
}
|
||||
ml, ok := l.services[serviceName]
|
||||
if !ok {
|
||||
t.Errorf("l.service[%q] is not set", serviceName)
|
||||
continue
|
||||
}
|
||||
if hdr := ml.hdr; hdr != tc.hdr {
|
||||
t.Errorf("header length = %v, want %v", hdr, tc.hdr)
|
||||
|
||||
}
|
||||
if msg := ml.msg; msg != tc.msg {
|
||||
t.Errorf("message length = %v, want %v", msg, tc.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFillMethodLoggerWithConfigStringPerMethod(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
hdr, msg uint64
|
||||
}{
|
||||
{
|
||||
in: "",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h}",
|
||||
hdr: maxUInt, msg: 0,
|
||||
},
|
||||
{
|
||||
in: "{h:314}",
|
||||
hdr: 314, msg: 0,
|
||||
},
|
||||
{
|
||||
in: "{m}",
|
||||
hdr: 0, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{m:213}",
|
||||
hdr: 0, msg: 213,
|
||||
},
|
||||
{
|
||||
in: "{h;m}",
|
||||
hdr: maxUInt, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h:314;m}",
|
||||
hdr: 314, msg: maxUInt,
|
||||
},
|
||||
{
|
||||
in: "{h;m:213}",
|
||||
hdr: maxUInt, msg: 213,
|
||||
},
|
||||
{
|
||||
in: "{h:314;m:213}",
|
||||
hdr: 314, msg: 213,
|
||||
},
|
||||
}
|
||||
const (
|
||||
serviceName = "service"
|
||||
methodName = "method"
|
||||
fullMethodName = serviceName + "/" + methodName
|
||||
)
|
||||
for _, tc := range testCases {
|
||||
c := fullMethodName + tc.in
|
||||
t.Logf("testing fillMethodLoggerWithConfigString(%q)", c)
|
||||
l := newEmptyLogger()
|
||||
if err := l.fillMethodLoggerWithConfigString(c); err != nil {
|
||||
t.Errorf("returned err %v, want nil", err)
|
||||
continue
|
||||
}
|
||||
ml, ok := l.methods[fullMethodName]
|
||||
if !ok {
|
||||
t.Errorf("l.methods[%q] is not set", fullMethodName)
|
||||
continue
|
||||
}
|
||||
if hdr := ml.hdr; hdr != tc.hdr {
|
||||
t.Errorf("header length = %v, want %v", hdr, tc.hdr)
|
||||
|
||||
}
|
||||
if msg := ml.msg; msg != tc.msg {
|
||||
t.Errorf("message length = %v, want %v", msg, tc.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFillMethodLoggerWithConfigStringInvalid(t *testing.T) {
|
||||
testCases := []string{
|
||||
"",
|
||||
"{}",
|
||||
"p.s/m{}",
|
||||
"p.s/m{a}",
|
||||
"p.s/m*",
|
||||
"p.s/**",
|
||||
"*/m",
|
||||
|
||||
"-p.s/*",
|
||||
"-p.s/m{h}",
|
||||
}
|
||||
l := &logger{}
|
||||
for _, tc := range testCases {
|
||||
if err := l.fillMethodLoggerWithConfigString(tc); err == nil {
|
||||
t.Errorf("fillMethodLoggerWithConfigString(%q) returned nil error, want non-nil", tc)
|
||||
}
|
||||
}
|
||||
}
|
542
vendor/google.golang.org/grpc/internal/binarylog/method_logger_test.go
generated
vendored
542
vendor/google.golang.org/grpc/internal/binarylog/method_logger_test.go
generated
vendored
@ -1,542 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package binarylog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
dpb "github.com/golang/protobuf/ptypes/duration"
|
||||
pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestLog(t *testing.T) {
|
||||
idGen.reset()
|
||||
ml := newMethodLogger(10, 10)
|
||||
// Set sink to testing buffer.
|
||||
buf := bytes.NewBuffer(nil)
|
||||
ml.sink = newWriterSink(buf)
|
||||
|
||||
addr := "1.2.3.4"
|
||||
port := 790
|
||||
tcpAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("%v:%d", addr, port))
|
||||
addr6 := "2001:1db8:85a3::8a2e:1370:7334"
|
||||
port6 := 796
|
||||
tcpAddr6, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("[%v]:%d", addr6, port6))
|
||||
|
||||
testProtoMsg := &pb.Message{
|
||||
Length: 1,
|
||||
Data: []byte{'a'},
|
||||
}
|
||||
testProtoBytes, _ := proto.Marshal(testProtoMsg)
|
||||
|
||||
testCases := []struct {
|
||||
config LogEntryConfig
|
||||
want *pb.GrpcLogEntry
|
||||
}{
|
||||
{
|
||||
config: &ClientHeader{
|
||||
OnClientSide: false,
|
||||
Header: map[string][]string{
|
||||
"a": {"b", "bb"},
|
||||
},
|
||||
MethodName: "testservice/testmethod",
|
||||
Authority: "test.service.io",
|
||||
Timeout: 2*time.Second + 3*time.Nanosecond,
|
||||
PeerAddr: tcpAddr,
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_SERVER,
|
||||
Payload: &pb.GrpcLogEntry_ClientHeader{
|
||||
ClientHeader: &pb.ClientHeader{
|
||||
Metadata: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "a", Value: []byte{'b'}},
|
||||
{Key: "a", Value: []byte{'b', 'b'}},
|
||||
},
|
||||
},
|
||||
MethodName: "testservice/testmethod",
|
||||
Authority: "test.service.io",
|
||||
Timeout: &dpb.Duration{
|
||||
Seconds: 2,
|
||||
Nanos: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
Peer: &pb.Address{
|
||||
Type: pb.Address_TYPE_IPV4,
|
||||
Address: addr,
|
||||
IpPort: uint32(port),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: &ClientHeader{
|
||||
OnClientSide: false,
|
||||
MethodName: "testservice/testmethod",
|
||||
Authority: "test.service.io",
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_SERVER,
|
||||
Payload: &pb.GrpcLogEntry_ClientHeader{
|
||||
ClientHeader: &pb.ClientHeader{
|
||||
Metadata: &pb.Metadata{},
|
||||
MethodName: "testservice/testmethod",
|
||||
Authority: "test.service.io",
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
config: &ServerHeader{
|
||||
OnClientSide: true,
|
||||
Header: map[string][]string{
|
||||
"a": {"b", "bb"},
|
||||
},
|
||||
PeerAddr: tcpAddr6,
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
|
||||
Payload: &pb.GrpcLogEntry_ServerHeader{
|
||||
ServerHeader: &pb.ServerHeader{
|
||||
Metadata: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "a", Value: []byte{'b'}},
|
||||
{Key: "a", Value: []byte{'b', 'b'}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
Peer: &pb.Address{
|
||||
Type: pb.Address_TYPE_IPV6,
|
||||
Address: addr6,
|
||||
IpPort: uint32(port6),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: &ClientMessage{
|
||||
OnClientSide: true,
|
||||
Message: testProtoMsg,
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
|
||||
Payload: &pb.GrpcLogEntry_Message{
|
||||
Message: &pb.Message{
|
||||
Length: uint32(len(testProtoBytes)),
|
||||
Data: testProtoBytes,
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
Peer: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
config: &ServerMessage{
|
||||
OnClientSide: false,
|
||||
Message: testProtoMsg,
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_SERVER,
|
||||
Payload: &pb.GrpcLogEntry_Message{
|
||||
Message: &pb.Message{
|
||||
Length: uint32(len(testProtoBytes)),
|
||||
Data: testProtoBytes,
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
Peer: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
config: &ClientHalfClose{
|
||||
OnClientSide: false,
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_SERVER,
|
||||
Payload: nil,
|
||||
PayloadTruncated: false,
|
||||
Peer: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
config: &ServerTrailer{
|
||||
OnClientSide: true,
|
||||
Err: status.Errorf(codes.Unavailable, "test"),
|
||||
PeerAddr: tcpAddr,
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
|
||||
Payload: &pb.GrpcLogEntry_Trailer{
|
||||
Trailer: &pb.Trailer{
|
||||
Metadata: &pb.Metadata{},
|
||||
StatusCode: uint32(codes.Unavailable),
|
||||
StatusMessage: "test",
|
||||
StatusDetails: nil,
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
Peer: &pb.Address{
|
||||
Type: pb.Address_TYPE_IPV4,
|
||||
Address: addr,
|
||||
IpPort: uint32(port),
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // Err is nil, Log OK status.
|
||||
config: &ServerTrailer{
|
||||
OnClientSide: true,
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
|
||||
Payload: &pb.GrpcLogEntry_Trailer{
|
||||
Trailer: &pb.Trailer{
|
||||
Metadata: &pb.Metadata{},
|
||||
StatusCode: uint32(codes.OK),
|
||||
StatusMessage: "",
|
||||
StatusDetails: nil,
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
Peer: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
config: &Cancel{
|
||||
OnClientSide: true,
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_CANCEL,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
|
||||
Payload: nil,
|
||||
PayloadTruncated: false,
|
||||
Peer: nil,
|
||||
},
|
||||
},
|
||||
|
||||
// gRPC headers should be omitted.
|
||||
{
|
||||
config: &ClientHeader{
|
||||
OnClientSide: false,
|
||||
Header: map[string][]string{
|
||||
"grpc-reserved": {"to be omitted"},
|
||||
":authority": {"to be omitted"},
|
||||
"a": {"b", "bb"},
|
||||
},
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_SERVER,
|
||||
Payload: &pb.GrpcLogEntry_ClientHeader{
|
||||
ClientHeader: &pb.ClientHeader{
|
||||
Metadata: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "a", Value: []byte{'b'}},
|
||||
{Key: "a", Value: []byte{'b', 'b'}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
config: &ServerHeader{
|
||||
OnClientSide: true,
|
||||
Header: map[string][]string{
|
||||
"grpc-reserved": {"to be omitted"},
|
||||
":authority": {"to be omitted"},
|
||||
"a": {"b", "bb"},
|
||||
},
|
||||
},
|
||||
want: &pb.GrpcLogEntry{
|
||||
Timestamp: nil,
|
||||
CallId: 1,
|
||||
SequenceIdWithinCall: 0,
|
||||
Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER,
|
||||
Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
|
||||
Payload: &pb.GrpcLogEntry_ServerHeader{
|
||||
ServerHeader: &pb.ServerHeader{
|
||||
Metadata: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "a", Value: []byte{'b'}},
|
||||
{Key: "a", Value: []byte{'b', 'b'}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
PayloadTruncated: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
buf.Reset()
|
||||
tc.want.SequenceIdWithinCall = uint64(i + 1)
|
||||
ml.Log(tc.config)
|
||||
inSink := new(pb.GrpcLogEntry)
|
||||
if err := proto.Unmarshal(buf.Bytes()[4:], inSink); err != nil {
|
||||
t.Errorf("failed to unmarshal bytes in sink to proto: %v", err)
|
||||
continue
|
||||
}
|
||||
inSink.Timestamp = nil // Strip timestamp before comparing.
|
||||
if !proto.Equal(inSink, tc.want) {
|
||||
t.Errorf("Log(%+v), in sink: %+v, want %+v", tc.config, inSink, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncateMetadataNotTruncated(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ml *MethodLogger
|
||||
mpPb *pb.Metadata
|
||||
}{
|
||||
{
|
||||
ml: newMethodLogger(maxUInt, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(2, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(1, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: nil},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(2, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1, 1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(2, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1}},
|
||||
{Key: "", Value: []byte{1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
// "grpc-trace-bin" is kept in log but not counted towards the size
|
||||
// limit.
|
||||
{
|
||||
ml: newMethodLogger(1, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1}},
|
||||
{Key: "grpc-trace-bin", Value: []byte("some.trace.key")},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
truncated := tc.ml.truncateMetadata(tc.mpPb)
|
||||
if truncated {
|
||||
t.Errorf("test case %v, returned truncated, want not truncated", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncateMetadataTruncated(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ml *MethodLogger
|
||||
mpPb *pb.Metadata
|
||||
|
||||
entryLen int
|
||||
}{
|
||||
{
|
||||
ml: newMethodLogger(2, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1, 1, 1}},
|
||||
},
|
||||
},
|
||||
entryLen: 0,
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(2, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1}},
|
||||
{Key: "", Value: []byte{1}},
|
||||
{Key: "", Value: []byte{1}},
|
||||
},
|
||||
},
|
||||
entryLen: 2,
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(2, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1, 1}},
|
||||
{Key: "", Value: []byte{1}},
|
||||
},
|
||||
},
|
||||
entryLen: 1,
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(2, maxUInt),
|
||||
mpPb: &pb.Metadata{
|
||||
Entry: []*pb.MetadataEntry{
|
||||
{Key: "", Value: []byte{1}},
|
||||
{Key: "", Value: []byte{1, 1}},
|
||||
},
|
||||
},
|
||||
entryLen: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
truncated := tc.ml.truncateMetadata(tc.mpPb)
|
||||
if !truncated {
|
||||
t.Errorf("test case %v, returned not truncated, want truncated", i)
|
||||
continue
|
||||
}
|
||||
if len(tc.mpPb.Entry) != tc.entryLen {
|
||||
t.Errorf("test case %v, entry length: %v, want: %v", i, len(tc.mpPb.Entry), tc.entryLen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncateMessageNotTruncated(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ml *MethodLogger
|
||||
msgPb *pb.Message
|
||||
}{
|
||||
{
|
||||
ml: newMethodLogger(maxUInt, maxUInt),
|
||||
msgPb: &pb.Message{
|
||||
Data: []byte{1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(maxUInt, 3),
|
||||
msgPb: &pb.Message{
|
||||
Data: []byte{1, 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
ml: newMethodLogger(maxUInt, 2),
|
||||
msgPb: &pb.Message{
|
||||
Data: []byte{1, 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
truncated := tc.ml.truncateMessage(tc.msgPb)
|
||||
if truncated {
|
||||
t.Errorf("test case %v, returned truncated, want not truncated", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncateMessageTruncated(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ml *MethodLogger
|
||||
msgPb *pb.Message
|
||||
|
||||
oldLength uint32
|
||||
}{
|
||||
{
|
||||
ml: newMethodLogger(maxUInt, 2),
|
||||
msgPb: &pb.Message{
|
||||
Length: 3,
|
||||
Data: []byte{1, 1, 1},
|
||||
},
|
||||
oldLength: 3,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
truncated := tc.ml.truncateMessage(tc.msgPb)
|
||||
if !truncated {
|
||||
t.Errorf("test case %v, returned not truncated, want truncated", i)
|
||||
continue
|
||||
}
|
||||
if len(tc.msgPb.Data) != int(tc.ml.messageMaxLen) {
|
||||
t.Errorf("test case %v, message length: %v, want: %v", i, len(tc.msgPb.Data), tc.ml.messageMaxLen)
|
||||
}
|
||||
if tc.msgPb.Length != tc.oldLength {
|
||||
t.Errorf("test case %v, message.Length field: %v, want: %v", i, tc.msgPb.Length, tc.oldLength)
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh
generated
vendored
33
vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh
generated
vendored
@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2018 gRPC authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -eux -o pipefail
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
|
||||
function finish {
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap finish EXIT
|
||||
|
||||
pushd "$TMP"
|
||||
mkdir -p grpc/binarylog/grpc_binarylog_v1
|
||||
curl https://raw.githubusercontent.com/grpc/grpc-proto/master/grpc/binlog/v1/binarylog.proto > grpc/binarylog/grpc_binarylog_v1/binarylog.proto
|
||||
|
||||
protoc --go_out=plugins=grpc,paths=source_relative:. -I. grpc/binarylog/grpc_binarylog_v1/*.proto
|
||||
popd
|
||||
rm -f ./grpc_binarylog_v1/*.pb.go
|
||||
cp "$TMP"/grpc/binarylog/grpc_binarylog_v1/*.pb.go ../../binarylog/grpc_binarylog_v1/
|
||||
|
179
vendor/google.golang.org/grpc/internal/binarylog/regexp_test.go
generated
vendored
179
vendor/google.golang.org/grpc/internal/binarylog/regexp_test.go
generated
vendored
@ -1,179 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package binarylog
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLongMethodConfigRegexp(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
out []string
|
||||
}{
|
||||
{in: "", out: nil},
|
||||
{in: "*/m", out: nil},
|
||||
|
||||
{
|
||||
in: "p.s/m{}",
|
||||
out: []string{"p.s/m{}", "p.s", "m", "{}"},
|
||||
},
|
||||
|
||||
{
|
||||
in: "p.s/m",
|
||||
out: []string{"p.s/m", "p.s", "m", ""},
|
||||
},
|
||||
{
|
||||
in: "p.s/m{h}",
|
||||
out: []string{"p.s/m{h}", "p.s", "m", "{h}"},
|
||||
},
|
||||
{
|
||||
in: "p.s/m{m}",
|
||||
out: []string{"p.s/m{m}", "p.s", "m", "{m}"},
|
||||
},
|
||||
{
|
||||
in: "p.s/m{h:123}",
|
||||
out: []string{"p.s/m{h:123}", "p.s", "m", "{h:123}"},
|
||||
},
|
||||
{
|
||||
in: "p.s/m{m:123}",
|
||||
out: []string{"p.s/m{m:123}", "p.s", "m", "{m:123}"},
|
||||
},
|
||||
{
|
||||
in: "p.s/m{h:123,m:123}",
|
||||
out: []string{"p.s/m{h:123,m:123}", "p.s", "m", "{h:123,m:123}"},
|
||||
},
|
||||
|
||||
{
|
||||
in: "p.s/*",
|
||||
out: []string{"p.s/*", "p.s", "*", ""},
|
||||
},
|
||||
{
|
||||
in: "p.s/*{h}",
|
||||
out: []string{"p.s/*{h}", "p.s", "*", "{h}"},
|
||||
},
|
||||
|
||||
{
|
||||
in: "s/m*",
|
||||
out: []string{"s/m*", "s", "m", "*"},
|
||||
},
|
||||
{
|
||||
in: "s/**",
|
||||
out: []string{"s/**", "s", "*", "*"},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
match := longMethodConfigRegexp.FindStringSubmatch(tc.in)
|
||||
if !reflect.DeepEqual(match, tc.out) {
|
||||
t.Errorf("in: %q, out: %q, want: %q", tc.in, match, tc.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeaderConfigRegexp(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
out []string
|
||||
}{
|
||||
{in: "{}", out: nil},
|
||||
{in: "{a:b}", out: nil},
|
||||
{in: "{m:123}", out: nil},
|
||||
{in: "{h:123;m:123}", out: nil},
|
||||
|
||||
{
|
||||
in: "{h}",
|
||||
out: []string{"{h}", ""},
|
||||
},
|
||||
{
|
||||
in: "{h:123}",
|
||||
out: []string{"{h:123}", "123"},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
match := headerConfigRegexp.FindStringSubmatch(tc.in)
|
||||
if !reflect.DeepEqual(match, tc.out) {
|
||||
t.Errorf("in: %q, out: %q, want: %q", tc.in, match, tc.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageConfigRegexp(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
out []string
|
||||
}{
|
||||
{in: "{}", out: nil},
|
||||
{in: "{a:b}", out: nil},
|
||||
{in: "{h:123}", out: nil},
|
||||
{in: "{h:123;m:123}", out: nil},
|
||||
|
||||
{
|
||||
in: "{m}",
|
||||
out: []string{"{m}", ""},
|
||||
},
|
||||
{
|
||||
in: "{m:123}",
|
||||
out: []string{"{m:123}", "123"},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
match := messageConfigRegexp.FindStringSubmatch(tc.in)
|
||||
if !reflect.DeepEqual(match, tc.out) {
|
||||
t.Errorf("in: %q, out: %q, want: %q", tc.in, match, tc.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeaderMessageConfigRegexp(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in string
|
||||
out []string
|
||||
}{
|
||||
{in: "{}", out: nil},
|
||||
{in: "{a:b}", out: nil},
|
||||
{in: "{h}", out: nil},
|
||||
{in: "{h:123}", out: nil},
|
||||
{in: "{m}", out: nil},
|
||||
{in: "{m:123}", out: nil},
|
||||
|
||||
{
|
||||
in: "{h;m}",
|
||||
out: []string{"{h;m}", "", ""},
|
||||
},
|
||||
{
|
||||
in: "{h:123;m}",
|
||||
out: []string{"{h:123;m}", "123", ""},
|
||||
},
|
||||
{
|
||||
in: "{h;m:123}",
|
||||
out: []string{"{h;m:123}", "", "123"},
|
||||
},
|
||||
{
|
||||
in: "{h:123;m:123}",
|
||||
out: []string{"{h:123;m:123}", "123", "123"},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
match := headerMessageConfigRegexp.FindStringSubmatch(tc.in)
|
||||
if !reflect.DeepEqual(match, tc.out) {
|
||||
t.Errorf("in: %q, out: %q, want: %q", tc.in, match, tc.out)
|
||||
}
|
||||
}
|
||||
}
|
59
vendor/google.golang.org/grpc/internal/binarylog/util_test.go
generated
vendored
59
vendor/google.golang.org/grpc/internal/binarylog/util_test.go
generated
vendored
@ -1,59 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package binarylog
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestParseMethodName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
methodName string
|
||||
service, method string
|
||||
}{
|
||||
{methodName: "/s/m", service: "s", method: "m"},
|
||||
{methodName: "/p.s/m", service: "p.s", method: "m"},
|
||||
{methodName: "/p/s/m", service: "p/s", method: "m"},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s, m, err := parseMethodName(tc.methodName)
|
||||
if err != nil {
|
||||
t.Errorf("Parsing %q got error %v, want nil", tc.methodName, err)
|
||||
continue
|
||||
}
|
||||
if s != tc.service || m != tc.method {
|
||||
t.Errorf("Parseing %q got service %q, method %q, want service %q, method %q",
|
||||
tc.methodName, s, m, tc.service, tc.method,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMethodNameInvalid(t *testing.T) {
|
||||
testCases := []string{
|
||||
"/",
|
||||
"/sm",
|
||||
"",
|
||||
"sm",
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
_, _, err := parseMethodName(tc)
|
||||
if err == nil {
|
||||
t.Errorf("Parsing %q got nil error, want non-nil error", tc)
|
||||
}
|
||||
}
|
||||
}
|
90
vendor/google.golang.org/grpc/internal/channelz/util_test.go
generated
vendored
90
vendor/google.golang.org/grpc/internal/channelz/util_test.go
generated
vendored
@ -1,90 +0,0 @@
|
||||
// +build linux,go1.10,!appengine
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// The test in this file should be run in an environment that has go1.10 or later,
|
||||
// as the function SyscallConn() (required to get socket option) was introduced
|
||||
// to net.TCPListener in go1.10.
|
||||
|
||||
package channelz_test
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"google.golang.org/grpc/internal/channelz"
|
||||
)
|
||||
|
||||
func TestGetSocketOpt(t *testing.T) {
|
||||
network, addr := "tcp", ":0"
|
||||
ln, err := net.Listen(network, addr)
|
||||
if err != nil {
|
||||
t.Fatalf("net.Listen(%s,%s) failed with err: %v", network, addr, err)
|
||||
}
|
||||
defer ln.Close()
|
||||
go func() {
|
||||
ln.Accept()
|
||||
}()
|
||||
conn, _ := net.Dial(network, ln.Addr().String())
|
||||
defer conn.Close()
|
||||
tcpc := conn.(*net.TCPConn)
|
||||
raw, err := tcpc.SyscallConn()
|
||||
if err != nil {
|
||||
t.Fatalf("SyscallConn() failed due to %v", err)
|
||||
}
|
||||
|
||||
l := &unix.Linger{Onoff: 1, Linger: 5}
|
||||
recvTimout := &unix.Timeval{Sec: 100}
|
||||
sendTimeout := &unix.Timeval{Sec: 8888}
|
||||
raw.Control(func(fd uintptr) {
|
||||
err := unix.SetsockoptLinger(int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER, l)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to SetsockoptLinger(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER, l, err)
|
||||
}
|
||||
err = unix.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, recvTimout)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to SetsockoptTimeval(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, recvTimout, err)
|
||||
}
|
||||
err = unix.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, sendTimeout)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to SetsockoptTimeval(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, sendTimeout, err)
|
||||
}
|
||||
})
|
||||
sktopt := channelz.GetSocketOption(conn)
|
||||
if !reflect.DeepEqual(sktopt.Linger, l) {
|
||||
t.Fatalf("get socket option linger, want: %v, got %v", l, sktopt.Linger)
|
||||
}
|
||||
if !reflect.DeepEqual(sktopt.RecvTimeout, recvTimout) {
|
||||
t.Logf("get socket option recv timeout, want: %v, got %v, may be caused by system allowing non or partial setting of this value", recvTimout, sktopt.RecvTimeout)
|
||||
}
|
||||
if !reflect.DeepEqual(sktopt.SendTimeout, sendTimeout) {
|
||||
t.Logf("get socket option send timeout, want: %v, got %v, may be caused by system allowing non or partial setting of this value", sendTimeout, sktopt.SendTimeout)
|
||||
}
|
||||
if sktopt == nil || sktopt.TCPInfo != nil && sktopt.TCPInfo.State != 1 {
|
||||
t.Fatalf("TCPInfo.State want 1 (TCP_ESTABLISHED), got %v", sktopt)
|
||||
}
|
||||
|
||||
sktopt = channelz.GetSocketOption(ln)
|
||||
if sktopt == nil || sktopt.TCPInfo == nil || sktopt.TCPInfo.State != 10 {
|
||||
t.Fatalf("TCPInfo.State want 10 (TCP_LISTEN), got %v", sktopt)
|
||||
}
|
||||
}
|
69
vendor/google.golang.org/grpc/internal/grpcsync/event_test.go
generated
vendored
69
vendor/google.golang.org/grpc/internal/grpcsync/event_test.go
generated
vendored
@ -1,69 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package grpcsync
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEventHasFired(t *testing.T) {
|
||||
e := NewEvent()
|
||||
if e.HasFired() {
|
||||
t.Fatal("e.HasFired() = true; want false")
|
||||
}
|
||||
if !e.Fire() {
|
||||
t.Fatal("e.Fire() = false; want true")
|
||||
}
|
||||
if !e.HasFired() {
|
||||
t.Fatal("e.HasFired() = false; want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEventDoneChannel(t *testing.T) {
|
||||
e := NewEvent()
|
||||
select {
|
||||
case <-e.Done():
|
||||
t.Fatal("e.HasFired() = true; want false")
|
||||
default:
|
||||
}
|
||||
if !e.Fire() {
|
||||
t.Fatal("e.Fire() = false; want true")
|
||||
}
|
||||
select {
|
||||
case <-e.Done():
|
||||
default:
|
||||
t.Fatal("e.HasFired() = false; want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEventMultipleFires(t *testing.T) {
|
||||
e := NewEvent()
|
||||
if e.HasFired() {
|
||||
t.Fatal("e.HasFired() = true; want false")
|
||||
}
|
||||
if !e.Fire() {
|
||||
t.Fatal("e.Fire() = false; want true")
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
if !e.HasFired() {
|
||||
t.Fatal("e.HasFired() = false; want true")
|
||||
}
|
||||
if e.Fire() {
|
||||
t.Fatal("e.Fire() = true; want false")
|
||||
}
|
||||
}
|
||||
}
|
118
vendor/google.golang.org/grpc/internal/leakcheck/leakcheck.go
generated
vendored
118
vendor/google.golang.org/grpc/internal/leakcheck/leakcheck.go
generated
vendored
@ -1,118 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2017 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package leakcheck contains functions to check leaked goroutines.
|
||||
//
|
||||
// Call "defer leakcheck.Check(t)" at the beginning of tests.
|
||||
package leakcheck
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var goroutinesToIgnore = []string{
|
||||
"testing.Main(",
|
||||
"testing.tRunner(",
|
||||
"testing.(*M).",
|
||||
"runtime.goexit",
|
||||
"created by runtime.gc",
|
||||
"created by runtime/trace.Start",
|
||||
"interestingGoroutines",
|
||||
"runtime.MHeap_Scavenger",
|
||||
"signal.signal_recv",
|
||||
"sigterm.handler",
|
||||
"runtime_mcall",
|
||||
"(*loggingT).flushDaemon",
|
||||
"goroutine in C code",
|
||||
}
|
||||
|
||||
// RegisterIgnoreGoroutine appends s into the ignore goroutine list. The
|
||||
// goroutines whose stack trace contains s will not be identified as leaked
|
||||
// goroutines. Not thread-safe, only call this function in init().
|
||||
func RegisterIgnoreGoroutine(s string) {
|
||||
goroutinesToIgnore = append(goroutinesToIgnore, s)
|
||||
}
|
||||
|
||||
func ignore(g string) bool {
|
||||
sl := strings.SplitN(g, "\n", 2)
|
||||
if len(sl) != 2 {
|
||||
return true
|
||||
}
|
||||
stack := strings.TrimSpace(sl[1])
|
||||
if strings.HasPrefix(stack, "testing.RunTests") {
|
||||
return true
|
||||
}
|
||||
|
||||
if stack == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, s := range goroutinesToIgnore {
|
||||
if strings.Contains(stack, s) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// interestingGoroutines returns all goroutines we care about for the purpose of
|
||||
// leak checking. It excludes testing or runtime ones.
|
||||
func interestingGoroutines() (gs []string) {
|
||||
buf := make([]byte, 2<<20)
|
||||
buf = buf[:runtime.Stack(buf, true)]
|
||||
for _, g := range strings.Split(string(buf), "\n\n") {
|
||||
if !ignore(g) {
|
||||
gs = append(gs, g)
|
||||
}
|
||||
}
|
||||
sort.Strings(gs)
|
||||
return
|
||||
}
|
||||
|
||||
// Errorfer is the interface that wraps the Errorf method. It's a subset of
|
||||
// testing.TB to make it easy to use Check.
|
||||
type Errorfer interface {
|
||||
Errorf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
func check(efer Errorfer, timeout time.Duration) {
|
||||
// Loop, waiting for goroutines to shut down.
|
||||
// Wait up to timeout, but finish as quickly as possible.
|
||||
deadline := time.Now().Add(timeout)
|
||||
var leaked []string
|
||||
for time.Now().Before(deadline) {
|
||||
if leaked = interestingGoroutines(); len(leaked) == 0 {
|
||||
return
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
for _, g := range leaked {
|
||||
efer.Errorf("Leaked goroutine: %v", g)
|
||||
}
|
||||
}
|
||||
|
||||
// Check looks at the currently-running goroutines and checks if there are any
|
||||
// interestring (created by gRPC) goroutines leaked. It waits up to 10 seconds
|
||||
// in the error cases.
|
||||
func Check(efer Errorfer) {
|
||||
check(efer, 10*time.Second)
|
||||
}
|
76
vendor/google.golang.org/grpc/internal/leakcheck/leakcheck_test.go
generated
vendored
76
vendor/google.golang.org/grpc/internal/leakcheck/leakcheck_test.go
generated
vendored
@ -1,76 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2017 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package leakcheck
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type testErrorfer struct {
|
||||
errorCount int
|
||||
errors []string
|
||||
}
|
||||
|
||||
func (e *testErrorfer) Errorf(format string, args ...interface{}) {
|
||||
e.errors = append(e.errors, fmt.Sprintf(format, args...))
|
||||
e.errorCount++
|
||||
}
|
||||
|
||||
func TestCheck(t *testing.T) {
|
||||
const leakCount = 3
|
||||
for i := 0; i < leakCount; i++ {
|
||||
go func() { time.Sleep(2 * time.Second) }()
|
||||
}
|
||||
if ig := interestingGoroutines(); len(ig) == 0 {
|
||||
t.Error("blah")
|
||||
}
|
||||
e := &testErrorfer{}
|
||||
check(e, time.Second)
|
||||
if e.errorCount != leakCount {
|
||||
t.Errorf("check found %v leaks, want %v leaks", e.errorCount, leakCount)
|
||||
t.Logf("leaked goroutines:\n%v", strings.Join(e.errors, "\n"))
|
||||
}
|
||||
check(t, 3*time.Second)
|
||||
}
|
||||
|
||||
func ignoredTestingLeak(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
|
||||
func TestCheckRegisterIgnore(t *testing.T) {
|
||||
RegisterIgnoreGoroutine("ignoredTestingLeak")
|
||||
const leakCount = 3
|
||||
for i := 0; i < leakCount; i++ {
|
||||
go func() { time.Sleep(2 * time.Second) }()
|
||||
}
|
||||
go func() { ignoredTestingLeak(3 * time.Second) }()
|
||||
if ig := interestingGoroutines(); len(ig) == 0 {
|
||||
t.Error("blah")
|
||||
}
|
||||
e := &testErrorfer{}
|
||||
check(e, time.Second)
|
||||
if e.errorCount != leakCount {
|
||||
t.Errorf("check found %v leaks, want %v leaks", e.errorCount, leakCount)
|
||||
t.Logf("leaked goroutines:\n%v", strings.Join(e.errors, "\n"))
|
||||
}
|
||||
check(t, 3*time.Second)
|
||||
}
|
96
vendor/google.golang.org/grpc/internal/testutils/pipe_listener.go
generated
vendored
96
vendor/google.golang.org/grpc/internal/testutils/pipe_listener.go
generated
vendored
@ -1,96 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package testutils contains testing helpers.
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errClosed = errors.New("closed")
|
||||
|
||||
type pipeAddr struct{}
|
||||
|
||||
func (p pipeAddr) Network() string { return "pipe" }
|
||||
func (p pipeAddr) String() string { return "pipe" }
|
||||
|
||||
// PipeListener is a listener with an unbuffered pipe. Each write will complete only once the other side reads. It
|
||||
// should only be created using NewPipeListener.
|
||||
type PipeListener struct {
|
||||
c chan chan<- net.Conn
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// NewPipeListener creates a new pipe listener.
|
||||
func NewPipeListener() *PipeListener {
|
||||
return &PipeListener{
|
||||
c: make(chan chan<- net.Conn),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Accept accepts a connection.
|
||||
func (p *PipeListener) Accept() (net.Conn, error) {
|
||||
var connChan chan<- net.Conn
|
||||
select {
|
||||
case <-p.done:
|
||||
return nil, errClosed
|
||||
case connChan = <-p.c:
|
||||
select {
|
||||
case <-p.done:
|
||||
close(connChan)
|
||||
return nil, errClosed
|
||||
default:
|
||||
}
|
||||
}
|
||||
c1, c2 := net.Pipe()
|
||||
connChan <- c1
|
||||
close(connChan)
|
||||
return c2, nil
|
||||
}
|
||||
|
||||
// Close closes the listener.
|
||||
func (p *PipeListener) Close() error {
|
||||
close(p.done)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Addr returns a pipe addr.
|
||||
func (p *PipeListener) Addr() net.Addr {
|
||||
return pipeAddr{}
|
||||
}
|
||||
|
||||
// Dialer dials a connection.
|
||||
func (p *PipeListener) Dialer() func(string, time.Duration) (net.Conn, error) {
|
||||
return func(string, time.Duration) (net.Conn, error) {
|
||||
connChan := make(chan net.Conn)
|
||||
select {
|
||||
case p.c <- connChan:
|
||||
case <-p.done:
|
||||
return nil, errClosed
|
||||
}
|
||||
conn, ok := <-connChan
|
||||
if !ok {
|
||||
return nil, errClosed
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
}
|
163
vendor/google.golang.org/grpc/internal/testutils/pipe_listener_test.go
generated
vendored
163
vendor/google.golang.org/grpc/internal/testutils/pipe_listener_test.go
generated
vendored
@ -1,163 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package testutils_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
)
|
||||
|
||||
func TestPipeListener(t *testing.T) {
|
||||
pl := testutils.NewPipeListener()
|
||||
recvdBytes := make(chan []byte)
|
||||
const want = "hello world"
|
||||
|
||||
go func() {
|
||||
c, err := pl.Accept()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
read := make([]byte, len(want))
|
||||
_, err = c.Read(read)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
recvdBytes <- read
|
||||
}()
|
||||
|
||||
dl := pl.Dialer()
|
||||
conn, err := dl("", time.Duration(0))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = conn.Write([]byte(want))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case gotBytes := <-recvdBytes:
|
||||
got := string(gotBytes)
|
||||
if got != want {
|
||||
t.Fatalf("expected to get %s, got %s", got, want)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Fatal("timed out waiting for server to receive bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnblocking(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
desc string
|
||||
blockFuncShouldError bool
|
||||
blockFunc func(*testutils.PipeListener, chan struct{}) error
|
||||
unblockFunc func(*testutils.PipeListener) error
|
||||
}{
|
||||
{
|
||||
desc: "Accept unblocks Dial",
|
||||
blockFunc: func(pl *testutils.PipeListener, done chan struct{}) error {
|
||||
dl := pl.Dialer()
|
||||
_, err := dl("", time.Duration(0))
|
||||
close(done)
|
||||
return err
|
||||
},
|
||||
unblockFunc: func(pl *testutils.PipeListener) error {
|
||||
_, err := pl.Accept()
|
||||
return err
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Close unblocks Dial",
|
||||
blockFuncShouldError: true, // because pl.Close will be called
|
||||
blockFunc: func(pl *testutils.PipeListener, done chan struct{}) error {
|
||||
dl := pl.Dialer()
|
||||
_, err := dl("", time.Duration(0))
|
||||
close(done)
|
||||
return err
|
||||
},
|
||||
unblockFunc: func(pl *testutils.PipeListener) error {
|
||||
return pl.Close()
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Dial unblocks Accept",
|
||||
blockFunc: func(pl *testutils.PipeListener, done chan struct{}) error {
|
||||
_, err := pl.Accept()
|
||||
close(done)
|
||||
return err
|
||||
},
|
||||
unblockFunc: func(pl *testutils.PipeListener) error {
|
||||
dl := pl.Dialer()
|
||||
_, err := dl("", time.Duration(0))
|
||||
return err
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Close unblocks Accept",
|
||||
blockFuncShouldError: true, // because pl.Close will be called
|
||||
blockFunc: func(pl *testutils.PipeListener, done chan struct{}) error {
|
||||
_, err := pl.Accept()
|
||||
close(done)
|
||||
return err
|
||||
},
|
||||
unblockFunc: func(pl *testutils.PipeListener) error {
|
||||
return pl.Close()
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Log(test.desc)
|
||||
testUnblocking(t, test.blockFunc, test.unblockFunc, test.blockFuncShouldError)
|
||||
}
|
||||
}
|
||||
|
||||
func testUnblocking(t *testing.T, blockFunc func(*testutils.PipeListener, chan struct{}) error, unblockFunc func(*testutils.PipeListener) error, blockFuncShouldError bool) {
|
||||
pl := testutils.NewPipeListener()
|
||||
dialFinished := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
err := blockFunc(pl, dialFinished)
|
||||
if blockFuncShouldError && err == nil {
|
||||
t.Error("expected blocking func to return error because pl.Close was called, but got nil")
|
||||
}
|
||||
|
||||
if !blockFuncShouldError && err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-dialFinished:
|
||||
t.Fatal("expected Dial to block until pl.Close or pl.Accept")
|
||||
default:
|
||||
}
|
||||
|
||||
if err := unblockFunc(pl); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-dialFinished:
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Fatal("expected Accept to unblock after pl.Accept was called")
|
||||
}
|
||||
}
|
481
vendor/google.golang.org/grpc/internal/transport/handler_server_test.go
generated
vendored
481
vendor/google.golang.org/grpc/internal/transport/handler_server_test.go
generated
vendored
@ -1,481 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2016 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package transport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
dpb "github.com/golang/protobuf/ptypes/duration"
|
||||
epb "google.golang.org/genproto/googleapis/rpc/errdetails"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestHandlerTransport_NewServerHandlerTransport(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
req *http.Request
|
||||
wantErr string
|
||||
modrw func(http.ResponseWriter) http.ResponseWriter
|
||||
check func(*serverHandlerTransport, *testCase) error
|
||||
}
|
||||
tests := []testCase{
|
||||
{
|
||||
name: "http/1.1",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
},
|
||||
wantErr: "gRPC requires HTTP/2",
|
||||
},
|
||||
{
|
||||
name: "bad method",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "GET",
|
||||
Header: http.Header{},
|
||||
RequestURI: "/",
|
||||
},
|
||||
wantErr: "invalid gRPC request method",
|
||||
},
|
||||
{
|
||||
name: "bad content type",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/foo"},
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
wantErr: "invalid gRPC request content-type",
|
||||
},
|
||||
{
|
||||
name: "not flusher",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
modrw: func(w http.ResponseWriter) http.ResponseWriter {
|
||||
// Return w without its Flush method
|
||||
type onlyCloseNotifier interface {
|
||||
http.ResponseWriter
|
||||
http.CloseNotifier
|
||||
}
|
||||
return struct{ onlyCloseNotifier }{w.(onlyCloseNotifier)}
|
||||
},
|
||||
wantErr: "gRPC requires a ResponseWriter supporting http.Flusher",
|
||||
},
|
||||
{
|
||||
name: "not closenotifier",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
modrw: func(w http.ResponseWriter) http.ResponseWriter {
|
||||
// Return w without its CloseNotify method
|
||||
type onlyFlusher interface {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
}
|
||||
return struct{ onlyFlusher }{w.(onlyFlusher)}
|
||||
},
|
||||
wantErr: "gRPC requires a ResponseWriter supporting http.CloseNotifier",
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
check: func(t *serverHandlerTransport, tt *testCase) error {
|
||||
if t.req != tt.req {
|
||||
return fmt.Errorf("t.req = %p; want %p", t.req, tt.req)
|
||||
}
|
||||
if t.rw == nil {
|
||||
return errors.New("t.rw = nil; want non-nil")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with timeout",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/grpc"},
|
||||
"Grpc-Timeout": {"200m"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
check: func(t *serverHandlerTransport, tt *testCase) error {
|
||||
if !t.timeoutSet {
|
||||
return errors.New("timeout not set")
|
||||
}
|
||||
if want := 200 * time.Millisecond; t.timeout != want {
|
||||
return fmt.Errorf("timeout = %v; want %v", t.timeout, want)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with bad timeout",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/grpc"},
|
||||
"Grpc-Timeout": {"tomorrow"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
wantErr: `rpc error: code = Internal desc = malformed time-out: transport: timeout unit is not recognized: "tomorrow"`,
|
||||
},
|
||||
{
|
||||
name: "with metadata",
|
||||
req: &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/grpc"},
|
||||
"meta-foo": {"foo-val"},
|
||||
"meta-bar": {"bar-val1", "bar-val2"},
|
||||
"user-agent": {"x/y a/b"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
},
|
||||
check: func(ht *serverHandlerTransport, tt *testCase) error {
|
||||
want := metadata.MD{
|
||||
"meta-bar": {"bar-val1", "bar-val2"},
|
||||
"user-agent": {"x/y a/b"},
|
||||
"meta-foo": {"foo-val"},
|
||||
"content-type": {"application/grpc"},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(ht.headerMD, want) {
|
||||
return fmt.Errorf("metdata = %#v; want %#v", ht.headerMD, want)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
rw := newTestHandlerResponseWriter()
|
||||
if tt.modrw != nil {
|
||||
rw = tt.modrw(rw)
|
||||
}
|
||||
got, gotErr := NewServerHandlerTransport(rw, tt.req, nil)
|
||||
if (gotErr != nil) != (tt.wantErr != "") || (gotErr != nil && gotErr.Error() != tt.wantErr) {
|
||||
t.Errorf("%s: error = %q; want %q", tt.name, gotErr.Error(), tt.wantErr)
|
||||
continue
|
||||
}
|
||||
if gotErr != nil {
|
||||
continue
|
||||
}
|
||||
if tt.check != nil {
|
||||
if err := tt.check(got.(*serverHandlerTransport), &tt); err != nil {
|
||||
t.Errorf("%s: %v", tt.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type testHandlerResponseWriter struct {
|
||||
*httptest.ResponseRecorder
|
||||
closeNotify chan bool
|
||||
}
|
||||
|
||||
func (w testHandlerResponseWriter) CloseNotify() <-chan bool { return w.closeNotify }
|
||||
func (w testHandlerResponseWriter) Flush() {}
|
||||
|
||||
func newTestHandlerResponseWriter() http.ResponseWriter {
|
||||
return testHandlerResponseWriter{
|
||||
ResponseRecorder: httptest.NewRecorder(),
|
||||
closeNotify: make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
type handleStreamTest struct {
|
||||
t *testing.T
|
||||
bodyw *io.PipeWriter
|
||||
rw testHandlerResponseWriter
|
||||
ht *serverHandlerTransport
|
||||
}
|
||||
|
||||
func newHandleStreamTest(t *testing.T) *handleStreamTest {
|
||||
bodyr, bodyw := io.Pipe()
|
||||
req := &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
Body: bodyr,
|
||||
}
|
||||
rw := newTestHandlerResponseWriter().(testHandlerResponseWriter)
|
||||
ht, err := NewServerHandlerTransport(rw, req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return &handleStreamTest{
|
||||
t: t,
|
||||
bodyw: bodyw,
|
||||
ht: ht.(*serverHandlerTransport),
|
||||
rw: rw,
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlerTransport_HandleStreams(t *testing.T) {
|
||||
st := newHandleStreamTest(t)
|
||||
handleStream := func(s *Stream) {
|
||||
if want := "/service/foo.bar"; s.method != want {
|
||||
t.Errorf("stream method = %q; want %q", s.method, want)
|
||||
}
|
||||
st.bodyw.Close() // no body
|
||||
st.ht.WriteStatus(s, status.New(codes.OK, ""))
|
||||
}
|
||||
st.ht.HandleStreams(
|
||||
func(s *Stream) { go handleStream(s) },
|
||||
func(ctx context.Context, method string) context.Context { return ctx },
|
||||
)
|
||||
wantHeader := http.Header{
|
||||
"Date": nil,
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Trailer": {"Grpc-Status", "Grpc-Message", "Grpc-Status-Details-Bin"},
|
||||
"Grpc-Status": {"0"},
|
||||
}
|
||||
if !reflect.DeepEqual(st.rw.HeaderMap, wantHeader) {
|
||||
t.Errorf("Header+Trailer Map: %#v; want %#v", st.rw.HeaderMap, wantHeader)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that codes.Unimplemented will close the body, per comment in handler_server.go.
|
||||
func TestHandlerTransport_HandleStreams_Unimplemented(t *testing.T) {
|
||||
handleStreamCloseBodyTest(t, codes.Unimplemented, "thingy is unimplemented")
|
||||
}
|
||||
|
||||
// Tests that codes.InvalidArgument will close the body, per comment in handler_server.go.
|
||||
func TestHandlerTransport_HandleStreams_InvalidArgument(t *testing.T) {
|
||||
handleStreamCloseBodyTest(t, codes.InvalidArgument, "bad arg")
|
||||
}
|
||||
|
||||
func handleStreamCloseBodyTest(t *testing.T, statusCode codes.Code, msg string) {
|
||||
st := newHandleStreamTest(t)
|
||||
|
||||
handleStream := func(s *Stream) {
|
||||
st.ht.WriteStatus(s, status.New(statusCode, msg))
|
||||
}
|
||||
st.ht.HandleStreams(
|
||||
func(s *Stream) { go handleStream(s) },
|
||||
func(ctx context.Context, method string) context.Context { return ctx },
|
||||
)
|
||||
wantHeader := http.Header{
|
||||
"Date": nil,
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Trailer": {"Grpc-Status", "Grpc-Message", "Grpc-Status-Details-Bin"},
|
||||
"Grpc-Status": {fmt.Sprint(uint32(statusCode))},
|
||||
"Grpc-Message": {encodeGrpcMessage(msg)},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(st.rw.HeaderMap, wantHeader) {
|
||||
t.Errorf("Header+Trailer mismatch.\n got: %#v\nwant: %#v", st.rw.HeaderMap, wantHeader)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlerTransport_HandleStreams_Timeout(t *testing.T) {
|
||||
bodyr, bodyw := io.Pipe()
|
||||
req := &http.Request{
|
||||
ProtoMajor: 2,
|
||||
Method: "POST",
|
||||
Header: http.Header{
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Grpc-Timeout": {"200m"},
|
||||
},
|
||||
URL: &url.URL{
|
||||
Path: "/service/foo.bar",
|
||||
},
|
||||
RequestURI: "/service/foo.bar",
|
||||
Body: bodyr,
|
||||
}
|
||||
rw := newTestHandlerResponseWriter().(testHandlerResponseWriter)
|
||||
ht, err := NewServerHandlerTransport(rw, req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runStream := func(s *Stream) {
|
||||
defer bodyw.Close()
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Errorf("timeout waiting for ctx.Done")
|
||||
return
|
||||
}
|
||||
err := s.ctx.Err()
|
||||
if err != context.DeadlineExceeded {
|
||||
t.Errorf("ctx.Err = %v; want %v", err, context.DeadlineExceeded)
|
||||
return
|
||||
}
|
||||
ht.WriteStatus(s, status.New(codes.DeadlineExceeded, "too slow"))
|
||||
}
|
||||
ht.HandleStreams(
|
||||
func(s *Stream) { go runStream(s) },
|
||||
func(ctx context.Context, method string) context.Context { return ctx },
|
||||
)
|
||||
wantHeader := http.Header{
|
||||
"Date": nil,
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Trailer": {"Grpc-Status", "Grpc-Message", "Grpc-Status-Details-Bin"},
|
||||
"Grpc-Status": {"4"},
|
||||
"Grpc-Message": {encodeGrpcMessage("too slow")},
|
||||
}
|
||||
if !reflect.DeepEqual(rw.HeaderMap, wantHeader) {
|
||||
t.Errorf("Header+Trailer Map mismatch.\n got: %#v\nwant: %#v", rw.HeaderMap, wantHeader)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandlerTransport_HandleStreams_MultiWriteStatus ensures that
|
||||
// concurrent "WriteStatus"s do not panic writing to closed "writes" channel.
|
||||
func TestHandlerTransport_HandleStreams_MultiWriteStatus(t *testing.T) {
|
||||
testHandlerTransportHandleStreams(t, func(st *handleStreamTest, s *Stream) {
|
||||
if want := "/service/foo.bar"; s.method != want {
|
||||
t.Errorf("stream method = %q; want %q", s.method, want)
|
||||
}
|
||||
st.bodyw.Close() // no body
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(5)
|
||||
for i := 0; i < 5; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
st.ht.WriteStatus(s, status.New(codes.OK, ""))
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
})
|
||||
}
|
||||
|
||||
// TestHandlerTransport_HandleStreams_WriteStatusWrite ensures that "Write"
|
||||
// following "WriteStatus" does not panic writing to closed "writes" channel.
|
||||
func TestHandlerTransport_HandleStreams_WriteStatusWrite(t *testing.T) {
|
||||
testHandlerTransportHandleStreams(t, func(st *handleStreamTest, s *Stream) {
|
||||
if want := "/service/foo.bar"; s.method != want {
|
||||
t.Errorf("stream method = %q; want %q", s.method, want)
|
||||
}
|
||||
st.bodyw.Close() // no body
|
||||
|
||||
st.ht.WriteStatus(s, status.New(codes.OK, ""))
|
||||
st.ht.Write(s, []byte("hdr"), []byte("data"), &Options{})
|
||||
})
|
||||
}
|
||||
|
||||
func testHandlerTransportHandleStreams(t *testing.T, handleStream func(st *handleStreamTest, s *Stream)) {
|
||||
st := newHandleStreamTest(t)
|
||||
st.ht.HandleStreams(
|
||||
func(s *Stream) { go handleStream(st, s) },
|
||||
func(ctx context.Context, method string) context.Context { return ctx },
|
||||
)
|
||||
}
|
||||
|
||||
func TestHandlerTransport_HandleStreams_ErrDetails(t *testing.T) {
|
||||
errDetails := []proto.Message{
|
||||
&epb.RetryInfo{
|
||||
RetryDelay: &dpb.Duration{Seconds: 60},
|
||||
},
|
||||
&epb.ResourceInfo{
|
||||
ResourceType: "foo bar",
|
||||
ResourceName: "service.foo.bar",
|
||||
Owner: "User",
|
||||
},
|
||||
}
|
||||
|
||||
statusCode := codes.ResourceExhausted
|
||||
msg := "you are being throttled"
|
||||
st, err := status.New(statusCode, msg).WithDetails(errDetails...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stBytes, err := proto.Marshal(st.Proto())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hst := newHandleStreamTest(t)
|
||||
handleStream := func(s *Stream) {
|
||||
hst.ht.WriteStatus(s, st)
|
||||
}
|
||||
hst.ht.HandleStreams(
|
||||
func(s *Stream) { go handleStream(s) },
|
||||
func(ctx context.Context, method string) context.Context { return ctx },
|
||||
)
|
||||
wantHeader := http.Header{
|
||||
"Date": nil,
|
||||
"Content-Type": {"application/grpc"},
|
||||
"Trailer": {"Grpc-Status", "Grpc-Message", "Grpc-Status-Details-Bin"},
|
||||
"Grpc-Status": {fmt.Sprint(uint32(statusCode))},
|
||||
"Grpc-Message": {encodeGrpcMessage(msg)},
|
||||
"Grpc-Status-Details-Bin": {encodeBinHeader(stBytes)},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(hst.rw.HeaderMap, wantHeader) {
|
||||
t.Errorf("Header+Trailer mismatch.\n got: %#v\nwant: %#v", hst.rw.HeaderMap, wantHeader)
|
||||
}
|
||||
}
|
237
vendor/google.golang.org/grpc/internal/transport/http_util_test.go
generated
vendored
237
vendor/google.golang.org/grpc/internal/transport/http_util_test.go
generated
vendored
@ -1,237 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2014 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package transport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestTimeoutEncode(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"12345678ns", "12345678n"},
|
||||
{"123456789ns", "123457u"},
|
||||
{"12345678us", "12345678u"},
|
||||
{"123456789us", "123457m"},
|
||||
{"12345678ms", "12345678m"},
|
||||
{"123456789ms", "123457S"},
|
||||
{"12345678s", "12345678S"},
|
||||
{"123456789s", "2057614M"},
|
||||
{"12345678m", "12345678M"},
|
||||
{"123456789m", "2057614H"},
|
||||
} {
|
||||
d, err := time.ParseDuration(test.in)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse duration string %s: %v", test.in, err)
|
||||
}
|
||||
out := encodeTimeout(d)
|
||||
if out != test.out {
|
||||
t.Fatalf("timeoutEncode(%s) = %s, want %s", test.in, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeoutDecode(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
s string
|
||||
// output
|
||||
d time.Duration
|
||||
err error
|
||||
}{
|
||||
{"1234S", time.Second * 1234, nil},
|
||||
{"1234x", 0, fmt.Errorf("transport: timeout unit is not recognized: %q", "1234x")},
|
||||
{"1", 0, fmt.Errorf("transport: timeout string is too short: %q", "1")},
|
||||
{"", 0, fmt.Errorf("transport: timeout string is too short: %q", "")},
|
||||
} {
|
||||
d, err := decodeTimeout(test.s)
|
||||
if d != test.d || fmt.Sprint(err) != fmt.Sprint(test.err) {
|
||||
t.Fatalf("timeoutDecode(%q) = %d, %v, want %d, %v", test.s, int64(d), err, int64(test.d), test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestContentSubtype(t *testing.T) {
|
||||
tests := []struct {
|
||||
contentType string
|
||||
want string
|
||||
wantValid bool
|
||||
}{
|
||||
{"application/grpc", "", true},
|
||||
{"application/grpc+", "", true},
|
||||
{"application/grpc+blah", "blah", true},
|
||||
{"application/grpc;", "", true},
|
||||
{"application/grpc;blah", "blah", true},
|
||||
{"application/grpcd", "", false},
|
||||
{"application/grpd", "", false},
|
||||
{"application/grp", "", false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got, gotValid := contentSubtype(tt.contentType)
|
||||
if got != tt.want || gotValid != tt.wantValid {
|
||||
t.Errorf("contentSubtype(%q) = (%v, %v); want (%v, %v)", tt.contentType, got, gotValid, tt.want, tt.wantValid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeGrpcMessage(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"", ""},
|
||||
{"Hello", "Hello"},
|
||||
{"\u0000", "%00"},
|
||||
{"%", "%25"},
|
||||
{"系统", "%E7%B3%BB%E7%BB%9F"},
|
||||
{string([]byte{0xff, 0xfe, 0xfd}), "%EF%BF%BD%EF%BF%BD%EF%BF%BD"},
|
||||
} {
|
||||
actual := encodeGrpcMessage(tt.input)
|
||||
if tt.expected != actual {
|
||||
t.Errorf("encodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that all the visible ASCII chars except '%' are not percent encoded.
|
||||
for i := ' '; i <= '~' && i != '%'; i++ {
|
||||
output := encodeGrpcMessage(string(i))
|
||||
if output != string(i) {
|
||||
t.Errorf("encodeGrpcMessage(%v) = %v, want %v", string(i), output, string(i))
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that all the invisible ASCII chars and '%' are percent encoded.
|
||||
for i := rune(0); i == '%' || (i >= rune(0) && i < ' ') || (i > '~' && i <= rune(127)); i++ {
|
||||
output := encodeGrpcMessage(string(i))
|
||||
expected := fmt.Sprintf("%%%02X", i)
|
||||
if output != expected {
|
||||
t.Errorf("encodeGrpcMessage(%v) = %v, want %v", string(i), output, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeGrpcMessage(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"", ""},
|
||||
{"Hello", "Hello"},
|
||||
{"H%61o", "Hao"},
|
||||
{"H%6", "H%6"},
|
||||
{"%G0", "%G0"},
|
||||
{"%E7%B3%BB%E7%BB%9F", "系统"},
|
||||
{"%EF%BF%BD", "<22>"},
|
||||
} {
|
||||
actual := decodeGrpcMessage(tt.input)
|
||||
if tt.expected != actual {
|
||||
t.Errorf("decodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that all the visible ASCII chars except '%' are not percent decoded.
|
||||
for i := ' '; i <= '~' && i != '%'; i++ {
|
||||
output := decodeGrpcMessage(string(i))
|
||||
if output != string(i) {
|
||||
t.Errorf("decodeGrpcMessage(%v) = %v, want %v", string(i), output, string(i))
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that all the invisible ASCII chars and '%' are percent decoded.
|
||||
for i := rune(0); i == '%' || (i >= rune(0) && i < ' ') || (i > '~' && i <= rune(127)); i++ {
|
||||
output := decodeGrpcMessage(fmt.Sprintf("%%%02X", i))
|
||||
if output != string(i) {
|
||||
t.Errorf("decodeGrpcMessage(%v) = %v, want %v", fmt.Sprintf("%%%02X", i), output, string(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decode an encoded string should get the same thing back, except for invalid
|
||||
// utf8 chars.
|
||||
func TestDecodeEncodeGrpcMessage(t *testing.T) {
|
||||
testCases := []struct {
|
||||
orig string
|
||||
want string
|
||||
}{
|
||||
{"", ""},
|
||||
{"hello", "hello"},
|
||||
{"h%6", "h%6"},
|
||||
{"%G0", "%G0"},
|
||||
{"系统", "系统"},
|
||||
{"Hello, 世界", "Hello, 世界"},
|
||||
|
||||
{string([]byte{0xff, 0xfe, 0xfd}), "<22><><EFBFBD>"},
|
||||
{string([]byte{0xff}) + "Hello" + string([]byte{0xfe}) + "世界" + string([]byte{0xfd}), "<22>Hello<6C>世界<E4B896>"},
|
||||
}
|
||||
for _, tC := range testCases {
|
||||
got := decodeGrpcMessage(encodeGrpcMessage(tC.orig))
|
||||
if got != tC.want {
|
||||
t.Errorf("decodeGrpcMessage(encodeGrpcMessage(%q)) = %q, want %q", tC.orig, got, tC.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const binaryValue = string(128)
|
||||
|
||||
func TestEncodeMetadataHeader(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
kin string
|
||||
vin string
|
||||
// output
|
||||
vout string
|
||||
}{
|
||||
{"key", "abc", "abc"},
|
||||
{"KEY", "abc", "abc"},
|
||||
{"key-bin", "abc", "YWJj"},
|
||||
{"key-bin", binaryValue, "woA"},
|
||||
} {
|
||||
v := encodeMetadataHeader(test.kin, test.vin)
|
||||
if !reflect.DeepEqual(v, test.vout) {
|
||||
t.Fatalf("encodeMetadataHeader(%q, %q) = %q, want %q", test.kin, test.vin, v, test.vout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeMetadataHeader(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
// input
|
||||
kin string
|
||||
vin string
|
||||
// output
|
||||
vout string
|
||||
err error
|
||||
}{
|
||||
{"a", "abc", "abc", nil},
|
||||
{"key-bin", "Zm9vAGJhcg==", "foo\x00bar", nil},
|
||||
{"key-bin", "Zm9vAGJhcg", "foo\x00bar", nil},
|
||||
{"key-bin", "woA=", binaryValue, nil},
|
||||
{"a", "abc,efg", "abc,efg", nil},
|
||||
} {
|
||||
v, err := decodeMetadataHeader(test.kin, test.vin)
|
||||
if !reflect.DeepEqual(v, test.vout) || !reflect.DeepEqual(err, test.err) {
|
||||
t.Fatalf("decodeMetadataHeader(%q, %q) = %q, %v, want %q, %v", test.kin, test.vin, v, err, test.vout, test.err)
|
||||
}
|
||||
}
|
||||
}
|
2375
vendor/google.golang.org/grpc/internal/transport/transport_test.go
generated
vendored
2375
vendor/google.golang.org/grpc/internal/transport/transport_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user