From fbc1139aa061719d08885535e4725d0a5ee1f8ff Mon Sep 17 00:00:00 2001 From: Scott84 Date: Fri, 2 Oct 2015 09:01:28 -0700 Subject: [PATCH 01/37] Update GRXWriter.m Corrected compiler warning for effectively pure virtual ObjC methods. --- src/objective-c/RxLibrary/GRXWriter.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/objective-c/RxLibrary/GRXWriter.m b/src/objective-c/RxLibrary/GRXWriter.m index 019fcbd7858..fee33f55563 100644 --- a/src/objective-c/RxLibrary/GRXWriter.m +++ b/src/objective-c/RxLibrary/GRXWriter.m @@ -35,4 +35,14 @@ @implementation GRXWriter +- (void)startWithWriteable:(id)writeable { + NSAssert(NO, @"Missing base implementation for %@", NSStringFromSelector(_cmd)); + [self doesNotRecognizeSelector:_cmd]; +} + +- (void)finishWithError:(NSError *)errorOrNil { + NSAssert(NO, @"Missing base implementation for %@", NSStringFromSelector(_cmd)); + [self doesNotRecognizeSelector:_cmd]; +} + @end From 4aca796ca291e7b0ef4fe2f4aa1c722fad642871 Mon Sep 17 00:00:00 2001 From: Carl Mastrangelo Date: Mon, 5 Oct 2015 16:17:47 -0700 Subject: [PATCH 02/37] Add initial interop tests --- tools/http2_interop/README.md | 9 + tools/http2_interop/doc.go | 6 + tools/http2_interop/frame.go | 11 + tools/http2_interop/frameheader.go | 109 ++++++++++ tools/http2_interop/http2interop.go | 245 +++++++++++++++++++++++ tools/http2_interop/http2interop_test.go | 50 +++++ tools/http2_interop/ping.go | 65 ++++++ tools/http2_interop/settings.go | 109 ++++++++++ tools/http2_interop/unknownframe.go | 54 +++++ 9 files changed, 658 insertions(+) create mode 100644 tools/http2_interop/README.md create mode 100644 tools/http2_interop/doc.go create mode 100644 tools/http2_interop/frame.go create mode 100644 tools/http2_interop/frameheader.go create mode 100644 tools/http2_interop/http2interop.go create mode 100644 tools/http2_interop/http2interop_test.go create mode 100644 tools/http2_interop/ping.go create mode 100644 tools/http2_interop/settings.go create mode 100644 tools/http2_interop/unknownframe.go diff --git a/tools/http2_interop/README.md b/tools/http2_interop/README.md new file mode 100644 index 00000000000..21688f09804 --- /dev/null +++ b/tools/http2_interop/README.md @@ -0,0 +1,9 @@ +HTTP/2 Interop Tests +==== + +This is a suite of tests that check a server to see if it plays nicely with other HTTP/2 clients. To run, just type: + +`go test -spec :1234` + +Where ":1234" is the ip:port of a running server. + diff --git a/tools/http2_interop/doc.go b/tools/http2_interop/doc.go new file mode 100644 index 00000000000..6c6b5cb1938 --- /dev/null +++ b/tools/http2_interop/doc.go @@ -0,0 +1,6 @@ +// http2interop project doc.go + +/* +http2interop document +*/ +package http2interop diff --git a/tools/http2_interop/frame.go b/tools/http2_interop/frame.go new file mode 100644 index 00000000000..12689e9b33d --- /dev/null +++ b/tools/http2_interop/frame.go @@ -0,0 +1,11 @@ +package http2interop + +import ( + "io" +) + +type Frame interface { + GetHeader() *FrameHeader + ParsePayload(io.Reader) error + MarshalBinary() ([]byte, error) +} diff --git a/tools/http2_interop/frameheader.go b/tools/http2_interop/frameheader.go new file mode 100644 index 00000000000..78fe4201f62 --- /dev/null +++ b/tools/http2_interop/frameheader.go @@ -0,0 +1,109 @@ +package http2interop + +import ( + "encoding/binary" + "fmt" + "io" +) + +type FrameHeader struct { + Length int + Type FrameType + Flags byte + Reserved Reserved + StreamID +} + +type Reserved bool + +func (r Reserved) String() string { + if r { + return "R" + } + return "" +} + +func (fh *FrameHeader) Parse(r io.Reader) error { + buf := make([]byte, 9) + if _, err := io.ReadFull(r, buf); err != nil { + return err + } + return fh.UnmarshalBinary(buf) +} + +func (fh *FrameHeader) UnmarshalBinary(b []byte) error { + if len(b) != 9 { + return fmt.Errorf("Invalid frame header length %d", len(b)) + } + *fh = FrameHeader{ + Length: int(b[0])<<16 | int(b[1])<<8 | int(b[2]), + Type: FrameType(b[3]), + Flags: b[4], + Reserved: Reserved(b[5]>>7 == 1), + StreamID: StreamID(binary.BigEndian.Uint32(b[5:9]) & 0x7fffffff), + } + return nil +} + +func (fh *FrameHeader) MarshalBinary() ([]byte, error) { + buf := make([]byte, 9, 9+fh.Length) + + if fh.Length > 0xFFFFFF || fh.Length < 0 { + return nil, fmt.Errorf("Invalid frame header length: %d", fh.Length) + } + if fh.StreamID < 0 { + return nil, fmt.Errorf("Invalid Stream ID: %v", fh.StreamID) + } + + buf[0], buf[1], buf[2] = byte(fh.Length>>16), byte(fh.Length>>8), byte(fh.Length) + buf[3] = byte(fh.Type) + buf[4] = fh.Flags + binary.BigEndian.PutUint32(buf[5:], uint32(fh.StreamID)) + + return buf, nil +} + +type StreamID int32 + +type FrameType byte + +func (ft FrameType) String() string { + switch ft { + case DataFrameType: + return "DATA" + case HeadersFrameType: + return "HEADERS" + case PriorityFrameType: + return "PRIORITY" + case ResetStreamFrameType: + return "RST_STREAM" + case SettingsFrameType: + return "SETTINGS" + case PushPromiseFrameType: + return "PUSH_PROMISE" + case PingFrameType: + return "PING" + case GoAwayFrameType: + return "GOAWAY" + case WindowUpdateFrameType: + return "WINDOW_UPDATE" + case ContinuationFrameType: + return "CONTINUATION" + default: + return fmt.Sprintf("UNKNOWN(%d)", byte(ft)) + } +} + +// Types +const ( + DataFrameType FrameType = 0 + HeadersFrameType FrameType = 1 + PriorityFrameType FrameType = 2 + ResetStreamFrameType FrameType = 3 + SettingsFrameType FrameType = 4 + PushPromiseFrameType FrameType = 5 + PingFrameType FrameType = 6 + GoAwayFrameType FrameType = 7 + WindowUpdateFrameType FrameType = 8 + ContinuationFrameType FrameType = 9 +) diff --git a/tools/http2_interop/http2interop.go b/tools/http2_interop/http2interop.go new file mode 100644 index 00000000000..f1bca7fe13d --- /dev/null +++ b/tools/http2_interop/http2interop.go @@ -0,0 +1,245 @@ +package http2interop + +import ( + "crypto/tls" + "fmt" + "io" + "log" +) + +const ( + Preface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" +) + +func parseFrame(r io.Reader) (Frame, error) { + fh := FrameHeader{} + if err := fh.Parse(r); err != nil { + return nil, err + } + var f Frame + switch fh.Type { + case PingFrameType: + f = &PingFrame{ + Header: fh, + } + case SettingsFrameType: + f = &SettingsFrame{ + Header: fh, + } + default: + f = &UnknownFrame{ + Header: fh, + } + } + if err := f.ParsePayload(r); err != nil { + return nil, err + } + + return f, nil +} + +func streamFrame(w io.Writer, f Frame) error { + raw, err := f.MarshalBinary() + if err != nil { + return err + } + if _, err := w.Write(raw); err != nil { + return err + } + return nil +} + +func getHttp2Conn(addr string) (*tls.Conn, error) { + config := &tls.Config{ + InsecureSkipVerify: true, + NextProtos: []string{"h2"}, + } + + conn, err := tls.Dial("tcp", addr, config) + if err != nil { + return nil, err + } + + return conn, nil +} + +func testClientShortSettings(addr string, length int) error { + c, err := getHttp2Conn(addr) + if err != nil { + return err + } + defer c.Close() + + if _, err := c.Write([]byte(Preface)); err != nil { + return err + } + + // Bad, settings, non multiple of 6 + sf := &UnknownFrame{ + Header: FrameHeader{ + Type: SettingsFrameType, + }, + Data: make([]byte, length), + } + if err := streamFrame(c, sf); err != nil { + return err + } + + for { + frame, err := parseFrame(c) + if err != nil { + return err + } + log.Println(frame) + } + + return nil +} + +func testClientPrefaceWithStreamId(addr string) error { + c, err := getHttp2Conn(addr) + if err != nil { + return err + } + defer c.Close() + + // Good so far + if _, err := c.Write([]byte(Preface)); err != nil { + return err + } + + // Bad, settings do not have ids + sf := &SettingsFrame{ + Header: FrameHeader{ + StreamID: 1, + }, + } + if err := streamFrame(c, sf); err != nil { + return err + } + + for { + frame, err := parseFrame(c) + if err != nil { + return err + } + log.Println(frame) + } + + return nil +} + +func testUnknownFrameType(addr string) error { + c, err := getHttp2Conn(addr) + if err != nil { + return err + } + defer c.Close() + + if _, err := c.Write([]byte(Preface)); err != nil { + return err + } + + // Send some settings, which are part of the client preface + sf := &SettingsFrame{} + if err := streamFrame(c, sf); err != nil { + return err + } + + // Write a bunch of invalid frame types. + for ft := ContinuationFrameType + 1; ft != 0; ft++ { + fh := &UnknownFrame{ + Header: FrameHeader{ + Type: ft, + }, + } + if err := streamFrame(c, fh); err != nil { + return err + } + } + + pf := &PingFrame{ + Data: []byte("01234567"), + } + if err := streamFrame(c, pf); err != nil { + return err + } + + for { + frame, err := parseFrame(c) + if err != nil { + return err + } + if npf, ok := frame.(*PingFrame); !ok { + continue + } else { + if string(npf.Data) != string(pf.Data) || npf.Header.Flags&PING_ACK == 0 { + return fmt.Errorf("Bad ping %+v", *npf) + } + return nil + } + } + + return nil +} + +func testShortPreface(addr string, prefacePrefix string) error { + c, err := getHttp2Conn(addr) + if err != nil { + return err + } + defer c.Close() + + if _, err := c.Write([]byte(prefacePrefix)); err != nil { + return err + } + + buf := make([]byte, 256) + for ; err == nil; _, err = c.Read(buf) { + } + // TODO: maybe check for a GOAWAY? + return err +} + +func testTLSMaxVersion(addr string, version uint16) error { + config := &tls.Config{ + InsecureSkipVerify: true, + NextProtos: []string{"h2"}, + MaxVersion: version, + } + conn, err := tls.Dial("tcp", addr, config) + if err != nil { + return err + } + defer conn.Close() + + buf := make([]byte, 256) + if n, err := conn.Read(buf); err != nil { + if n != 0 { + return fmt.Errorf("Expected no bytes to be read, but was %d", n) + } + return err + } + return nil +} + +func testTLSApplicationProtocol(addr string) error { + config := &tls.Config{ + InsecureSkipVerify: true, + NextProtos: []string{"h2c"}, + } + conn, err := tls.Dial("tcp", addr, config) + if err != nil { + return err + } + defer conn.Close() + + buf := make([]byte, 256) + if n, err := conn.Read(buf); err != nil { + if n != 0 { + return fmt.Errorf("Expected no bytes to be read, but was %d", n) + } + return err + } + return nil +} diff --git a/tools/http2_interop/http2interop_test.go b/tools/http2_interop/http2interop_test.go new file mode 100644 index 00000000000..3b687c035e8 --- /dev/null +++ b/tools/http2_interop/http2interop_test.go @@ -0,0 +1,50 @@ +package http2interop + +import ( + "crypto/tls" + "flag" + "io" + "os" + "testing" +) + +var ( + serverSpec = flag.String("spec", ":50051", "The server spec to test") +) + +func TestShortPreface(t *testing.T) { + for i := 0; i < len(Preface)-1; i++ { + if err := testShortPreface(*serverSpec, Preface[:i]+"X"); err != io.EOF { + t.Error("Expected an EOF but was", err) + } + } +} + +func TestUnknownFrameType(t *testing.T) { + if err := testUnknownFrameType(*serverSpec); err != nil { + t.Fatal(err) + } +} + +func TestTLSApplicationProtocol(t *testing.T) { + if err := testTLSApplicationProtocol(*serverSpec); err != io.EOF { + t.Fatal("Expected an EOF but was", err) + } +} + +func TestTLSMaxVersion(t *testing.T) { + if err := testTLSMaxVersion(*serverSpec, tls.VersionTLS11); err != io.EOF { + t.Fatal("Expected an EOF but was", err) + } +} + +func TestClientPrefaceWithStreamId(t *testing.T) { + if err := testClientPrefaceWithStreamId(*serverSpec); err != io.EOF { + t.Fatal("Expected an EOF but was", err) + } +} + +func TestMain(m *testing.M) { + flag.Parse() + os.Exit(m.Run()) +} diff --git a/tools/http2_interop/ping.go b/tools/http2_interop/ping.go new file mode 100644 index 00000000000..6011eed4511 --- /dev/null +++ b/tools/http2_interop/ping.go @@ -0,0 +1,65 @@ +package http2interop + +import ( + "fmt" + "io" +) + +type PingFrame struct { + Header FrameHeader + Data []byte +} + +const ( + PING_ACK = 0x01 +) + +func (f *PingFrame) GetHeader() *FrameHeader { + return &f.Header +} + +func (f *PingFrame) ParsePayload(r io.Reader) error { + raw := make([]byte, f.Header.Length) + if _, err := io.ReadFull(r, raw); err != nil { + return err + } + return f.UnmarshalPayload(raw) +} + +func (f *PingFrame) UnmarshalPayload(raw []byte) error { + if f.Header.Length != len(raw) { + return fmt.Errorf("Invalid Payload length %d != %d", f.Header.Length, len(raw)) + } + if f.Header.Length != 8 { + return fmt.Errorf("Invalid Payload length %d", f.Header.Length) + } + + f.Data = []byte(string(raw)) + + return nil +} + +func (f *PingFrame) MarshalPayload() ([]byte, error) { + if len(f.Data) != 8 { + return nil, fmt.Errorf("Invalid Payload length %d", len(f.Data)) + } + return []byte(string(f.Data)), nil +} + +func (f *PingFrame) MarshalBinary() ([]byte, error) { + payload, err := f.MarshalPayload() + if err != nil { + return nil, err + } + + f.Header.Length = len(payload) + f.Header.Type = PingFrameType + header, err := f.Header.MarshalBinary() + if err != nil { + return nil, err + } + + header = append(header, payload...) + + return header, nil +} diff --git a/tools/http2_interop/settings.go b/tools/http2_interop/settings.go new file mode 100644 index 00000000000..5a2b1ada651 --- /dev/null +++ b/tools/http2_interop/settings.go @@ -0,0 +1,109 @@ +package http2interop + +import ( + "encoding/binary" + "fmt" + "io" +) + +const ( + SETTINGS_ACK = 1 +) + +type SettingsFrame struct { + Header FrameHeader + Params []SettingsParameter +} + +type SettingsIdentifier uint16 + +const ( + SettingsHeaderTableSize SettingsIdentifier = 1 + SettingsEnablePush SettingsIdentifier = 2 + SettingsMaxConcurrentStreams SettingsIdentifier = 3 + SettingsInitialWindowSize SettingsIdentifier = 4 + SettingsMaxFrameSize SettingsIdentifier = 5 + SettingsMaxHeaderListSize SettingsIdentifier = 6 +) + +func (si SettingsIdentifier) String() string { + switch si { + case SettingsHeaderTableSize: + return "HEADER_TABLE_SIZE" + case SettingsEnablePush: + return "ENABLE_PUSH" + case SettingsMaxConcurrentStreams: + return "MAX_CONCURRENT_STREAMS" + case SettingsInitialWindowSize: + return "INITIAL_WINDOW_SIZE" + case SettingsMaxFrameSize: + return "MAX_FRAME_SIZE" + case SettingsMaxHeaderListSize: + return "MAX_HEADER_LIST_SIZE" + default: + return fmt.Sprintf("UNKNOWN(%d)", uint16(si)) + } +} + +type SettingsParameter struct { + Identifier SettingsIdentifier + Value uint32 +} + +func (f *SettingsFrame) GetHeader() *FrameHeader { + return &f.Header +} + +func (f *SettingsFrame) ParsePayload(r io.Reader) error { + raw := make([]byte, f.Header.Length) + if _, err := io.ReadFull(r, raw); err != nil { + return err + } + return f.UnmarshalPayload(raw) +} + +func (f *SettingsFrame) UnmarshalPayload(raw []byte) error { + if f.Header.Length != len(raw) { + return fmt.Errorf("Invalid Payload length %d != %d", f.Header.Length, len(raw)) + } + + if f.Header.Length%6 != 0 { + return fmt.Errorf("Invalid Payload length %d", f.Header.Length) + } + + f.Params = make([]SettingsParameter, 0, f.Header.Length/6) + for i := 0; i < len(raw); i += 6 { + f.Params = append(f.Params, SettingsParameter{ + Identifier: SettingsIdentifier(binary.BigEndian.Uint16(raw[i : i+2])), + Value: binary.BigEndian.Uint32(raw[i+2 : i+6]), + }) + } + return nil +} + +func (f *SettingsFrame) MarshalPayload() ([]byte, error) { + raw := make([]byte, 0, len(f.Params)*6) + for i, p := range f.Params { + binary.BigEndian.PutUint16(raw[i*6:i*6+2], uint16(p.Identifier)) + binary.BigEndian.PutUint32(raw[i*6+2:i*6+6], p.Value) + } + return raw, nil +} + +func (f *SettingsFrame) MarshalBinary() ([]byte, error) { + payload, err := f.MarshalPayload() + if err != nil { + return nil, err + } + + f.Header.Length = len(payload) + f.Header.Type = SettingsFrameType + header, err := f.Header.MarshalBinary() + if err != nil { + return nil, err + } + + header = append(header, payload...) + + return header, nil +} diff --git a/tools/http2_interop/unknownframe.go b/tools/http2_interop/unknownframe.go new file mode 100644 index 00000000000..0450e7e976c --- /dev/null +++ b/tools/http2_interop/unknownframe.go @@ -0,0 +1,54 @@ +package http2interop + +import ( + "fmt" + "io" +) + +type UnknownFrame struct { + Header FrameHeader + Data []byte +} + +func (f *UnknownFrame) GetHeader() *FrameHeader { + return &f.Header +} + +func (f *UnknownFrame) ParsePayload(r io.Reader) error { + raw := make([]byte, f.Header.Length) + if _, err := io.ReadFull(r, raw); err != nil { + return err + } + return f.UnmarshalPayload(raw) +} + +func (f *UnknownFrame) UnmarshalPayload(raw []byte) error { + if f.Header.Length != len(raw) { + return fmt.Errorf("Invalid Payload length %d != %d", f.Header.Length, len(raw)) + } + + f.Data = []byte(string(raw)) + + return nil +} + +func (f *UnknownFrame) MarshalPayload() ([]byte, error) { + return []byte(string(f.Data)), nil +} + +func (f *UnknownFrame) MarshalBinary() ([]byte, error) { + f.Header.Length = len(f.Data) + buf, err := f.Header.MarshalBinary() + if err != nil { + return nil, err + } + + payload, err := f.MarshalPayload() + if err != nil { + return nil, err + } + + buf = append(buf, payload...) + + return buf, nil +} From 5bd75d789c77891b6dfee3dd619a67ec5be444d3 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 8 Sep 2015 10:55:20 -0700 Subject: [PATCH 03/37] implement C# wrapping for plugin API --- src/csharp/Grpc.Core/Credentials.cs | 52 ++++++++ src/csharp/Grpc.Core/Grpc.Core.csproj | 1 + .../Internal/CredentialsSafeHandle.cs | 8 ++ .../NativeMetadataCredentialsPlugin.cs | 112 ++++++++++++++++++ .../Grpc.IntegrationTesting.csproj | 1 + .../MetadataCredentialsTest.cs | 100 ++++++++++++++++ src/csharp/ext/grpc_csharp_ext.c | 41 ++++++- 7 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs create mode 100644 src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs index 4fcac0c4c00..e653d3688cf 100644 --- a/src/csharp/Grpc.Core/Credentials.cs +++ b/src/csharp/Grpc.Core/Credentials.cs @@ -32,10 +32,17 @@ #endregion using System; +using System.Collections.Generic; +using System.Threading.Tasks; + using Grpc.Core.Internal; +using Grpc.Core.Utils; namespace Grpc.Core { + // TODO: rename + public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata); + /// /// Client-side credentials. Used for creation of a secure channel. /// @@ -135,4 +142,49 @@ namespace Grpc.Core return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); } } + + /// + /// Client-side credentials that delegate metadata based auth to an interceptor. + /// + public partial class MetadataCredentials : Credentials + { + readonly AsyncAuthInterceptor interceptor; + + public MetadataCredentials(AsyncAuthInterceptor interceptor) + { + this.interceptor = interceptor; + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor); + return plugin.Credentials; + } + } + + public sealed class CompositeCredentials : Credentials + { + readonly List credentials; + + public CompositeCredentials(params Credentials[] credentials) + { + Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials."); + this.credentials = new List(credentials); + } + + public static CompositeCredentials Create(params Credentials[] credentials) + { + return new CompositeCredentials(credentials); + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + var nativeComposite = credentials[0].ToNativeCredentials(); + for (int i = 1; i < credentials.Count; i++) + { + nativeComposite = CredentialsSafeHandle.CreateComposite(nativeComposite, credentials[i].ToNativeCredentials()); + } + return nativeComposite; + } + } } diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index ad2af17bc75..04c3eda1130 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -49,6 +49,7 @@ + diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs index feed3353624..bab45108e02 100644 --- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs @@ -43,6 +43,9 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] static extern CredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey); + [DllImport("grpc_csharp_ext.dll")] + static extern CredentialsSafeHandle grpcsharp_composite_credentials_create(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2); + [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_credentials_release(IntPtr credentials); @@ -69,6 +72,11 @@ namespace Grpc.Core.Internal } } + public static CredentialsSafeHandle CreateComposite(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2) + { + return grpcsharp_composite_credentials_create(creds1, creds2); + } + protected override bool ReleaseHandle() { grpcsharp_credentials_release(handle); diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs new file mode 100644 index 00000000000..6662a73b17a --- /dev/null +++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs @@ -0,0 +1,112 @@ +#region Copyright notice and license +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +using Grpc.Core.Logging; +using Grpc.Core.Utils; + +namespace Grpc.Core.Internal +{ + internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy); + + internal class NativeMetadataCredentialsPlugin + { + const string GetMetadataExceptionMsg = "Exception occured in metadata credentials plugin."; + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); + + [DllImport("grpc_csharp_ext.dll")] + static extern CredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor); + + [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)] + static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails); + + AsyncAuthInterceptor interceptor; + GCHandle gcHandle; + NativeMetadataInterceptor nativeInterceptor; + CredentialsSafeHandle credentials; + + public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor) + { + this.interceptor = Preconditions.CheckNotNull(interceptor, "interceptor"); + this.nativeInterceptor = NativeMetadataInterceptorHandler; + + // Make sure the callback doesn't get garbage collected until it is destroyed. + this.gcHandle = GCHandle.Alloc(this.nativeInterceptor, GCHandleType.Normal); + this.credentials = grpcsharp_metadata_credentials_create_from_plugin(nativeInterceptor); + } + + public CredentialsSafeHandle Credentials + { + get { return credentials; } + } + + private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy) + { + if (isDestroy) + { + gcHandle.Free(); + return; + } + + try + { + string serviceUrl = Marshal.PtrToStringAnsi(serviceUrlPtr); + StartGetMetadata(serviceUrl, callbackPtr, userDataPtr); + } + catch (Exception e) + { + grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, null, StatusCode.Unknown, GetMetadataExceptionMsg); + Logger.Error(e, GetMetadataExceptionMsg); + } + } + + private async void StartGetMetadata(string serviceUrl, IntPtr callbackPtr, IntPtr userDataPtr) + { + try + { + var metadata = new Metadata(); + await interceptor(serviceUrl, metadata); + using (var metadataArray = MetadataArraySafeHandle.Create(metadata)) + { + grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, metadataArray, StatusCode.OK, null); + } + } + catch (Exception e) + { + grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, null, StatusCode.Unknown, GetMetadataExceptionMsg); + Logger.Error(e, GetMetadataExceptionMsg); + } + } + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index a0bcf431f7b..f0a39acf753 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -96,6 +96,7 @@ + diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs new file mode 100644 index 00000000000..76991dfc209 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs @@ -0,0 +1,100 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Utils; +using Grpc.Testing; +using NUnit.Framework; + +namespace Grpc.IntegrationTesting +{ + public class MetadataCredentialsTest + { + const string Host = "localhost"; + Server server; + Channel channel; + TestService.ITestServiceClient client; + + [TestFixtureSetUp] + public void Init() + { + var serverCredentials = new SslServerCredentials(new[] { new KeyCertificatePair( + File.ReadAllText(TestCredentials.ServerCertChainPath), + File.ReadAllText(TestCredentials.ServerPrivateKeyPath)) }); + server = new Server + { + Services = { TestService.BindService(new TestServiceImpl()) }, + Ports = { { Host, ServerPort.PickUnused, serverCredentials } } + }; + server.Start(); + + var options = new List + { + new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride) + }; + + var asyncAuthInterceptor = new AsyncAuthInterceptor(async (authUri, metadata) => + { + await Task.Delay(100); // make sure the operation is asynchronous. + metadata.Add("authorization", "SECRET_TOKEN"); + }); + + var clientCredentials = CompositeCredentials.Create( + new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)), + new MetadataCredentials(asyncAuthInterceptor) + ); + channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options); + client = TestService.NewClient(channel); + } + + [TestFixtureTearDown] + public void Cleanup() + { + channel.ShutdownAsync().Wait(); + server.ShutdownAsync().Wait(); + } + + [Test] + public void MetadataCredentials() + { + var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 }); + Assert.AreEqual(10, response.Payload.Body.Length); + } + } +} diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 51e0728fb9d..657f999ad4e 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -68,7 +68,7 @@ grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) { /* * Helper to maintain lifetime of batch op inputs and store batch op outputs. */ -typedef struct gprcsharp_batch_context { +typedef struct grpcsharp_batch_context { grpc_metadata_array send_initial_metadata; grpc_byte_buffer *send_message; struct { @@ -892,6 +892,45 @@ grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr, return grpc_server_add_secure_http2_port(server, addr, creds); } +GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_composite_credentials_create( + grpc_credentials *creds1, + grpc_credentials *creds2) { + return grpc_composite_credentials_create(creds1, creds2, NULL); +} + +/* Metadata credentials plugin */ + +GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin( + void *callback_ptr, void *user_data, grpc_metadata_array *metadata, + grpc_status_code status, const char *error_details) { + grpc_credentials_plugin_metadata_cb cb = (grpc_credentials_plugin_metadata_cb)callback_ptr; + cb(user_data, metadata->metadata, metadata->count, status, error_details); +} + +typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)( + void *state, const char *service_url, void *callback_ptr, + void *user_data, gpr_int32 is_destroy); + +static void grpcsharp_get_metadata_handler(void *state, const char *service_url, + grpc_credentials_plugin_metadata_cb cb, void *user_data) { + grpcsharp_metadata_interceptor_func interceptor = (grpcsharp_metadata_interceptor_func)state; + interceptor(state, service_url, (void*)cb, user_data, 0); +} + +static void grpcsharp_metadata_credentials_destroy_handler(void *state) { + grpcsharp_metadata_interceptor_func interceptor = (grpcsharp_metadata_interceptor_func)state; + interceptor(state, NULL, NULL, NULL, 1); +} + +GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin( + grpcsharp_metadata_interceptor_func metadata_interceptor) { + grpc_metadata_credentials_plugin plugin; + plugin.get_metadata = grpcsharp_get_metadata_handler; + plugin.destroy = grpcsharp_metadata_credentials_destroy_handler; + plugin.state = metadata_interceptor; + return grpc_metadata_credentials_create_from_plugin(plugin, NULL); +} + /* Logging */ typedef void(GPR_CALLTYPE *grpcsharp_log_func)(const char *file, gpr_int32 line, From 74f39e185eaddfb07e9b024b0d8aec547cd83821 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 23 Sep 2015 20:14:56 -0700 Subject: [PATCH 04/37] Migrate C# to the new auth API --- src/csharp/Grpc.Auth/AuthInterceptors.cs | 24 ++-- src/csharp/Grpc.Auth/Grpc.Auth.csproj | 1 + src/csharp/Grpc.Auth/GrpcCredentials.cs | 93 +++++++++++++++ src/csharp/Grpc.Core.Tests/ClientBaseTest.cs | 62 ---------- src/csharp/Grpc.Core.Tests/CredentialsTest.cs | 109 ++++++++++++++++++ .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 2 +- .../Grpc.Core.Tests/MarshallingErrorsTest.cs | 4 +- src/csharp/Grpc.Core/CallOptions.cs | 16 ++- src/csharp/Grpc.Core/ClientBase.cs | 31 ++--- src/csharp/Grpc.Core/Credentials.cs | 72 ++++++++++-- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 10 +- .../Grpc.Core/Internal/CallSafeHandle.cs | 8 ++ .../Grpc.Core/Internal/ChannelSafeHandle.cs | 6 +- .../Grpc.IntegrationTesting.Client.csproj | 49 ++++++++ .../packages.config | 11 ++ .../Grpc.IntegrationTesting.Server.csproj | 49 ++++++++ .../packages.config | 11 ++ .../Grpc.IntegrationTesting/InteropClient.cs | 52 +++++---- .../MetadataCredentialsTest.cs | 7 +- src/csharp/ext/grpc_csharp_ext.c | 5 + 20 files changed, 481 insertions(+), 141 deletions(-) create mode 100644 src/csharp/Grpc.Auth/GrpcCredentials.cs delete mode 100644 src/csharp/Grpc.Core.Tests/ClientBaseTest.cs create mode 100644 src/csharp/Grpc.Core.Tests/CredentialsTest.cs create mode 100644 src/csharp/Grpc.IntegrationTesting.Client/packages.config create mode 100644 src/csharp/Grpc.IntegrationTesting.Server/packages.config diff --git a/src/csharp/Grpc.Auth/AuthInterceptors.cs b/src/csharp/Grpc.Auth/AuthInterceptors.cs index c8ab4d9af6f..fa925667751 100644 --- a/src/csharp/Grpc.Auth/AuthInterceptors.cs +++ b/src/csharp/Grpc.Auth/AuthInterceptors.cs @@ -41,8 +41,8 @@ using Grpc.Core.Utils; namespace Grpc.Auth { /// - /// Factory methods to create authorization interceptors. Interceptors created can be registered with gRPC client classes (autogenerated client stubs that - /// inherit from ). + /// Factory methods to create authorization interceptors. + /// /// public static class AuthInterceptors { @@ -50,31 +50,29 @@ namespace Grpc.Auth private const string Schema = "Bearer"; /// - /// Creates interceptor that will obtain access token from any credential type that implements + /// Creates an that will obtain access token from any credential type that implements /// ITokenAccess. (e.g. GoogleCredential). /// /// The credential to use to obtain access tokens. - /// The header interceptor. - public static HeaderInterceptor FromCredential(ITokenAccess credential) + /// The interceptor. + public static AsyncAuthInterceptor FromCredential(ITokenAccess credential) { - return new HeaderInterceptor((method, authUri, metadata) => + return new AsyncAuthInterceptor(async (authUri, metadata) => { - // TODO(jtattermusch): Rethink synchronous wait to obtain the result. - var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None) - .ConfigureAwait(false).GetAwaiter().GetResult(); + var accessToken = await credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None).ConfigureAwait(false); metadata.Add(CreateBearerTokenHeader(accessToken)); }); } /// - /// Creates OAuth2 interceptor that will use given access token as authorization. + /// Creates an that will use given access token as authorization. /// /// OAuth2 access token. - /// The header interceptor. - public static HeaderInterceptor FromAccessToken(string accessToken) + /// The interceptor. + public static AsyncAuthInterceptor FromAccessToken(string accessToken) { Preconditions.CheckNotNull(accessToken); - return new HeaderInterceptor((method, authUri, metadata) => + return new AsyncAuthInterceptor(async (authUri, metadata) => { metadata.Add(CreateBearerTokenHeader(accessToken)); }); diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index 4fb087d4a34..80ab07d2ae5 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -78,6 +78,7 @@ Version.cs + diff --git a/src/csharp/Grpc.Auth/GrpcCredentials.cs b/src/csharp/Grpc.Auth/GrpcCredentials.cs new file mode 100644 index 00000000000..496d8e14164 --- /dev/null +++ b/src/csharp/Grpc.Auth/GrpcCredentials.cs @@ -0,0 +1,93 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Threading; + +using Google.Apis.Auth.OAuth2; +using Grpc.Core; +using Grpc.Core.Utils; + +namespace Grpc.Auth +{ + /// + /// Factory methods to create instances of class. + /// + public static class GrpcCredentials + { + /// + /// Creates a instance that will obtain access tokens + /// from any credential that implements ITokenAccess. (e.g. GoogleCredential). + /// + /// The credential to use to obtain access tokens. + /// The MetadataCredentials instance. + public static MetadataCredentials Create(ITokenAccess credential) + { + return new MetadataCredentials(AuthInterceptors.FromCredential(credential)); + } + + /// + /// Convenience method to create a instance from + /// ITokenAccess credential and SslCredentials instance. + /// + /// The credential to use to obtain access tokens. + /// The SslCredentials instance. + /// The composite credential for access token based auth over a secure channel. + public static CompositeCredentials Create(ITokenAccess credential, SslCredentials sslCredentials) + { + return CompositeCredentials.Create(Create(credential), sslCredentials); + } + + /// + /// Creates an instance of that will use given access token to authenticate + /// with a gRPC service. + /// + /// OAuth2 access token. + /// /// The MetadataCredentials instance. + public static MetadataCredentials FromAccessToken(string accessToken) + { + return new MetadataCredentials(AuthInterceptors.FromAccessToken(accessToken)); + } + + /// + /// Converts a ITokenAccess object into a object supported + /// by gRPC. + /// + /// + /// + public static MetadataCredentials ToGrpcCredentials(this ITokenAccess credential) + { + return GrpcCredentials.Create(credential); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs b/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs deleted file mode 100644 index 2dc10ebe971..00000000000 --- a/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs +++ /dev/null @@ -1,62 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#endregion - -using System; -using Grpc.Core; -using Grpc.Core.Internal; -using Grpc.Core.Utils; -using NUnit.Framework; - -namespace Grpc.Core.Tests -{ - public class ClientBaseTest - { - [Test] - public void GetAuthUriBase_Valid() - { - Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com")); - Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com/")); - Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com:443/")); - Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com:443/")); - } - - [Test] - public void GetAuthUriBase_Invalid() - { - Assert.IsNull(ClientBase.GetAuthUriBase("some.googleapi.com:")); - Assert.IsNull(ClientBase.GetAuthUriBase("https://some.googleapi.com/")); - Assert.IsNull(ClientBase.GetAuthUriBase("dns://some.googleapi.com:443")); // just two slashes - Assert.IsNull(ClientBase.GetAuthUriBase("")); - } - } -} diff --git a/src/csharp/Grpc.Core.Tests/CredentialsTest.cs b/src/csharp/Grpc.Core.Tests/CredentialsTest.cs new file mode 100644 index 00000000000..5048144f98a --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/CredentialsTest.cs @@ -0,0 +1,109 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class CredentialsTest + { + [Test] + public void InsecureCredentials_IsNonComposable() + { + Assert.IsFalse(Credentials.Insecure.IsComposable); + } + + [Test] + public void CompositeCredentials_Create() + { + new CompositeCredentials(new FakeCredentials(true), new FakeCredentials(true), new FakeCredentials(true)); + } + + [Test] + public void CompositeCredentials_ComposeAtLeastTwo() + { + Assert.Throws(typeof(ArgumentException), () => new CompositeCredentials(new FakeCredentials(true))); + } + + [Test] + public void CompositeCredentials_ForbidsNonComposable() + { + Assert.Throws(typeof(ArgumentException), () => new CompositeCredentials(new FakeCredentials(true), new FakeCredentials(false))); + } + + [Test] + public void CompositeCredentials_ToNativeCredentials() + { + var composite = new CompositeCredentials(new MetadataCredentials(async (uri, m) => { await Task.Delay(1); }), new SslCredentials()); + using (var nativeComposite = composite.ToNativeCredentials()) + { + } + } + + [Test] + public void CompositeCredentials_OnlyOneConnectorCredentialAllowed() + { + var composite = new CompositeCredentials(new SslCredentials(), new SslCredentials()); + // it makes no sense to compose multiple ssl credentials. + Assert.Throws(typeof(ArgumentException), () => composite.ToNativeCredentials()); + } + + private class FakeCredentials : Credentials + { + readonly bool composable; + + public FakeCredentials(bool composable) + { + this.composable = composable; + } + + internal override bool IsComposable + { + get { return composable; } + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + return null; + } + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index f730936062d..0ebfaa0a62d 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -63,8 +63,8 @@ Version.cs - + diff --git a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs index 83707e0c6da..37fb36946af 100644 --- a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs +++ b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs @@ -119,7 +119,7 @@ namespace Grpc.Core.Tests [Test] public void RequestParsingError_UnaryRequest() { - helper.UnaryHandler = new UnaryServerMethod((request, context) => + helper.UnaryHandler = new UnaryServerMethod((request, context) => { return Task.FromResult("RESPONSE"); }); @@ -161,7 +161,7 @@ namespace Grpc.Core.Tests { helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => { - CollectionAssert.AreEqual(new [] {"A", "B"}, await requestStream.ToListAsync()); + CollectionAssert.AreEqual(new[] { "A", "B" }, await requestStream.ToListAsync()); return "RESPONSE"; }); var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs index c3bc9c31564..c708fcdfc49 100644 --- a/src/csharp/Grpc.Core/CallOptions.cs +++ b/src/csharp/Grpc.Core/CallOptions.cs @@ -49,6 +49,7 @@ namespace Grpc.Core CancellationToken cancellationToken; WriteOptions writeOptions; ContextPropagationToken propagationToken; + Credentials credentials; /// /// Creates a new instance of CallOptions struct. @@ -58,14 +59,16 @@ namespace Grpc.Core /// Can be used to request cancellation of the call. /// Write options that will be used for this call. /// Context propagation token obtained from . + /// Credentials to use for this call. public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken), - WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null) + WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, Credentials credentials = null) { this.headers = headers; this.deadline = deadline; this.cancellationToken = cancellationToken; this.writeOptions = writeOptions; this.propagationToken = propagationToken; + this.credentials = credentials; } /// @@ -114,6 +117,17 @@ namespace Grpc.Core } } + /// + /// Credentials to use for this call. + /// + public Credentials Credentials + { + get + { + return this.credentials; + } + } + /// /// Returns new instance of with /// Headers set to the value provided. Values of all other fields are preserved. diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs index f4533e735cb..e5b398062b2 100644 --- a/src/csharp/Grpc.Core/ClientBase.cs +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -40,18 +40,17 @@ namespace Grpc.Core /// /// Interceptor for call headers. /// - public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata); + /// Header interceptor is no longer to recommented way to perform authentication. + /// For header (initial metadata) based auth such as OAuth2 or JWT access token, use . + /// + public delegate void HeaderInterceptor(IMethod method, Metadata metadata); /// /// Base class for client-side stubs. /// public abstract class ClientBase { - // Regex for removal of the optional DNS scheme, trailing port, and trailing backslash - static readonly Regex ChannelTargetPattern = new Regex(@"^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$"); - readonly Channel channel; - readonly string authUriBase; /// /// Initializes a new instance of ClientBase class. @@ -60,13 +59,14 @@ namespace Grpc.Core public ClientBase(Channel channel) { this.channel = channel; - this.authUriBase = GetAuthUriBase(channel.Target); } /// - /// Can be used to register a custom header (request metadata) interceptor. + /// Can be used to register a custom header interceptor. /// The interceptor is invoked each time a new call on this client is started. + /// It is not recommented to use header interceptor to add auth headers to RPC calls. /// + /// public HeaderInterceptor HeaderInterceptor { get; @@ -115,24 +115,9 @@ namespace Grpc.Core { options = options.WithHeaders(new Metadata()); } - var authUri = authUriBase != null ? authUriBase + method.ServiceName : null; - interceptor(method, authUri, options.Headers); + interceptor(method, options.Headers); } return new CallInvocationDetails(channel, method, Host, options); } - - /// - /// Creates Auth URI base from channel's target (the one passed at channel creation). - /// Fully-qualified service name is to be appended to this. - /// - internal static string GetAuthUriBase(string target) - { - var match = ChannelTargetPattern.Match(target); - if (!match.Success) - { - return null; - } - return "https://" + match.Groups[2].Value + "/"; - } } } diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs index e653d3688cf..fcef627b25e 100644 --- a/src/csharp/Grpc.Core/Credentials.cs +++ b/src/csharp/Grpc.Core/Credentials.cs @@ -40,9 +40,6 @@ using Grpc.Core.Utils; namespace Grpc.Core { - // TODO: rename - public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata); - /// /// Client-side credentials. Used for creation of a secure channel. /// @@ -69,12 +66,26 @@ namespace Grpc.Core /// The native credentials. internal abstract CredentialsSafeHandle ToNativeCredentials(); + /// + /// Returns true if this credential type allows being composed by CompositeCredentials. + /// + internal virtual bool IsComposable + { + get { return true; } + } + private sealed class InsecureCredentialsImpl : Credentials { internal override CredentialsSafeHandle ToNativeCredentials() { return null; } + + // Composing insecure credentials makes no sense. + internal override bool IsComposable + { + get { return false; } + } } } @@ -143,13 +154,26 @@ namespace Grpc.Core } } + /// + /// Asynchronous authentication interceptor for . + /// + /// URL of a service to which current remote call needs to authenticate + /// Metadata to populate with entries that will be added to outgoing call's headers. + /// + public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata); + /// /// Client-side credentials that delegate metadata based auth to an interceptor. + /// The interceptor is automatically invoked for each remote call that uses MetadataCredentials. /// public partial class MetadataCredentials : Credentials { readonly AsyncAuthInterceptor interceptor; + /// + /// Initializes a new instance of MetadataCredentials class. + /// + /// authentication interceptor public MetadataCredentials(AsyncAuthInterceptor interceptor) { this.interceptor = interceptor; @@ -162,16 +186,34 @@ namespace Grpc.Core } } + /// + /// Credentials that allow composing multiple credentials objects into one object. + /// public sealed class CompositeCredentials : Credentials { readonly List credentials; + /// + /// Initializes a new instance of CompositeCredentials class. + /// The resulting credentials object will be composite of all the credentials specified as parameters. + /// + /// credentials to compose public CompositeCredentials(params Credentials[] credentials) { Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials."); + foreach (var cred in credentials) + { + Preconditions.CheckArgument(cred.IsComposable, "Cannot create composite credentials: one or more credential objects do not allow composition."); + } this.credentials = new List(credentials); } + /// + /// Creates a new instance of CompositeCredentials class by composing + /// multiple Credentials objects. + /// + /// credentials to compose + /// The new CompositeCredentials public static CompositeCredentials Create(params Credentials[] credentials) { return new CompositeCredentials(credentials); @@ -179,12 +221,28 @@ namespace Grpc.Core internal override CredentialsSafeHandle ToNativeCredentials() { - var nativeComposite = credentials[0].ToNativeCredentials(); - for (int i = 1; i < credentials.Count; i++) + return ToNativeRecursive(0); + } + + // Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier. + // In practice, we won't usually see composites from more than two credentials anyway. + private CredentialsSafeHandle ToNativeRecursive(int startIndex) + { + if (startIndex == credentials.Count - 1) + { + return credentials[startIndex].ToNativeCredentials(); + } + + using (var cred1 = credentials[startIndex].ToNativeCredentials()) + using (var cred2 = ToNativeRecursive(startIndex + 1)) { - nativeComposite = CredentialsSafeHandle.CreateComposite(nativeComposite, credentials[i].ToNativeCredentials()); + var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2); + if (nativeComposite.IsInvalid) + { + throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials."); + } + return nativeComposite; } - return nativeComposite; } } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index e3b00781c62..800462c8540 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -344,9 +344,13 @@ namespace Grpc.Core.Internal var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance; - return details.Channel.Handle.CreateCall(environment.CompletionRegistry, - parentCall, ContextPropagationToken.DefaultMask, cq, - details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value)); + var credentials = details.Options.Credentials; + using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null) + { + return details.Channel.Handle.CreateCall(environment.CompletionRegistry, + parentCall, ContextPropagationToken.DefaultMask, cq, + details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials); + } } // Make sure that once cancellationToken for this call is cancelled, Cancel() will be called. diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index c3611a7761f..0be7a4dd3a1 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -98,6 +98,9 @@ namespace Grpc.Core.Internal static extern GRPCCallError grpcsharp_call_send_initial_metadata(CallSafeHandle call, BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray); + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CredentialsSafeHandle credentials); + [DllImport("grpc_csharp_ext.dll")] static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call); @@ -113,6 +116,11 @@ namespace Grpc.Core.Internal this.completionRegistry = completionRegistry; } + public void SetCredentials(CredentialsSafeHandle credentials) + { + grpcsharp_call_set_credentials(this, credentials).CheckOk(); + } + public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags) { var ctx = BatchContextSafeHandle.Create(); diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs index 7a1c6e3dacd..d270d77526f 100644 --- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs @@ -82,9 +82,13 @@ namespace Grpc.Core.Internal return grpcsharp_secure_channel_create(credentials, target, channelArgs); } - public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) + public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CredentialsSafeHandle credentials) { var result = grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline); + if (credentials != null) + { + result.SetCredentials(credentials); + } result.SetCompletionRegistry(registry); return result; } diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj index 2c38c9645c5..8bc2082a1da 100644 --- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj +++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj @@ -9,6 +9,7 @@ Grpc.IntegrationTesting.Client Grpc.IntegrationTesting.Client.Program v4.5 + 6d22e68f true @@ -38,7 +39,47 @@ C:\keys\Grpc.snk + + False + ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll + + + False + ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll + + + False + ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll + + + False + ..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + + + False + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + + + False + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + + + False + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll + + @@ -60,5 +101,13 @@ + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting.Client/packages.config b/src/csharp/Grpc.IntegrationTesting.Client/packages.config new file mode 100644 index 00000000000..7a02c95db91 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting.Client/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj index 949ad61375c..1eadbeb9206 100644 --- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj +++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj @@ -9,6 +9,7 @@ Grpc.IntegrationTesting.Server Grpc.IntegrationTesting.Server.Program v4.5 + d9ee8e52 true @@ -38,7 +39,47 @@ C:\keys\Grpc.snk + + False + ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll + + + False + ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll + + + False + ..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll + + + False + ..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + + + False + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + + + False + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + + + False + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll + + @@ -60,5 +101,13 @@ + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting.Server/packages.config b/src/csharp/Grpc.IntegrationTesting.Server/packages.config new file mode 100644 index 00000000000..7a02c95db91 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting.Server/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 504d798b893..d3b7fe87f3c 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -33,11 +33,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using CommandLine; +using CommandLine.Text; using Google.Apis.Auth.OAuth2; using Google.Protobuf; using Grpc.Auth; @@ -45,8 +47,6 @@ using Grpc.Core; using Grpc.Core.Utils; using Grpc.Testing; using NUnit.Framework; -using CommandLine.Text; -using System.IO; namespace Grpc.IntegrationTesting { @@ -117,6 +117,20 @@ namespace Grpc.IntegrationTesting private async Task Run() { var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure; + + if (options.TestCase == "jwt_token_creds") + { + var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); + Assert.IsTrue(googleCredential.IsCreateScopedRequired); + credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials); + } + + if (options.TestCase == "compute_engine_creds") + { + var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); + Assert.IsFalse(googleCredential.IsCreateScopedRequired); + credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials); + } List channelOptions = null; if (!string.IsNullOrEmpty(options.ServerHostOverride)) @@ -155,10 +169,10 @@ namespace Grpc.IntegrationTesting await RunEmptyStreamAsync(client); break; case "compute_engine_creds": - await RunComputeEngineCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope); + RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope); break; case "jwt_token_creds": - await RunJwtTokenCredsAsync(client, options.DefaultServiceAccount); + RunJwtTokenCreds(client, options.DefaultServiceAccount); break; case "oauth2_auth_token": await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope); @@ -318,13 +332,10 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) + public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) { Console.WriteLine("running compute_engine_creds"); - var credential = await GoogleCredential.GetApplicationDefaultAsync(); - Assert.IsFalse(credential.IsCreateScopedRequired); - client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); - + var request = new SimpleRequest { ResponseType = PayloadType.COMPRESSABLE, @@ -334,6 +345,7 @@ namespace Grpc.IntegrationTesting FillOauthScope = true }; + // not setting credentials here because they were set on channel already var response = client.UnaryCall(request); Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); @@ -344,13 +356,10 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount) + public static void RunJwtTokenCreds(TestService.TestServiceClient client, string defaultServiceAccount) { Console.WriteLine("running jwt_token_creds"); - var credential = await GoogleCredential.GetApplicationDefaultAsync(); - Assert.IsTrue(credential.IsCreateScopedRequired); - client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); - + var request = new SimpleRequest { ResponseType = PayloadType.COMPRESSABLE, @@ -359,6 +368,7 @@ namespace Grpc.IntegrationTesting FillUsername = true, }; + // not setting credentials here because they were set on channel already var response = client.UnaryCall(request); Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); @@ -373,15 +383,14 @@ namespace Grpc.IntegrationTesting ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); string oauth2Token = await credential.GetAccessTokenForRequestAsync(); - client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); - + var credentials = GrpcCredentials.FromAccessToken(oauth2Token); var request = new SimpleRequest { FillUsername = true, FillOauthScope = true }; - var response = client.UnaryCall(request); + var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); Assert.False(string.IsNullOrEmpty(response.OauthScope)); Assert.True(oauthScope.Contains(response.OauthScope)); @@ -392,18 +401,15 @@ namespace Grpc.IntegrationTesting public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) { Console.WriteLine("running per_rpc_creds"); - ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); - string accessToken = await credential.GetAccessTokenForRequestAsync(); - var headerInterceptor = AuthInterceptors.FromAccessToken(accessToken); + ITokenAccess googleCredential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); + var credentials = GrpcCredentials.Create(googleCredential); var request = new SimpleRequest { FillUsername = true, }; - var headers = new Metadata(); - headerInterceptor(null, "", headers); - var response = client.UnaryCall(request, headers: headers); + var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); Assert.AreEqual(defaultServiceAccount, response.Username); Console.WriteLine("Passed!"); diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs index 76991dfc209..790bade89d4 100644 --- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs @@ -54,9 +54,7 @@ namespace Grpc.IntegrationTesting [TestFixtureSetUp] public void Init() { - var serverCredentials = new SslServerCredentials(new[] { new KeyCertificatePair( - File.ReadAllText(TestCredentials.ServerCertChainPath), - File.ReadAllText(TestCredentials.ServerPrivateKeyPath)) }); + var serverCredentials = new SslServerCredentials(new[] { new KeyCertificatePair(File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)) }); server = new Server { Services = { TestService.BindService(new TestServiceImpl()) }, @@ -77,8 +75,7 @@ namespace Grpc.IntegrationTesting var clientCredentials = CompositeCredentials.Create( new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)), - new MetadataCredentials(asyncAuthInterceptor) - ); + new MetadataCredentials(asyncAuthInterceptor)); channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options); client = TestService.NewClient(channel); } diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 657f999ad4e..0f05347dc51 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -785,6 +785,11 @@ grpcsharp_call_send_initial_metadata(grpc_call *call, NULL); } +GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials(grpc_call *call, + grpc_credentials *creds) { + return grpc_call_set_credentials(call, creds); +} + /* Server */ GPR_EXPORT grpc_server *GPR_CALLTYPE From 9e5e7e9a6cde7f9d91b00cb65b3c99e01916c813 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 24 Sep 2015 10:34:05 -0700 Subject: [PATCH 05/37] a small interop client refactoring --- .../Grpc.IntegrationTesting/InteropClient.cs | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index d3b7fe87f3c..c99084d1a90 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -115,6 +115,24 @@ namespace Grpc.IntegrationTesting } private async Task Run() + { + var credentials = await CreateCredentialsAsync(); + + List channelOptions = null; + if (!string.IsNullOrEmpty(options.ServerHostOverride)) + { + channelOptions = new List + { + new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) + }; + } + var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); + TestService.TestServiceClient client = new TestService.TestServiceClient(channel); + await RunTestCaseAsync(client, options); + await channel.ShutdownAsync(); + } + + private async Task CreateCredentialsAsync() { var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure; @@ -131,19 +149,7 @@ namespace Grpc.IntegrationTesting Assert.IsFalse(googleCredential.IsCreateScopedRequired); credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials); } - - List channelOptions = null; - if (!string.IsNullOrEmpty(options.ServerHostOverride)) - { - channelOptions = new List - { - new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) - }; - } - var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); - TestService.TestServiceClient client = new TestService.TestServiceClient(channel); - await RunTestCaseAsync(client, options); - await channel.ShutdownAsync(); + return credentials; } private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options) From 92981d5c3db1c140118a0d192e6c7f75203b9055 Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 6 Oct 2015 14:45:01 -0700 Subject: [PATCH 06/37] remove flag use_prod_roots in interop test and add use_test_ca per the interop test spec --- test/cpp/interop/client.cc | 2 +- test/cpp/interop/client_helper.cc | 10 +++++----- tools/gce_setup/grpc_docker.sh | 8 ++++---- tools/run_tests/run_interop_tests.py | 3 +-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc index dbe29395b4f..ee64716f3f6 100644 --- a/test/cpp/interop/client.cc +++ b/test/cpp/interop/client.cc @@ -46,7 +46,7 @@ #include "test/cpp/util/test_config.h" DEFINE_bool(use_tls, false, "Whether to use tls."); -DEFINE_bool(use_prod_roots, false, "True to use SSL roots for google"); +DEFINE_bool(use_test_ca, true, "False to use SSL roots for google"); DEFINE_int32(server_port, 0, "Server port."); DEFINE_string(server_host, "127.0.0.1", "Server host to connect to"); DEFINE_string(server_host_override, "foo.test.google.fr", diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc index cbad21e318e..61b46d25aa0 100644 --- a/test/cpp/interop/client_helper.cc +++ b/test/cpp/interop/client_helper.cc @@ -52,7 +52,7 @@ #include "test/cpp/util/create_test_channel.h" DECLARE_bool(use_tls); -DECLARE_bool(use_prod_roots); +DECLARE_bool(use_test_ca); DECLARE_int32(server_port); DECLARE_string(server_host); DECLARE_string(server_host_override); @@ -102,7 +102,7 @@ std::shared_ptr CreateChannelForTestCase( GPR_ASSERT(FLAGS_use_tls); creds = GoogleComputeEngineCredentials(); return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_use_tls, FLAGS_use_prod_roots, creds); + FLAGS_use_tls, !FLAGS_use_test_ca, creds); } else if (test_case == "jwt_token_creds") { std::shared_ptr creds; GPR_ASSERT(FLAGS_use_tls); @@ -111,15 +111,15 @@ std::shared_ptr CreateChannelForTestCase( creds = ServiceAccountJWTAccessCredentials(json_key, token_lifetime.count()); return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_use_tls, FLAGS_use_prod_roots, creds); + FLAGS_use_tls, !FLAGS_use_test_ca, creds); } else if (test_case == "oauth2_auth_token") { grpc::string raw_token = GetOauth2AccessToken(); std::shared_ptr creds = AccessTokenCredentials(raw_token); return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_use_tls, FLAGS_use_prod_roots, creds); + FLAGS_use_tls, !FLAGS_use_test_ca, creds); } else { return CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_use_tls, FLAGS_use_prod_roots); + FLAGS_use_tls, !FLAGS_use_test_ca); } } diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh index fdb77363273..1ac0209e278 100755 --- a/tools/gce_setup/grpc_docker.sh +++ b/tools/gce_setup/grpc_docker.sh @@ -1489,7 +1489,7 @@ grpc_interop_gen_cxx_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_prod_roots"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca=false"; local gfe_flags=$(_grpc_prod_gfe_flags) local the_cmd="$cmd_prefix $test_script $gfe_flags $@"; echo $the_cmd @@ -1502,7 +1502,7 @@ grpc_cloud_prod_gen_cxx_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_auth_service_account_creds_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_prod_roots"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca=false"; local gfe_flags=$(_grpc_prod_gfe_flags) local added_gfe_flags=$(_grpc_svc_acc_test_flags) local the_cmd="$cmd_prefix $test_script $gfe_flags $added_gfe_flags $@"; @@ -1516,7 +1516,7 @@ grpc_cloud_prod_auth_service_account_creds_gen_cxx_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_auth_compute_engine_creds_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_prod_roots"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca=false"; local gfe_flags=$(_grpc_prod_gfe_flags) local added_gfe_flags=$(_grpc_gce_test_flags) local the_cmd="$cmd_prefix $test_script $gfe_flags $added_gfe_flags $@"; @@ -1530,7 +1530,7 @@ grpc_cloud_prod_auth_compute_engine_creds_gen_cxx_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_auth_jwt_token_creds_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_prod_roots"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca=false"; local gfe_flags=$(_grpc_prod_gfe_flags) local added_gfe_flags=$(_grpc_jwt_token_test_flags) local the_cmd="$cmd_prefix $test_script $gfe_flags $added_gfe_flags $@"; diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 48c34f68713..39c9e53ce7f 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -62,7 +62,6 @@ _CLOUD_TO_CLOUD_BASE_ARGS = [ _SSL_CERT_ENV = { 'SSL_CERT_FILE':'/usr/local/share/grpc/roots.pem' } # TODO(jtattermusch) unify usage of --use_tls and --use_tls=true -# TODO(jtattermusch) unify usage of --use_prod_roots and --use_test_ca # TODO(jtattermusch) go uses --tls_ca_file instead of --use_test_ca @@ -75,7 +74,7 @@ class CXXLanguage: def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + - ['--use_tls=true','--use_prod_roots']) + ['--use_tls=true','--use_test_ca=false']) def cloud_to_cloud_args(self): return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS + From f928dc6bbb0f583d04d03df83030c1e4c2dbbf3b Mon Sep 17 00:00:00 2001 From: Sree Kuchibhotla Date: Tue, 6 Oct 2015 17:40:02 -0700 Subject: [PATCH 07/37] Fix incorrect assert --- src/core/channel/compress_filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c index 182fbf18bfc..c32f150715c 100644 --- a/src/core/channel/compress_filter.c +++ b/src/core/channel/compress_filter.c @@ -242,7 +242,7 @@ static void process_send_ops(grpc_call_element *elem, GPR_ASSERT(calld->remaining_slice_bytes > 0); /* Increase input ref count, gpr_slice_buffer_add takes ownership. */ gpr_slice_buffer_add(&calld->slices, gpr_slice_ref(sop->data.slice)); - GPR_ASSERT(GPR_SLICE_LENGTH(sop->data.slice) >= + GPR_ASSERT(GPR_SLICE_LENGTH(sop->data.slice) <= calld->remaining_slice_bytes); calld->remaining_slice_bytes -= (gpr_uint32)GPR_SLICE_LENGTH(sop->data.slice); From 5bd7005833b60d9db31860049458b122fa496599 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 6 Oct 2015 16:47:49 -0700 Subject: [PATCH 08/37] introduce the new split-type credentials api --- src/csharp/Grpc.Auth/GrpcCredentials.cs | 10 +- ...dentialsTest.cs => CallCredentialsTest.cs} | 58 +------ .../Grpc.Core.Tests/ChannelCredentialsTest.cs | 73 +++++++++ src/csharp/Grpc.Core.Tests/ChannelTest.cs | 10 +- src/csharp/Grpc.Core.Tests/FakeCredentials.cs | 73 +++++++++ .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 4 +- .../Grpc.Core.Tests/Internal/AsyncCallTest.cs | 2 +- .../Grpc.Core.Tests/MockServiceHelper.cs | 2 +- src/csharp/Grpc.Core/CallCredentials.cs | 142 +++++++++++++++++ src/csharp/Grpc.Core/CallOptions.cs | 6 +- src/csharp/Grpc.Core/Channel.cs | 4 +- .../{Credentials.cs => ChannelCredentials.cs} | 146 ++++++++---------- src/csharp/Grpc.Core/Grpc.Core.csproj | 3 +- .../Grpc.Examples.MathClient/MathClient.cs | 2 +- .../MathClientServerTests.cs | 2 +- .../HealthClientServerTest.cs | 2 +- .../Grpc.IntegrationTesting/InteropClient.cs | 8 +- .../MetadataCredentialsTest.cs | 2 +- 18 files changed, 393 insertions(+), 156 deletions(-) rename src/csharp/Grpc.Core.Tests/{CredentialsTest.cs => CallCredentialsTest.cs} (52%) create mode 100644 src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs create mode 100644 src/csharp/Grpc.Core.Tests/FakeCredentials.cs create mode 100644 src/csharp/Grpc.Core/CallCredentials.cs rename src/csharp/Grpc.Core/{Credentials.cs => ChannelCredentials.cs} (61%) diff --git a/src/csharp/Grpc.Auth/GrpcCredentials.cs b/src/csharp/Grpc.Auth/GrpcCredentials.cs index 496d8e14164..d8b10804c6e 100644 --- a/src/csharp/Grpc.Auth/GrpcCredentials.cs +++ b/src/csharp/Grpc.Auth/GrpcCredentials.cs @@ -41,7 +41,7 @@ using Grpc.Core.Utils; namespace Grpc.Auth { /// - /// Factory methods to create instances of class. + /// Factory methods to create instances of and classes. /// public static class GrpcCredentials { @@ -57,15 +57,15 @@ namespace Grpc.Auth } /// - /// Convenience method to create a instance from + /// Convenience method to create a instance from /// ITokenAccess credential and SslCredentials instance. /// /// The credential to use to obtain access tokens. /// The SslCredentials instance. - /// The composite credential for access token based auth over a secure channel. - public static CompositeCredentials Create(ITokenAccess credential, SslCredentials sslCredentials) + /// The channel credentials for access token based auth over a secure channel. + public static ChannelCredentials Create(ITokenAccess credential, SslCredentials sslCredentials) { - return CompositeCredentials.Create(Create(credential), sslCredentials); + return ChannelCredentials.Create(sslCredentials, Create(credential)); } /// diff --git a/src/csharp/Grpc.Core.Tests/CredentialsTest.cs b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs similarity index 52% rename from src/csharp/Grpc.Core.Tests/CredentialsTest.cs rename to src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs index 5048144f98a..451963229a4 100644 --- a/src/csharp/Grpc.Core.Tests/CredentialsTest.cs +++ b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs @@ -43,67 +43,23 @@ using NUnit.Framework; namespace Grpc.Core.Tests { - public class CredentialsTest + public class CallCredentialsTest { [Test] - public void InsecureCredentials_IsNonComposable() + public void CallCredentials_ComposeAtLeastTwo() { - Assert.IsFalse(Credentials.Insecure.IsComposable); + Assert.Throws(typeof(ArgumentException), () => CallCredentials.Compose(new FakeCallCredentials())); } [Test] - public void CompositeCredentials_Create() + public void CallCredentials_ToNativeCredentials() { - new CompositeCredentials(new FakeCredentials(true), new FakeCredentials(true), new FakeCredentials(true)); - } - - [Test] - public void CompositeCredentials_ComposeAtLeastTwo() - { - Assert.Throws(typeof(ArgumentException), () => new CompositeCredentials(new FakeCredentials(true))); - } - - [Test] - public void CompositeCredentials_ForbidsNonComposable() - { - Assert.Throws(typeof(ArgumentException), () => new CompositeCredentials(new FakeCredentials(true), new FakeCredentials(false))); - } - - [Test] - public void CompositeCredentials_ToNativeCredentials() - { - var composite = new CompositeCredentials(new MetadataCredentials(async (uri, m) => { await Task.Delay(1); }), new SslCredentials()); + var composite = CallCredentials.Compose( + new MetadataCredentials(async (uri, m) => { await Task.Delay(1); }), + new MetadataCredentials(async (uri, m) => { await Task.Delay(2); })); using (var nativeComposite = composite.ToNativeCredentials()) { } } - - [Test] - public void CompositeCredentials_OnlyOneConnectorCredentialAllowed() - { - var composite = new CompositeCredentials(new SslCredentials(), new SslCredentials()); - // it makes no sense to compose multiple ssl credentials. - Assert.Throws(typeof(ArgumentException), () => composite.ToNativeCredentials()); - } - - private class FakeCredentials : Credentials - { - readonly bool composable; - - public FakeCredentials(bool composable) - { - this.composable = composable; - } - - internal override bool IsComposable - { - get { return composable; } - } - - internal override CredentialsSafeHandle ToNativeCredentials() - { - return null; - } - } } } diff --git a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs new file mode 100644 index 00000000000..489bf385756 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs @@ -0,0 +1,73 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class ChannelCredentialsTest + { + [Test] + public void InsecureCredentials_IsNonComposable() + { + Assert.IsFalse(ChannelCredentials.Insecure.IsComposable); + } + + [Test] + public void ChannelCredentials_CreateComposite() + { + var composite = ChannelCredentials.Create(new FakeChannelCredentials(true), new FakeCallCredentials()); + Assert.IsFalse(composite.IsComposable); + + Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(null, new FakeCallCredentials())); + Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(new FakeChannelCredentials(true), null)); + + // forbid composing non-composable + Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials())); + } + + [Test] + public void ChannelCredentials_CreateWrapped() + { + ChannelCredentials.Create(new FakeCallCredentials()); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs index dfbd92879e7..f4ae9abefd8 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs @@ -44,13 +44,13 @@ namespace Grpc.Core.Tests [Test] public void Constructor_RejectsInvalidParams() { - Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure)); + Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, ChannelCredentials.Insecure)); } [Test] public void State_IdleAfterCreation() { - var channel = new Channel("localhost", Credentials.Insecure); + var channel = new Channel("localhost", ChannelCredentials.Insecure); Assert.AreEqual(ChannelState.Idle, channel.State); channel.ShutdownAsync().Wait(); } @@ -58,7 +58,7 @@ namespace Grpc.Core.Tests [Test] public void WaitForStateChangedAsync_InvalidArgument() { - var channel = new Channel("localhost", Credentials.Insecure); + var channel = new Channel("localhost", ChannelCredentials.Insecure); Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure)); channel.ShutdownAsync().Wait(); } @@ -66,7 +66,7 @@ namespace Grpc.Core.Tests [Test] public void ResolvedTarget() { - var channel = new Channel("127.0.0.1", Credentials.Insecure); + var channel = new Channel("127.0.0.1", ChannelCredentials.Insecure); Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1")); channel.ShutdownAsync().Wait(); } @@ -74,7 +74,7 @@ namespace Grpc.Core.Tests [Test] public void Shutdown_AllowedOnlyOnce() { - var channel = new Channel("localhost", Credentials.Insecure); + var channel = new Channel("localhost", ChannelCredentials.Insecure); channel.ShutdownAsync().Wait(); Assert.Throws(typeof(InvalidOperationException), () => channel.ShutdownAsync().GetAwaiter().GetResult()); } diff --git a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs new file mode 100644 index 00000000000..87d55cd276a --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs @@ -0,0 +1,73 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + internal class FakeChannelCredentials : ChannelCredentials + { + readonly bool composable; + + public FakeChannelCredentials(bool composable) + { + this.composable = composable; + } + + internal override bool IsComposable + { + get { return composable; } + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + return null; + } + } + + internal class FakeCallCredentials : CallCredentials + { + internal override CredentialsSafeHandle ToNativeCredentials() + { + return null; + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 0ebfaa0a62d..91d072ababe 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -63,8 +63,10 @@ Version.cs + + - + diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs index 685c5f7d6cb..246072bff13 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs @@ -49,7 +49,7 @@ namespace Grpc.Core.Internal.Tests [SetUp] public void Init() { - channel = new Channel("localhost", Credentials.Insecure); + channel = new Channel("localhost", ChannelCredentials.Insecure); fakeCall = new FakeNativeCall(); diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs index 765732c7687..567e04eddcc 100644 --- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs +++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs @@ -154,7 +154,7 @@ namespace Grpc.Core.Tests { if (channel == null) { - channel = new Channel(Host, GetServer().Ports.Single().BoundPort, Credentials.Insecure); + channel = new Channel(Host, GetServer().Ports.Single().BoundPort, ChannelCredentials.Insecure); } return channel; } diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs new file mode 100644 index 00000000000..809c9f412d0 --- /dev/null +++ b/src/csharp/Grpc.Core/CallCredentials.cs @@ -0,0 +1,142 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +using Grpc.Core.Internal; +using Grpc.Core.Utils; + +namespace Grpc.Core +{ + /// + /// Client-side call credentials. Provide authorization with per-call granularity. + /// + public abstract class CallCredentials + { + /// + /// Composes multiple multiple CallCredentials objects into + /// a single CallCredentials object. + /// + /// credentials to compose + /// The new CompositeCallCredentials + public static CallCredentials Compose(params CallCredentials[] credentials) + { + return new CompositeCallCredentials(credentials); + } + + /// + /// Creates native object for the credentials. + /// + /// The native credentials. + internal abstract CredentialsSafeHandle ToNativeCredentials(); + } + + /// + /// Asynchronous authentication interceptor for . + /// + /// URL of a service to which current remote call needs to authenticate + /// Metadata to populate with entries that will be added to outgoing call's headers. + /// + public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata); + + /// + /// Client-side credentials that delegate metadata based auth to an interceptor. + /// The interceptor is automatically invoked for each remote call that uses MetadataCredentials. + /// + public class MetadataCredentials : CallCredentials + { + readonly AsyncAuthInterceptor interceptor; + + /// + /// Initializes a new instance of MetadataCredentials class. + /// + /// authentication interceptor + public MetadataCredentials(AsyncAuthInterceptor interceptor) + { + this.interceptor = interceptor; + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor); + return plugin.Credentials; + } + } + + /// + /// Credentials that allow composing multiple credentials objects into one object. + /// + internal sealed class CompositeCallCredentials : CallCredentials + { + readonly List credentials; + + /// + /// Initializes a new instance of CompositeCallCredentials class. + /// The resulting credentials object will be composite of all the credentials specified as parameters. + /// + /// credentials to compose + public CompositeCallCredentials(params CallCredentials[] credentials) + { + Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials."); + this.credentials = new List(credentials); + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + return ToNativeRecursive(0); + } + + // Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier. + // In practice, we won't usually see composites from more than two credentials anyway. + private CredentialsSafeHandle ToNativeRecursive(int startIndex) + { + if (startIndex == credentials.Count - 1) + { + return credentials[startIndex].ToNativeCredentials(); + } + + using (var cred1 = credentials[startIndex].ToNativeCredentials()) + using (var cred2 = ToNativeRecursive(startIndex + 1)) + { + var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2); + if (nativeComposite.IsInvalid) + { + throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials."); + } + return nativeComposite; + } + } + } +} diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs index c708fcdfc49..c0f94c63c2f 100644 --- a/src/csharp/Grpc.Core/CallOptions.cs +++ b/src/csharp/Grpc.Core/CallOptions.cs @@ -49,7 +49,7 @@ namespace Grpc.Core CancellationToken cancellationToken; WriteOptions writeOptions; ContextPropagationToken propagationToken; - Credentials credentials; + CallCredentials credentials; /// /// Creates a new instance of CallOptions struct. @@ -61,7 +61,7 @@ namespace Grpc.Core /// Context propagation token obtained from . /// Credentials to use for this call. public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken), - WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, Credentials credentials = null) + WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, CallCredentials credentials = null) { this.headers = headers; this.deadline = deadline; @@ -120,7 +120,7 @@ namespace Grpc.Core /// /// Credentials to use for this call. /// - public Credentials Credentials + public CallCredentials Credentials { get { diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index f1942727cde..6b99055d4c8 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -68,7 +68,7 @@ namespace Grpc.Core /// Target of the channel. /// Credentials to secure the channel. /// Channel options. - public Channel(string target, Credentials credentials, IEnumerable options = null) + public Channel(string target, ChannelCredentials credentials, IEnumerable options = null) { this.target = Preconditions.CheckNotNull(target, "target"); this.environment = GrpcEnvironment.AddRef(); @@ -96,7 +96,7 @@ namespace Grpc.Core /// The port. /// Credentials to secure the channel. /// Channel options. - public Channel(string host, int port, Credentials credentials, IEnumerable options = null) : + public Channel(string host, int port, ChannelCredentials credentials, IEnumerable options = null) : this(string.Format("{0}:{1}", host, port), credentials, options) { } diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs similarity index 61% rename from src/csharp/Grpc.Core/Credentials.cs rename to src/csharp/Grpc.Core/ChannelCredentials.cs index fcef627b25e..599674e02bd 100644 --- a/src/csharp/Grpc.Core/Credentials.cs +++ b/src/csharp/Grpc.Core/ChannelCredentials.cs @@ -41,17 +41,17 @@ using Grpc.Core.Utils; namespace Grpc.Core { /// - /// Client-side credentials. Used for creation of a secure channel. + /// Client-side channel credentials. Used for creation of a secure channel. /// - public abstract class Credentials + public abstract class ChannelCredentials { - static readonly Credentials InsecureInstance = new InsecureCredentialsImpl(); + static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl(); /// - /// Returns instance of credential that provides no security and + /// Returns instance of credentials that provides no security and /// will result in creating an unsecure channel with no encryption whatsoever. /// - public static Credentials Insecure + public static ChannelCredentials Insecure { get { @@ -59,6 +59,29 @@ namespace Grpc.Core } } + /// + /// Creates a new instance of ChannelCredentials class by composing + /// given channel credentials with call credentials. + /// + /// Channel credentials. + /// Call credentials. + /// The new composite ChannelCredentials + public static ChannelCredentials Create(ChannelCredentials channelCredentials, CallCredentials callCredentials) + { + return new CompositeChannelCredentials(channelCredentials, callCredentials); + } + + /// + /// Creates a new instance of ChannelCredentials by wrapping + /// an instance of CallCredentials. + /// + /// Call credentials. + /// The ChannelCredentials wrapping given call credentials. + public static ChannelCredentials Create(CallCredentials callCredentials) + { + return new WrappedCallCredentials(callCredentials); + } + /// /// Creates native object for the credentials. May return null if insecure channel /// should be created. @@ -71,28 +94,22 @@ namespace Grpc.Core /// internal virtual bool IsComposable { - get { return true; } + get { return false; } } - private sealed class InsecureCredentialsImpl : Credentials + private sealed class InsecureCredentialsImpl : ChannelCredentials { internal override CredentialsSafeHandle ToNativeCredentials() { return null; } - - // Composing insecure credentials makes no sense. - internal override bool IsComposable - { - get { return false; } - } } } /// /// Client-side SSL credentials. /// - public sealed class SslCredentials : Credentials + public sealed class SslCredentials : ChannelCredentials { readonly string rootCertificates; readonly KeyCertificatePair keyCertificatePair; @@ -148,6 +165,12 @@ namespace Grpc.Core } } + // Composing composite makes no sense. + internal override bool IsComposable + { + get { return true; } + } + internal override CredentialsSafeHandle ToNativeCredentials() { return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); @@ -155,94 +178,61 @@ namespace Grpc.Core } /// - /// Asynchronous authentication interceptor for . + /// Credentials that allow composing one object and + /// one or more objects into a single . /// - /// URL of a service to which current remote call needs to authenticate - /// Metadata to populate with entries that will be added to outgoing call's headers. - /// - public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata); - - /// - /// Client-side credentials that delegate metadata based auth to an interceptor. - /// The interceptor is automatically invoked for each remote call that uses MetadataCredentials. - /// - public partial class MetadataCredentials : Credentials + internal sealed class CompositeChannelCredentials : ChannelCredentials { - readonly AsyncAuthInterceptor interceptor; + readonly ChannelCredentials channelCredentials; + readonly CallCredentials callCredentials; /// - /// Initializes a new instance of MetadataCredentials class. + /// Initializes a new instance of CompositeChannelCredentials class. + /// The resulting credentials object will be composite of all the credentials specified as parameters. /// - /// authentication interceptor - public MetadataCredentials(AsyncAuthInterceptor interceptor) + /// channelCredentials to compose + /// channelCredentials to compose + public CompositeChannelCredentials(ChannelCredentials channelCredentials, CallCredentials callCredentials) { - this.interceptor = interceptor; + this.channelCredentials = Preconditions.CheckNotNull(channelCredentials); + this.callCredentials = Preconditions.CheckNotNull(callCredentials); + Preconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition."); } internal override CredentialsSafeHandle ToNativeCredentials() { - NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor); - return plugin.Credentials; + using (var cred1 = channelCredentials.ToNativeCredentials()) + using (var cred2 = callCredentials.ToNativeCredentials()) + { + var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2); + if (nativeComposite.IsInvalid) + { + throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials."); + } + return nativeComposite; + } } } /// - /// Credentials that allow composing multiple credentials objects into one object. + /// Credentials wrapping as . /// - public sealed class CompositeCredentials : Credentials + internal sealed class WrappedCallCredentials : ChannelCredentials { - readonly List credentials; + readonly CallCredentials callCredentials; /// - /// Initializes a new instance of CompositeCredentials class. - /// The resulting credentials object will be composite of all the credentials specified as parameters. + /// Wraps instance of CallCredentials as ChannelCredentials. /// - /// credentials to compose - public CompositeCredentials(params Credentials[] credentials) + /// credentials to wrap + public WrappedCallCredentials(CallCredentials callCredentials) { - Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials."); - foreach (var cred in credentials) - { - Preconditions.CheckArgument(cred.IsComposable, "Cannot create composite credentials: one or more credential objects do not allow composition."); - } - this.credentials = new List(credentials); - } - - /// - /// Creates a new instance of CompositeCredentials class by composing - /// multiple Credentials objects. - /// - /// credentials to compose - /// The new CompositeCredentials - public static CompositeCredentials Create(params Credentials[] credentials) - { - return new CompositeCredentials(credentials); + this.callCredentials = Preconditions.CheckNotNull(callCredentials); } internal override CredentialsSafeHandle ToNativeCredentials() { - return ToNativeRecursive(0); - } - - // Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier. - // In practice, we won't usually see composites from more than two credentials anyway. - private CredentialsSafeHandle ToNativeRecursive(int startIndex) - { - if (startIndex == credentials.Count - 1) - { - return credentials[startIndex].ToNativeCredentials(); - } - - using (var cred1 = credentials[startIndex].ToNativeCredentials()) - using (var cred2 = ToNativeRecursive(startIndex + 1)) - { - var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2); - if (nativeComposite.IsInvalid) - { - throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials."); - } - return nativeComposite; - } + return callCredentials.ToNativeCredentials(); } } } diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 04c3eda1130..92d4e19eac2 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -48,6 +48,7 @@ + @@ -80,7 +81,7 @@ - + diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs index 01e4a80babc..64e429ed5a3 100644 --- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs +++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs @@ -39,7 +39,7 @@ namespace Math { public static void Main(string[] args) { - var channel = new Channel("127.0.0.1", 23456, Credentials.Insecure); + var channel = new Channel("127.0.0.1", 23456, ChannelCredentials.Insecure); Math.IMathClient client = new Math.MathClient(channel); MathExamples.DivExample(client); diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index e2975b5da93..290d42808e7 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -61,7 +61,7 @@ namespace Math.Tests Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } }; server.Start(); - channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); + channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure); client = Math.NewClient(channel); } diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs index 6c3a53bec05..d90f21c2e1c 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs +++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs @@ -63,7 +63,7 @@ namespace Grpc.HealthCheck.Tests Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } }; server.Start(); - channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure); + channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure); client = Grpc.Health.V1Alpha.Health.NewClient(channel); } diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index c99084d1a90..0df4ee35ba9 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -132,22 +132,22 @@ namespace Grpc.IntegrationTesting await channel.ShutdownAsync(); } - private async Task CreateCredentialsAsync() + private async Task CreateCredentialsAsync() { - var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure; + var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : ChannelCredentials.Insecure; if (options.TestCase == "jwt_token_creds") { var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); Assert.IsTrue(googleCredential.IsCreateScopedRequired); - credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials); + credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials()); } if (options.TestCase == "compute_engine_creds") { var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); Assert.IsFalse(googleCredential.IsCreateScopedRequired); - credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials); + credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials()); } return credentials; } diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs index 790bade89d4..5325b2fa148 100644 --- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs @@ -73,7 +73,7 @@ namespace Grpc.IntegrationTesting metadata.Add("authorization", "SECRET_TOKEN"); }); - var clientCredentials = CompositeCredentials.Create( + var clientCredentials = ChannelCredentials.Create( new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)), new MetadataCredentials(asyncAuthInterceptor)); channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options); From 64824bebea2dfdeb273776c0ba14c370941af1bb Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Tue, 6 Oct 2015 19:45:36 -0700 Subject: [PATCH 09/37] Fixed unprotected access to call field --- src/core/surface/call.c | 16 ++++++++++++---- src/core/surface/call.h | 5 ++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index d15a3bcbade..c8b880b0ad0 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -522,8 +522,12 @@ static void set_compression_algorithm(grpc_call *call, } grpc_compression_algorithm grpc_call_get_compression_algorithm( - const grpc_call *call) { - return call->compression_algorithm; + grpc_call *call) { + grpc_compression_algorithm algorithm; + gpr_mu_lock(&call->mu); + algorithm = call->compression_algorithm; + gpr_mu_unlock(&call->mu); + return algorithm; } static void set_encodings_accepted_by_peer( @@ -561,8 +565,12 @@ gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call) { return call->encodings_accepted_by_peer; } -gpr_uint32 grpc_call_get_message_flags(const grpc_call *call) { - return call->incoming_message_flags; +gpr_uint32 grpc_call_get_message_flags(grpc_call *call) { + gpr_uint32 flags; + gpr_mu_lock(&call->mu); + flags = call->incoming_message_flags; + gpr_mu_unlock(&call->mu); + return flags; } static void set_status_details(grpc_call *call, status_source source, diff --git a/src/core/surface/call.h b/src/core/surface/call.h index f421a81619f..cd1db3d417c 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -169,10 +169,9 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem); gpr_uint8 grpc_call_is_client(grpc_call *call); -grpc_compression_algorithm grpc_call_get_compression_algorithm( - const grpc_call *call); +grpc_compression_algorithm grpc_call_get_compression_algorithm(grpc_call *call); -gpr_uint32 grpc_call_get_message_flags(const grpc_call *call); +gpr_uint32 grpc_call_get_message_flags(grpc_call *call); /** Returns a bitset for the encodings (compression algorithms) supported by \a * call's peer. From b17b7f48710c16f72f617d79ffb2bceed0b9f8bc Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 7 Oct 2015 08:48:51 -0700 Subject: [PATCH 10/37] Add a timeout to benchmark test runs --- test/cpp/qps/driver.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index ac763e4b3c6..dd5c4f4f73f 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -82,9 +82,12 @@ static deque get_hosts(const string& name) { namespace runsc { // ClientContext allocator -static ClientContext* AllocContext(list* contexts) { +template +static ClientContext* AllocContext(list* contexts, T deadline) { contexts->emplace_back(); - return &contexts->back(); + auto context = &contexts->back(); + context->set_deadline(deadline); + return context; } struct ServerData { @@ -147,6 +150,11 @@ std::unique_ptr RunScenario( // Trim to just what we need workers.resize(num_clients + num_servers); + gpr_timespec deadline = + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_seconds( + warmup_seconds + benchmark_seconds + 20, GPR_TIMESPAN)); + // Start servers using runsc::ServerData; // servers is array rather than std::vector to avoid gcc-4.4 issues @@ -160,7 +168,7 @@ std::unique_ptr RunScenario( result_server_config.set_host(workers[i]); *args.mutable_setup() = server_config; servers[i].stream = - servers[i].stub->RunServer(runsc::AllocContext(&contexts)); + servers[i].stub->RunServer(runsc::AllocContext(&contexts, deadline)); GPR_ASSERT(servers[i].stream->Write(args)); ServerStatus init_status; GPR_ASSERT(servers[i].stream->Read(&init_status)); @@ -188,7 +196,7 @@ std::unique_ptr RunScenario( result_client_config.set_host(workers[i + num_servers]); *args.mutable_setup() = client_config; clients[i].stream = - clients[i].stub->RunTest(runsc::AllocContext(&contexts)); + clients[i].stub->RunTest(runsc::AllocContext(&contexts, deadline)); GPR_ASSERT(clients[i].stream->Write(args)); ClientStatus init_status; GPR_ASSERT(clients[i].stream->Read(&init_status)); From 706a010e3472951e45f34e31d34a16ab91a7b559 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 24 Sep 2015 18:34:39 -0700 Subject: [PATCH 11/37] stop gcc complaints about func ptr conversions --- src/csharp/ext/grpc_csharp_ext.c | 52 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 0f05347dc51..679ca43d749 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -665,16 +665,16 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call, } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata( - grpc_call *call, grpcsharp_batch_context *ctx) { - /* TODO: don't use magic number */ - grpc_op ops[1]; - ops[0].op = GRPC_OP_RECV_INITIAL_METADATA; - ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata); - ops[0].flags = 0; - ops[0].reserved = NULL; + grpc_call *call, grpcsharp_batch_context *ctx) { + /* TODO: don't use magic number */ + grpc_op ops[1]; + ops[0].op = GRPC_OP_RECV_INITIAL_METADATA; + ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata); + ops[0].flags = 0; + ops[0].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE @@ -898,41 +898,43 @@ grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr, } GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_composite_credentials_create( - grpc_credentials *creds1, - grpc_credentials *creds2) { - return grpc_composite_credentials_create(creds1, creds2, NULL); + grpc_credentials *creds1, + grpc_credentials *creds2) { + return grpc_composite_credentials_create(creds1, creds2, NULL); } /* Metadata credentials plugin */ GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin( - void *callback_ptr, void *user_data, grpc_metadata_array *metadata, - grpc_status_code status, const char *error_details) { - grpc_credentials_plugin_metadata_cb cb = (grpc_credentials_plugin_metadata_cb)callback_ptr; - cb(user_data, metadata->metadata, metadata->count, status, error_details); + grpc_credentials_plugin_metadata_cb cb, + void *user_data, grpc_metadata_array *metadata, + grpc_status_code status, const char *error_details) { + cb(user_data, metadata->metadata, metadata->count, status, error_details); } typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)( - void *state, const char *service_url, void *callback_ptr, - void *user_data, gpr_int32 is_destroy); + void *state, const char *service_url, grpc_credentials_plugin_metadata_cb cb, + void *user_data, gpr_int32 is_destroy); static void grpcsharp_get_metadata_handler(void *state, const char *service_url, - grpc_credentials_plugin_metadata_cb cb, void *user_data) { - grpcsharp_metadata_interceptor_func interceptor = (grpcsharp_metadata_interceptor_func)state; - interceptor(state, service_url, (void*)cb, user_data, 0); + grpc_credentials_plugin_metadata_cb cb, void *user_data) { + grpcsharp_metadata_interceptor_func interceptor = + (grpcsharp_metadata_interceptor_func)(gpr_intptr)state; + interceptor(state, service_url, cb, user_data, 0); } static void grpcsharp_metadata_credentials_destroy_handler(void *state) { - grpcsharp_metadata_interceptor_func interceptor = (grpcsharp_metadata_interceptor_func)state; - interceptor(state, NULL, NULL, NULL, 1); + grpcsharp_metadata_interceptor_func interceptor = + (grpcsharp_metadata_interceptor_func)(gpr_intptr)state; + interceptor(state, NULL, NULL, NULL, 1); } GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin( - grpcsharp_metadata_interceptor_func metadata_interceptor) { + grpcsharp_metadata_interceptor_func metadata_interceptor) { grpc_metadata_credentials_plugin plugin; plugin.get_metadata = grpcsharp_get_metadata_handler; plugin.destroy = grpcsharp_metadata_credentials_destroy_handler; - plugin.state = metadata_interceptor; + plugin.state = (void*)(gpr_intptr)metadata_interceptor; return grpc_metadata_credentials_create_from_plugin(plugin, NULL); } From a006b5f33ba39ed7eb49e6d140f9da2d375de9c6 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 7 Oct 2015 13:14:35 -0700 Subject: [PATCH 12/37] change default value of use_test_ca --- test/cpp/interop/client.cc | 2 +- tools/gce_setup/grpc_docker.sh | 10 +++++----- tools/run_tests/run_interop_tests.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc index ee64716f3f6..cb9b396beb5 100644 --- a/test/cpp/interop/client.cc +++ b/test/cpp/interop/client.cc @@ -46,7 +46,7 @@ #include "test/cpp/util/test_config.h" DEFINE_bool(use_tls, false, "Whether to use tls."); -DEFINE_bool(use_test_ca, true, "False to use SSL roots for google"); +DEFINE_bool(use_test_ca, false, "False to use SSL roots for google"); DEFINE_int32(server_port, 0, "Server port."); DEFINE_string(server_host, "127.0.0.1", "Server host to connect to"); DEFINE_string(server_host_override, "foo.test.google.fr", diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh index 1ac0209e278..e50706ec74b 100755 --- a/tools/gce_setup/grpc_docker.sh +++ b/tools/gce_setup/grpc_docker.sh @@ -1477,7 +1477,7 @@ grpc_cloud_prod_auth_compute_engine_creds_gen_node_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_interop_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca"; local the_cmd="$cmd_prefix $test_script $@"; echo $the_cmd } @@ -1489,7 +1489,7 @@ grpc_interop_gen_cxx_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca=false"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls"; local gfe_flags=$(_grpc_prod_gfe_flags) local the_cmd="$cmd_prefix $test_script $gfe_flags $@"; echo $the_cmd @@ -1502,7 +1502,7 @@ grpc_cloud_prod_gen_cxx_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_auth_service_account_creds_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca=false"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls"; local gfe_flags=$(_grpc_prod_gfe_flags) local added_gfe_flags=$(_grpc_svc_acc_test_flags) local the_cmd="$cmd_prefix $test_script $gfe_flags $added_gfe_flags $@"; @@ -1516,7 +1516,7 @@ grpc_cloud_prod_auth_service_account_creds_gen_cxx_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_auth_compute_engine_creds_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca=false"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls"; local gfe_flags=$(_grpc_prod_gfe_flags) local added_gfe_flags=$(_grpc_gce_test_flags) local the_cmd="$cmd_prefix $test_script $gfe_flags $added_gfe_flags $@"; @@ -1530,7 +1530,7 @@ grpc_cloud_prod_auth_compute_engine_creds_gen_cxx_cmd() { # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_auth_jwt_token_creds_gen_cxx_cmd() { local cmd_prefix="sudo docker run grpc/cxx"; - local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls --use_test_ca=false"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --use_tls"; local gfe_flags=$(_grpc_prod_gfe_flags) local added_gfe_flags=$(_grpc_jwt_token_test_flags) local the_cmd="$cmd_prefix $test_script $gfe_flags $added_gfe_flags $@"; diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 39c9e53ce7f..209270f0c62 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -74,11 +74,11 @@ class CXXLanguage: def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + - ['--use_tls=true','--use_test_ca=false']) + ['--use_tls=true']) def cloud_to_cloud_args(self): return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS + - ['--use_tls=true']) + ['--use_tls=true', '--use_test_ca=true']) def cloud_to_prod_env(self): return {} From 2189719b8f37f13870bde8a43549de3b3b58385d Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 15:42:21 -0700 Subject: [PATCH 13/37] increase timeout for build step jobs to 10 mins --- tools/run_tests/run_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index a05fbe806a8..cb366c0a15c 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -660,7 +660,7 @@ if make_targets: make_commands = itertools.chain.from_iterable(make_jobspec(cfg, list(targets), makefile) for cfg in build_configs for (makefile, targets) in make_targets.iteritems()) build_steps.extend(set(make_commands)) build_steps.extend(set( - jobset.JobSpec(cmdline, environ={'CONFIG': cfg}) + jobset.JobSpec(cmdline, environ={'CONFIG': cfg}, timeout_seconds=10*60) for cfg in build_configs for l in languages for cmdline in l.build_steps())) From 351da8d113ae6faf3e82923cc18aabfad7f36d51 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 8 Oct 2015 02:55:08 +0200 Subject: [PATCH 14/37] Improving run_tests's build step. -) The prebuild step is now going to retry 5 times. -) Stop on failure in the build steps. --- tools/run_tests/run_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 6423ecfd7cb..dffebc238fd 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -612,7 +612,7 @@ for l in languages: set(l.make_targets())) build_steps = list(set( - jobset.JobSpec(cmdline, environ={'CONFIG': cfg}) + jobset.JobSpec(cmdline, environ={'CONFIG': cfg}, flake_retries=5) for cfg in build_configs for l in languages for cmdline in l.pre_build_steps())) @@ -731,7 +731,7 @@ def _build_and_run( check_cancelled, newline_on_success, travis, cache, xml_report=None): """Do one pass of building & running tests.""" # build latest sequentially - if not jobset.run(build_steps, maxjobs=1, + if not jobset.run(build_steps, maxjobs=1, stop_on_failure=True, newline_on_success=newline_on_success, travis=travis): return 1 From 7828e813f780d95814db67fc2aac8a3e104ac743 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 17:27:48 -0700 Subject: [PATCH 15/37] make C# interop test args parsing compliant with spec --- src/csharp/Grpc.IntegrationTesting/InteropClient.cs | 12 +++++++----- src/csharp/Grpc.IntegrationTesting/InteropServer.cs | 7 ++++--- tools/run_tests/run_interop_tests.py | 6 +++--- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 0df4ee35ba9..0ed2910ae02 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -66,11 +66,13 @@ namespace Grpc.IntegrationTesting [Option("test_case", DefaultValue = "large_unary")] public string TestCase { get; set; } - [Option("use_tls")] - public bool UseTls { get; set; } + // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls) + [Option("use_tls", DefaultValue = false)] + public bool? UseTls { get; set; } - [Option("use_test_ca")] - public bool UseTestCa { get; set; } + // Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca) + [Option("use_test_ca", DefaultValue = false)] + public bool? UseTestCa { get; set; } [Option("default_service_account", Required = false)] public string DefaultServiceAccount { get; set; } @@ -134,7 +136,7 @@ namespace Grpc.IntegrationTesting private async Task CreateCredentialsAsync() { - var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : ChannelCredentials.Insecure; + var credentials = options.UseTls.Value ? TestCredentials.CreateTestClientCredentials(options.UseTestCa.Value) : ChannelCredentials.Insecure; if (options.TestCase == "jwt_token_creds") { diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs index 513f8722d64..29f842be2ec 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs @@ -54,8 +54,9 @@ namespace Grpc.IntegrationTesting [Option("port", DefaultValue = 8070)] public int Port { get; set; } - [Option("use_tls")] - public bool UseTls { get; set; } + // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls) + [Option("use_tls", DefaultValue = false)] + public bool? UseTls { get; set; } [HelpOption] public string GetUsage() @@ -99,7 +100,7 @@ namespace Grpc.IntegrationTesting string host = "0.0.0.0"; int port = options.Port; - if (options.UseTls) + if (options.UseTls.Value) { server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials()); } diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 374dec1851c..abc4b6e6fb7 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -100,17 +100,17 @@ class CSharpLanguage: def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + - ['--use_tls']) + ['--use_tls=true']) def cloud_to_cloud_args(self): return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS + - ['--use_tls', '--use_test_ca']) + ['--use_tls=true', '--use_test_ca=true']) def cloud_to_prod_env(self): return _SSL_CERT_ENV def server_args(self): - return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls'] + return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls=true'] def __str__(self): return 'csharp' From bcf988f0f3c77537f5ac4e67caedb3dca752ae0d Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 8 Oct 2015 03:00:42 +0200 Subject: [PATCH 16/37] Splitting out bundle install for ruby into the prebuild step. --- tools/run_tests/build_ruby.sh | 2 -- tools/run_tests/pre_build_ruby.sh | 39 +++++++++++++++++++++++++++++++ tools/run_tests/run_tests.py | 2 +- 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100755 tools/run_tests/pre_build_ruby.sh diff --git a/tools/run_tests/build_ruby.sh b/tools/run_tests/build_ruby.sh index 259f336ef22..6d23c316c5a 100755 --- a/tools/run_tests/build_ruby.sh +++ b/tools/run_tests/build_ruby.sh @@ -37,6 +37,4 @@ export GRPC_CONFIG=${CONFIG:-opt} cd $(dirname $0)/../../src/ruby rm -rf ./tmp - -bundle install rake compile:grpc diff --git a/tools/run_tests/pre_build_ruby.sh b/tools/run_tests/pre_build_ruby.sh new file mode 100755 index 00000000000..569a1d0333b --- /dev/null +++ b/tools/run_tests/pre_build_ruby.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set -ex + +export GRPC_CONFIG=${CONFIG:-opt} + +# change to grpc's ruby directory +cd $(dirname $0)/../../src/ruby + +bundle install diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 6423ecfd7cb..d38c0c96ee6 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -284,7 +284,7 @@ class RubyLanguage(object): environ=_FORCE_ENVIRON_FOR_WRAPPERS)] def pre_build_steps(self): - return [] + return [['tools/run_tests/pre_build_ruby.sh']] def make_targets(self): return ['static_c'] From 6d0bccf276f782a70fa93b025a6d8d5ff269e623 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 18:19:54 -0700 Subject: [PATCH 17/37] update C# regenerate proto script --- src/csharp/generate_proto_csharp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh index a17f45b5874..f879e074aa5 100755 --- a/src/csharp/generate_proto_csharp.sh +++ b/src/csharp/generate_proto_csharp.sh @@ -42,7 +42,7 @@ $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \ -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto $PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \ - -I $INTEROP_DIR/proto $INTEROP_DIR/proto/*.proto + -I ../.. ../../test/proto/*.proto $PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \ -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto From 317cb72f9b3eea63426c7f8f8838036823127416 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 18:22:56 -0700 Subject: [PATCH 18/37] remove extra copy of test.proto --- .../Grpc.IntegrationTesting.csproj | 3 - .../Grpc.IntegrationTesting/proto/empty.proto | 43 ------ .../proto/messages.proto | 132 ------------------ .../Grpc.IntegrationTesting/proto/test.proto | 71 ---------- 4 files changed, 249 deletions(-) delete mode 100644 src/csharp/Grpc.IntegrationTesting/proto/empty.proto delete mode 100644 src/csharp/Grpc.IntegrationTesting/proto/messages.proto delete mode 100644 src/csharp/Grpc.IntegrationTesting/proto/test.proto diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index a0bcf431f7b..e9cf3671af0 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -118,9 +118,6 @@ - - - PreserveNewest diff --git a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto b/src/csharp/Grpc.IntegrationTesting/proto/empty.proto deleted file mode 100644 index 6d0eb937d67..00000000000 --- a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto +++ /dev/null @@ -1,43 +0,0 @@ - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package grpc.testing; - -// An empty message that you can re-use to avoid defining duplicated empty -// messages in your project. A typical example is to use it as argument or the -// return value of a service API. For instance: -// -// service Foo { -// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; -// }; -// -message Empty {} diff --git a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto b/src/csharp/Grpc.IntegrationTesting/proto/messages.proto deleted file mode 100644 index 7df85e3c136..00000000000 --- a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto +++ /dev/null @@ -1,132 +0,0 @@ - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Message definitions to be used by integration test service definitions. - -syntax = "proto3"; - -package grpc.testing; - -// The type of payload that should be returned. -enum PayloadType { - // Compressable text format. - COMPRESSABLE = 0; - - // Uncompressable binary format. - UNCOMPRESSABLE = 1; - - // Randomly chosen from all other formats defined in this enum. - RANDOM = 2; -} - -// A block of data, to simply increase gRPC message size. -message Payload { - // The type of data in body. - PayloadType type = 1; - // Primary contents of payload. - bytes body = 2; -} - -// Unary request. -message SimpleRequest { - // Desired payload type in the response from the server. - // If response_type is RANDOM, server randomly chooses one from other formats. - PayloadType response_type = 1; - - // Desired payload size in the response from the server. - // If response_type is COMPRESSABLE, this denotes the size before compression. - int32 response_size = 2; - - // Optional input payload sent along with the request. - Payload payload = 3; - - // Whether SimpleResponse should include username. - bool fill_username = 4; - - // Whether SimpleResponse should include OAuth scope. - bool fill_oauth_scope = 5; -} - -// Unary response, as configured by the request. -message SimpleResponse { - // Payload to increase message size. - Payload payload = 1; - // The user the request came from, for verifying authentication was - // successful when the client expected it. - string username = 2; - // OAuth scope. - string oauth_scope = 3; -} - -// Client-streaming request. -message StreamingInputCallRequest { - // Optional input payload sent along with the request. - Payload payload = 1; - - // Not expecting any payload from the response. -} - -// Client-streaming response. -message StreamingInputCallResponse { - // Aggregated size of payloads received from the client. - int32 aggregated_payload_size = 1; -} - -// Configuration for a particular response. -message ResponseParameters { - // Desired payload sizes in responses from the server. - // If response_type is COMPRESSABLE, this denotes the size before compression. - int32 size = 1; - - // Desired interval between consecutive responses in the response stream in - // microseconds. - int32 interval_us = 2; -} - -// Server-streaming request. -message StreamingOutputCallRequest { - // Desired payload type in the response from the server. - // If response_type is RANDOM, the payload from each response in the stream - // might be of different types. This is to simulate a mixed type of payload - // stream. - PayloadType response_type = 1; - - // Configuration for each expected response message. - repeated ResponseParameters response_parameters = 2; - - // Optional input payload sent along with the request. - Payload payload = 3; -} - -// Server-streaming response, as configured by the request and parameters. -message StreamingOutputCallResponse { - // Payload to increase response size. - Payload payload = 1; -} diff --git a/src/csharp/Grpc.IntegrationTesting/proto/test.proto b/src/csharp/Grpc.IntegrationTesting/proto/test.proto deleted file mode 100644 index 5496f72af07..00000000000 --- a/src/csharp/Grpc.IntegrationTesting/proto/test.proto +++ /dev/null @@ -1,71 +0,0 @@ - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// An integration test service that covers all the method signature permutations -// of unary/streaming requests/responses. -syntax = "proto3"; - -import "empty.proto"; -import "messages.proto"; - -package grpc.testing; - -// A simple service to test the various types of RPCs and experiment with -// performance with various types of payload. -service TestService { - // One empty request followed by one empty response. - rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); - - // One request followed by one response. - rpc UnaryCall(SimpleRequest) returns (SimpleResponse); - - // One request followed by a sequence of responses (streamed download). - // The server returns the payload with client desired type and sizes. - rpc StreamingOutputCall(StreamingOutputCallRequest) - returns (stream StreamingOutputCallResponse); - - // A sequence of requests followed by one response (streamed upload). - // The server returns the aggregated size of client payload as the result. - rpc StreamingInputCall(stream StreamingInputCallRequest) - returns (StreamingInputCallResponse); - - // A sequence of requests with each request served by the server immediately. - // As one request could lead to multiple responses, this interface - // demonstrates the idea of full duplexing. - rpc FullDuplexCall(stream StreamingOutputCallRequest) - returns (stream StreamingOutputCallResponse); - - // A sequence of requests followed by a sequence of responses. - // The server buffers all the client requests and then serves them in order. A - // stream of responses are returned to the client when the server starts with - // first request. - rpc HalfDuplexCall(stream StreamingOutputCallRequest) - returns (stream StreamingOutputCallResponse); -} From 70f86526936ba70e8f4e4dab8edfeb25a554c933 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 18:23:51 -0700 Subject: [PATCH 19/37] regenerate generated interop testing files --- src/csharp/Grpc.IntegrationTesting/Empty.cs | 5 +- .../Grpc.IntegrationTesting/Messages.cs | 446 ++++++++++++++++-- src/csharp/Grpc.IntegrationTesting/Test.cs | 37 +- .../Grpc.IntegrationTesting/TestGrpc.cs | 188 +++++++- 4 files changed, 625 insertions(+), 51 deletions(-) diff --git a/src/csharp/Grpc.IntegrationTesting/Empty.cs b/src/csharp/Grpc.IntegrationTesting/Empty.cs index 28c28c9afd5..9bf2b8f7cf7 100644 --- a/src/csharp/Grpc.IntegrationTesting/Empty.cs +++ b/src/csharp/Grpc.IntegrationTesting/Empty.cs @@ -1,5 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: empty.proto +// source: test/proto/empty.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code @@ -23,7 +23,8 @@ namespace Grpc.Testing { static Empty() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5YgZwcm90bzM=")); + "ChZ0ZXN0L3Byb3RvL2VtcHR5LnByb3RvEgxncnBjLnRlc3RpbmciBwoFRW1w", + "dHliBnByb3RvMw==")); descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs index a3cbb7d76eb..51a56f067b5 100644 --- a/src/csharp/Grpc.IntegrationTesting/Messages.cs +++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs @@ -1,5 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: messages.proto +// source: test/proto/messages.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code @@ -21,37 +21,48 @@ namespace Grpc.Testing { static Messages() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE", - "dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5", - "GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB", - "KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6", - "ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv", - "YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl", - "GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n", - "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0", - "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK", - "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl", - "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf", - "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo", - "BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs", - "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu", - "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu", - "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg", - "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0", - "Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu", - "UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V", - "TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRACYgZwcm90bzM=")); + "Chl0ZXN0L3Byb3RvL21lc3NhZ2VzLnByb3RvEgxncnBjLnRlc3RpbmciQAoH", + "UGF5bG9hZBInCgR0eXBlGAEgASgOMhkuZ3JwYy50ZXN0aW5nLlBheWxvYWRU", + "eXBlEgwKBGJvZHkYAiABKAwiKwoKRWNob1N0YXR1cxIMCgRjb2RlGAEgASgF", + "Eg8KB21lc3NhZ2UYAiABKAkioQIKDVNpbXBsZVJlcXVlc3QSMAoNcmVzcG9u", + "c2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIVCg1y", + "ZXNwb25zZV9zaXplGAIgASgFEiYKB3BheWxvYWQYAyABKAsyFS5ncnBjLnRl", + "c3RpbmcuUGF5bG9hZBIVCg1maWxsX3VzZXJuYW1lGAQgASgIEhgKEGZpbGxf", + "b2F1dGhfc2NvcGUYBSABKAgSOwoUcmVzcG9uc2VfY29tcHJlc3Npb24YBiAB", + "KA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEKD3Jlc3BvbnNl", + "X3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzIl8KDlNp", + "bXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu", + "UGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0aF9zY29wZRgDIAEo", + "CSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYKB3BheWxvYWQYASAB", + "KAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJlYW1pbmdJbnB1dENh", + "bGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRfc2l6ZRgBIAEoBSI3", + "ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEoBRITCgtpbnRlcnZh", + "bF91cxgCIAEoBSKlAgoaU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QSMAoN", + "cmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlw", + "ZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAuZ3JwYy50ZXN0aW5n", + "LlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50", + "ZXN0aW5nLlBheWxvYWQSOwoUcmVzcG9uc2VfY29tcHJlc3Npb24YBiABKA4y", + "HS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEKD3Jlc3BvbnNlX3N0", + "YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzIkUKG1N0cmVh", + "bWluZ091dHB1dENhbGxSZXNwb25zZRImCgdwYXlsb2FkGAEgASgLMhUuZ3Jw", + "Yy50ZXN0aW5nLlBheWxvYWQiMwoNUmVjb25uZWN0SW5mbxIOCgZwYXNzZWQY", + "ASABKAgSEgoKYmFja29mZl9tcxgCIAMoBSo/CgtQYXlsb2FkVHlwZRIQCgxD", + "T01QUkVTU0FCTEUQABISCg5VTkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRAC", + "KjIKD0NvbXByZXNzaW9uVHlwZRIICgROT05FEAASCAoER1pJUBABEgsKB0RF", + "RkxBVEUQAmIGcHJvdG8z")); descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, new pbr::FileDescriptor[] { }, - new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedCodeInfo[] { + new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.CompressionType), }, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Payload), new[]{ "Type", "Body" }, null, null, null), - new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.EchoStatus), new[]{ "Code", "Message" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompression", "ResponseStatus" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleResponse), new[]{ "Payload", "Username", "OauthScope" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), new[]{ "Payload" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), new[]{ "AggregatedPayloadSize" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ResponseParameters), new[]{ "Size", "IntervalUs" }, null, null, null), - new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload" }, null, null, null), - new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null) + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseCompression", "ResponseStatus" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ReconnectInfo), new[]{ "Passed", "BackoffMs" }, null, null, null) })); } #endregion @@ -64,6 +75,12 @@ namespace Grpc.Testing { RANDOM = 2, } + public enum CompressionType { + NONE = 0, + GZIP = 1, + DEFLATE = 2, + } + #endregion #region Messages @@ -195,13 +212,141 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class EchoStatus : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EchoStatus()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public EchoStatus() { + OnConstruction(); + } + + partial void OnConstruction(); + + public EchoStatus(EchoStatus other) : this() { + code_ = other.code_; + message_ = other.message_; + } + + public EchoStatus Clone() { + return new EchoStatus(this); + } + + public const int CodeFieldNumber = 1; + private int code_; + public int Code { + get { return code_; } + set { + code_ = value; + } + } + + public const int MessageFieldNumber = 2; + private string message_ = ""; + public string Message { + get { return message_; } + set { + message_ = pb::Preconditions.CheckNotNull(value, "value"); + } + } + + public override bool Equals(object other) { + return Equals(other as EchoStatus); + } + + public bool Equals(EchoStatus other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Code != other.Code) return false; + if (Message != other.Message) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (Code != 0) hash ^= Code.GetHashCode(); + if (Message.Length != 0) hash ^= Message.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (Code != 0) { + output.WriteRawTag(8); + output.WriteInt32(Code); + } + if (Message.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Message); + } + } + + public int CalculateSize() { + int size = 0; + if (Code != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Code); + } + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + return size; + } + + public void MergeFrom(EchoStatus other) { + if (other == null) { + return; + } + if (other.Code != 0) { + Code = other.Code; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Code = input.ReadInt32(); + break; + } + case 18: { + Message = input.ReadString(); + break; + } + } + } + } + + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class SimpleRequest : pb::IMessage { private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SimpleRequest()); public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { - get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; } + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { @@ -220,6 +365,8 @@ namespace Grpc.Testing { Payload = other.payload_ != null ? other.Payload.Clone() : null; fillUsername_ = other.fillUsername_; fillOauthScope_ = other.fillOauthScope_; + responseCompression_ = other.responseCompression_; + ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null; } public SimpleRequest Clone() { @@ -271,6 +418,24 @@ namespace Grpc.Testing { } } + public const int ResponseCompressionFieldNumber = 6; + private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE; + public global::Grpc.Testing.CompressionType ResponseCompression { + get { return responseCompression_; } + set { + responseCompression_ = value; + } + } + + public const int ResponseStatusFieldNumber = 7; + private global::Grpc.Testing.EchoStatus responseStatus_; + public global::Grpc.Testing.EchoStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + public override bool Equals(object other) { return Equals(other as SimpleRequest); } @@ -287,6 +452,8 @@ namespace Grpc.Testing { if (!object.Equals(Payload, other.Payload)) return false; if (FillUsername != other.FillUsername) return false; if (FillOauthScope != other.FillOauthScope) return false; + if (ResponseCompression != other.ResponseCompression) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; return true; } @@ -297,6 +464,8 @@ namespace Grpc.Testing { if (payload_ != null) hash ^= Payload.GetHashCode(); if (FillUsername != false) hash ^= FillUsername.GetHashCode(); if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode(); + if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); return hash; } @@ -325,6 +494,14 @@ namespace Grpc.Testing { output.WriteRawTag(40); output.WriteBool(FillOauthScope); } + if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) { + output.WriteRawTag(48); + output.WriteEnum((int) ResponseCompression); + } + if (responseStatus_ != null) { + output.WriteRawTag(58); + output.WriteMessage(ResponseStatus); + } } public int CalculateSize() { @@ -344,6 +521,12 @@ namespace Grpc.Testing { if (FillOauthScope != false) { size += 1 + 1; } + if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } return size; } @@ -369,6 +552,15 @@ namespace Grpc.Testing { if (other.FillOauthScope != false) { FillOauthScope = other.FillOauthScope; } + if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) { + ResponseCompression = other.ResponseCompression; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + responseStatus_ = new global::Grpc.Testing.EchoStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } } public void MergeFrom(pb::CodedInputStream input) { @@ -401,6 +593,17 @@ namespace Grpc.Testing { FillOauthScope = input.ReadBool(); break; } + case 48: { + responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum(); + break; + } + case 58: { + if (responseStatus_ == null) { + responseStatus_ = new global::Grpc.Testing.EchoStatus(); + } + input.ReadMessage(responseStatus_); + break; + } } } } @@ -413,7 +616,7 @@ namespace Grpc.Testing { public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { - get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; } + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { @@ -573,7 +776,7 @@ namespace Grpc.Testing { public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { - get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; } + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { @@ -681,7 +884,7 @@ namespace Grpc.Testing { public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { - get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; } + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { @@ -783,7 +986,7 @@ namespace Grpc.Testing { public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { - get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; } + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { @@ -911,7 +1114,7 @@ namespace Grpc.Testing { public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { - get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; } + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { @@ -928,6 +1131,8 @@ namespace Grpc.Testing { responseType_ = other.responseType_; responseParameters_ = other.responseParameters_.Clone(); Payload = other.payload_ != null ? other.Payload.Clone() : null; + responseCompression_ = other.responseCompression_; + ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null; } public StreamingOutputCallRequest Clone() { @@ -960,6 +1165,24 @@ namespace Grpc.Testing { } } + public const int ResponseCompressionFieldNumber = 6; + private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE; + public global::Grpc.Testing.CompressionType ResponseCompression { + get { return responseCompression_; } + set { + responseCompression_ = value; + } + } + + public const int ResponseStatusFieldNumber = 7; + private global::Grpc.Testing.EchoStatus responseStatus_; + public global::Grpc.Testing.EchoStatus ResponseStatus { + get { return responseStatus_; } + set { + responseStatus_ = value; + } + } + public override bool Equals(object other) { return Equals(other as StreamingOutputCallRequest); } @@ -974,6 +1197,8 @@ namespace Grpc.Testing { if (ResponseType != other.ResponseType) return false; if(!responseParameters_.Equals(other.responseParameters_)) return false; if (!object.Equals(Payload, other.Payload)) return false; + if (ResponseCompression != other.ResponseCompression) return false; + if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false; return true; } @@ -982,6 +1207,8 @@ namespace Grpc.Testing { if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode(); hash ^= responseParameters_.GetHashCode(); if (payload_ != null) hash ^= Payload.GetHashCode(); + if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode(); + if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode(); return hash; } @@ -999,6 +1226,14 @@ namespace Grpc.Testing { output.WriteRawTag(26); output.WriteMessage(Payload); } + if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) { + output.WriteRawTag(48); + output.WriteEnum((int) ResponseCompression); + } + if (responseStatus_ != null) { + output.WriteRawTag(58); + output.WriteMessage(ResponseStatus); + } } public int CalculateSize() { @@ -1010,6 +1245,12 @@ namespace Grpc.Testing { if (payload_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } + if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression); + } + if (responseStatus_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus); + } return size; } @@ -1027,6 +1268,15 @@ namespace Grpc.Testing { } Payload.MergeFrom(other.Payload); } + if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) { + ResponseCompression = other.ResponseCompression; + } + if (other.responseStatus_ != null) { + if (responseStatus_ == null) { + responseStatus_ = new global::Grpc.Testing.EchoStatus(); + } + ResponseStatus.MergeFrom(other.ResponseStatus); + } } public void MergeFrom(pb::CodedInputStream input) { @@ -1051,6 +1301,17 @@ namespace Grpc.Testing { input.ReadMessage(payload_); break; } + case 48: { + responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum(); + break; + } + case 58: { + if (responseStatus_ == null) { + responseStatus_ = new global::Grpc.Testing.EchoStatus(); + } + input.ReadMessage(responseStatus_); + break; + } } } } @@ -1063,7 +1324,7 @@ namespace Grpc.Testing { public static pb::MessageParser Parser { get { return _parser; } } public static pbr::MessageDescriptor Descriptor { - get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; } + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[8]; } } pbr::MessageDescriptor pb::IMessage.Descriptor { @@ -1165,6 +1426,127 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class ReconnectInfo : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ReconnectInfo()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[9]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public ReconnectInfo() { + OnConstruction(); + } + + partial void OnConstruction(); + + public ReconnectInfo(ReconnectInfo other) : this() { + passed_ = other.passed_; + backoffMs_ = other.backoffMs_.Clone(); + } + + public ReconnectInfo Clone() { + return new ReconnectInfo(this); + } + + public const int PassedFieldNumber = 1; + private bool passed_; + public bool Passed { + get { return passed_; } + set { + passed_ = value; + } + } + + public const int BackoffMsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_backoffMs_codec + = pb::FieldCodec.ForInt32(18); + private readonly pbc::RepeatedField backoffMs_ = new pbc::RepeatedField(); + public pbc::RepeatedField BackoffMs { + get { return backoffMs_; } + } + + public override bool Equals(object other) { + return Equals(other as ReconnectInfo); + } + + public bool Equals(ReconnectInfo other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Passed != other.Passed) return false; + if(!backoffMs_.Equals(other.backoffMs_)) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (Passed != false) hash ^= Passed.GetHashCode(); + hash ^= backoffMs_.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (Passed != false) { + output.WriteRawTag(8); + output.WriteBool(Passed); + } + backoffMs_.WriteTo(output, _repeated_backoffMs_codec); + } + + public int CalculateSize() { + int size = 0; + if (Passed != false) { + size += 1 + 1; + } + size += backoffMs_.CalculateSize(_repeated_backoffMs_codec); + return size; + } + + public void MergeFrom(ReconnectInfo other) { + if (other == null) { + return; + } + if (other.Passed != false) { + Passed = other.Passed; + } + backoffMs_.Add(other.backoffMs_); + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Passed = input.ReadBool(); + break; + } + case 18: + case 16: { + backoffMs_.AddEntriesFrom(input, _repeated_backoffMs_codec); + break; + } + } + } + } + + } + #endregion } diff --git a/src/csharp/Grpc.IntegrationTesting/Test.cs b/src/csharp/Grpc.IntegrationTesting/Test.cs index 466ec57d3dc..cf477070587 100644 --- a/src/csharp/Grpc.IntegrationTesting/Test.cs +++ b/src/csharp/Grpc.IntegrationTesting/Test.cs @@ -1,5 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: test.proto +// source: test/proto/test.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code @@ -21,21 +21,26 @@ namespace Grpc.Testing { static Test() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "Cgp0ZXN0LnByb3RvEgxncnBjLnRlc3RpbmcaC2VtcHR5LnByb3RvGg5tZXNz", - "YWdlcy5wcm90bzK7BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3Jw", - "Yy50ZXN0aW5nLkVtcHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5", - "Q2FsbBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0", - "aW5nLlNpbXBsZVJlc3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5n", - "cnBjLnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBj", - "LnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3Ry", - "ZWFtaW5nSW5wdXRDYWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0", - "Q2FsbFJlcXVlc3QaKC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxs", - "UmVzcG9uc2UoARJpCg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5T", - "dHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJl", - "YW1pbmdPdXRwdXRDYWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxs", - "EiguZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0Giku", - "Z3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAFi", - "BnByb3RvMw==")); + "ChV0ZXN0L3Byb3RvL3Rlc3QucHJvdG8SDGdycGMudGVzdGluZxoWdGVzdC9w", + "cm90by9lbXB0eS5wcm90bxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bzK7", + "BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3JwYy50ZXN0aW5nLkVt", + "cHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5Q2FsbBIbLmdycGMu", + "dGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5nLlNpbXBsZVJl", + "c3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5ncnBjLnRlc3Rpbmcu", + "U3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBjLnRlc3RpbmcuU3Ry", + "ZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3RyZWFtaW5nSW5wdXRD", + "YWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0Q2FsbFJlcXVlc3Qa", + "KC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxsUmVzcG9uc2UoARJp", + "Cg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5TdHJlYW1pbmdPdXRw", + "dXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJlYW1pbmdPdXRwdXRD", + "YWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxsEiguZ3JwYy50ZXN0", + "aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0GikuZ3JwYy50ZXN0aW5n", + "LlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAEyVQoUVW5pbXBsZW1l", + "bnRlZFNlcnZpY2USPQoRVW5pbXBsZW1lbnRlZENhbGwSEy5ncnBjLnRlc3Rp", + "bmcuRW1wdHkaEy5ncnBjLnRlc3RpbmcuRW1wdHkyfwoQUmVjb25uZWN0U2Vy", + "dmljZRIxCgVTdGFydBITLmdycGMudGVzdGluZy5FbXB0eRoTLmdycGMudGVz", + "dGluZy5FbXB0eRI4CgRTdG9wEhMuZ3JwYy50ZXN0aW5nLkVtcHR5GhsuZ3Jw", + "Yy50ZXN0aW5nLlJlY29ubmVjdEluZm9iBnByb3RvMw==")); descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, new pbr::FileDescriptor[] { global::Grpc.Testing.Proto.Empty.Descriptor, global::Grpc.Testing.Messages.Descriptor, }, new pbr::GeneratedCodeInfo(null, null)); diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs index f63e1484759..8c884b74086 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs @@ -1,5 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: test.proto +// source: test/proto/test.proto #region Designer generated code using System; @@ -207,5 +207,191 @@ namespace Grpc.Testing { } } + public static class UnimplementedService + { + static readonly string __ServiceName = "grpc.testing.UnimplementedService"; + + static readonly Marshaller __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom); + + static readonly Method __Method_UnimplementedCall = new Method( + MethodType.Unary, + __ServiceName, + "UnimplementedCall", + __Marshaller_Empty, + __Marshaller_Empty); + + // service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Grpc.Testing.Test.Descriptor.Services[1]; } + } + + // client interface + public interface IUnimplementedServiceClient + { + global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options); + AsyncUnaryCall UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options); + } + + // server-side interface + public interface IUnimplementedService + { + Task UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context); + } + + // client stub + public class UnimplementedServiceClient : ClientBase, IUnimplementedServiceClient + { + public UnimplementedServiceClient(Channel channel) : base(channel) + { + } + public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.BlockingUnaryCall(call, request); + } + public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options) + { + var call = CreateCall(__Method_UnimplementedCall, options); + return Calls.BlockingUnaryCall(call, request); + } + public AsyncUnaryCall UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncUnaryCall UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options) + { + var call = CreateCall(__Method_UnimplementedCall, options); + return Calls.AsyncUnaryCall(call, request); + } + } + + // creates service definition that can be registered with a server + public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl) + { + return ServerServiceDefinition.CreateBuilder(__ServiceName) + .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build(); + } + + // creates a new client + public static UnimplementedServiceClient NewClient(Channel channel) + { + return new UnimplementedServiceClient(channel); + } + + } + public static class ReconnectService + { + static readonly string __ServiceName = "grpc.testing.ReconnectService"; + + static readonly Marshaller __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom); + static readonly Marshaller __Marshaller_ReconnectInfo = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom); + + static readonly Method __Method_Start = new Method( + MethodType.Unary, + __ServiceName, + "Start", + __Marshaller_Empty, + __Marshaller_Empty); + + static readonly Method __Method_Stop = new Method( + MethodType.Unary, + __ServiceName, + "Stop", + __Marshaller_Empty, + __Marshaller_ReconnectInfo); + + // service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Grpc.Testing.Test.Descriptor.Services[2]; } + } + + // client interface + public interface IReconnectServiceClient + { + global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options); + AsyncUnaryCall StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall StartAsync(global::Grpc.Testing.Empty request, CallOptions options); + global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options); + AsyncUnaryCall StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall StopAsync(global::Grpc.Testing.Empty request, CallOptions options); + } + + // server-side interface + public interface IReconnectService + { + Task Start(global::Grpc.Testing.Empty request, ServerCallContext context); + Task Stop(global::Grpc.Testing.Empty request, ServerCallContext context); + } + + // client stub + public class ReconnectServiceClient : ClientBase, IReconnectServiceClient + { + public ReconnectServiceClient(Channel channel) : base(channel) + { + } + public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken)); + return Calls.BlockingUnaryCall(call, request); + } + public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options) + { + var call = CreateCall(__Method_Start, options); + return Calls.BlockingUnaryCall(call, request); + } + public AsyncUnaryCall StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncUnaryCall StartAsync(global::Grpc.Testing.Empty request, CallOptions options) + { + var call = CreateCall(__Method_Start, options); + return Calls.AsyncUnaryCall(call, request); + } + public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken)); + return Calls.BlockingUnaryCall(call, request); + } + public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options) + { + var call = CreateCall(__Method_Stop, options); + return Calls.BlockingUnaryCall(call, request); + } + public AsyncUnaryCall StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken)); + return Calls.AsyncUnaryCall(call, request); + } + public AsyncUnaryCall StopAsync(global::Grpc.Testing.Empty request, CallOptions options) + { + var call = CreateCall(__Method_Stop, options); + return Calls.AsyncUnaryCall(call, request); + } + } + + // creates service definition that can be registered with a server + public static ServerServiceDefinition BindService(IReconnectService serviceImpl) + { + return ServerServiceDefinition.CreateBuilder(__ServiceName) + .AddMethod(__Method_Start, serviceImpl.Start) + .AddMethod(__Method_Stop, serviceImpl.Stop).Build(); + } + + // creates a new client + public static ReconnectServiceClient NewClient(Channel channel) + { + return new ReconnectServiceClient(channel); + } + + } } #endregion From 48423fc84362e195854a7e2bcf244ff29f03cee7 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 18:59:16 -0700 Subject: [PATCH 20/37] move C# nuget restore on linux to prebuild phase --- tools/run_tests/build_csharp.sh | 12 ++------- tools/run_tests/pre_build_csharp.sh | 41 +++++++++++++++++++++++++++++ tools/run_tests/run_tests.py | 5 +++- 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100755 tools/run_tests/pre_build_csharp.sh diff --git a/tools/run_tests/build_csharp.sh b/tools/run_tests/build_csharp.sh index eae7bd50405..6737d88b273 100755 --- a/tools/run_tests/build_csharp.sh +++ b/tools/run_tests/build_csharp.sh @@ -37,14 +37,6 @@ else MSBUILD_CONFIG="Release" fi -# change to gRPC repo root -cd $(dirname $0)/../.. +cd $(dirname $0)/../../src/csharp -root=`pwd` - -if [ -n "$NUGET" ] -then - $NUGET restore src/csharp/Grpc.sln -fi - -xbuild /p:Configuration=$MSBUILD_CONFIG src/csharp/Grpc.sln +xbuild /p:Configuration=$MSBUILD_CONFIG Grpc.sln diff --git a/tools/run_tests/pre_build_csharp.sh b/tools/run_tests/pre_build_csharp.sh new file mode 100755 index 00000000000..42ff60bea22 --- /dev/null +++ b/tools/run_tests/pre_build_csharp.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set -ex + +# cd to gRPC csharp directory +cd $(dirname $0)/../../src/csharp + +root=`pwd` + +if [ -n "$NUGET" ] +then + $NUGET restore Grpc.sln +fi diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 6423ecfd7cb..69a480ac850 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -321,7 +321,10 @@ class CSharpLanguage(object): for assembly in assemblies] def pre_build_steps(self): - return [] + if self.platform == 'windows': + return [] + else: + return [['tools/run_tests/pre_build_csharp.sh']] def make_targets(self): # For Windows, this target doesn't really build anything, From 874aec02b45dd3c3a8e8ae6c158ead268cbc1d47 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 19:26:19 -0700 Subject: [PATCH 21/37] move nuget restore into prebuild step on windows --- tools/jenkins/run_jenkins.sh | 4 ---- tools/run_tests/pre_build_c.bat | 21 +++++++++++++++++++++ tools/run_tests/pre_build_csharp.bat | 22 ++++++++++++++++++++++ tools/run_tests/run_tests.py | 7 +++++-- 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 tools/run_tests/pre_build_c.bat create mode 100644 tools/run_tests/pre_build_csharp.bat diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh index f79e739f6ae..67cfc2bb0a4 100755 --- a/tools/jenkins/run_jenkins.sh +++ b/tools/jenkins/run_jenkins.sh @@ -63,10 +63,6 @@ then # Prevent msbuild from picking up "platform" env variable, which would break the build unset platform - # TODO(jtattermusch): integrate nuget restore in a nicer way. - /cygdrive/c/nuget/nuget.exe restore vsprojects/grpc.sln - /cygdrive/c/nuget/nuget.exe restore src/csharp/Grpc.sln - python tools/run_tests/run_tests.py -t -l $language -x report.xml $@ || true elif [ "$platform" == "macos" ] diff --git a/tools/run_tests/pre_build_c.bat b/tools/run_tests/pre_build_c.bat new file mode 100644 index 00000000000..ac8a375ad7d --- /dev/null +++ b/tools/run_tests/pre_build_c.bat @@ -0,0 +1,21 @@ +@rem Performs nuget restore step for C/C++. + +setlocal + +@rem enter repo root +cd /d %~dp0\..\.. + +@rem Location of nuget.exe +set NUGET=C:\nuget\nuget.exe + +if exists %NUGET% ( + %NUGET% restore vsprojects/grpc.sln || goto :error +) + +endlocal + +goto :EOF + +:error +echo Failed! +exit /b %errorlevel% diff --git a/tools/run_tests/pre_build_csharp.bat b/tools/run_tests/pre_build_csharp.bat new file mode 100644 index 00000000000..f5890c27431 --- /dev/null +++ b/tools/run_tests/pre_build_csharp.bat @@ -0,0 +1,22 @@ +@rem Performs nuget restore step for C#. + +setlocal + +@rem enter repo root +cd /d %~dp0\..\.. + +@rem Location of nuget.exe +set NUGET=C:\nuget\nuget.exe + +if exists %NUGET% ( + %NUGET% restore vsprojects/grpc_csharp_ext.sln || goto :error + %NUGET% restore src/csharp/Grpc.sln || goto :error +) + +endlocal + +goto :EOF + +:error +echo Failed! +exit /b %errorlevel% diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 69a480ac850..d5036d55d8b 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -167,7 +167,10 @@ class CLanguage(object): return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target] def pre_build_steps(self): - return [] + if self.platform == 'windows': + return [['tools\\run_tests\\pre_build_c.bat']] + else: + return [] def build_steps(self): return [] @@ -322,7 +325,7 @@ class CSharpLanguage(object): def pre_build_steps(self): if self.platform == 'windows': - return [] + return [['tools\\run_tests\\pre_build_csharp.bat']] else: return [['tools/run_tests/pre_build_csharp.sh']] From 6438cfcaf2441c402cef8e53e8ca60429e91282e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 19:41:23 -0700 Subject: [PATCH 22/37] fix if exist syntax in .bat files --- tools/run_tests/pre_build_c.bat | 2 +- tools/run_tests/pre_build_csharp.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/run_tests/pre_build_c.bat b/tools/run_tests/pre_build_c.bat index ac8a375ad7d..f0449f3c424 100644 --- a/tools/run_tests/pre_build_c.bat +++ b/tools/run_tests/pre_build_c.bat @@ -8,7 +8,7 @@ cd /d %~dp0\..\.. @rem Location of nuget.exe set NUGET=C:\nuget\nuget.exe -if exists %NUGET% ( +if exist %NUGET% ( %NUGET% restore vsprojects/grpc.sln || goto :error ) diff --git a/tools/run_tests/pre_build_csharp.bat b/tools/run_tests/pre_build_csharp.bat index f5890c27431..853a8f43255 100644 --- a/tools/run_tests/pre_build_csharp.bat +++ b/tools/run_tests/pre_build_csharp.bat @@ -8,7 +8,7 @@ cd /d %~dp0\..\.. @rem Location of nuget.exe set NUGET=C:\nuget\nuget.exe -if exists %NUGET% ( +if exist %NUGET% ( %NUGET% restore vsprojects/grpc_csharp_ext.sln || goto :error %NUGET% restore src/csharp/Grpc.sln || goto :error ) From 64d7c2461a525a7dacb1e8e7479d93c4ab56dfd2 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 08:02:27 -0700 Subject: [PATCH 23/37] make C# auth interop tests up to spec --- .../Grpc.IntegrationTesting/InteropClient.cs | 31 +++++++++++++------ tools/run_tests/run_interop_tests.py | 4 +++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 0ed2910ae02..888b5c312fe 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -46,6 +46,7 @@ using Grpc.Auth; using Grpc.Core; using Grpc.Core.Utils; using Grpc.Testing; +using Newtonsoft.Json.Linq; using NUnit.Framework; namespace Grpc.IntegrationTesting @@ -180,13 +181,13 @@ namespace Grpc.IntegrationTesting RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope); break; case "jwt_token_creds": - RunJwtTokenCreds(client, options.DefaultServiceAccount); + RunJwtTokenCreds(client); break; case "oauth2_auth_token": - await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope); + await RunOAuth2AuthTokenAsync(client, options.OAuthScope); break; case "per_rpc_creds": - await RunPerRpcCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope); + await RunPerRpcCredsAsync(client, options.OAuthScope); break; case "cancel_after_begin": await RunCancelAfterBeginAsync(client); @@ -364,7 +365,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static void RunJwtTokenCreds(TestService.TestServiceClient client, string defaultServiceAccount) + public static void RunJwtTokenCreds(TestService.TestServiceClient client) { Console.WriteLine("running jwt_token_creds"); @@ -381,11 +382,11 @@ namespace Grpc.IntegrationTesting Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); Assert.AreEqual(314159, response.Payload.Body.Length); - Assert.AreEqual(defaultServiceAccount, response.Username); + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); Console.WriteLine("Passed!"); } - public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) + public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope) { Console.WriteLine("running oauth2_auth_token"); ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); @@ -402,11 +403,11 @@ namespace Grpc.IntegrationTesting Assert.False(string.IsNullOrEmpty(response.OauthScope)); Assert.True(oauthScope.Contains(response.OauthScope)); - Assert.AreEqual(defaultServiceAccount, response.Username); + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); Console.WriteLine("Passed!"); } - public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) + public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope) { Console.WriteLine("running per_rpc_creds"); ITokenAccess googleCredential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); @@ -419,7 +420,7 @@ namespace Grpc.IntegrationTesting var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); - Assert.AreEqual(defaultServiceAccount, response.Username); + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); Console.WriteLine("Passed!"); } @@ -499,5 +500,17 @@ namespace Grpc.IntegrationTesting { return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; } + + // extracts the client_email field from service account file used for auth test cases + private static string GetEmailFromServiceAccountFile() + { + string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"); + Assert.IsNotNull(keyFile); + + var jobject = JObject.Parse(File.ReadAllText(keyFile)); + string email = jobject.GetValue("client_email").Value(); + Assert.IsTrue(email.Length > 0); // spec requires nonempty client email. + return email; + } } } diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 45efa572f95..c1b4cf8a12b 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -312,6 +312,10 @@ def add_auth_options(language, test_case, cmdline, env): if test_case in ['per_rpc_creds', 'oauth2_auth_token']: cmdline += [oauth_scope_arg] + if test_case == 'oauth2_auth_token' and language == 'c++': + # C++ oauth2 test uses GCE creds and thus needs to know the default account + cmdline += [default_account_arg] + if test_case == 'compute_engine_creds': cmdline += [oauth_scope_arg, default_account_arg] From 9d8a65218f440c27b42d389053b0107b45065cbd Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 08:43:42 -0700 Subject: [PATCH 24/37] prevent ArgumentNullException in credentials plugin --- .../Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs index 6662a73b17a..f76492cba4a 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs @@ -86,7 +86,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, null, StatusCode.Unknown, GetMetadataExceptionMsg); + grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg); Logger.Error(e, GetMetadataExceptionMsg); } } @@ -97,6 +97,7 @@ namespace Grpc.Core.Internal { var metadata = new Metadata(); await interceptor(serviceUrl, metadata); + using (var metadataArray = MetadataArraySafeHandle.Create(metadata)) { grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, metadataArray, StatusCode.OK, null); @@ -104,7 +105,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, null, StatusCode.Unknown, GetMetadataExceptionMsg); + grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg); Logger.Error(e, GetMetadataExceptionMsg); } } From cf72a3adfe8ab55775d8e0d648fb62f8b4e58f1d Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 08:44:20 -0700 Subject: [PATCH 25/37] use JWT credentials for per_rpc_creds --- src/csharp/Grpc.IntegrationTesting/InteropClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 888b5c312fe..cb50b44841f 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -410,7 +410,7 @@ namespace Grpc.IntegrationTesting public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope) { Console.WriteLine("running per_rpc_creds"); - ITokenAccess googleCredential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); + ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); var credentials = GrpcCredentials.Create(googleCredential); var request = new SimpleRequest From bfe8a9febc97c0de542fe01c5ecb05512e7afd12 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Thu, 8 Oct 2015 09:05:28 -0700 Subject: [PATCH 26/37] Fixes the broken ruby interop tests --- src/ruby/lib/grpc/generic/client_stub.rb | 22 ++++++++++++++-------- src/ruby/spec/generic/client_stub_spec.rb | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb index 8c923845298..b8e33ad295a 100644 --- a/src/ruby/lib/grpc/generic/client_stub.rb +++ b/src/ruby/lib/grpc/generic/client_stub.rb @@ -176,8 +176,7 @@ module GRPC deadline: deadline, timeout: timeout, parent: parent) - kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method) - md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri) + md = update_metadata(kw, method) return c.request_response(req, **md) unless return_op # return the operation view of the active_call; define #execute as a @@ -244,8 +243,7 @@ module GRPC deadline: deadline, timeout: timeout, parent: parent) - kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method) - md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri) + md = update_metadata(kw, method) return c.client_streamer(requests, **md) unless return_op # return the operation view of the active_call; define #execute as a @@ -322,8 +320,7 @@ module GRPC deadline: deadline, timeout: timeout, parent: parent) - kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method) - md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri) + md = update_metadata(kw, method) return c.server_streamer(req, **md, &blk) unless return_op # return the operation view of the active_call; define #execute @@ -439,8 +436,7 @@ module GRPC deadline: deadline, timeout: timeout, parent: parent) - kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method) - md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri) + md = update_metadata(kw, method) return c.bidi_streamer(requests, **md, &blk) unless return_op # return the operation view of the active_call; define #execute @@ -454,6 +450,16 @@ module GRPC private + def update_metadata(kw, method) + return kw if @update_metadata.nil? + just_jwt_uri = self.class.update_with_jwt_aud_uri({}, @host, method) + updated = @update_metadata.call(just_jwt_uri) + + # keys should be lowercase + updated = Hash[updated.each_pair.map { |k, v| [k.downcase, v] }] + kw.merge(updated) + end + # Creates a new active stub # # @param method [string] the method being called. diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index a05433df75e..c5173aee1d5 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -159,6 +159,20 @@ describe 'ClientStub' do th.join end + it 'should downcase the keys provided by the metadata updater' do + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @pass, + k1: 'downcased-key-v1', k2: 'v2') + update_md = proc do |md| + md[:K1] = 'downcased-key-v1' + md + end + stub = GRPC::ClientStub.new(host, @cq, update_metadata: update_md) + expect(get_response(stub)).to eq(@resp) + th.join + end + it 'should send a request when configured using an override channel' do server_port = create_test_server alt_host = "localhost:#{server_port}" From 3ee1da84d3507ec901fffb89c93a51b9d84e7e10 Mon Sep 17 00:00:00 2001 From: Nate Kibler Date: Thu, 8 Oct 2015 09:20:40 -0700 Subject: [PATCH 27/37] Fixed a typo in the README --- src/objective-c/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/README.md b/src/objective-c/README.md index 6c27657def0..775f9a095fb 100644 --- a/src/objective-c/README.md +++ b/src/objective-c/README.md @@ -153,7 +153,7 @@ _protoc_, in which case no system modification nor renaming is necessary. ### Integrate the generated gRPC library without using Cocoapods -You need to compile the generated `.pbpbjc.*` files (the enums and messages) without ARC support, +You need to compile the generated `.pbobjc.*` files (the enums and messages) without ARC support, and the generated `.pbrpc.*` files (the services) with ARC support. The generated code depends on v0.5+ of the Objective-C gRPC runtime library and v3.0.0-alpha-3+ of the Objective-C Protobuf runtime library. From d73ca4817a116b07dfefe322c715757a7616cd70 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 10:21:01 -0700 Subject: [PATCH 28/37] fix compilation with VS2010 --- src/core/compression/algorithm.c | 2 ++ src/core/surface/byte_buffer.c | 1 + src/core/surface/call.c | 1 + 3 files changed, 4 insertions(+) diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c index d55e499f5ea..fd95a3c8912 100644 --- a/src/core/compression/algorithm.c +++ b/src/core/compression/algorithm.c @@ -101,6 +101,7 @@ grpc_compression_algorithm grpc_compression_algorithm_for_level( default: /* we shouldn't be making it here */ abort(); + return GRPC_COMPRESS_NONE; } } @@ -116,6 +117,7 @@ grpc_compression_level grpc_compression_level_for_algorithm( } } abort(); + return GRPC_COMPRESS_LEVEL_NONE; } void grpc_compression_options_init(grpc_compression_options *opts) { diff --git a/src/core/surface/byte_buffer.c b/src/core/surface/byte_buffer.c index a930949f2d4..295ef5ab0ee 100644 --- a/src/core/surface/byte_buffer.c +++ b/src/core/surface/byte_buffer.c @@ -97,4 +97,5 @@ size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) { } gpr_log(GPR_ERROR, "should never reach here"); abort(); + return 0; } diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 07c3ff6ae4e..8a7a772821e 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -436,6 +436,7 @@ static grpc_cq_completion *allocate_completion(grpc_call *call) { } gpr_log(GPR_ERROR, "should never reach here"); abort(); + return NULL; } static void done_completion(grpc_exec_ctx *exec_ctx, void *call, From a6e68f163c938223754b0caba31c1bc63c53d9a4 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 09:58:52 -0700 Subject: [PATCH 29/37] rename grpc.native.csharp_ext nuget to grpc.native.csharp --- src/csharp/Grpc.Core/Grpc.Core.nuspec | 2 +- src/csharp/build_packages.bat | 4 ++-- vsprojects/nuget_package/README.md | 2 +- ...c.native.csharp_ext.nuspec => grpc.native.csharp.nuspec} | 6 +++--- ...rpc.native.csharp_ext.props => grpc.native.csharp.props} | 0 ...native.csharp_ext.targets => grpc.native.csharp.targets} | 0 6 files changed, 7 insertions(+), 7 deletions(-) rename vsprojects/nuget_package/{grpc.native.csharp_ext.nuspec => grpc.native.csharp.nuspec} (85%) rename vsprojects/nuget_package/{grpc.native.csharp_ext.props => grpc.native.csharp.props} (100%) rename vsprojects/nuget_package/{grpc.native.csharp_ext.targets => grpc.native.csharp.targets} (100%) diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec index 06de55c8c3c..67a04afc22d 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.nuspec +++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec @@ -16,7 +16,7 @@ gRPC RPC Protocol HTTP/2 - + diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat index a3505b1e012..b864a955a89 100644 --- a/src/csharp/build_packages.bat +++ b/src/csharp/build_packages.bat @@ -20,9 +20,9 @@ endlocal @call ..\..\vsprojects\build_plugins.bat || goto :error -%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error +%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp.nuspec -Version %CORE_VERSION% || goto :error %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error -%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error +%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpVersion=%CORE_VERSION% || goto :error %NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error %NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error diff --git a/vsprojects/nuget_package/README.md b/vsprojects/nuget_package/README.md index 00bb400d661..9fcbb5f85df 100644 --- a/vsprojects/nuget_package/README.md +++ b/vsprojects/nuget_package/README.md @@ -16,7 +16,7 @@ Build all flavors of gRPC C# extension and package them as a NuGet package. ``` buildall.bat -nuget pack grpc.native.csharp_ext.nuspec +nuget pack grpc.native.csharp.nuspec ``` When building the NuGet package, ignore the "Assembly outside lib folder" warnings (they DLLs are not assemblies, they are native libraries). diff --git a/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec b/vsprojects/nuget_package/grpc.native.csharp.nuspec similarity index 85% rename from vsprojects/nuget_package/grpc.native.csharp_ext.nuspec rename to vsprojects/nuget_package/grpc.native.csharp.nuspec index 39791a5d8e0..50b56e9e6e6 100644 --- a/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec +++ b/vsprojects/nuget_package/grpc.native.csharp.nuspec @@ -1,7 +1,7 @@  - grpc.native.csharp_ext + grpc.native.csharp $version$ Google Inc. grpc-packages @@ -20,8 +20,8 @@ - - + + diff --git a/vsprojects/nuget_package/grpc.native.csharp_ext.props b/vsprojects/nuget_package/grpc.native.csharp.props similarity index 100% rename from vsprojects/nuget_package/grpc.native.csharp_ext.props rename to vsprojects/nuget_package/grpc.native.csharp.props diff --git a/vsprojects/nuget_package/grpc.native.csharp_ext.targets b/vsprojects/nuget_package/grpc.native.csharp.targets similarity index 100% rename from vsprojects/nuget_package/grpc.native.csharp_ext.targets rename to vsprojects/nuget_package/grpc.native.csharp.targets From 601f03c3085bb4369cd8b9b6cedf81c31108bf13 Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Thu, 8 Oct 2015 12:00:49 -0700 Subject: [PATCH 30/37] removed a few more linuxbrew references --- examples/php/README.md | 3 +-- src/objective-c/README.md | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/php/README.md b/examples/php/README.md index a4ee8e698b9..8fb060863a3 100644 --- a/examples/php/README.md +++ b/examples/php/README.md @@ -8,7 +8,7 @@ This requires PHP 5.5 or greater. INSTALL ------- - - On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. Run the following command to install gRPC. + - On Mac OS X, install [homebrew][]. Run the following command to install gRPC. ```sh $ curl -fsSL https://goo.gl/getgrpc | bash -s php @@ -59,7 +59,6 @@ TUTORIAL You can find a more detailed tutorial in [gRPC Basics: PHP][] [homebrew]:http://brew.sh -[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [Node]:https://github.com/grpc/grpc/tree/master/examples/node [gRPC Basics: PHP]:http://www.grpc.io/docs/tutorials/basic/php.html diff --git a/src/objective-c/README.md b/src/objective-c/README.md index 775f9a095fb..a861a9f6f93 100644 --- a/src/objective-c/README.md +++ b/src/objective-c/README.md @@ -17,7 +17,7 @@ services. ## Install protoc with the gRPC plugin -On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. +On Mac OS X, install [homebrew][]. Run the following command to install _protoc_ and the gRPC _protoc_ plugin: ```sh @@ -168,7 +168,6 @@ Objective-C Protobuf runtime library. [Protocol Buffers]:https://developers.google.com/protocol-buffers/ [homebrew]:http://brew.sh -[linuxbrew]:https://github.com/Homebrew/linuxbrew [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [example Podfile]:https://github.com/grpc/grpc/blob/master/src/objective-c/examples/Sample/Podfile [sample app]: https://github.com/grpc/grpc/tree/master/src/objective-c/examples/Sample From 6d3f9ac527359395de530f062da7e07de8bcb9fa Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Wed, 7 Oct 2015 13:42:10 -0700 Subject: [PATCH 31/37] php: update package.xml to prepare for 0.6.1 release --- src/php/ext/grpc/package.xml | 30 ++++++++++++++++++++---------- src/php/ext/grpc/php_grpc.c | 17 +++++++++++------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml index f41902f041e..921cfc6ae68 100644 --- a/src/php/ext/grpc/package.xml +++ b/src/php/ext/grpc/package.xml @@ -10,10 +10,10 @@ grpc-packages@google.com yes - 2015-09-24 - + 2015-10-07 + - 0.6.0 + 0.6.1 0.6.0 @@ -22,12 +22,7 @@ BSD -- support per message compression disable -- expose per-call host override option -- expose connectivity API -- expose channel target and call peer -- add user-agent -- update to wrap gRPC C core library beta version 0.11.0 +- fixed undefined constant fatal error when run with apache/nginx #2275 @@ -44,7 +39,7 @@ - + @@ -118,5 +113,20 @@ Update to wrap gRPC C Core version 0.10.0 - update to wrap gRPC C core library beta version 0.11.0 + + + 0.6.1 + 0.6.0 + + + beta + beta + + 2015-10-07 + BSD + +- fixed undefined constant fatal error when run with apache/nginx #2275 + + diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c index 4ad78ea0a31..fcd94a63062 100644 --- a/src/php/ext/grpc/php_grpc.c +++ b/src/php/ext/grpc/php_grpc.c @@ -150,7 +150,7 @@ PHP_MINIT_FUNCTION(grpc) { CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\STATUS_INVALID_ARGUMENT", GRPC_STATUS_INVALID_ARGUMENT, - CONST_CS | CONST_PERSISTENT); + CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\STATUS_DEADLINE_EXCEEDED", GRPC_STATUS_DEADLINE_EXCEEDED, CONST_CS | CONST_PERSISTENT); @@ -173,7 +173,8 @@ PHP_MINIT_FUNCTION(grpc) { CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED", GRPC_STATUS_ABORTED, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE", GRPC_STATUS_OUT_OF_RANGE, + REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE", + GRPC_STATUS_OUT_OF_RANGE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNIMPLEMENTED", GRPC_STATUS_UNIMPLEMENTED, @@ -202,7 +203,8 @@ PHP_MINIT_FUNCTION(grpc) { GRPC_OP_RECV_INITIAL_METADATA, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE", - GRPC_OP_RECV_MESSAGE, CONST_CS | CONST_PERSISTENT); + GRPC_OP_RECV_MESSAGE, + CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT", GRPC_OP_RECV_STATUS_ON_CLIENT, CONST_CS | CONST_PERSISTENT); @@ -212,11 +214,14 @@ PHP_MINIT_FUNCTION(grpc) { /* Register connectivity state constants */ REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_IDLE", - GRPC_CHANNEL_IDLE, CONST_CS | CONST_PERSISTENT); + GRPC_CHANNEL_IDLE, + CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_CONNECTING", - GRPC_CHANNEL_CONNECTING, CONST_CS | CONST_PERSISTENT); + GRPC_CHANNEL_CONNECTING, + CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_READY", - GRPC_CHANNEL_READY, CONST_CS | CONST_PERSISTENT); + GRPC_CHANNEL_READY, + CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_TRANSIENT_FAILURE", GRPC_CHANNEL_TRANSIENT_FAILURE, CONST_CS | CONST_PERSISTENT); From 52f6fc1e1eb617b20b6ebc784dad65fa582b5aa7 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 8 Oct 2015 23:25:06 +0200 Subject: [PATCH 32/37] All of the subprojects need to generate a report, otherwise Jenkins will be sad. --- tools/jenkins/run_jenkins.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh index 67cfc2bb0a4..0e1af2a2a9a 100755 --- a/tools/jenkins/run_jenkins.sh +++ b/tools/jenkins/run_jenkins.sh @@ -86,3 +86,9 @@ else echo "Unknown platform $platform" exit 1 fi + +if [ ! -e reports/index.html ] +then + mkdir -p reports + echo 'No reports generated.' > reports/index.html +fi From 0c331880d0062f39f434ba8ad2341252e38bed79 Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Thu, 8 Oct 2015 14:51:54 -0700 Subject: [PATCH 33/37] Hid test-only functions from surface/call.h --- BUILD | 3 + build.yaml | 1 + gRPC.podspec | 2 + src/core/surface/call.c | 12 ++-- src/core/surface/call.h | 10 --- src/core/surface/call_test_only.h | 65 +++++++++++++++++++ test/core/end2end/tests/compressed_payload.c | 11 ++-- test/cpp/interop/client_helper.h | 6 +- test/cpp/interop/server_helper.cc | 6 +- tools/doxygen/Doxyfile.core.internal | 1 + tools/run_tests/sources_and_headers.json | 4 ++ vsprojects/vcxproj/grpc/grpc.vcxproj | 1 + vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 3 + .../grpc_unsecure/grpc_unsecure.vcxproj | 1 + .../grpc_unsecure.vcxproj.filters | 3 + 15 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 src/core/surface/call_test_only.h diff --git a/BUILD b/BUILD index 3e2a45b8a0a..ffeb31e424b 100644 --- a/BUILD +++ b/BUILD @@ -223,6 +223,7 @@ cc_library( "src/core/surface/api_trace.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", + "src/core/surface/call_test_only.h", "src/core/surface/channel.h", "src/core/surface/completion_queue.h", "src/core/surface/event_string.h", @@ -509,6 +510,7 @@ cc_library( "src/core/surface/api_trace.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", + "src/core/surface/call_test_only.h", "src/core/surface/channel.h", "src/core/surface/completion_queue.h", "src/core/surface/event_string.h", @@ -1296,6 +1298,7 @@ objc_library( "src/core/surface/api_trace.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", + "src/core/surface/call_test_only.h", "src/core/surface/channel.h", "src/core/surface/completion_queue.h", "src/core/surface/event_string.h", diff --git a/build.yaml b/build.yaml index 98fb0348ca3..e277b60b77e 100644 --- a/build.yaml +++ b/build.yaml @@ -183,6 +183,7 @@ filegroups: - src/core/surface/api_trace.h - src/core/surface/byte_buffer_queue.h - src/core/surface/call.h + - src/core/surface/call_test_only.h - src/core/surface/channel.h - src/core/surface/completion_queue.h - src/core/surface/event_string.h diff --git a/gRPC.podspec b/gRPC.podspec index 717e7005ee5..6378cf0413c 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -227,6 +227,7 @@ Pod::Spec.new do |s| 'src/core/surface/api_trace.h', 'src/core/surface/byte_buffer_queue.h', 'src/core/surface/call.h', + 'src/core/surface/call_test_only.h', 'src/core/surface/channel.h', 'src/core/surface/completion_queue.h', 'src/core/surface/event_string.h', @@ -518,6 +519,7 @@ Pod::Spec.new do |s| 'src/core/surface/api_trace.h', 'src/core/surface/byte_buffer_queue.h', 'src/core/surface/call.h', + 'src/core/surface/call_test_only.h', 'src/core/surface/channel.h', 'src/core/surface/completion_queue.h', 'src/core/surface/event_string.h', diff --git a/src/core/surface/call.c b/src/core/surface/call.c index c8b880b0ad0..630be2f73ac 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -521,7 +521,7 @@ static void set_compression_algorithm(grpc_call *call, call->compression_algorithm = algo; } -grpc_compression_algorithm grpc_call_get_compression_algorithm( +grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm( grpc_call *call) { grpc_compression_algorithm algorithm; gpr_mu_lock(&call->mu); @@ -561,11 +561,15 @@ static void set_encodings_accepted_by_peer( } } -gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call) { - return call->encodings_accepted_by_peer; +gpr_uint32 grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) { + gpr_uint32 encodings_accepted_by_peer; + gpr_mu_lock(&call->mu); + encodings_accepted_by_peer = call->encodings_accepted_by_peer; + gpr_mu_unlock(&call->mu); + return encodings_accepted_by_peer; } -gpr_uint32 grpc_call_get_message_flags(grpc_call *call) { +gpr_uint32 grpc_call_test_only_get_message_flags(grpc_call *call) { gpr_uint32 flags; gpr_mu_lock(&call->mu); flags = call->incoming_message_flags; diff --git a/src/core/surface/call.h b/src/core/surface/call.h index cd1db3d417c..9b7c6f9bfbe 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -169,16 +169,6 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem); gpr_uint8 grpc_call_is_client(grpc_call *call); -grpc_compression_algorithm grpc_call_get_compression_algorithm(grpc_call *call); - -gpr_uint32 grpc_call_get_message_flags(grpc_call *call); - -/** Returns a bitset for the encodings (compression algorithms) supported by \a - * call's peer. - * - * To be indexed by grpc_compression_algorithm enum values. */ -gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call); - #ifdef __cplusplus } #endif diff --git a/src/core/surface/call_test_only.h b/src/core/surface/call_test_only.h new file mode 100644 index 00000000000..df4be3248b2 --- /dev/null +++ b/src/core/surface/call_test_only.h @@ -0,0 +1,65 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H +#define GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Return the compression algorithm from \a call. + * + * \warning This function should \b only be used in test code. */ +grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm( + grpc_call *call); + +/** Return the message flags from \a call. + * + * \warning This function should \b only be used in test code. */ +gpr_uint32 grpc_call_test_only_get_message_flags(grpc_call *call); + +/** Returns a bitset for the encodings (compression algorithms) supported by \a + * call's peer. + * + * To be indexed by grpc_compression_algorithm enum values. */ +gpr_uint32 grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call); + + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H */ diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c index a4614a2aba4..f321fe1e7c7 100644 --- a/test/core/end2end/tests/compressed_payload.c +++ b/test/core/end2end/tests/compressed_payload.c @@ -46,7 +46,7 @@ #include "test/core/end2end/cq_verifier.h" #include "src/core/channel/channel_args.h" #include "src/core/channel/compress_filter.h" -#include "src/core/surface/call.h" +#include "src/core/surface/call_test_only.h" enum { TIMEOUT = 200000 }; @@ -196,12 +196,13 @@ static void request_with_payload_template( cq_expect_completion(cqv, tag(101), 1); cq_verify(cqv); - GPR_ASSERT(GPR_BITCOUNT(grpc_call_get_encodings_accepted_by_peer(s)) == 3); - GPR_ASSERT(GPR_BITGET(grpc_call_get_encodings_accepted_by_peer(s), + GPR_ASSERT( + GPR_BITCOUNT(grpc_call_test_only_get_encodings_accepted_by_peer(s)) == 3); + GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s), GRPC_COMPRESS_NONE) != 0); - GPR_ASSERT(GPR_BITGET(grpc_call_get_encodings_accepted_by_peer(s), + GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s), GRPC_COMPRESS_DEFLATE) != 0); - GPR_ASSERT(GPR_BITGET(grpc_call_get_encodings_accepted_by_peer(s), + GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s), GRPC_COMPRESS_GZIP) != 0); op = ops; diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h index 0221df93db5..ace193042ee 100644 --- a/test/cpp/interop/client_helper.h +++ b/test/cpp/interop/client_helper.h @@ -38,7 +38,7 @@ #include -#include "src/core/surface/call.h" +#include "src/core/surface/call_test_only.h" namespace grpc { namespace testing { @@ -57,11 +57,11 @@ class InteropClientContextInspector { // Inspector methods, able to peek inside ClientContext, follow. grpc_compression_algorithm GetCallCompressionAlgorithm() const { - return grpc_call_get_compression_algorithm(context_.call_); + return grpc_call_test_only_get_compression_algorithm(context_.call_); } gpr_uint32 GetMessageFlags() const { - return grpc_call_get_message_flags(context_.call_); + return grpc_call_test_only_get_message_flags(context_.call_); } private: diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc index 45707508466..5138a38170a 100644 --- a/test/cpp/interop/server_helper.cc +++ b/test/cpp/interop/server_helper.cc @@ -38,7 +38,7 @@ #include #include -#include "src/core/surface/call.h" +#include "src/core/surface/call_test_only.h" #include "test/core/end2end/data/ssl_test_data.h" DECLARE_bool(use_tls); @@ -65,11 +65,11 @@ InteropServerContextInspector::InteropServerContextInspector( grpc_compression_algorithm InteropServerContextInspector::GetCallCompressionAlgorithm() const { - return grpc_call_get_compression_algorithm(context_.call_); + return grpc_call_test_only_get_compression_algorithm(context_.call_); } gpr_uint32 InteropServerContextInspector::GetEncodingsAcceptedByClient() const { - return grpc_call_get_encodings_accepted_by_peer(context_.call_); + return grpc_call_test_only_get_encodings_accepted_by_peer(context_.call_); } std::shared_ptr diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 5658a102d75..5fd3ee70d63 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -858,6 +858,7 @@ src/core/statistics/census_rpc_stats.h \ src/core/surface/api_trace.h \ src/core/surface/byte_buffer_queue.h \ src/core/surface/call.h \ +src/core/surface/call_test_only.h \ src/core/surface/channel.h \ src/core/surface/completion_queue.h \ src/core/surface/event_string.h \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 1ceff15a3be..76d66ed7a07 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -12365,6 +12365,7 @@ "src/core/surface/api_trace.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", + "src/core/surface/call_test_only.h", "src/core/surface/channel.h", "src/core/surface/completion_queue.h", "src/core/surface/event_string.h", @@ -12607,6 +12608,7 @@ "src/core/surface/call.h", "src/core/surface/call_details.c", "src/core/surface/call_log_batch.c", + "src/core/surface/call_test_only.h", "src/core/surface/channel.c", "src/core/surface/channel.h", "src/core/surface/channel_connectivity.c", @@ -12861,6 +12863,7 @@ "src/core/surface/api_trace.h", "src/core/surface/byte_buffer_queue.h", "src/core/surface/call.h", + "src/core/surface/call_test_only.h", "src/core/surface/channel.h", "src/core/surface/completion_queue.h", "src/core/surface/event_string.h", @@ -13073,6 +13076,7 @@ "src/core/surface/call.h", "src/core/surface/call_details.c", "src/core/surface/call_log_batch.c", + "src/core/surface/call_test_only.h", "src/core/surface/channel.c", "src/core/surface/channel.h", "src/core/surface/channel_connectivity.c", diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index 183edbc05bf..88b883f67cf 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -344,6 +344,7 @@ + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index 66ce9ca05be..1a46ac8e34b 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -743,6 +743,9 @@ src\core\surface + + src\core\surface + src\core\surface diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index b527179f9f3..cddd00374b2 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -323,6 +323,7 @@ + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index 7be3c9ec93b..01e0d8dadde 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -641,6 +641,9 @@ src\core\surface + + src\core\surface + src\core\surface From e2686282ace62f8b6a5e9ed7c836b415605d053f Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 16:27:07 -0700 Subject: [PATCH 34/37] kill interop clients on timeout --- tools/run_tests/dockerjob.py | 34 ++++++++++----------------- tools/run_tests/jobset.py | 6 ++++- tools/run_tests/run_interop_tests.py | 35 +++++++++++++++++++++------- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/tools/run_tests/dockerjob.py b/tools/run_tests/dockerjob.py index 11686d46b09..266edd4375b 100755 --- a/tools/run_tests/dockerjob.py +++ b/tools/run_tests/dockerjob.py @@ -38,18 +38,15 @@ import subprocess _DEVNULL = open(os.devnull, 'w') -def wait_for_file(filepath, timeout_seconds=15): - """Wait until given file exists and returns its content.""" - started = time.time() - while time.time() - started < timeout_seconds: - if os.path.isfile(filepath): - with open(filepath, 'r') as f: - content = f.read() - # make sure we don't return empty content - if content: - return content - time.sleep(1) - raise Exception('Failed to read file %s.' % filepath) + +def random_name(base_name): + """Randomizes given base name.""" + return '%s_%s' % (base_name, uuid.uuid4()) + + +def docker_kill(cid): + """Kills a docker container. Returns True if successful.""" + return subprocess.call(['docker','kill', str(cid)]) == 0 def docker_mapped_port(cid, port): @@ -92,23 +89,16 @@ class DockerJob: def __init__(self, spec): self._spec = spec self._job = jobset.Job(spec, bin_hash=None, newline_on_success=True, travis=True, add_env={}, xml_report=None) - self._cidfile = spec.cidfile - self._cid = None - - def cid(self): - """Gets cid of this container""" - if not self._cid: - self._cid = wait_for_file(self._cidfile) - return self._cid + self._container_name = spec.container_name def mapped_port(self, port): - return docker_mapped_port(self.cid(), port) + return docker_mapped_port(self._container_name, port) def kill(self, suppress_failure=False): """Sends kill signal to the container.""" if suppress_failure: self._job.suppress_failure_message() - return subprocess.call(['docker','kill', self.cid()]) == 0 + return docker_kill(self._container_name) def is_running(self): """Polls a job and returns True if given job is still running.""" diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py index 87be703b4cd..17a63c02e84 100755 --- a/tools/run_tests/jobset.py +++ b/tools/run_tests/jobset.py @@ -135,13 +135,14 @@ class JobSpec(object): def __init__(self, cmdline, shortname=None, environ=None, hash_targets=None, cwd=None, shell=False, timeout_seconds=5*60, flake_retries=0, - timeout_retries=0): + timeout_retries=0, kill_handler=None): """ Arguments: cmdline: a list of arguments to pass as the command line environ: a dictionary of environment variables to set in the child process hash_targets: which files to include in the hash representing the jobs version (or empty, indicating the job should not be hashed) + kill_handler: a handler that will be called whenever job.kill() is invoked """ if environ is None: environ = {} @@ -156,6 +157,7 @@ class JobSpec(object): self.timeout_seconds = timeout_seconds self.flake_retries = flake_retries self.timeout_retries = timeout_retries + self.kill_handler = kill_handler def identity(self): return '%r %r %r' % (self.cmdline, self.environ, self.hash_targets) @@ -254,6 +256,8 @@ class Job(object): def kill(self): if self._state == _RUNNING: self._state = _KILLED + if self._spec.kill_handler: + self._spec.kill_handler(self) self._process.terminate() def suppress_failure_message(self): diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index f328f4642ee..4d09ae7fcda 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -321,17 +321,29 @@ def add_auth_options(language, test_case, cmdline, env): return (cmdline, env) +def _job_kill_handler(job): + if job._spec.container_name: + dockerjob.docker_kill(job._spec.container_name) + + def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False): """Creates jobspec for cloud-to-prod interop test""" cmdline = language.cloud_to_prod_args() + ['--test_case=%s' % test_case] cwd = language.client_cwd environ = language.cloud_to_prod_env() + container_name = None if auth: cmdline, environ = add_auth_options(language, test_case, cmdline, environ) cmdline = bash_login_cmdline(cmdline) if docker_image: - cmdline = docker_run_cmdline(cmdline, image=docker_image, cwd=cwd, environ=environ) + container_name = dockerjob.random_name('interop_client_%s' % language) + cmdline = docker_run_cmdline(cmdline, + image=docker_image, + cwd=cwd, + environ=environ, + docker_args=['--net=host', + '--name', container_name]) cwd = None environ = None @@ -343,7 +355,9 @@ def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False): shortname="%s:%s:%s" % (suite_name, language, test_case), timeout_seconds=2*60, flake_retries=5 if args.allow_flakes else 0, - timeout_retries=2 if args.allow_flakes else 0) + timeout_retries=2 if args.allow_flakes else 0, + kill_handler=_job_kill_handler) + test_job.container_name = container_name return test_job @@ -356,11 +370,14 @@ def cloud_to_cloud_jobspec(language, test_case, server_name, server_host, '--server_port=%s' % server_port ]) cwd = language.client_cwd if docker_image: + container_name = dockerjob.random_name('interop_client_%s' % language) cmdline = docker_run_cmdline(cmdline, image=docker_image, cwd=cwd, - docker_args=['--net=host']) + docker_args=['--net=host', + '--name', container_name]) cwd = None + test_job = jobset.JobSpec( cmdline=cmdline, cwd=cwd, @@ -368,25 +385,27 @@ def cloud_to_cloud_jobspec(language, test_case, server_name, server_host, test_case), timeout_seconds=2*60, flake_retries=5 if args.allow_flakes else 0, - timeout_retries=2 if args.allow_flakes else 0) + timeout_retries=2 if args.allow_flakes else 0, + kill_handler=_job_kill_handler) + test_job.container_name = container_name return test_job def server_jobspec(language, docker_image): """Create jobspec for running a server""" - cidfile = tempfile.mktemp() + container_name = dockerjob.random_name('interop_server_%s' % language) cmdline = bash_login_cmdline(language.server_args() + ['--port=%s' % _DEFAULT_SERVER_PORT]) docker_cmdline = docker_run_cmdline(cmdline, image=docker_image, cwd=language.server_cwd, docker_args=['-p', str(_DEFAULT_SERVER_PORT), - '--cidfile', cidfile]) + '--name', container_name]) server_job = jobset.JobSpec( cmdline=docker_cmdline, - shortname="interop_server:%s" % language, + shortname="interop_server_%s" % language, timeout_seconds=30*60) - server_job.cidfile = cidfile + server_job.container_name = container_name return server_job From 9b9812133c8310a07d60a2c7b2b0effb6dba24ad Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 17:25:52 -0700 Subject: [PATCH 35/37] use --name instead of --cidfile --- tools/jenkins/build_interop_image.sh | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tools/jenkins/build_interop_image.sh b/tools/jenkins/build_interop_image.sh index 3664eed84d9..166efbd9e2f 100755 --- a/tools/jenkins/build_interop_image.sh +++ b/tools/jenkins/build_interop_image.sh @@ -77,7 +77,7 @@ docker build -t $BASE_IMAGE --force-rm=true tools/jenkins/$BASE_NAME || exit $? # Create a local branch so the child Docker script won't complain git branch -f jenkins-docker -CIDFILE=`mktemp -u --suffix=.cid` +CONTAINER_NAME="build_${BASE_NAME}_$(uuidgen)" # Prepare image for interop tests, commit it on success. (docker run \ @@ -85,17 +85,14 @@ CIDFILE=`mktemp -u --suffix=.cid` -i $TTY_FLAG \ $MOUNT_ARGS \ -v /tmp/ccache:/tmp/ccache \ - --cidfile=$CIDFILE \ + --name=$CONTAINER_NAME \ $BASE_IMAGE \ bash -l /var/local/jenkins/grpc/tools/jenkins/$BASE_NAME/build_interop.sh \ - && docker commit `cat $CIDFILE` $INTEROP_IMAGE \ + && docker commit $CONTAINER_NAME $INTEROP_IMAGE \ && echo "Successfully built image $INTEROP_IMAGE") EXITCODE=$? # remove intermediate container, possibly killing it first -docker rm -f `cat $CIDFILE` - -# remove the cidfile -rm -rf `cat $CIDFILE` +docker rm -f $CONTAINER_NAME exit $EXITCODE From 65854ebbd26f13294cdcf30484adb8f5c3d3ba29 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 17:35:44 -0700 Subject: [PATCH 36/37] stop using --cidfile for run_tests --- tools/jenkins/build_docker_and_run_tests.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tools/jenkins/build_docker_and_run_tests.sh b/tools/jenkins/build_docker_and_run_tests.sh index 8b7809f2e23..6e3166ce579 100755 --- a/tools/jenkins/build_docker_and_run_tests.sh +++ b/tools/jenkins/build_docker_and_run_tests.sh @@ -53,8 +53,8 @@ DOCKER_IMAGE_NAME=grpc_jenkins_slave${docker_suffix}_`sha1sum tools/jenkins/grpc # Make sure docker image has been built. Should be instantaneous if so. docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_jenkins_slave$docker_suffix -# Make sure the CID file is gone. -rm -f docker.cid +# Choose random name for docker container +CONTAINER_NAME="run_tests_$(uuidgen)" # Run tests inside docker docker run \ @@ -70,23 +70,21 @@ docker run \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $(which docker):/bin/docker \ -w /var/local/git/grpc \ - --cidfile=docker.cid \ + --name=$CONTAINER_NAME \ $DOCKER_IMAGE_NAME \ bash -l /var/local/jenkins/grpc/tools/jenkins/docker_run_tests.sh || DOCKER_FAILED="true" -DOCKER_CID=`cat docker.cid` - if [ "$XML_REPORT" != "" ] then - docker cp "$DOCKER_CID:/var/local/git/grpc/$XML_REPORT" $git_root + docker cp "$CONTAINER_NAME:/var/local/git/grpc/$XML_REPORT" $git_root fi -docker cp "$DOCKER_CID:/var/local/git/grpc/reports.zip" $git_root || true +docker cp "$CONTAINER_NAME:/var/local/git/grpc/reports.zip" $git_root || true unzip $git_root/reports.zip -d $git_root || true rm -f reports.zip # remove the container, possibly killing it first -docker rm -f $DOCKER_CID || true +docker rm -f $CONTAINER_NAME || true if [ "$DOCKER_FAILED" != "" ] && [ "$XML_REPORT" == "" ] then From c86909ce71b04a78a6cf7f662e1ce937d7f8ef3b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 9 Oct 2015 09:25:26 -0700 Subject: [PATCH 37/37] Fixed node interop build script and Dockerfile --- tools/jenkins/grpc_interop_node/Dockerfile | 1 + tools/jenkins/grpc_interop_node/build_interop.sh | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/jenkins/grpc_interop_node/Dockerfile b/tools/jenkins/grpc_interop_node/Dockerfile index 587227b9429..db5aff844de 100644 --- a/tools/jenkins/grpc_interop_node/Dockerfile +++ b/tools/jenkins/grpc_interop_node/Dockerfile @@ -48,6 +48,7 @@ RUN apt-get update && apt-get install -y \ libc6-dbg \ libc6-dev \ libgtest-dev \ + libssl-dev \ libtool \ make \ strace \ diff --git a/tools/jenkins/grpc_interop_node/build_interop.sh b/tools/jenkins/grpc_interop_node/build_interop.sh index 84e25e33088..3b69715c9af 100755 --- a/tools/jenkins/grpc_interop_node/build_interop.sh +++ b/tools/jenkins/grpc_interop_node/build_interop.sh @@ -45,5 +45,4 @@ make install-certs # build Node interop client & server npm install -g node-gyp -make install_c -C /var/local/git/grpc -(cd src/node && npm install && node-gyp rebuild) +(npm install && node-gyp rebuild)