Skip to content

Commit 1f33b33

Browse files
Merge branch 'grpc:master' into master
2 parents f472436 + 64322c3 commit 1f33b33

File tree

47 files changed

+321
-108
lines changed

Some content is hidden

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

47 files changed

+321
-108
lines changed

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module(
22
name = "grpc-java",
33
compatibility_level = 0,
44
repo_name = "io_grpc_grpc_java",
5-
version = "1.74.0-SNAPSHOT", # CURRENT_GRPC_VERSION
5+
version = "1.75.0-SNAPSHOT", # CURRENT_GRPC_VERSION
66
)
77

88
# GRPC_DEPS_START

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ For [Bazel](https://bazel.build), you can either
102102
https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.73.0
103103

104104
Development snapshots are available in [Sonatypes's snapshot
105-
repository](https://oss.sonatype.org/content/repositories/snapshots/).
105+
repository](https://central.sonatype.com/repository/maven-snapshots/).
106106

107107
Generated Code
108108
--------------

RELEASING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ Tagging the Release
160160
repository can then be `released`, which will begin the process of pushing
161161
the new artifacts to Maven Central (the staging repository will be destroyed
162162
in the process). You can see the complete process for releasing to Maven
163-
Central on the [OSSRH site](https://central.sonatype.org/pages/releasing-the-deployment.html).
163+
Central on the [OSSRH site](https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#deploying).
164164

165165
10. We have containers for each release to detect compatibility regressions with
166166
old releases. Generate one for the new release by following the [GCR image

binder/src/androidTest/java/io/grpc/binder/internal/BinderClientTransportTest.java

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@
1717
package io.grpc.binder.internal;
1818

1919
import static com.google.common.truth.Truth.assertThat;
20+
import static java.util.concurrent.TimeUnit.SECONDS;
2021

2122
import android.content.Context;
2223
import android.os.DeadObjectException;
2324
import android.os.Parcel;
2425
import android.os.RemoteException;
2526
import androidx.test.core.app.ApplicationProvider;
2627
import androidx.test.ext.junit.runners.AndroidJUnit4;
27-
import com.google.common.util.concurrent.Futures;
28-
import com.google.common.util.concurrent.ListenableFuture;
2928
import com.google.common.util.concurrent.SettableFuture;
3029
import com.google.errorprone.annotations.CanIgnoreReturnValue;
3130
import com.google.errorprone.annotations.concurrent.GuardedBy;
@@ -39,13 +38,13 @@
3938
import io.grpc.Status;
4039
import io.grpc.Status.Code;
4140
import io.grpc.binder.AndroidComponentAddress;
42-
import io.grpc.binder.AsyncSecurityPolicy;
4341
import io.grpc.binder.BinderServerBuilder;
4442
import io.grpc.binder.HostServices;
4543
import io.grpc.binder.SecurityPolicy;
4644
import io.grpc.binder.internal.OneWayBinderProxies.BlackHoleOneWayBinderProxy;
4745
import io.grpc.binder.internal.OneWayBinderProxies.BlockingBinderDecorator;
4846
import io.grpc.binder.internal.OneWayBinderProxies.ThrowingOneWayBinderProxy;
47+
import io.grpc.binder.internal.SettableAsyncSecurityPolicy.AuthRequest;
4948
import io.grpc.internal.ClientStream;
5049
import io.grpc.internal.ClientStreamListener;
5150
import io.grpc.internal.ClientTransportFactory.ClientTransportOptions;
@@ -64,7 +63,6 @@
6463
import java.util.concurrent.Executors;
6564
import java.util.concurrent.LinkedBlockingQueue;
6665
import java.util.concurrent.ScheduledExecutorService;
67-
import java.util.concurrent.TimeUnit;
6866
import javax.annotation.Nullable;
6967
import org.junit.After;
7068
import org.junit.Before;
@@ -193,7 +191,7 @@ public void tearDown() throws Exception {
193191
private static void shutdownAndTerminate(ExecutorService executorService)
194192
throws InterruptedException {
195193
executorService.shutdownNow();
196-
if (!executorService.awaitTermination(TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
194+
if (!executorService.awaitTermination(TIMEOUT_SECONDS, SECONDS)) {
197195
throw new AssertionError("executor failed to terminate promptly");
198196
}
199197
}
@@ -375,26 +373,32 @@ public void testBlackHoleEndpointConnectTimeout() throws Exception {
375373

376374
@Test
377375
public void testBlackHoleSecurityPolicyConnectTimeout() throws Exception {
376+
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy();
378377
transport =
379378
new BinderClientTransportBuilder()
380-
.setSecurityPolicy(blockingSecurityPolicy)
379+
.setSecurityPolicy(securityPolicy)
381380
.setReadyTimeoutMillis(1_234)
382381
.build();
383382
transport.start(transportListener).run();
383+
// Take the next authRequest but don't respond to it, in order to trigger the ready timeout.
384+
AuthRequest authRequest = securityPolicy.takeNextAuthRequest(TIMEOUT_SECONDS, SECONDS);
385+
384386
Status transportStatus = transportListener.awaitShutdown();
385387
assertThat(transportStatus.getCode()).isEqualTo(Code.DEADLINE_EXCEEDED);
386388
assertThat(transportStatus.getDescription()).contains("1234");
387389
transportListener.awaitTermination();
388-
blockingSecurityPolicy.provideNextCheckAuthorizationResult(Status.OK);
390+
391+
// If the transport gave up waiting on auth, it should cancel its request.
392+
assertThat(authRequest.isCancelled()).isTrue();
389393
}
390394

391395
@Test
392396
public void testAsyncSecurityPolicyFailure() throws Exception {
393397
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy();
394398
transport = new BinderClientTransportBuilder().setSecurityPolicy(securityPolicy).build();
395399
RuntimeException exception = new NullPointerException();
396-
securityPolicy.setAuthorizationException(exception);
397400
transport.start(transportListener).run();
401+
securityPolicy.takeNextAuthRequest(TIMEOUT_SECONDS, SECONDS).setResult(exception);
398402
Status transportStatus = transportListener.awaitShutdown();
399403
assertThat(transportStatus.getCode()).isEqualTo(Code.INTERNAL);
400404
assertThat(transportStatus.getCause()).isEqualTo(exception);
@@ -405,13 +409,27 @@ public void testAsyncSecurityPolicyFailure() throws Exception {
405409
public void testAsyncSecurityPolicySuccess() throws Exception {
406410
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy();
407411
transport = new BinderClientTransportBuilder().setSecurityPolicy(securityPolicy).build();
408-
securityPolicy.setAuthorizationResult(Status.PERMISSION_DENIED);
409412
transport.start(transportListener).run();
413+
securityPolicy
414+
.takeNextAuthRequest(TIMEOUT_SECONDS, SECONDS)
415+
.setResult(Status.PERMISSION_DENIED);
410416
Status transportStatus = transportListener.awaitShutdown();
411417
assertThat(transportStatus.getCode()).isEqualTo(Code.PERMISSION_DENIED);
412418
transportListener.awaitTermination();
413419
}
414420

421+
@Test
422+
public void testAsyncSecurityPolicyCancelledUponExternalTermination() throws Exception {
423+
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy();
424+
transport = new BinderClientTransportBuilder().setSecurityPolicy(securityPolicy).build();
425+
transport.start(transportListener).run();
426+
AuthRequest authRequest = securityPolicy.takeNextAuthRequest(TIMEOUT_SECONDS, SECONDS);
427+
transport.shutdownNow(Status.UNAVAILABLE); // 'authRequest' remains unanswered!
428+
transportListener.awaitShutdown();
429+
transportListener.awaitTermination();
430+
assertThat(authRequest.isCancelled()).isTrue();
431+
}
432+
415433
private static void startAndAwaitReady(
416434
BinderTransport.BinderClientTransport transport, TestTransportListener transportListener)
417435
throws Exception {
@@ -433,7 +451,7 @@ public void transportShutdown(Status shutdownStatus) {
433451
}
434452

435453
public Status awaitShutdown() throws Exception {
436-
return shutdownStatus.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
454+
return shutdownStatus.get(TIMEOUT_SECONDS, SECONDS);
437455
}
438456

439457
@Override
@@ -444,7 +462,7 @@ public void transportTerminated() {
444462
}
445463

446464
public void awaitTermination() throws Exception {
447-
isTerminated.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
465+
isTerminated.get(TIMEOUT_SECONDS, SECONDS);
448466
}
449467

450468
@Override
@@ -455,7 +473,7 @@ public void transportReady() {
455473
}
456474

457475
public void awaitReady() throws Exception {
458-
isReady.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
476+
isReady.get(TIMEOUT_SECONDS, SECONDS);
459477
}
460478

461479
@Override
@@ -571,25 +589,4 @@ public Status checkAuthorization(int uid) {
571589
}
572590
}
573591
}
574-
575-
/** An AsyncSecurityPolicy that lets a test specify the outcome of checkAuthorizationAsync(). */
576-
static class SettableAsyncSecurityPolicy extends AsyncSecurityPolicy {
577-
private SettableFuture<Status> result = SettableFuture.create();
578-
579-
public void clearAuthorizationResult() {
580-
result = SettableFuture.create();
581-
}
582-
583-
public boolean setAuthorizationResult(Status status) {
584-
return result.set(status);
585-
}
586-
587-
public boolean setAuthorizationException(Throwable t) {
588-
return result.setException(t);
589-
}
590-
591-
public ListenableFuture<Status> checkAuthorizationAsync(int uid) {
592-
return Futures.nonCancellationPropagating(result);
593-
}
594-
}
595592
}

binder/src/main/java/io/grpc/binder/internal/BinderTransport.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ public static final class BinderClientTransport extends BinderTransport
582582

583583
@GuardedBy("this")
584584
private ScheduledFuture<?> readyTimeoutFuture; // != null iff timeout scheduled.
585+
@GuardedBy("this")
586+
@Nullable private ListenableFuture<Status> authResultFuture; // null before we check auth.
585587

586588
/**
587589
* Constructs a new transport instance.
@@ -756,6 +758,9 @@ void notifyTerminated() {
756758
readyTimeoutFuture.cancel(false);
757759
readyTimeoutFuture = null;
758760
}
761+
if (authResultFuture != null) {
762+
authResultFuture.cancel(false); // No effect if already complete.
763+
}
759764
serviceBinding.unbind();
760765
clientTransportListener.transportTerminated();
761766
}
@@ -775,13 +780,13 @@ protected void handleSetupTransport(Parcel parcel) {
775780
shutdownInternal(
776781
Status.UNAVAILABLE.withDescription("Malformed SETUP_TRANSPORT data"), true);
777782
} else {
778-
ListenableFuture<Status> authFuture =
783+
authResultFuture =
779784
(securityPolicy instanceof AsyncSecurityPolicy)
780785
? ((AsyncSecurityPolicy) securityPolicy).checkAuthorizationAsync(remoteUid)
781786
: Futures.submit(
782787
() -> securityPolicy.checkAuthorization(remoteUid), offloadExecutor);
783788
Futures.addCallback(
784-
authFuture,
789+
authResultFuture,
785790
new FutureCallback<Status>() {
786791
@Override
787792
public void onSuccess(Status result) {
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2025 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.binder.internal;
18+
19+
import static com.google.common.base.Preconditions.checkState;
20+
21+
import com.google.common.util.concurrent.ListenableFuture;
22+
import com.google.common.util.concurrent.SettableFuture;
23+
import io.grpc.Status;
24+
import io.grpc.binder.AsyncSecurityPolicy;
25+
import java.util.concurrent.LinkedBlockingDeque;
26+
import java.util.concurrent.TimeUnit;
27+
import java.util.concurrent.TimeoutException;
28+
29+
/**
30+
* An {@link AsyncSecurityPolicy} that lets unit tests verify the exact order of authorization
31+
* requests and respond to them one at a time.
32+
*/
33+
public class SettableAsyncSecurityPolicy extends AsyncSecurityPolicy {
34+
private final LinkedBlockingDeque<AuthRequest> pendingRequests = new LinkedBlockingDeque<>();
35+
36+
@Override
37+
public ListenableFuture<Status> checkAuthorizationAsync(int uid) {
38+
AuthRequest request = new AuthRequest(uid);
39+
pendingRequests.add(request);
40+
return request.resultFuture;
41+
}
42+
43+
/**
44+
* Waits for the next "check authorization" request to be made and returns it, throwing in case no
45+
* request arrives in time.
46+
*/
47+
public AuthRequest takeNextAuthRequest(long timeout, TimeUnit unit)
48+
throws InterruptedException, TimeoutException {
49+
AuthRequest nextAuthRequest = pendingRequests.poll(timeout, unit);
50+
if (nextAuthRequest == null) {
51+
throw new TimeoutException();
52+
}
53+
return nextAuthRequest;
54+
}
55+
56+
/** Represents a single call to {@link AsyncSecurityPolicy#checkAuthorizationAsync(int)}. */
57+
public static class AuthRequest {
58+
59+
/** The argument passed to {@link AsyncSecurityPolicy#checkAuthorizationAsync(int)}. */
60+
public final int uid;
61+
62+
private final SettableFuture<Status> resultFuture = SettableFuture.create();
63+
64+
private AuthRequest(int uid) {
65+
this.uid = uid;
66+
}
67+
68+
/** Provides this SecurityPolicy's response to this authorization request. */
69+
public void setResult(Status result) {
70+
checkState(resultFuture.set(result));
71+
}
72+
73+
/** Simulates an exceptional response to this authorization request. */
74+
public void setResult(Throwable t) {
75+
checkState(resultFuture.setException(t));
76+
}
77+
78+
/** Tests if the future returned for this authorization request was cancelled by the caller. */
79+
public boolean isCancelled() {
80+
return resultFuture.isCancelled();
81+
}
82+
}
83+
}

build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ subprojects {
2121
apply plugin: "net.ltgt.errorprone"
2222

2323
group = "io.grpc"
24-
version = "1.74.0-SNAPSHOT" // CURRENT_GRPC_VERSION
24+
version = "1.75.0-SNAPSHOT" // CURRENT_GRPC_VERSION
2525

2626
repositories {
2727
maven { // The google mirror is less flaky than mavenCentral()
@@ -389,11 +389,11 @@ subprojects {
389389
url = new File(rootProject.repositoryDir).toURI()
390390
} else {
391391
String stagingUrl
392+
String baseUrl = "https://ossrh-staging-api.central.sonatype.com/service/local"
392393
if (rootProject.hasProperty('repositoryId')) {
393-
stagingUrl = 'https://oss.sonatype.org/service/local/staging/deployByRepositoryId/' +
394-
rootProject.repositoryId
394+
stagingUrl = "${baseUrl}/staging/deployByRepositoryId/" + rootProject.repositoryId
395395
} else {
396-
stagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
396+
stagingUrl = "${baseUrl}/staging/deploy/maven2/"
397397
}
398398
credentials {
399399
if (rootProject.hasProperty('ossrhUsername') && rootProject.hasProperty('ossrhPassword')) {
@@ -402,7 +402,7 @@ subprojects {
402402
}
403403
}
404404
def releaseUrl = stagingUrl
405-
def snapshotUrl = 'https://oss.sonatype.org/content/repositories/snapshots/'
405+
def snapshotUrl = 'https://central.sonatype.com/repository/maven-snapshots/'
406406
url = version.endsWith('SNAPSHOT') ? snapshotUrl : releaseUrl
407407
}
408408
}

buildscripts/grpc-java-artifacts/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ RUN curl -Ls https://github.com/Kitware/CMake/releases/download/v3.26.3/cmake-3.
3131
tar xz -C /var/local
3232

3333
# Install Maven
34-
RUN curl -Ls https://dlcdn.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz | \
34+
RUN curl -Ls https://archive.apache.org/dist/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz | \
3535
tar xz -C /var/local
3636
ENV PATH /var/local/cmake-3.26.3-linux-x86_64/bin:/var/local/apache-maven-3.8.8/bin:$PATH
3737

buildscripts/sonatype-upload.sh

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ if [ -z "$USERNAME" -o -z "$PASSWORD" ]; then
5959
exit 1
6060
fi
6161

62-
STAGING_URL="https://oss.sonatype.org/service/local/staging"
62+
STAGING_URL="https://ossrh-staging-api.central.sonatype.com/service/local/staging"
6363

6464
# We go through the effort of using deloyByRepositoryId/ because it is
6565
# _substantially_ faster to upload files than deploy/maven2/. When using
@@ -108,3 +108,18 @@ XML="
108108
</promoteRequest>"
109109
curl --fail-with-body -X POST -d "$XML" -u "$USERPASS" -H "Content-Type: application/xml" \
110110
"$STAGING_URL/profiles/$PROFILE_ID/finish"
111+
112+
# TODO (okshiva): After 2-3 releases make it automatic.
113+
# After closing the repository on the staging API, we must manually trigger
114+
# its upload to the main Central Publisher Portal. We set publishing_type=automatic
115+
# to have it release automatically upon passing validation.
116+
# echo "Triggering release of repository ${REPOID} to the Central Portal"
117+
118+
# MANUAL_API_URL="https://ossrh-staging-api.central.sonatype.com/service/local/manual"
119+
120+
#curl --fail-with-body -X POST \
121+
# -H "Authorization: Bearer ${USERPASS}" \
122+
# -H "Content-Type: application/json" \
123+
# "${MANUAL_API_URL}/upload/repository/${REPOID}?publishing_type=automatic"
124+
125+
# echo "Release triggered. Monitor progress at https://central.sonatype.com/publishing/deployments"

compiler/src/test/golden/TestDeprecatedService.java.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName;
88
* </pre>
99
*/
1010
@javax.annotation.Generated(
11-
value = "by gRPC proto compiler (version 1.74.0-SNAPSHOT)",
11+
value = "by gRPC proto compiler (version 1.75.0-SNAPSHOT)",
1212
comments = "Source: grpc/testing/compiler/test.proto")
1313
@io.grpc.stub.annotations.GrpcGenerated
1414
@java.lang.Deprecated

0 commit comments

Comments
 (0)