• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #endregion
18 
19 using System;
20 using System.Collections.Generic;
21 using System.Linq;
22 using System.Threading;
23 using System.Threading.Tasks;
24 using Grpc.Core;
25 using Grpc.Core.Utils;
26 using Grpc.Testing;
27 using NUnit.Framework;
28 
29 namespace Grpc.IntegrationTesting
30 {
31     public class XdsInteropClientTest
32     {
33         const string Host = "localhost";
34 
35         BackendServiceImpl backendService;
36 
37         Server backendServer;
38         Server lbStatsServer;
39         Channel lbStatsChannel;
40         LoadBalancerStatsService.LoadBalancerStatsServiceClient lbStatsClient;
41 
42         XdsInteropClient xdsInteropClient;
43 
44         [OneTimeSetUp]
Init()45         public void Init()
46         {
47             backendService = new BackendServiceImpl();
48 
49             // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
50             backendServer = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
51             {
52                 Services = { TestService.BindService(backendService) },
53                 Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
54             };
55             backendServer.Start();
56 
57             xdsInteropClient = new XdsInteropClient(new XdsInteropClient.ClientOptions
58             {
59                 NumChannels = 1,
60                 Qps = 1,
61                 RpcTimeoutSec = 10,
62                 Rpc = "UnaryCall",
63                 Server = $"{Host}:{backendServer.Ports.Single().BoundPort}",
64             });
65 
66             // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
67             lbStatsServer = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
68             {
69                 Services = { LoadBalancerStatsService.BindService(new LoadBalancerStatsServiceImpl(xdsInteropClient.StatsWatcher)) },
70                 Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
71             };
72             lbStatsServer.Start();
73 
74             int port = lbStatsServer.Ports.Single().BoundPort;
75             lbStatsChannel = new Channel(Host, port, ChannelCredentials.Insecure);
76             lbStatsClient = new LoadBalancerStatsService.LoadBalancerStatsServiceClient(lbStatsChannel);
77         }
78 
79         [OneTimeTearDown]
Cleanup()80         public void Cleanup()
81         {
82             lbStatsChannel.ShutdownAsync().Wait();
83             lbStatsServer.ShutdownAsync().Wait();
84             backendServer.ShutdownAsync().Wait();
85         }
86 
87         [Test]
SmokeTest()88         public async Task SmokeTest()
89         {
90             string backendName = "backend1";
91             backendService.UnaryHandler = (request, context) =>
92             {
93                 return Task.FromResult(new SimpleResponse { Hostname = backendName });
94             };
95 
96             var cancellationTokenSource = new CancellationTokenSource();
97             var runChannelsTask = xdsInteropClient.RunChannelsAsync(cancellationTokenSource.Token);
98 
99             var stats = await lbStatsClient.GetClientStatsAsync(new LoadBalancerStatsRequest
100             {
101                 NumRpcs = 5,
102                 TimeoutSec = 10,
103             }, deadline: DateTime.UtcNow.AddSeconds(30));
104 
105             Assert.AreEqual(0, stats.NumFailures);
106             Assert.AreEqual(backendName, stats.RpcsByPeer.Keys.Single());
107             Assert.AreEqual(5, stats.RpcsByPeer[backendName]);
108             Assert.AreEqual("UnaryCall", stats.RpcsByMethod.Keys.Single());
109             Assert.AreEqual(backendName, stats.RpcsByMethod["UnaryCall"].RpcsByPeer_.Keys.Single());
110             Assert.AreEqual(5, stats.RpcsByMethod["UnaryCall"].RpcsByPeer_[backendName]);
111 
112             await Task.Delay(100);
113 
114             var stats2 = await lbStatsClient.GetClientStatsAsync(new LoadBalancerStatsRequest
115             {
116                 NumRpcs = 3,
117                 TimeoutSec = 10,
118             }, deadline: DateTime.UtcNow.AddSeconds(30));
119 
120             Assert.AreEqual(0, stats2.NumFailures);
121             Assert.AreEqual(backendName, stats2.RpcsByPeer.Keys.Single());
122             Assert.AreEqual(3, stats2.RpcsByPeer[backendName]);
123             Assert.AreEqual("UnaryCall", stats2.RpcsByMethod.Keys.Single());
124             Assert.AreEqual(backendName, stats2.RpcsByMethod["UnaryCall"].RpcsByPeer_.Keys.Single());
125             Assert.AreEqual(3, stats2.RpcsByMethod["UnaryCall"].RpcsByPeer_[backendName]);
126 
127             cancellationTokenSource.Cancel();
128             await runChannelsTask;
129         }
130 
131         [Test]
HostnameReadFromResponseHeaders()132         public async Task HostnameReadFromResponseHeaders()
133         {
134             string correctBackendName = "backend1";
135             backendService.UnaryHandler = async (request, context) =>
136             {
137                 await context.WriteResponseHeadersAsync(new Metadata { {"hostname", correctBackendName} });
138                 return new SimpleResponse { Hostname = "wrong_hostname" };
139             };
140 
141             var cancellationTokenSource = new CancellationTokenSource();
142             var runChannelsTask = xdsInteropClient.RunChannelsAsync(cancellationTokenSource.Token);
143 
144             var stats = await lbStatsClient.GetClientStatsAsync(new LoadBalancerStatsRequest
145             {
146                 NumRpcs = 3,
147                 TimeoutSec = 10,
148             }, deadline: DateTime.UtcNow.AddSeconds(30));
149 
150             Assert.AreEqual(0, stats.NumFailures);
151             Assert.AreEqual(correctBackendName, stats.RpcsByPeer.Keys.Single());
152             Assert.AreEqual(3, stats.RpcsByPeer[correctBackendName]);
153 
154             cancellationTokenSource.Cancel();
155             await runChannelsTask;
156         }
157 
158         public class BackendServiceImpl : TestService.TestServiceBase
159         {
160             public UnaryServerMethod<SimpleRequest, SimpleResponse> UnaryHandler { get; set; }
161             public UnaryServerMethod<Empty, Empty> EmptyHandler { get; set; }
162 
UnaryCall(SimpleRequest request, ServerCallContext context)163             public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
164             {
165                 return UnaryHandler(request, context);
166             }
167 
EmptyCall(Empty request, ServerCallContext context)168             public override Task<Empty> EmptyCall(Empty request, ServerCallContext context)
169             {
170                 return EmptyHandler(request, context);
171             }
172         }
173     }
174 }
175