-
Notifications
You must be signed in to change notification settings - Fork 12
/
BaseIntegrationTests.cs
192 lines (172 loc) · 8.13 KB
/
BaseIntegrationTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Debugger.RemoteFrameRpc;
using Debugger.RemoteThreadRpc;
using Debugger.SbModuleRpc;
using DebuggerGrpcClient;
using DebuggerGrpcServer;
using Grpc.Core;
using LldbApi;
using NSubstitute;
using NUnit.Framework;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.ExceptionServices;
using Microsoft.VisualStudio.Threading;
namespace DebuggerGrpcClientServer.Tests
{
/// <summary>
/// Class that all test fixtures for gRPC client-server tests should inherit from.
/// It sets up and tears down the server and its services.
/// Also, it ensures that all the object stores are empty after each test.
/// </summary>
abstract class BaseIntegrationTests
{
private List<ExceptionDispatchInfo> exceptions;
private ServerInfo serverInfo;
protected void BaseSetUp()
{
Assert.IsNull(serverInfo);
var grpcConnectionFactory =
new GrpcConnectionFactory(new JoinableTaskContext().Factory);
serverInfo = CreateServer(new PipeCallInvokerFactory(), grpcConnectionFactory);
exceptions = new List<ExceptionDispatchInfo>();
// Store RPC exceptions keeping stack trace.
Connection.RpcException += e => exceptions.Add(ExceptionDispatchInfo.Capture(e));
// Make sure everything gets deleted immediately. We're checking this on shutdown!
Connection.BulkDeleteBatchSize = 1;
}
protected void BaseTearDown()
{
Assert.IsNotNull(serverInfo);
Connection.Shutdown();
CallInvoker.Dispose();
// Temporarily disabling the deprecated method call warning
// (that method is meant to be called from this class).
// Also wait synchronously, should be fine in tests and
// ITestAction doesn't have an async version.
#pragma warning disable 618, VSTHRD002
Server.ShutdownTask.Wait();
#pragma warning restore 618, VSTHRD002
try
{
Assert.Multiple(() =>
{
Assert.AreEqual(0, ProcessStore.Count);
Assert.AreEqual(0, FrameStore.Count);
Assert.AreEqual(0, ThreadStore.Count);
Assert.AreEqual(0, ValueStore.Count);
Assert.AreEqual(0, FunctionStore.Count);
Assert.AreEqual(0, ModuleStore.Count);
Assert.AreEqual(0, SectionStore.Count);
Assert.AreEqual(0, SymbolStore.Count);
Assert.IsEmpty(exceptions);
});
}
finally
{
exceptions = null;
serverInfo = null;
}
}
#region Server info aliases
protected PipeServiceBinder Server => serverInfo.Server;
protected PipeCallInvoker CallInvoker => serverInfo.CallInvoker;
protected GrpcConnection Connection => serverInfo.Connection;
protected ConcurrentDictionary<int, SbProcess> ProcessStore => serverInfo.Stores.Process;
protected ObjectStore<RemoteFrame> FrameStore => serverInfo.Stores.Frame;
protected ObjectStore<RemoteThread> ThreadStore => serverInfo.Stores.Thread;
protected ObjectStore<RemoteValue> ValueStore => serverInfo.Stores.Value;
protected ObjectStore<SbFunction> FunctionStore => serverInfo.Stores.Function;
protected UniqueObjectStore<SbModule> ModuleStore => serverInfo.Stores.Module;
protected ObjectStore<SbSection> SectionStore => serverInfo.Stores.Section;
protected ObjectStore<SbSymbol> SymbolStore => serverInfo.Stores.Symbol;
#endregion
#region Server setup helper types/methods
private class RemoteObjectStores
{
public ConcurrentDictionary<int, SbProcess> Process { get; } =
new ConcurrentDictionary<int, SbProcess>();
public ObjectStore<SbAddress> Address { get; } = new ObjectStore<SbAddress>();
public ObjectStore<RemoteFrame> Frame { get; } =
new ObjectStore<RemoteFrame>();
public ObjectStore<RemoteThread> Thread { get; } =
new ObjectStore<RemoteThread>();
public ObjectStore<RemoteValue> Value { get; } =
new ObjectStore<RemoteValue>();
public ObjectStore<SbFunction> Function { get; } =
new ObjectStore<SbFunction>();
public UniqueObjectStore<SbModule> Module { get; } =
new UniqueObjectStore<SbModule>(SbModuleEqualityComparer.Instance);
public ObjectStore<SbSection> Section { get; } =
new ObjectStore<SbSection>();
public ObjectStore<SbSymbol> Symbol { get; } =
new ObjectStore<SbSymbol>();
}
private class LldbMockFactories
{
public ILldbFileSpecFactory FileSpec { get; } = Substitute.For<ILldbFileSpecFactory>();
}
private class ServerInfo
{
public PipeServiceBinder Server { get; }
public PipeCallInvoker CallInvoker { get; }
public GrpcConnection Connection { get; }
public RemoteObjectStores Stores { get; }
public LldbMockFactories MockFactories { get; }
public ServerInfo(PipeServiceBinder server, PipeCallInvoker callInvoker,
GrpcConnection connection, RemoteObjectStores stores,
LldbMockFactories mockFactories)
{
Server = server;
CallInvoker = callInvoker;
Connection = connection;
Stores = stores;
MockFactories = mockFactories;
}
}
private ServerInfo CreateServer(
PipeCallInvokerFactory callInvokerFactory, GrpcConnectionFactory connectionFactory)
{
PipeCallInvoker callInvoker = callInvokerFactory.Create();
GrpcConnection connection = connectionFactory.Create(callInvoker);
string[] inPipeHandles, outPipeHandles;
callInvoker.GetClientPipeHandles(out inPipeHandles, out outPipeHandles);
// Note: The client's out handles are the server's in handles and vice versa.
PipeServiceBinder server = new PipeServiceBinder(outPipeHandles, inPipeHandles);
var stores = new RemoteObjectStores();
var mockFactories = new LldbMockFactories();
BindServices(server, stores, mockFactories);
server.Start();
return new ServerInfo(server, callInvoker, connection, stores, mockFactories);
}
// This method should grow as we find necessary to interact with other services.
private void BindServices(ServiceBinderBase server, RemoteObjectStores stores,
LldbMockFactories mockFactories)
{
var remoteFrameRpc =
new RemoteFrameRpcServiceImpl(stores.Value, stores.Function, stores.Symbol,
stores.Module, stores.Frame, stores.Thread);
var remoteModuleRpc = new SbModuleRpcServiceImpl(
stores.Module, stores.Address, stores.Section, mockFactories.FileSpec);
var remoteThreadRpc = new RemoteThreadRpcServiceImpl(
stores.Process, stores.Thread,
stores.Frame, stores.Module);
RemoteFrameRpcService.BindService(server, remoteFrameRpc);
SbModuleRpcService.BindService(server, remoteModuleRpc);
RemoteThreadRpcService.BindService(server, remoteThreadRpc);
}
#endregion
}
}