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-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)); + } +} diff --git a/spring-cloud-gcp-samples/pom.xml b/spring-cloud-gcp-samples/pom.xml index e993507d60..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 @@ -160,6 +161,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} 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 new file mode 100644 index 0000000000..4af36460d5 --- /dev/null +++ b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java @@ -0,0 +1,53 @@ +/* + * 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.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.native", matches = "true") +@ExtendWith(SpringExtension.class) +@TestPropertySource("classpath:application-test.properties") +@SpringBootTest(properties = "run.commandline.runner=off") +public class FirestoreSampleAppNativeIntegrationTests { + + 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(); + assertNotNull(encodedKeyFromAutoConfig); + } +}