Skip to content

Commit 80c3c99

Browse files
committed
core: Move io.grpc to grpc-api
io.grpc has fewer dependencies than io.grpc.internal. Moving it to a separate artifact lets users use the API without bringing in the deps. If the library has an optional dependency on grpc, that can be quite convenient. We now version-pin both grpc-api and grpc-core, since both contain internal APIs. I had to change a few tests in grpc-api to avoid FakeClock. Moving FakeClock to grpc-api was difficult because it uses io.grpc.internal.TimeProvider, which can't be moved since it is a production class. Having grpc-api's tests depend on grpc-core's test classes would be weird and cause a circular dependincy. Having grpc-api's tests depend on grpc-core is likely possible, but weird and fairly unnecessary at this point. So instead I rewrote the tests to avoid FakeClock. Fixes #1447
1 parent f3731ea commit 80c3c99

File tree

157 files changed

+220
-95
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

157 files changed

+220
-95
lines changed

BUILD.bazel

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ java_library(
2929
name = "java_grpc_library_deps__do_not_reference",
3030
visibility = ["//visibility:public"],
3131
exports = [
32-
"//core",
32+
"//api",
3333
"//protobuf",
3434
"//stub",
3535
"//stub:javax_annotation",
@@ -43,7 +43,7 @@ java_library(
4343
name = "java_lite_grpc_library_deps__do_not_reference",
4444
visibility = ["//visibility:public"],
4545
exports = [
46-
"//core",
46+
"//api",
4747
"//protobuf-lite",
4848
"//stub",
4949
"//stub:javax_annotation",

all/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ buildscript {
1111
}
1212

1313
def subprojects = [
14+
project(':grpc-api'),
1415
project(':grpc-auth'),
1516
project(':grpc-core'),
1617
project(':grpc-context'),

alts/BUILD.bazel

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ java_library(
88
deps = [
99
":handshaker_java_grpc",
1010
":handshaker_java_proto",
11-
"//core",
11+
"//api",
1212
"//core:internal",
1313
"//netty",
1414
"//stub",
@@ -35,8 +35,8 @@ java_library(
3535
deps = [
3636
":alts_internal",
3737
":handshaker_java_grpc",
38+
"//api",
3839
"//auth",
39-
"//core",
4040
"//core:internal",
4141
"//netty",
4242
"@com_google_auth_google_auth_library_oauth2_http//jar",

api/BUILD.bazel

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
java_library(
2+
name = "api",
3+
srcs = glob([
4+
"src/main/java/**/*.java",
5+
]),
6+
visibility = ["//visibility:public"],
7+
deps = [
8+
"//context",
9+
"@com_google_code_findbugs_jsr305//jar",
10+
"@com_google_guava_failureaccess//jar", # future transitive dep of Guava. See #5214
11+
"@com_google_guava_guava//jar",
12+
"@com_google_j2objc_j2objc_annotations//jar",
13+
],
14+
)

api/build.gradle

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
description = 'gRPC: API'
2+
3+
dependencies {
4+
compile project(':grpc-context'),
5+
libraries.errorprone,
6+
libraries.jsr305,
7+
libraries.animalsniffer_annotations
8+
compile (libraries.guava) {
9+
// prefer 2.3.2 from libraries instead of 2.1.3
10+
exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
11+
// prefer 3.0.2 from libraries instead of 3.0.1
12+
exclude group: 'com.google.code.findbugs', module: 'jsr305'
13+
// prefer 1.17 from libraries instead of 1.14
14+
exclude group: 'org.codehaus.mojo', module: 'animal-sniffer-annotations'
15+
}
16+
17+
testCompile project(':grpc-context').sourceSets.test.output,
18+
project(':grpc-testing'),
19+
project(':grpc-grpclb'),
20+
libraries.guava_testlib
21+
22+
jmh project(':grpc-core')
23+
24+
signature "org.codehaus.mojo.signature:java17:1.0@signature"
25+
signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature"
26+
}
27+
28+
javadoc {
29+
// We want io.grpc.Internal, but not io.grpc.Internal*
30+
exclude 'io/grpc/Internal?*.java'
31+
exclude 'io/grpc/internal/**'
32+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

core/src/test/java/io/grpc/ContextsTest.java api/src/test/java/io/grpc/ContextsTest.java

+25-5
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@
2828
import static org.junit.Assert.assertTrue;
2929
import static org.junit.Assert.fail;
3030

31-
import io.grpc.internal.FakeClock;
31+
import com.google.common.util.concurrent.testing.TestingExecutors;
3232
import io.grpc.internal.NoopServerCall;
3333
import java.util.ArrayList;
3434
import java.util.Arrays;
3535
import java.util.List;
36+
import java.util.concurrent.ScheduledExecutorService;
37+
import java.util.concurrent.ScheduledFuture;
3638
import java.util.concurrent.TimeUnit;
3739
import java.util.concurrent.TimeoutException;
3840
import org.junit.Test;
@@ -213,11 +215,29 @@ public void statusFromCancelled_shouldReturnStatusWithCauseAttached() {
213215

214216
@Test
215217
public void statusFromCancelled_TimeoutExceptionShouldMapToDeadlineExceeded() {
216-
FakeClock fakeClock = new FakeClock();
218+
final long expectedDelay = 100;
219+
final TimeUnit expectedUnit = TimeUnit.SECONDS;
220+
class MockScheduledExecutorService extends ForwardingScheduledExecutorService {
221+
private ScheduledExecutorService delegate = TestingExecutors.noOpScheduledExecutor();
222+
Runnable command;
223+
224+
@Override public ScheduledExecutorService delegate() {
225+
return delegate;
226+
}
227+
228+
@Override public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
229+
if (delay > unit.convert(expectedDelay, expectedUnit)) {
230+
fail("Delay larger than expected: " + delay + " " + unit);
231+
}
232+
this.command = command;
233+
return super.schedule(command, delay, unit);
234+
}
235+
}
236+
237+
MockScheduledExecutorService executorService = new MockScheduledExecutorService();
217238
Context.CancellableContext cancellableContext = Context.current()
218-
.withDeadlineAfter(100, TimeUnit.NANOSECONDS, fakeClock.getScheduledExecutorService());
219-
fakeClock.forwardTime(System.nanoTime(), TimeUnit.NANOSECONDS);
220-
fakeClock.forwardNanos(100);
239+
.withDeadlineAfter(expectedDelay, expectedUnit, executorService);
240+
executorService.command.run();
221241

222242
assertTrue(cancellableContext.isCancelled());
223243
assertThat(cancellableContext.cancellationCause(), instanceOf(TimeoutException.class));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2019 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc;
18+
19+
import com.google.common.util.concurrent.ForwardingExecutorService;
20+
import java.util.concurrent.Callable;
21+
import java.util.concurrent.ScheduledExecutorService;
22+
import java.util.concurrent.ScheduledFuture;
23+
import java.util.concurrent.TimeUnit;
24+
25+
/**
26+
* Forwards all methods to delegate.
27+
*/
28+
abstract class ForwardingScheduledExecutorService extends ForwardingExecutorService
29+
implements ScheduledExecutorService {
30+
@Override
31+
protected abstract ScheduledExecutorService delegate();
32+
33+
@Override
34+
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
35+
return delegate().schedule(callable, delay, unit);
36+
}
37+
38+
@Override
39+
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
40+
return delegate().schedule(command, delay, unit);
41+
}
42+
43+
@Override
44+
public ScheduledFuture<?> scheduleAtFixedRate(
45+
Runnable command, long initialDelay, long period, TimeUnit unit) {
46+
return delegate().scheduleAtFixedRate(command, initialDelay, period, unit);
47+
}
48+
49+
@Override
50+
public ScheduledFuture<?> scheduleWithFixedDelay(
51+
Runnable command, long initialDelay, long delay, TimeUnit unit) {
52+
return delegate().scheduleWithFixedDelay(command, initialDelay, delay, unit);
53+
}
54+
}

core/src/test/java/io/grpc/SynchronizationContextTest.java api/src/test/java/io/grpc/SynchronizationContextTest.java

+43-22
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
import static org.mockito.Mockito.never;
2626
import static org.mockito.Mockito.verify;
2727

28+
import com.google.common.util.concurrent.testing.TestingExecutors;
2829
import io.grpc.SynchronizationContext.ScheduledHandle;
29-
import io.grpc.internal.FakeClock;
3030
import java.util.concurrent.BlockingQueue;
3131
import java.util.concurrent.CountDownLatch;
3232
import java.util.concurrent.LinkedBlockingQueue;
33+
import java.util.concurrent.ScheduledExecutorService;
34+
import java.util.concurrent.ScheduledFuture;
3335
import java.util.concurrent.TimeUnit;
3436
import java.util.concurrent.atomic.AtomicBoolean;
3537
import java.util.concurrent.atomic.AtomicReference;
@@ -231,54 +233,54 @@ public Void answer(InvocationOnMock invocation) {
231233

232234
@Test
233235
public void schedule() {
234-
FakeClock clock = new FakeClock();
236+
MockScheduledExecutorService executorService = new MockScheduledExecutorService();
235237
ScheduledHandle handle =
236-
syncContext.schedule(task1, 110, TimeUnit.NANOSECONDS, clock.getScheduledExecutorService());
237-
assertThat(handle.isPending()).isTrue();
238-
assertThat(clock.runDueTasks()).isEqualTo(0);
239-
assertThat(clock.forwardNanos(109)).isEqualTo(0);
238+
syncContext.schedule(task1, 110, TimeUnit.NANOSECONDS, executorService);
239+
assertThat(executorService.delay)
240+
.isEqualTo(executorService.unit.convert(110, TimeUnit.NANOSECONDS));
240241
assertThat(handle.isPending()).isTrue();
241242
verify(task1, never()).run();
242243

243-
assertThat(clock.forwardNanos(1)).isEqualTo(1);
244+
executorService.command.run();
244245
assertThat(handle.isPending()).isFalse();
245246
verify(task1).run();
246247
}
247248

248249
@Test
249250
public void scheduleDueImmediately() {
250-
FakeClock clock = new FakeClock();
251-
ScheduledHandle handle =
252-
syncContext.schedule(task1, -1, TimeUnit.NANOSECONDS, clock.getScheduledExecutorService());
251+
MockScheduledExecutorService executorService = new MockScheduledExecutorService();
252+
ScheduledHandle handle = syncContext.schedule(task1, -1, TimeUnit.NANOSECONDS, executorService);
253+
assertThat(executorService.delay)
254+
.isEqualTo(executorService.unit.convert(-1, TimeUnit.NANOSECONDS));
253255
verify(task1, never()).run();
254256
assertThat(handle.isPending()).isTrue();
255257

256-
assertThat(clock.runDueTasks()).isEqualTo(1);
258+
executorService.command.run();
257259
assertThat(handle.isPending()).isFalse();
258260
verify(task1).run();
259261
}
260262

261263
@Test
262264
public void scheduleHandle_cancel() {
263-
FakeClock clock = new FakeClock();
265+
MockScheduledExecutorService executorService = new MockScheduledExecutorService();
264266
ScheduledHandle handle =
265-
syncContext.schedule(task1, 110, TimeUnit.NANOSECONDS, clock.getScheduledExecutorService());
266-
assertThat(handle.isPending()).isTrue();
267-
assertThat(clock.runDueTasks()).isEqualTo(0);
267+
syncContext.schedule(task1, 110, TimeUnit.NANOSECONDS, executorService);
268268
assertThat(handle.isPending()).isTrue();
269+
assertThat(executorService.delay)
270+
.isEqualTo(executorService.unit.convert(110, TimeUnit.NANOSECONDS));
269271

270272
handle.cancel();
271273
assertThat(handle.isPending()).isFalse();
272274
syncContext.drain();
273-
assertThat(clock.numPendingTasks()).isEqualTo(0);
275+
assertThat(executorService.future.isCancelled()).isTrue();
274276
verify(task1, never()).run();
275277
}
276278

277279
// Test that a scheduled task is cancelled after the timer has expired on the
278280
// ScheduledExecutorService, but before the task is run.
279281
@Test
280282
public void scheduledHandle_cancelRacesWithTimerExpiration() throws Exception {
281-
FakeClock clock = new FakeClock();
283+
MockScheduledExecutorService executorService = new MockScheduledExecutorService();
282284

283285
final CountDownLatch task1Running = new CountDownLatch(1);
284286
final LinkedBlockingQueue<ScheduledHandle> task2HandleQueue = new LinkedBlockingQueue<>();
@@ -309,17 +311,17 @@ public void run() {
309311
}
310312
};
311313

312-
ScheduledHandle handle =
313-
syncContext.schedule(task2, 10, TimeUnit.NANOSECONDS, clock.getScheduledExecutorService());
314+
ScheduledHandle handle = syncContext.schedule(task2, 10, TimeUnit.NANOSECONDS, executorService);
314315
// This will execute and block in task1
315316
sideThread.start();
316317

317318
// Make sure task1 is running and blocking the execution
318319
assertThat(task1Running.await(5, TimeUnit.SECONDS)).isTrue();
319320

320321
// Timer expires. task2 will be enqueued, but blocked by task1
321-
assertThat(clock.forwardNanos(10)).isEqualTo(1);
322-
assertThat(clock.numPendingTasks()).isEqualTo(0);
322+
assertThat(executorService.delay)
323+
.isEqualTo(executorService.unit.convert(10, TimeUnit.NANOSECONDS));
324+
executorService.command.run();
323325
assertThat(handle.isPending()).isTrue();
324326

325327
// Enqueue task3 following task2
@@ -335,6 +337,25 @@ public void run() {
335337
assertThat(handle.isPending()).isFalse();
336338
verify(task2, never()).run();
337339
verify(task3).run();
338-
assertThat(clock.numPendingTasks()).isEqualTo(0);
340+
}
341+
342+
static class MockScheduledExecutorService extends ForwardingScheduledExecutorService {
343+
private ScheduledExecutorService delegate = TestingExecutors.noOpScheduledExecutor();
344+
345+
Runnable command;
346+
long delay;
347+
TimeUnit unit;
348+
ScheduledFuture<?> future;
349+
350+
@Override public ScheduledExecutorService delegate() {
351+
return delegate;
352+
}
353+
354+
@Override public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
355+
this.command = command;
356+
this.delay = delay;
357+
this.unit = unit;
358+
return future = super.schedule(command, delay, unit);
359+
}
339360
}
340361
}

auth/BUILD.bazel

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ java_library(
55
]),
66
visibility = ["//visibility:public"],
77
deps = [
8-
"//core",
8+
"//api",
99
"@com_google_auth_google_auth_library_credentials//jar",
1010
"@com_google_code_findbugs_jsr305//jar",
1111
"@com_google_guava_guava//jar",

auth/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
description = "gRPC: Auth"
22
dependencies {
3-
compile project(':grpc-core'),
3+
compile project(':grpc-api'),
44
libraries.google_auth_credentials
55
testCompile project(':grpc-testing'),
66
libraries.google_auth_oauth2_http

build.gradle

+2-1
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ subprojects {
390390
"grpc-protobuf-nano"
391391
])) {
392392
asNode().dependencies.'*'.findAll() { dep ->
393-
dep.artifactId.text() == 'grpc-core'
393+
dep.artifactId.text() in ['grpc-api', 'grpc-core']
394394
}.each() { core ->
395395
core.version*.value = "[" + core.version.text() + "]"
396396
}
@@ -452,6 +452,7 @@ def baselineGrpcVersion = '1.6.1'
452452
def publicApiSubprojects = [
453453
// TODO: uncomment after grpc-alts, grpc-bom artifact is published.
454454
// ':grpc-alts',
455+
//':grpc-api',
455456
':grpc-auth',
456457
//':grpc-bom',
457458
':grpc-context',

0 commit comments

Comments
 (0)