Skip to content

Commit a087860

Browse files
ludochgae-java-bot
authored andcommitted
Add E2E and unit tests for TaskQueue namespace data path in App Engine Java runtimes.
PiperOrigin-RevId: 970251315 Change-Id: I9c398d71d2b48e43a7ee939a2bbfad76f90e27f0
1 parent 068aadc commit a087860

3 files changed

Lines changed: 103 additions & 62 deletions

File tree

‎applications/proberapp/src/main/java/app/ProberApp.java‎

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import static java.util.concurrent.TimeUnit.SECONDS;
2525
import static org.junit.Assert.assertThrows;
2626

27+
import com.google.appengine.api.NamespaceManager;
2728
import com.google.appengine.api.appidentity.AppIdentityService;
2829
import com.google.appengine.api.appidentity.AppIdentityServiceFactory;
2930
import com.google.appengine.api.appidentity.PublicCertificate;
@@ -593,28 +594,28 @@ private static void testThreadPool(HttpServletRequest request) throws Exception
593594
private static final int DNS_PORT = 53;
594595

595596
/**
596-
* Constructs a DNS query packet for the domain consisting of the given labels. See
597-
* <a href="https://tools.ietf.org/html/rfc1035#section-4.1.1">RFC1035, section 4.1.1</a>.
597+
* Constructs a DNS query packet for the domain consisting of the given labels. See <a
598+
* href="https://tools.ietf.org/html/rfc1035#section-4.1.1">RFC1035, section 4.1.1</a>.
598599
*
599600
* @param packetId the 16-bit packet id
600601
* @param labels the "labels" making up the domain, for example {@code google}, {@code com}.
601602
*/
602603
private static byte[] dnsQueryPacket(short packetId, String... labels) throws IOException {
603604
try (ByteArrayOutputStream bout = new ByteArrayOutputStream();
604605
DataOutputStream dout = new DataOutputStream(bout)) {
605-
dout.writeShort(packetId); // [0-1] packet id
606-
dout.writeShort(0x100); // [2-3] flags, here just recursion desired (RD)
607-
dout.writeShort(1); // [4-5] number of queries (QDCOUNT)
608-
dout.writeShort(0); // [6-7] unused count field for DNS response packets
609-
dout.writeShort(0); // [8-9] unused count field for DNS response packets
610-
dout.writeShort(0); // [10-11] unused count field for DNS response packets
606+
dout.writeShort(packetId); // [0-1] packet id
607+
dout.writeShort(0x100); // [2-3] flags, here just recursion desired (RD)
608+
dout.writeShort(1); // [4-5] number of queries (QDCOUNT)
609+
dout.writeShort(0); // [6-7] unused count field for DNS response packets
610+
dout.writeShort(0); // [8-9] unused count field for DNS response packets
611+
dout.writeShort(0); // [10-11] unused count field for DNS response packets
611612
for (String label : labels) {
612-
dout.write(label.length()); // label length
613-
dout.writeBytes(label); // label bytes
613+
dout.write(label.length()); // label length
614+
dout.writeBytes(label); // label bytes
614615
}
615-
dout.write(0); // empty label to indicate end of query
616-
dout.writeShort(1); // QTYPE, set to 1 = A (host address)
617-
dout.writeShort(1); // QCLASS, set to 1 = IN (internet)
616+
dout.write(0); // empty label to indicate end of query
617+
dout.writeShort(1); // QTYPE, set to 1 = A (host address)
618+
dout.writeShort(1); // QCLASS, set to 1 = IN (internet)
618619
dout.flush();
619620
return bout.toByteArray();
620621
}
@@ -648,8 +649,7 @@ private static void testUDPUsingDNS(HttpServletRequest request) throws IOExcepti
648649
* <p>This test is a port of the following Python e2e test:
649650
* apphosting/api/remote_socket/e2e/ssl_aeta_test.py
650651
*
651-
* <p>The file roots.jks it depends on was generated by
652-
* google3/security/cacerts:roots_jks.
652+
* <p>The file roots.jks it depends on was generated by google3/security/cacerts:roots_jks.
653653
*/
654654
private static void testSslRequest(HttpServletRequest request) throws Exception {
655655
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
@@ -1018,8 +1018,7 @@ private static void testCompositeImages(HttpServletRequest request) throws Excep
10181018
int width = image.getWidth();
10191019
int height = image.getHeight();
10201020
List<Composite> composites = new ArrayList<>();
1021-
composites.add(
1022-
ImagesServiceFactory.makeComposite(image, 0, 0, 1f, Composite.Anchor.TOP_LEFT));
1021+
composites.add(ImagesServiceFactory.makeComposite(image, 0, 0, 1f, Composite.Anchor.TOP_LEFT));
10231022
composites.add(
10241023
ImagesServiceFactory.makeComposite(image, width, 0, 1f, Composite.Anchor.TOP_LEFT));
10251024
Image compositeImage = imagesService.composite(composites, width * 2, height, 0);
@@ -1093,6 +1092,25 @@ private static void testPushQueue(HttpServletRequest request) throws Exception {
10931092
}
10941093
}
10951094
}
1095+
1096+
// Verify task creation with namespace set (regression test for b/498824773 / omg/95354)
1097+
String previousNamespace = NamespaceManager.get();
1098+
try {
1099+
NamespaceManager.set("prober-test-namespace");
1100+
for (int i = 0; i < maxTries; i++) {
1101+
try {
1102+
queue.add();
1103+
break;
1104+
} catch (TransientFailureException e) {
1105+
if (i == maxTries - 1) {
1106+
throw new AssertionError(
1107+
"exhausted retry limit to add a push task with namespace to push-queue", e);
1108+
}
1109+
}
1110+
}
1111+
} finally {
1112+
NamespaceManager.set(previousNamespace);
1113+
}
10961114
}
10971115

