blob: 15b54cc77ee0b1c34775d6973d9ac27865a21fa8 [file] [log] [blame]
package client
import (
"context"
"io/ioutil"
"net"
"path"
"testing"
repb "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2"
svpb "github.com/bazelbuild/remote-apis/build/bazel/semver"
"google.golang.org/grpc"
)
const (
// This key pair for `foo.example.com` was generated using https://golang.org/src/crypto/tls/generate_cert.go
tlsCert = `
-----BEGIN CERTIFICATE-----
MIIC/zCCAeegAwIBAgIQa6p4srafgw0S6iDvt7rlXzANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQKEwdBY21lIENvMB4XDTIwMTAwODA5NTExM1oXDTIxMTAwODA5NTEx
M1owEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAM1Mo2UOcQxkPHs2+oaclJsPZo80Cqb0Oze0zxA9uFXg6SiklqPjWUPc
o2TTBmbpw6t2Cv6Ywr6cTB7PJXCruOFo5x+6rZlzjrfqArYn3Btv64/6SwaarIEW
UcisWDvcEW+QArAmsJo39RL4ptsb+0Eoqkm1WeQ31XWh9i7W0F3qy43lC4k5QpXb
imeevejwk3TMFAnAc8dBXxNDg3gr9isDq2yH1ZhJ/4BNcle6WYNny0Uh9kYCLCWe
PK1ZYOeT1rRCtBJTg7w1/e0Qpln6V/MsJNtgt14vYPsHAsW+AMLycN1f9/8T7joz
6/D8GVMC5Vaz2z5CxeNb5ifCQkmEN8kCAwEAAaNRME8wDgYDVR0PAQH/BAQDAgWg
MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwGgYDVR0RBBMwEYIP
Zm9vLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQB0d9y7XyLwWMBMxIRL
5rdgk9AvpVKX5FtYkJmxG7F9p67GlLhy314SyPDaUm/tl0yf/LM9m7BM7m9900mO
9qjfTi6wc0Co9dDMhi4rh0CPlEilWpiA7wAyM0eVQPJx+wv/u/8aDzVy/Cr8wLwi
UyXETaAVsbrHmoIMQgyy0boTDzBwwhx8e/heqaZfV6H6RsBpChYFIF0A7T92bu91
WmSA9kfUwzYeOvLyX/s+J77U/bnYo4Fl/LnBkBr1vkTPF9xGWYZFU0Ok/uk9TyrB
vI06wv3H6phi4fWDMbWuSiBHr3AefTqcxkBcaxYCzLgOdRJEnV1GWdw/Gt9PNyJ2
IJff
-----END CERTIFICATE-----
`
tlsKey = `
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNTKNlDnEMZDx7
NvqGnJSbD2aPNAqm9Ds3tM8QPbhV4OkopJaj41lD3KNk0wZm6cOrdgr+mMK+nEwe
zyVwq7jhaOcfuq2Zc4636gK2J9wbb+uP+ksGmqyBFlHIrFg73BFvkAKwJrCaN/US
+KbbG/tBKKpJtVnkN9V1ofYu1tBd6suN5QuJOUKV24pnnr3o8JN0zBQJwHPHQV8T
Q4N4K/YrA6tsh9WYSf+ATXJXulmDZ8tFIfZGAiwlnjytWWDnk9a0QrQSU4O8Nf3t
EKZZ+lfzLCTbYLdeL2D7BwLFvgDC8nDdX/f/E+46M+vw/BlTAuVWs9s+QsXjW+Yn
wkJJhDfJAgMBAAECggEAOdsALQl92FUjKkIbJfZYdr5HU9IBsn0fdxpwRA5wtVr1
uitv/G2kiVhTf6Vsp3H3X4mbnZYlQ5w+Y2xTC8aJCpUKlUmBhL4pGTFMZFMlV2Ia
C3Ao1oqeVJ6am6feEbh5/WujJksw97UPTrJeK19eVkWEf9MoqwUFFep3u0l0XRK9
zR5ZhhZe+3C1DS3r7P89/7ZlnqLuba94fIqwn11D7jzmiZQBuBLa6X16grGs03Gb
LoBoiTj7g0a6nSEcDen5jI8oPrZuMWAlTXLYb68eCgvU2FXe0A2PFZzh8XQ71Y4J
Y6L0oGGiTThgphsH/bqQi03mF/Hd0BcIlBe+8mPSFQKBgQDuUI5ENq650eOf6PPh
abLl+cmBIxNdfFYZHB5IapDfqKBK3imD3QYT4cBdbcQ0PWjbFj/aCgkPYCmMxBSX
WGVohhH4sXHNIS0BL6dGalQhE+C3tWkzg79AE84tTrvijVuOom3RiR0SGzBQ4YBl
boPPKinY6Hz6FEhlfWdlwR0GcwKBgQDciN2m1wNG6gkDg/2OEn+g79boKPdI0lC4
VTfQ6xDKwGs2N8HIOoeXHhTStgkPCeNmxuOtEtqfKKRpje2ZRFvjZWOh6t+CvX0w
ZE+GhJtBC0ODYQ9+Hai1HgBbLYrMR44cRWRx5uMD4/v4Vrg7jdtpUICeonPd4mMD
ppgV0Ze90wKBgBWu+LLWMuGvakGjhYUuA9wO9TmtwlZQONlCCLNYFuRyyFrniel4
k9P9R254zVBfggnlJVwma5qdikpHkQQQQ/HVuQ7ivlMGwLyJ5HNwu0TjNSAh/nd0
dlNTOgA/WLMNX5ZDyzA0hJOgK65ARll0S8Puty4IQU7Tx56MYXsNriFnAoGBAI1g
+Kfio2ks1AZ68WvJFCT6XM2Mpar7mV/y0cuPRr6USKcDa6mPTClm0Xab2IbZkfzr
eD4WHi12gqBgqnddSYMoFo1Q42UPUVhalljoXhd+vxNUf/gbz3H8/8F0Gs0G+mXJ
XrFekR6HY5s7DPSw5n5Ha41HG/ydC1jlzg3+xcadAoGBAIZ/ZJpnC2Tv8poGHbmD
B3hWlPIQSU2dEGQCEhiGhzoi7muXmYqx5t8YnMGLGmsltLxD95KhACrTZZmBGiUS
HavFSkKMI1EuncwH2ooshIF9ZQqYNpIH7YGxnzDgNXnmeb26FI+b0uuxW74PWZrL
h4A58eQ+JGSLao6JSmi2T0tZ
-----END PRIVATE KEY-----
`
instance = "instance"
)
func TestCreateTLSConfig(t *testing.T) {
t.Run("EmptyDialParams", func(t *testing.T) {
_, err := createTLSConfig(DialParams{})
if err != nil {
t.Errorf("Could not create TLS config: %v", err)
}
})
t.Run("OverrideServerName", func(t *testing.T) {
tlsConfig, err := createTLSConfig(DialParams{
TLSServerName: "foo.example.com",
})
if err != nil {
t.Errorf("Could not create TLS config: %v", err)
}
if tlsConfig.ServerName != "foo.example.com" {
t.Errorf("Expected ServerName to be 'foo.example.com', got '%v'", tlsConfig.ServerName)
}
})
t.Run("UseClientCertificate", func(t *testing.T) {
t.Run("OnlyTLSClientAuthCert", func(t *testing.T) {
_, err := createTLSConfig(DialParams{
TLSClientAuthCert: "/foo/bar",
})
if err == nil {
t.Error("Expected error creating mTLS config without auth-key, got nil")
}
})
t.Run("OnlyTLSClientAuthKey", func(t *testing.T) {
_, err := createTLSConfig(DialParams{
TLSClientAuthKey: "/foo/bar",
})
if err == nil {
t.Error("Expected error creating mTLS config without auth-cert, got nil")
}
})
t.Run("OnlyTLSClientAuthCert", func(t *testing.T) {
certPath := path.Join(t.TempDir(), "cert.pem")
if err := ioutil.WriteFile(certPath, []byte(tlsCert), 0644); err != nil {
t.Fatalf("Could not write '%v': %v", certPath, err)
}
keyPath := path.Join(t.TempDir(), "key.pem")
if err := ioutil.WriteFile(keyPath, []byte(tlsKey), 0644); err != nil {
t.Fatalf("Could not write '%v': %v", keyPath, err)
}
tlsConfig, err := createTLSConfig(DialParams{
TLSClientAuthCert: certPath,
TLSClientAuthKey: keyPath,
})
if err != nil {
t.Errorf("Could not create TLS config: %v", err)
}
if len(tlsConfig.Certificates) != 1 {
t.Errorf("Expected exactly 1 certificate, got: %v", tlsConfig.Certificates)
}
})
})
}
func TestVersionComparison(t *testing.T) {
latestSupportedVersion := &svpb.SemVer{Major: 2, Minor: 1}
serverCapabilities := &repb.ServerCapabilities{
HighApiVersion: latestSupportedVersion,
}
if !highAPIVersionNewerThanOrEqualTo(serverCapabilities, 1, 9) {
t.Errorf("Got: !(2.1 >= 1.9")
}
if !highAPIVersionNewerThanOrEqualTo(serverCapabilities, 2, 0) {
t.Errorf("Got: !(2.1 >= 2.0")
}
if highAPIVersionNewerThanOrEqualTo(serverCapabilities, 2, 2) {
t.Errorf("Got: 2.1 >= 2.2")
}
if highAPIVersionNewerThanOrEqualTo(&repb.ServerCapabilities{}, 0, 1) {
t.Errorf("Got: empty >= 0.1")
}
if highAPIVersionNewerThanOrEqualTo(nil, 0, 1) {
t.Errorf("Got: nil >= 0.1")
}
}
func TestActionSupportsPlatformProperties(t *testing.T) {
if supportsActionPlatformProperties(&repb.ServerCapabilities{HighApiVersion: &svpb.SemVer{Major: 2, Minor: 1}}) {
t.Errorf("Got platform properties field suppported for v2.1 (expected only for v >= 2.2)")
}
if !supportsActionPlatformProperties(&repb.ServerCapabilities{HighApiVersion: &svpb.SemVer{Major: 2, Minor: 2}}) {
t.Errorf("Got platform properties field not suppported for v2.2 (expected for v >= 2.2)")
}
if !supportsActionPlatformProperties(&repb.ServerCapabilities{HighApiVersion: &svpb.SemVer{Major: 2, Minor: 3}}) {
t.Errorf("Got platform properties field not suppported for v2.3 (expected for v >= 2.2)")
}
}
func TestCommandUsesOutputPaths(t *testing.T) {
if supportsCommandOutputPaths(&repb.ServerCapabilities{HighApiVersion: &svpb.SemVer{Major: 2, Minor: 0}}) {
t.Errorf("Got `output_paths` field suppported for v2.0 (expected only for v >= 2.1)")
}
if !supportsCommandOutputPaths(&repb.ServerCapabilities{HighApiVersion: &svpb.SemVer{Major: 2, Minor: 1}}) {
t.Errorf("Got `output_paths` field not suppported for v2.1 (expected for v >= 2.1)")
}
if !supportsCommandOutputPaths(&repb.ServerCapabilities{HighApiVersion: &svpb.SemVer{Major: 2, Minor: 2}}) {
t.Errorf("Got `output_paths` field not suppported for v2.2 (expected for v >= 2.1)")
}
}
func TestNewClient(t *testing.T) {
t.Parallel()
ctx := context.Background()
c, err := NewClient(ctx, instance, DialParams{
Service: "server",
NoSecurity: true,
}, StartupCapabilities(false))
if err != nil {
t.Fatalf("Error creating client: %v", err)
}
defer c.Close()
}
func TestNewClientFromConnection(t *testing.T) {
t.Parallel()
ctx := context.Background()
l, err := net.Listen("tcp", ":0")
if err != nil {
t.Fatalf("Cannot listen: %v", err)
}
conn, err := grpc.Dial(l.Addr().String(), grpc.WithInsecure())
if err != nil {
t.Fatalf("Cannot establish gRPC connection: %v", err)
}
c, err := NewClientFromConnection(ctx, instance, conn, conn, StartupCapabilities(false))
if err != nil {
t.Fatalf("Error creating client: %v", err)
}
defer c.Close()
_, err = NewClientFromConnection(ctx, instance, nil, conn, StartupCapabilities(false))
if err == nil {
t.Fatalf("Expected error got nil")
}
_, err = NewClientFromConnection(ctx, instance, conn, nil, StartupCapabilities(false))
if err == nil {
t.Fatalf("Expected error got nil")
}
}