fix: cancel even when vrpc is not started yet and fix newRealCall (#2… · googleapis/java-bigtable@45905a0 (original) (raw)

``

1

`+

/*

`

``

2

`+

`

``

3

`+

`

``

4

`+

`

``

5

`+

`

``

6

`+

`

``

7

`+

`

``

8

`+

`

``

9

`+

`

``

10

`+

`

``

11

`+

`

``

12

`+

`

``

13

`+

`

``

14

`+

`

``

15

`+

*/

`

``

16

`+

package com.google.cloud.bigtable.data.v2.stub;

`

``

17

+

``

18

`+

import static com.google.common.truth.Truth.assertThat;

`

``

19

`+

import static org.junit.Assert.fail;

`

``

20

+

``

21

`+

import com.google.api.core.ApiFuture;

`

``

22

`+

import com.google.api.gax.core.NoCredentialsProvider;

`

``

23

`+

import com.google.bigtable.v2.BigtableGrpc;

`

``

24

`+

import com.google.bigtable.v2.ClientConfiguration;

`

``

25

`+

import com.google.bigtable.v2.GetClientConfigurationRequest;

`

``

26

`+

import com.google.bigtable.v2.OpenSessionResponse;

`

``

27

`+

import com.google.bigtable.v2.PeerInfo;

`

``

28

`+

import com.google.bigtable.v2.SessionRequest;

`

``

29

`+

import com.google.bigtable.v2.SessionResponse;

`

``

30

`+

import com.google.cloud.bigtable.data.v2.BigtableDataSettings;

`

``

31

`+

import com.google.cloud.bigtable.data.v2.models.Query;

`

``

32

`+

import com.google.cloud.bigtable.data.v2.models.Row;

`

``

33

`+

import com.google.cloud.bigtable.data.v2.models.TableId;

`

``

34

`+

import io.grpc.Context;

`

``

35

`+

import io.grpc.ForwardingServerCall;

`

``

36

`+

import io.grpc.Metadata;

`

``

37

`+

import io.grpc.Server;

`

``

38

`+

import io.grpc.ServerCall;

`

``

39

`+

import io.grpc.ServerCallHandler;

`

``

40

`+

import io.grpc.ServerInterceptor;

`

``

41

`+

import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;

`

``

42

`+

import io.grpc.stub.StreamObserver;

`

``

43

`+

import java.io.IOException;

`

``

44

`+

import java.util.Base64;

`

``

45

`+

import java.util.concurrent.ExecutionException;

`

``

46

`+

import java.util.concurrent.Executors;

`

``

47

`+

import java.util.concurrent.ScheduledExecutorService;

`

``

48

`+

import java.util.concurrent.TimeUnit;

`

``

49

`+

import org.junit.After;

`

``

50

`+

import org.junit.Before;

`

``

51

`+

import org.junit.Test;

`

``

52

+

``

53

`+

public class SessionDeadlineTest {

`

``

54

+

``

55

`+

private Server server;

`

``

56

`+

private EnhancedBigtableStubSettings defaultSettings;

`

``

57

`+

private FakeDataService fakeDataService;

`

``

58

+

``

59

`+

@Before

`

``

60

`+

public void setUp() throws IOException {

`

``

61

`+

fakeDataService = new FakeDataService();

`

``

62

`+

server =

`

``

63

`+

NettyServerBuilder.forPort(0)

`

``

64

`+

.addService(fakeDataService)

`

``

65

`+

.intercept(new ResponseHeaderInterceptor())

`

``

66

`+

.build()

`

``

67

`+

.start();

`

``

68

+

``

69

`+

defaultSettings =

`

``

70

`+

BigtableDataSettings.newBuilderForEmulator(server.getPort())

`

``

71

`+

.setProjectId("fake-project")

`

``

72

`+

.setInstanceId("fake-instance")

`

``

73

`+

.setAppProfileId("fake-app-profile")

`

``

74

`+

.setCredentialsProvider(NoCredentialsProvider.create())

`

``

75

`+

.build()

`

``

76

`+

.getStubSettings();

`

``

77

`+

}

`

``

78

+

``

79

`+

@After

`

``

80

`+

public void tearDown() throws InterruptedException {

`

``

81

`+

if (fakeDataService != null) {

`

``

82

`+

fakeDataService.shutdown();

`

``

83

`+

}

`

``

84

`+

if (server != null) {

`

``

85

`+

server.shutdownNow();

`

``

86

`+

server.awaitTermination();

`

``

87

`+

}

`

``

88

`+

}

`

``

89

+

``

90

`+

@Test(timeout = 1000)

`

``

91

`+

public void testShortDeadlineCancellation() throws Exception {

`

``

92

`+

EnhancedBigtableStubSettings settings =

`

``

93

`+

defaultSettings.toBuilder().setSessionsEnabled(true).build();

`

``

94

+

``

95

`+

try (EnhancedBigtableStub stub = EnhancedBigtableStub.create(settings)) {

`

``

96

`+

Query request = Query.create(TableId.of("fake-table")).rowKey("row-key");

`

``

97

+

``

98

`+

try (io.grpc.Context.CancellableContext ctx =

`

``

99

`+

io.grpc.Context.current()

`

``

100

`+

.withDeadlineAfter(

`

``

101

`+

5,

`

``

102

`+

TimeUnit.MILLISECONDS,

`

``

103

`+

settings.getBackgroundExecutorProvider().getExecutor())) {

`

``

104

+

``

105

`+

ctx.run(

`

``

106

`+

() -> {

`

``

107

`+

ApiFuture future = stub.readRowCallable().futureCall(request);

`

``

108

`+

try {

`

``

109

`+

future.get();

`

``

110

`+

fail("Should throw exception");

`

``

111

`+

} catch (ExecutionException e) {

`

``

112

`+

assertThat(e).hasMessageThat().contains("DEADLINE_EXCEEDED");

`

``

113

`+

} catch (InterruptedException e) {

`

``

114

`+

fail("Should not throw interrupted exception");

`

``

115

`+

}

`

``

116

`+

});

`

``

117

`+

}

`

``

118

`+

}

`

``

119

`+

}

`

``

120

+

``

121

`+

@Test(timeout = 10000)

`

``

122

`+

public void testMissedHeartbeat() throws Exception {

`

``

123

`+

EnhancedBigtableStubSettings settings =

`

``

124

`+

defaultSettings.toBuilder().setSessionsEnabled(true).build();

`

``

125

+

``

126

`+

try (EnhancedBigtableStub stub = EnhancedBigtableStub.create(settings)) {

`

``

127

`+

Query request = Query.create(TableId.of("fake-table")).rowKey("row-key");

`

``

128

+

``

129

`+

try (Context.CancellableContext ctx =

`

``

130

`+

Context.current()

`

``

131

`+

.withDeadlineAfter(

`

``

132

`+

1, TimeUnit.SECONDS, settings.getBackgroundExecutorProvider().getExecutor())) {

`

``

133

`+

ctx.run(

`

``

134

`+

() -> {

`

``

135

`+

ApiFuture future = stub.readRowCallable().futureCall(request);

`

``

136

`+

try {

`

``

137

`+

future.get();

`

``

138

`+

fail("Should throw exception");

`

``

139

`+

} catch (ExecutionException e) {

`

``

140

`+

assertThat(e).hasMessageThat().contains("missed heartbeat");

`

``

141

`+

} catch (InterruptedException e) {

`

``

142

`+

fail("Should not throw interrupted exception");

`

``

143

`+

}

`

``

144

`+

});

`

``

145

`+

}

`

``

146

`+

}

`

``

147

`+

}

`

``

148

+

``

149

`+

private static class FakeDataService extends BigtableGrpc.BigtableImplBase {

`

``

150

`+

private final ScheduledExecutorService serverExecutor = Executors.newScheduledThreadPool(4);

`

``

151

+

``

152

`+

public void shutdown() {

`

``

153

`+

serverExecutor.shutdownNow();

`

``

154

`+

}

`

``

155

+

``

156

`+

@Override

`

``

157

`+

public void getClientConfiguration(

`

``

158

`+

GetClientConfigurationRequest request,

`

``

159

`+

StreamObserver responseObserver) {

`

``

160

`+

responseObserver.onNext(

`

``

161

`+

ClientConfiguration.newBuilder()

`

``

162

`+

.setSessionConfiguration(

`

``

163

`+

com.google.bigtable.v2.SessionClientConfiguration.newBuilder()

`

``

164

`+

.setSessionLoad(1)

`

``

165

`+

.build())

`

``

166

`+

.build());

`

``

167

`+

responseObserver.onCompleted();

`

``

168

`+

}

`

``

169

+

``

170

`+

@Override

`

``

171

`+

public StreamObserver openTable(

`

``

172

`+

StreamObserver responseObserver) {

`

``

173

`+

return new StreamObserver() {

`

``

174

`+

@Override

`

``

175

`+

public void onNext(SessionRequest sessionRequest) {

`

``

176

`+

if (sessionRequest.hasOpenSession()) {

`

``

177

`+

responseObserver.onNext(

`

``

178

`+

SessionResponse.newBuilder()

`

``

179

`+

.setOpenSession(OpenSessionResponse.getDefaultInstance())

`

``

180

`+

.build());

`

``

181

`+

} else if (sessionRequest.hasVirtualRpc()) {

`

``

182

`+

// Server hangs

`

``

183

`+

}

`

``

184

`+

}

`

``

185

+

``

186

`+

@Override

`

``

187

`+

public void onError(Throwable t) {}

`

``

188

+

``

189

`+

@Override

`

``

190

`+

public void onCompleted() {

`

``

191

`+

responseObserver.onCompleted();

`

``

192

`+

}

`

``

193

`+

};

`

``

194

`+

}

`

``

195

`+

}

`

``

196

+

``

197

`+

private static class ResponseHeaderInterceptor implements ServerInterceptor {

`

``

198

`+

@Override

`

``

199

`+

public <ReqT, RespT> ServerCall.Listener interceptCall(

`

``

200

`+

ServerCall<ReqT, RespT> serverCall,

`

``

201

`+

Metadata metadata,

`

``

202

`+

ServerCallHandler<ReqT, RespT> serverCallHandler) {

`

``

203

`+

return serverCallHandler.startCall(

`

``

204

`+

new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(serverCall) {

`

``

205

`+

@Override

`

``

206

`+

public void sendHeaders(Metadata headers) {

`

``

207

`+

Metadata.Key peerInfoKey =

`

``

208

`+

Metadata.Key.of("bigtable-peer-info", Metadata.ASCII_STRING_MARSHALLER);

`

``

209

`+

String encoded =

`

``

210

`+

Base64.getUrlEncoder()

`

``

211

`+

.encodeToString(

`

``

212

`+

PeerInfo.newBuilder()

`

``

213

`+

.setApplicationFrontendRegion("us-east1")

`

``

214

`+

.build()

`

``

215

`+

.toByteArray());

`

``

216

`+

headers.put(peerInfoKey, encoded);

`

``

217

`+

super.sendHeaders(headers);

`

``

218

`+

}

`

``

219

+

``

220

`+

@Override

`

``

221

`+

public void close(io.grpc.Status status, Metadata trailers) {

`

``

222

`+

super.close(status, trailers);

`

``

223

`+

}

`

``

224

`+

},

`

``

225

`+

metadata);

`

``

226

`+

}

`

``

227

`+

}

`

``

228

`+

}

`