10981116
private static void testPullQueue(HttpServletRequest request) throws Exception {

‎applications/proberapp_jakarta/src/main/java/app/ProberApp.java‎

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import static java.util.concurrent.TimeUnit.SECONDS;
2525
import static org.junit.Assert.assertThrows;
2626

27+
import com.google.appengine.api.NamespaceManager;
2728
import com.google.appengine.api.appidentity.AppIdentityService;
2829
import com.google.appengine.api.appidentity.AppIdentityServiceFactory;
2930
import com.google.appengine.api.appidentity.PublicCertificate;
@@ -593,28 +594,28 @@ private static void testThreadPool(HttpServletRequest request) throws Exception
593594
private static final int DNS_PORT = 53;
594595

595596
/**
596-
* Constructs a DNS query packet for the domain consisting of the given labels. See
597-
* <a href="https://tools.ietf.org/html/rfc1035#section-4.1.1">RFC1035, section 4.1.1</a>.
597+
* Constructs a DNS query packet for the domain consisting of the given labels. See <a
598+
* href="https://tools.ietf.org/html/rfc1035#section-4.1.1">RFC1035, section 4.1.1</a>.
598599
*
599600
* @param packetId the 16-bit packet id
600601
* @param labels the "labels" making up the domain, for example {@code google}, {@code com}.
601602
*/
602603
private static byte[] dnsQueryPacket(short packetId, String... labels) throws IOException {
603604
try (ByteArrayOutputStream bout = new ByteArrayOutputStream();
604605
DataOutputStream dout = new DataOutputStream(bout)) {
605-
dout.writeShort(packetId); // [0-1] packet id
606-
dout.writeShort(0x100); // [2-3] flags, here just recursion desired (RD)
607-
dout.writeShort(1); // [4-5] number of queries (QDCOUNT)
608-
dout.writeShort(0); // [6-7] unused count field for DNS response packets
609-
dout.writeShort(0); // [8-9] unused count field for DNS response packets
610-
dout.writeShort(0); // [10-11] unused count field for DNS response packets
606+
dout.writeShort(packetId); // [0-1] packet id
607+
dout.writeShort(0x100); // [2-3] flags, here just recursion desired (RD)
608+
dout.writeShort(1); // [4-5] number of queries (QDCOUNT)
609+
dout.writeShort(0); // [6-7] unused count field for DNS response packets
610+
dout.writeShort(0); // [8-9] unused count field for DNS response packets
611+
dout.writeShort(0); // [10-11] unused count field for DNS response packets
611612
for (String label : labels) {
612-
dout.write(label.length()); // label length
613-
dout.writeBytes(label); // label bytes
613+
dout.write(label.length()); // label length
614+
dout.writeBytes(label); // label bytes
614615
}
615-
dout.write(0); // empty label to indicate end of query
616-
dout.writeShort(1); // QTYPE, set to 1 = A (host address)
617-
dout.writeShort(1); // QCLASS, set to 1 = IN (internet)
616+
dout.write(0); // empty label to indicate end of query
617+
dout.writeShort(1); // QTYPE, set to 1 = A (host address)
618+
dout.writeShort(1); // QCLASS, set to 1 = IN (internet)
618619
dout.flush();
619620
return bout.toByteArray();
620621
}
@@ -648,8 +649,7 @@ private static void testUDPUsingDNS(HttpServletRequest request) throws IOExcepti
648649
* <p>This test is a port of the following Python e2e test:
649650
* apphosting/api/remote_socket/e2e/ssl_aeta_test.py
650651
*
651-
* <p>The file roots.jks it depends on was generated by
652-
* google3/security/cacerts:roots_jks.
652+
* <p>The file roots.jks it depends on was generated by google3/security/cacerts:roots_jks.
653653
*/
654654
private static void testSslRequest(HttpServletRequest request) throws Exception {
655655
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
@@ -1018,8 +1018,7 @@ private static void testCompositeImages(HttpServletRequest request) throws Excep
10181018
int width = image.getWidth();
10191019
int height = image.getHeight();
10201020
List<Composite> composites = new ArrayList<>();
1021-
composites.add(
1022-
ImagesServiceFactory.makeComposite(image, 0, 0, 1f, Composite.Anchor.TOP_LEFT));
1021+
composites.add(ImagesServiceFactory.makeComposite(image, 0, 0, 1f, Composite.Anchor.TOP_LEFT));
10231022
composites.add(
10241023
ImagesServiceFactory.makeComposite(image, width, 0, 1f, Composite.Anchor.TOP_LEFT));
10251024
Image compositeImage = imagesService.composite(composites, width * 2, height, 0);
@@ -1093,6 +1092,25 @@ private static void testPushQueue(HttpServletRequest request) throws Exception {
10931092
}
10941093
}
10951094
}
1095+
1096+
// Verify task creation with namespace set (regression test for b/498824773 / omg/95354)
1097+
String previousNamespace = NamespaceManager.get();
1098+
try {
1099+
NamespaceManager.set("prober-test-namespace");
1100+
for (int i = 0; i < maxTries; i++) {
1101+
try {
1102+
queue.add();
1103+
break;
1104+
} catch (TransientFailureException e) {
1105+
if (i == maxTries - 1) {
1106+
throw new AssertionError(
1107+
"exhausted retry limit to add a push task with namespace to push-queue", e);
1108+
}
1109+
}
1110+
}
1111+
} finally {
1112+
NamespaceManager.set(previousNamespace);
1113+
}
10961114
}
10971115

