From f4be8dcdbdb46984e356c50bfd861070ae22a8ff Mon Sep 17 00:00:00 2001 From: Min Zhu Date: Mon, 26 Aug 2024 15:10:08 -0400 Subject: [PATCH 1/4] fix: add runtime hint for Credentials on GcpProperties. --- .../core/CredentialsRuntimeHints.java | 39 +++++++++++++++++++ .../autoconfigure/core/GcpProperties.java | 2 + .../core/CredentialsRuntimeHintsTest.java | 34 ++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHints.java create mode 100644 spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHintsTest.java diff --git a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHints.java b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHints.java new file mode 100644 index 0000000000..2cb48a4c81 --- /dev/null +++ b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHints.java @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spring.autoconfigure.core; + +import com.google.cloud.spring.core.Credentials; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeReference; + +public class CredentialsRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints + .reflection() + .registerType( + TypeReference.of(Credentials.class), + hint -> + hint.withMembers( + MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, + MemberCategory.INVOKE_DECLARED_METHODS, + MemberCategory.DECLARED_FIELDS)); + } +} diff --git a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/GcpProperties.java b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/GcpProperties.java index 7138958224..c29a98db59 100644 --- a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/GcpProperties.java +++ b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/GcpProperties.java @@ -20,9 +20,11 @@ import com.google.cloud.spring.core.CredentialsSupplier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.context.annotation.ImportRuntimeHints; /** Top-level auto-config settings. */ @ConfigurationProperties("spring.cloud.gcp") +@ImportRuntimeHints(CredentialsRuntimeHints.class) public class GcpProperties implements CredentialsSupplier { /** GCP project ID where services are running. */ diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHintsTest.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHintsTest.java new file mode 100644 index 0000000000..9c8ec26f42 --- /dev/null +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHintsTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spring.autoconfigure.core; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection; + +import com.google.cloud.spring.core.Credentials; +import org.junit.jupiter.api.Test; +import org.springframework.aot.hint.RuntimeHints; + +class CredentialsRuntimeHintsTest { + @Test + void registerCredentials() { + RuntimeHints runtimeHints = new RuntimeHints(); + CredentialsRuntimeHints registrar = new CredentialsRuntimeHints(); + registrar.registerHints(runtimeHints, null); + assertThat(runtimeHints).matches(reflection().onType(Credentials.class)); + } +} From 93ec52709c146cf35fa4a437e6fb2ad55dff17a0 Mon Sep 17 00:00:00 2001 From: Min Zhu Date: Mon, 9 Sep 2024 21:07:15 -0400 Subject: [PATCH 2/4] pass in ci sa key to test with sample. --- .github/workflows/NativeTests.yaml | 4 ++++ spring-cloud-gcp-samples/pom.xml | 1 + 2 files changed, 5 insertions(+) diff --git a/.github/workflows/NativeTests.yaml b/.github/workflows/NativeTests.yaml index 49fdc8202c..9b7351c3b4 100644 --- a/.github/workflows/NativeTests.yaml +++ b/.github/workflows/NativeTests.yaml @@ -86,6 +86,10 @@ jobs: components: 'native-image' github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: 'true' + - name: Setup env for test + run: echo "SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY_BASE64=$(echo -n $SA_KEY | base64 -w 0)" >> "$GITHUB_ENV" + env: + SA_KEY: ${{ secrets.SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY }} - name: Native Tests in Modules id: intTest env: diff --git a/spring-cloud-gcp-samples/pom.xml b/spring-cloud-gcp-samples/pom.xml index 492a7b54e8..d21daf5ec1 100644 --- a/spring-cloud-gcp-samples/pom.xml +++ b/spring-cloud-gcp-samples/pom.xml @@ -160,6 +160,7 @@ ${env.DB_PASSWORD} projects/spring-cloud-gcp-ci-native/locations/us-central1/clusters/testcluster/instances/testpostgres code_samples_test_db + ${env.SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY_BASE64} From 2ab6ea6ab3415222681f847783d1f33a688568f1 Mon Sep 17 00:00:00 2001 From: Min Zhu Date: Wed, 11 Sep 2024 10:20:09 -0400 Subject: [PATCH 3/4] add test to verify property is accessible in graalvm mode. --- ...estoreSampleAppNativeIntegrationTests.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java diff --git a/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java new file mode 100644 index 0000000000..83e19851f5 --- /dev/null +++ b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.google.cloud.spring.autoconfigure.firestore.GcpFirestoreProperties; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@EnabledIfSystemProperty(named = "it.firestore", matches = "true") +@ExtendWith(SpringExtension.class) +@TestPropertySource("classpath:application-test.properties") +@SpringBootTest +public class FirestoreSampleAppNativeIntegrationTests { + + @Value("${spring.cloud.gcp.firestore.credentials.encoded-key:default}") + private String encodedKeyFromValue; + + private final Logger logger = + LoggerFactory.getLogger(FirestoreSampleAppNativeIntegrationTests.class); + @Autowired private ApplicationContext applicationContext; + + @Test + void credentialsPropertiesAreAccessibleTest() { + String encodedKeyFromAutoConfig = + applicationContext.getBean(GcpFirestoreProperties.class).getCredentials().getEncodedKey(); + + if (encodedKeyFromValue.equals("default")) { + // nothing to assert if not set. + logger.info("firestore.credentials.encoded-key is not set."); + } else { + // set this property only for graalvm test, verify it is correctly loaded in autoconfig + logger.info("encodedKey is read in. This should be the graalvm test."); + assertNotNull(encodedKeyFromAutoConfig); + } + } +} From 279f843af72e43b5468a182020ae3ad10ff50d69 Mon Sep 17 00:00:00 2001 From: Min Zhu Date: Wed, 11 Sep 2024 11:35:36 -0400 Subject: [PATCH 4/4] do not run application for native test. remove unecessary property value. --- spring-cloud-gcp-samples/pom.xml | 1 + .../java/com/example/FirestoreSampleApp.java | 2 ++ ...estoreSampleAppNativeIntegrationTests.java | 22 ++++++------------- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/spring-cloud-gcp-samples/pom.xml b/spring-cloud-gcp-samples/pom.xml index 66601828e9..fdb1a5a746 100644 --- a/spring-cloud-gcp-samples/pom.xml +++ b/spring-cloud-gcp-samples/pom.xml @@ -143,6 +143,7 @@ true true true + true true true true diff --git a/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/main/java/com/example/FirestoreSampleApp.java b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/main/java/com/example/FirestoreSampleApp.java index c9c11f9676..5e8309d6b5 100644 --- a/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/main/java/com/example/FirestoreSampleApp.java +++ b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/main/java/com/example/FirestoreSampleApp.java @@ -31,6 +31,7 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ImportRuntimeHints; @@ -53,6 +54,7 @@ public static void main(String[] args) { } @Bean + @ConditionalOnProperty(name = "run.commandline.runner", havingValue = "true", matchIfMissing = true) public CommandLineRunner commandLineRunner() { return args -> { writeDocumentFromMap(); diff --git a/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java index 83e19851f5..4af36460d5 100644 --- a/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java +++ b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java @@ -25,37 +25,29 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; -@EnabledIfSystemProperty(named = "it.firestore", matches = "true") +@EnabledIfSystemProperty(named = "it.firestore.native", matches = "true") @ExtendWith(SpringExtension.class) @TestPropertySource("classpath:application-test.properties") -@SpringBootTest +@SpringBootTest(properties = "run.commandline.runner=off") public class FirestoreSampleAppNativeIntegrationTests { - @Value("${spring.cloud.gcp.firestore.credentials.encoded-key:default}") - private String encodedKeyFromValue; - private final Logger logger = LoggerFactory.getLogger(FirestoreSampleAppNativeIntegrationTests.class); @Autowired private ApplicationContext applicationContext; @Test void credentialsPropertiesAreAccessibleTest() { + logger.info( + "This test is only needed for graalvm compilation test" + + " to verify the encoded-key property is accessible." + + " Turn on by it.firestore.native=true"); String encodedKeyFromAutoConfig = applicationContext.getBean(GcpFirestoreProperties.class).getCredentials().getEncodedKey(); - - if (encodedKeyFromValue.equals("default")) { - // nothing to assert if not set. - logger.info("firestore.credentials.encoded-key is not set."); - } else { - // set this property only for graalvm test, verify it is correctly loaded in autoconfig - logger.info("encodedKey is read in. This should be the graalvm test."); - assertNotNull(encodedKeyFromAutoConfig); - } + assertNotNull(encodedKeyFromAutoConfig); } }