Skip to content

Commit a2f9268

Browse files
Protobuf Java Cross-version validation in OSS.
PiperOrigin-RevId: 585139332
1 parent 62d5d9b commit a2f9268

File tree

4 files changed

+184
-16
lines changed

4 files changed

+184
-16
lines changed

java/core/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ LITE_TEST_EXCLUSIONS = [
487487
"src/test/java/com/google/protobuf/Proto2SchemaTest.java",
488488
"src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java",
489489
"src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java",
490+
"src/test/java/com/google/protobuf/RuntimeVersionTest.java",
490491
"src/test/java/com/google/protobuf/ServiceTest.java",
491492
"src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java",
492493
"src/test/java/com/google/protobuf/TestBadIdentifiers.java",

java/core/src/main/java/com/google/protobuf/RuntimeVersion.java

+58-16
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99

1010
/**
1111
* Provides the version of this Protobuf Java runtime, and methods for Protobuf Java gencode to
12-
* validate that versions are compatible.
12+
* validate that versions are compatible. Fields and methods in this class should be only accessed
13+
* by related unit tests and Protobuf Java gencode, and should not be used elsewhere.
1314
*/
1415
public final class RuntimeVersion {
1516

@@ -19,35 +20,71 @@ public enum RuntimeDomain {
1920
PUBLIC,
2021
}
2122

22-
// The version information for this runtime.
23+
// The version of this runtime.
2324
// Automatically updated by Protobuf release process. Do not edit manually.
24-
private static final RuntimeDomain DOMAIN = RuntimeDomain.PUBLIC;
25-
private static final int MAJOR = 3;
26-
private static final int MINOR = 26;
27-
private static final int PATCH = 0;
28-
private static final String SUFFIX = "-dev";
25+
public static final RuntimeDomain DOMAIN = RuntimeDomain.PUBLIC;
26+
public static final int MAJOR = 3;
27+
public static final int MINOR = 26;
28+
public static final int PATCH = 0;
29+
public static final String SUFFIX = "-dev";
30+
private static final String VERSION_STRING = versionString(MAJOR, MINOR, PATCH, SUFFIX);
2931

3032
/**
31-
* Validates that the gencode version is compatible with this runtime version. Currently, no
32-
* validation takes place, but only checks that version numbers valid.
33+
* Validates that the gencode version is compatible with this runtime version according to
34+
* https://protobuf.dev/support/cross-version-runtime-guarantee/.
3335
*
34-
* <p>This method is only for Protobuf Java gencode; do not call it elsewhere.
36+
* <p>This method is currently only used by Protobuf Java gencode in OSS.
3537
*
36-
* <p>In the future, we will validate Protobuf Java versions according to
37-
* https://protobuf.dev/support/cross-version-runtime-guarantee/
38+
* <p>This method is only for Protobuf Java gencode; do not call it elsewhere.
3839
*
39-
* @param domain the domain where Protobuf Java code was generated. Currently unused.
40+
* @param domain the domain where Protobuf Java code was generated. Currently ignored.
4041
* @param major the major version of Protobuf Java gencode.
4142
* @param minor the minor version of Protobuf Java gencode.
4243
* @param patch the micro/patch version of Protobuf Java gencode.
43-
* @param suffix the version suffix e.g. "-rc2", "-dev", etc. Currently unused.
44+
* @param suffix the version suffix e.g. "-rc2", "-dev", etc.
45+
* @throws ProtobufRuntimeVersionException if versions are incompatible.
4446
*/
4547
public static void validateProtobufGencodeVersion(
4648
RuntimeDomain domain, int major, int minor, int patch, String suffix) {
47-
// TODO: b/298200443 - Add cross-version validations.
49+
50+
// Check the environmental variable, and temporarily disable poison pills if it's set to true.
51+
String disableFlag = java.lang.System.getenv("TEMORARILY_DISABLE_PROTOBUF_VERSION_CHECK");
52+
if (disableFlag != null && disableFlag.equals("true")) {
53+
return;
54+
}
55+
56+
// Check that version numbers are valid.
4857
if (major < 0 || minor < 0 || patch < 0) {
4958
throw new ProtobufRuntimeVersionException(
50-
String.format("Invalid gencode version: %d.%d.%d", major, minor, patch));
59+
"Invalid gencode version: " + versionString(major, minor, patch, suffix));
60+
}
61+
62+
String gencodeVersionString = versionString(major, minor, patch, suffix);
63+
// Check that runtime major version is the same as the gencode major version.
64+
if (major != MAJOR) {
65+
throw new ProtobufRuntimeVersionException(
66+
String.format(
67+
"Mismatched Protobuf Gencode/Runtime major versions: gencode %s, runtime %s. Same"
68+
+ " major version is required.",
69+
gencodeVersionString, VERSION_STRING));
70+
}
71+
72+
// Check that runtime version is newer than the gencode version.
73+
if (MINOR < minor || (MINOR == minor && PATCH < patch)) {
74+
throw new ProtobufRuntimeVersionException(
75+
String.format(
76+
"Protobuf Java runtime version cannot be older than the gencode version:"
77+
+ "gencode %s, runtime %s.",
78+
gencodeVersionString, VERSION_STRING));
79+
}
80+
81+
// Check that runtime version suffix is the same as the gencode version suffix.
82+
if (!suffix.equals(SUFFIX)) {
83+
throw new ProtobufRuntimeVersionException(
84+
String.format(
85+
"Mismatched Protobuf Gencode/Runtime version suffixes: gencode %s, runtime %s."
86+
+ " Version suffixes must be the same.",
87+
gencodeVersionString, VERSION_STRING));
5188
}
5289
}
5390

@@ -60,4 +97,9 @@ public ProtobufRuntimeVersionException(String message) {
6097
super(message);
6198
}
6299
}
100+
101+
/** Gets the version string given the version segments. */
102+
private static String versionString(int major, int minor, int patch, String suffix) {
103+
return String.format("%d.%d.%d%s", major, minor, patch, suffix);
104+
}
63105
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Protocol Buffers - Google's data interchange format
2+
// Copyright 2008 Google Inc. All rights reserved.
3+
//
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file or at
6+
// https://developers.google.com/open-source/licenses/bsd
7+
8+
package com.google.protobuf;
9+
10+
import static com.google.common.truth.Truth.assertThat;
11+
import static org.junit.Assert.assertThrows;
12+
13+
import org.junit.Test;
14+
import org.junit.runner.RunWith;
15+
import org.junit.runners.JUnit4;
16+
17+
@RunWith(JUnit4.class)
18+
public final class RuntimeVersionTest {
19+
20+
@Test
21+
public void versionValidation_invalidVersionNumbers() {
22+
RuntimeVersion.ProtobufRuntimeVersionException thrown =
23+
assertThrows(
24+
RuntimeVersion.ProtobufRuntimeVersionException.class,
25+
() ->
26+
RuntimeVersion.validateProtobufGencodeVersion(
27+
RuntimeVersion.DOMAIN,
28+
-1,
29+
RuntimeVersion.MINOR,
30+
RuntimeVersion.PATCH,
31+
RuntimeVersion.SUFFIX));
32+
assertThat(thrown).hasMessageThat().contains("Invalid gencode version: -1");
33+
}
34+
35+
@Test
36+
public void versionValidation_mismatchingMajorDisallowed() {
37+
int gencodeMajor = 1;
38+
RuntimeVersion.ProtobufRuntimeVersionException thrown =
39+
assertThrows(
40+
RuntimeVersion.ProtobufRuntimeVersionException.class,
41+
() ->
42+
RuntimeVersion.validateProtobufGencodeVersion(
43+
RuntimeVersion.DOMAIN,
44+
gencodeMajor,
45+
RuntimeVersion.MINOR,
46+
RuntimeVersion.PATCH,
47+
RuntimeVersion.SUFFIX));
48+
assertThat(thrown)
49+
.hasMessageThat()
50+
.contains("Mismatched Protobuf Gencode/Runtime major versions");
51+
}
52+
53+
@Test
54+
public void versionValidation_versionNumbersAllTheSameAllowed() {
55+
RuntimeVersion.validateProtobufGencodeVersion(
56+
RuntimeVersion.DOMAIN,
57+
RuntimeVersion.MAJOR,
58+
RuntimeVersion.MINOR,
59+
RuntimeVersion.PATCH,
60+
RuntimeVersion.SUFFIX);
61+
}
62+
63+
@Test
64+
public void versionValidation_NewerRuntimeVersionAllowed() {
65+
int gencodeMinor = RuntimeVersion.MINOR - 1;
66+
RuntimeVersion.validateProtobufGencodeVersion(
67+
RuntimeVersion.DOMAIN,
68+
RuntimeVersion.MAJOR,
69+
gencodeMinor,
70+
RuntimeVersion.PATCH,
71+
RuntimeVersion.SUFFIX);
72+
}
73+
74+
@Test
75+
public void versionValidation_OlderRuntimeVersionDisallowed() {
76+
int gencodeMinor = RuntimeVersion.MINOR + 1;
77+
RuntimeVersion.ProtobufRuntimeVersionException thrown =
78+
assertThrows(
79+
RuntimeVersion.ProtobufRuntimeVersionException.class,
80+
() ->
81+
RuntimeVersion.validateProtobufGencodeVersion(
82+
RuntimeVersion.DOMAIN,
83+
RuntimeVersion.MAJOR,
84+
gencodeMinor,
85+
RuntimeVersion.PATCH,
86+
RuntimeVersion.SUFFIX));
87+
assertThat(thrown)
88+
.hasMessageThat()
89+
.contains("Protobuf Java runtime version cannot be older than the gencode version");
90+
91+
int gencodePatch = RuntimeVersion.PATCH + 1;
92+
thrown =
93+
assertThrows(
94+
RuntimeVersion.ProtobufRuntimeVersionException.class,
95+
() ->
96+
RuntimeVersion.validateProtobufGencodeVersion(
97+
RuntimeVersion.DOMAIN,
98+
RuntimeVersion.MAJOR,
99+
RuntimeVersion.MINOR,
100+
gencodePatch,
101+
RuntimeVersion.SUFFIX));
102+
assertThat(thrown)
103+
.hasMessageThat()
104+
.contains("Protobuf Java runtime version cannot be older than the gencode version");
105+
}
106+
107+
@Test
108+
public void versionValidation_differentVesionSuffixDisallowed() {
109+
String gencodeSuffix = "-test";
110+
RuntimeVersion.ProtobufRuntimeVersionException thrown =
111+
assertThrows(
112+
RuntimeVersion.ProtobufRuntimeVersionException.class,
113+
() ->
114+
RuntimeVersion.validateProtobufGencodeVersion(
115+
RuntimeVersion.DOMAIN,
116+
RuntimeVersion.MAJOR,
117+
RuntimeVersion.MINOR,
118+
RuntimeVersion.PATCH,
119+
gencodeSuffix));
120+
assertThat(thrown)
121+
.hasMessageThat()
122+
.contains("Mismatched Protobuf Gencode/Runtime version suffixes");
123+
}
124+
}

java/lite/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@
225225
<exclude>Proto2SchemaTest.java</exclude>
226226
<exclude>Proto2UnknownEnumValueTest.java</exclude>
227227
<exclude>RepeatedFieldBuilderV3Test.java</exclude>
228+
<exclude>RuntimeVersionTest.java</exclude>
228229
<exclude>ServiceTest.java</exclude>
229230
<exclude>SingleFieldBuilderV3Test.java</exclude>
230231
<exclude>TestBadIdentifiers.java</exclude>

0 commit comments

Comments
 (0)