1/*
2 *
3 * Copyright 2014 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19package transport
20
21import (
22	"fmt"
23	"reflect"
24	"testing"
25	"time"
26)
27
28func (s) TestTimeoutDecode(t *testing.T) {
29	for _, test := range []struct {
30		// input
31		s string
32		// output
33		d   time.Duration
34		err error
35	}{
36		{"1234S", time.Second * 1234, nil},
37		{"1234x", 0, fmt.Errorf("transport: timeout unit is not recognized: %q", "1234x")},
38		{"1", 0, fmt.Errorf("transport: timeout string is too short: %q", "1")},
39		{"", 0, fmt.Errorf("transport: timeout string is too short: %q", "")},
40	} {
41		d, err := decodeTimeout(test.s)
42		if d != test.d || fmt.Sprint(err) != fmt.Sprint(test.err) {
43			t.Fatalf("timeoutDecode(%q) = %d, %v, want %d, %v", test.s, int64(d), err, int64(test.d), test.err)
44		}
45	}
46}
47
48func (s) TestEncodeGrpcMessage(t *testing.T) {
49	for _, tt := range []struct {
50		input    string
51		expected string
52	}{
53		{"", ""},
54		{"Hello", "Hello"},
55		{"\u0000", "%00"},
56		{"%", "%25"},
57		{"系统", "%E7%B3%BB%E7%BB%9F"},
58		{string([]byte{0xff, 0xfe, 0xfd}), "%EF%BF%BD%EF%BF%BD%EF%BF%BD"},
59	} {
60		actual := encodeGrpcMessage(tt.input)
61		if tt.expected != actual {
62			t.Errorf("encodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected)
63		}
64	}
65
66	// make sure that all the visible ASCII chars except '%' are not percent encoded.
67	for i := ' '; i <= '~' && i != '%'; i++ {
68		output := encodeGrpcMessage(string(i))
69		if output != string(i) {
70			t.Errorf("encodeGrpcMessage(%v) = %v, want %v", string(i), output, string(i))
71		}
72	}
73
74	// make sure that all the invisible ASCII chars and '%' are percent encoded.
75	for i := rune(0); i == '%' || (i >= rune(0) && i < ' ') || (i > '~' && i <= rune(127)); i++ {
76		output := encodeGrpcMessage(string(i))
77		expected := fmt.Sprintf("%%%02X", i)
78		if output != expected {
79			t.Errorf("encodeGrpcMessage(%v) = %v, want %v", string(i), output, expected)
80		}
81	}
82}
83
84func (s) TestDecodeGrpcMessage(t *testing.T) {
85	for _, tt := range []struct {
86		input    string
87		expected string
88	}{
89		{"", ""},
90		{"Hello", "Hello"},
91		{"H%61o", "Hao"},
92		{"H%6", "H%6"},
93		{"%G0", "%G0"},
94		{"%E7%B3%BB%E7%BB%9F", "系统"},
95		{"%EF%BF%BD", "�"},
96	} {
97		actual := decodeGrpcMessage(tt.input)
98		if tt.expected != actual {
99			t.Errorf("decodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected)
100		}
101	}
102
103	// make sure that all the visible ASCII chars except '%' are not percent decoded.
104	for i := ' '; i <= '~' && i != '%'; i++ {
105		output := decodeGrpcMessage(string(i))
106		if output != string(i) {
107			t.Errorf("decodeGrpcMessage(%v) = %v, want %v", string(i), output, string(i))
108		}
109	}
110
111	// make sure that all the invisible ASCII chars and '%' are percent decoded.
112	for i := rune(0); i == '%' || (i >= rune(0) && i < ' ') || (i > '~' && i <= rune(127)); i++ {
113		output := decodeGrpcMessage(fmt.Sprintf("%%%02X", i))
114		if output != string(i) {
115			t.Errorf("decodeGrpcMessage(%v) = %v, want %v", fmt.Sprintf("%%%02X", i), output, string(i))
116		}
117	}
118}
119
120// Decode an encoded string should get the same thing back, except for invalid
121// utf8 chars.
122func (s) TestDecodeEncodeGrpcMessage(t *testing.T) {
123	testCases := []struct {
124		orig string
125		want string
126	}{
127		{"", ""},
128		{"hello", "hello"},
129		{"h%6", "h%6"},
130		{"%G0", "%G0"},
131		{"系统", "系统"},
132		{"Hello, 世界", "Hello, 世界"},
133
134		{string([]byte{0xff, 0xfe, 0xfd}), "���"},
135		{string([]byte{0xff}) + "Hello" + string([]byte{0xfe}) + "世界" + string([]byte{0xfd}), "�Hello�世界�"},
136	}
137	for _, tC := range testCases {
138		got := decodeGrpcMessage(encodeGrpcMessage(tC.orig))
139		if got != tC.want {
140			t.Errorf("decodeGrpcMessage(encodeGrpcMessage(%q)) = %q, want %q", tC.orig, got, tC.want)
141		}
142	}
143}
144
145const binaryValue = "\u0080"
146
147func (s) TestEncodeMetadataHeader(t *testing.T) {
148	for _, test := range []struct {
149		// input
150		kin string
151		vin string
152		// output
153		vout string
154	}{
155		{"key", "abc", "abc"},
156		{"KEY", "abc", "abc"},
157		{"key-bin", "abc", "YWJj"},
158		{"key-bin", binaryValue, "woA"},
159	} {
160		v := encodeMetadataHeader(test.kin, test.vin)
161		if !reflect.DeepEqual(v, test.vout) {
162			t.Fatalf("encodeMetadataHeader(%q, %q) = %q, want %q", test.kin, test.vin, v, test.vout)
163		}
164	}
165}
166
167func (s) TestDecodeMetadataHeader(t *testing.T) {
168	for _, test := range []struct {
169		// input
170		kin string
171		vin string
172		// output
173		vout string
174		err  error
175	}{
176		{"a", "abc", "abc", nil},
177		{"key-bin", "Zm9vAGJhcg==", "foo\x00bar", nil},
178		{"key-bin", "Zm9vAGJhcg", "foo\x00bar", nil},
179		{"key-bin", "woA=", binaryValue, nil},
180		{"a", "abc,efg", "abc,efg", nil},
181	} {
182		v, err := decodeMetadataHeader(test.kin, test.vin)
183		if !reflect.DeepEqual(v, test.vout) || !reflect.DeepEqual(err, test.err) {
184			t.Fatalf("decodeMetadataHeader(%q, %q) = %q, %v, want %q, %v", test.kin, test.vin, v, err, test.vout, test.err)
185		}
186	}
187}
188
189func (s) TestParseDialTarget(t *testing.T) {
190	for _, test := range []struct {
191		target, wantNet, wantAddr string
192	}{
193		{"unix:a", "unix", "a"},
194		{"unix:a/b/c", "unix", "a/b/c"},
195		{"unix:/a", "unix", "/a"},
196		{"unix:/a/b/c", "unix", "/a/b/c"},
197		{"unix://a", "unix", "a"},
198		{"unix://a/b/c", "unix", "/b/c"},
199		{"unix:///a", "unix", "/a"},
200		{"unix:///a/b/c", "unix", "/a/b/c"},
201		{"unix:etcd:0", "unix", "etcd:0"},
202		{"unix:///tmp/unix-3", "unix", "/tmp/unix-3"},
203		{"unix://domain", "unix", "domain"},
204		{"unix://etcd:0", "unix", "etcd:0"},
205		{"unix:///etcd:0", "unix", "/etcd:0"},
206		{"passthrough://unix://domain", "tcp", "passthrough://unix://domain"},
207		{"https://google.com:443", "tcp", "https://google.com:443"},
208		{"dns:///google.com", "tcp", "dns:///google.com"},
209		{"/unix/socket/address", "tcp", "/unix/socket/address"},
210	} {
211		gotNet, gotAddr := parseDialTarget(test.target)
212		if gotNet != test.wantNet || gotAddr != test.wantAddr {
213			t.Errorf("parseDialTarget(%q) = %s, %s want %s, %s", test.target, gotNet, gotAddr, test.wantNet, test.wantAddr)
214		}
215	}
216}
217