10981116
private static void testPullQueue(HttpServletRequest request) throws Exception {

‎runtime/impl/src/test/java/com/google/apphosting/runtime/ApiProxyImplTest.java‎

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
import com.google.apphosting.api.ApiStats;
3535
import com.google.apphosting.api.CloudTrace;
3636
import com.google.apphosting.api.CloudTraceContext;
37+
import com.google.apphosting.api.proto2api.ApiBasePb.DoubleProto;
38+
import com.google.apphosting.api.proto2api.ApiBasePb.Integer32Proto;
39+
import com.google.apphosting.api.proto2api.ApiBasePb.StringProto;
40+
import com.google.apphosting.api.proto2api.ApiBasePb.VoidProto;
3741
import com.google.apphosting.base.AppVersionKey;
3842
import com.google.apphosting.base.protos.AppinfoPb.AppInfo;
3943
import com.google.apphosting.base.protos.Codes.Code;
@@ -50,10 +54,6 @@
5054
import com.google.apphosting.base.protos.TraceEvents.TraceEventsProto;
5155
import com.google.apphosting.base.protos.TraceId;
5256
import com.google.apphosting.base.protos.TracePb.TraceContextProto;
53-
import com.google.apphosting.api.proto2api.ApiBasePb.DoubleProto;
54-
import com.google.apphosting.api.proto2api.ApiBasePb.Integer32Proto;
55-
import com.google.apphosting.api.proto2api.ApiBasePb.StringProto;
56-
import com.google.apphosting.api.proto2api.ApiBasePb.VoidProto;
5757
import com.google.apphosting.runtime.anyrpc.APIHostClientInterface;
5858
import com.google.apphosting.runtime.anyrpc.AnyRpcCallback;
5959
import com.google.apphosting.runtime.anyrpc.AnyRpcClientContext;
@@ -90,10 +90,7 @@
9090
import org.junit.runner.RunWith;
9191
import org.junit.runners.JUnit4;
9292

93-
/**
94-
* Unit tests for the ApiProxyImpl implementation.
95-
*
96-
*/
93+
/** Unit tests for the ApiProxyImpl implementation. */
9794
@RunWith(JUnit4.class)
9895
public class ApiProxyImplTest {
9996

@@ -137,8 +134,7 @@ public class ApiProxyImplTest {
137134
public void setUp() throws IOException {
138135
rootDirectory = temporaryFolder.newFolder("appengine" + System.nanoTime());
139136
maxConcurrentApiCalls = 10;
140-
oracle =
141-
new ApiDeadlineOracle.Builder().initDeadlineMap().build();
137+
oracle = new ApiDeadlineOracle.Builder().initDeadlineMap().build();
142138
sleepSemaphore = new Semaphore(0);
143139
APIHostClientInterface apiHost = createAPIHost();
144140
delegate =
@@ -201,12 +197,7 @@ public void update() {}
201197
}
202198
};
203199

204-
AppInfo appInfo =
205-
AppInfo.newBuilder()
206-
.setAppId(APP_ID)
207-
.setVersionId(VERSION_ID)
208-
.build();
209-
200+
AppInfo appInfo = AppInfo.newBuilder().setAppId(APP_ID).setVersionId(VERSION_ID).build();
210201

211202
ApplicationEnvironment appEnv =
212203
new ApplicationEnvironment(
@@ -398,8 +389,7 @@ public void testDatacenterAttribute() {
398389

399390
@Test
400391
public void testDefaultVersionHostname() {
401-
upRequest =
402-
upRequest.toBuilder().setDefaultVersionHostname("foo.bar.com").buildPartial();
392+
upRequest = upRequest.toBuilder().setDefaultVersionHostname("foo.bar.com").buildPartial();
403393
environment = createEnvironment();
404394
assertThat(environment.getAttributes().get(ApiProxyImpl.DEFAULT_VERSION_HOSTNAME))
405395
.isEqualTo("foo.bar.com");
@@ -1058,6 +1048,29 @@ public void testCurrentNamespace() {
10581048
assertThat(namespace).isEqualTo("request-ns");
10591049
}
10601050

1051+
@Test
1052+
public void testCurrentNamespace_caseInsensitiveHeaders() {
1053+
// Test lowercase headers (e.g. sent by Envoy proxy or HTTP/2)
1054+
HttpRequest httpRequest =
1055+
upRequest.getRequest().toBuilder()
1056+
.addHeaders(
1057+
ParsedHttpHeader.newBuilder()
1058+
.setKey("x-appengine-default-namespace")
1059+
.setValue("request-ns-lower"))
1060+
.addHeaders(
1061+
ParsedHttpHeader.newBuilder()
1062+
.setKey("x-appengine-current-namespace")
1063+
.setValue("current-ns-lower"))
1064+
.buildPartial();
1065+
upRequest = upRequest.toBuilder().setRequest(httpRequest).buildPartial();
1066+
ApiProxy.Environment localEnvironment = createEnvironment();
1067+
Map<String, Object> attributes = localEnvironment.getAttributes();
1068+
String namespace = (String) attributes.get(CURRENT_NAMESPACE_KEY);
1069+
assertThat(namespace).isEqualTo("current-ns-lower");
1070+
namespace = (String) attributes.get(APPS_NAMESPACE_KEY);
1071+
assertThat(namespace).isEqualTo("request-ns-lower");
1072+
}
1073+
10611074
@Test
10621075
public void testAsync_traceDisabled() throws ExecutionException, InterruptedException {
10631076
StringProto request = StringProto.getDefaultInstance();
@@ -1438,11 +1451,7 @@ public void testAsync_capabilityDisabledError() {
14381451

14391452
@Test
14401453
public void testDefaultLogsSetting() throws IOException {
1441-
AppInfo appInfo =
1442-
AppInfo.newBuilder()
1443-
.setAppId(APP_ID)
1444-
.setVersionId(VERSION_ID)
1445-
.build();
1454+
AppInfo appInfo = AppInfo.newBuilder().setAppId(APP_ID).setVersionId(VERSION_ID).build();
14461455

14471456
appVersion = createAppVersion(appInfo, rootDirectory);
14481457

@@ -1465,11 +1474,7 @@ public void testCurrentRequestThreadFactory() throws InterruptedException, IOExc
14651474
ImmutableMap.of(),
14661475
rootDirectory,
14671476
ApplicationEnvironment.RuntimeConfiguration.DEFAULT_FOR_TEST);
1468-
AppInfo appInfo =
1469-
AppInfo.newBuilder()
1470-
.setAppId(APP_ID)
1471-
.setVersionId(VERSION_ID)
1472-
.build();
1477+
AppInfo appInfo = AppInfo.newBuilder().setAppId(APP_ID).setVersionId(VERSION_ID).build();
14731478
appVersion =
14741479
AppVersion.builder()
14751480
.setAppVersionKey(AppVersionKey.of(APP_ID, VERSION_ID))

0 commit comments

Comments
 (0)