[英]How to provide credentials for Spanner integration tests with Spring Boot, R2DBC and TestContainers (Spanner Emulator)
Here is the error from the execution of the integration tests:这是执行集成测试的错误:
com.google.cloud.spanner.SpannerException:
UNAUTHENTICATED: com.google.api.gax.rpc.UnauthenticatedException: io.grpc.StatusRuntimeException:
UNAUTHENTICATED: Request is missing required authentication credential.
Expected OAuth 2 access token, login cookie or other valid authentication credential.
See https://developers.google.com/identity/sign-in/web/devconsole-project.
code (simplified for easier and faster reproducing):代码(为了更容易和更快的复制而简化):
@ExtendWith(SpringExtension.class)
@SpringBootTest
@ActiveProfiles("it")
@DirtiesContext
public class SpannerIT {
static final String PROJECT_ID = "emulator-config";
static final String INSTANCE_ID = "test-instance";
static final String DATABASE_NAME = "test-database";
static SpannerEmulatorContainer spannerContainer;
@Autowired
private R2dbcEntityTemplate template;
@DynamicPropertySource
static void properties(DynamicPropertyRegistry r) {
r.add("spring.cloud.gcp.spanner.emulator-host", spannerContainer::getEmulatorGrpcEndpoint);
r.add("spring.r2dbc.url", () -> "r2dbc:cloudspanner://" + spannerContainer.getEmulatorHttpEndpoint() +
"/projects/" + PROJECT_ID + "/instances/" + INSTANCE_ID + "/databases/" + DATABASE_NAME);
}
@BeforeAll
public static void beforeAll() {
spannerContainer = new SpannerEmulatorContainer(
DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator").withTag("1.4.1"));
spannerContainer.start();
}
@AfterAll
public static void afterAll() {
spannerContainer.stop();
}
@Test
void test() {
StepVerifier.create(
template.select(Query.query(CriteriaDefinition.empty()), SomeClazz.class)
)
.verifyComplete();
}
@Data
@Table("test")
public class SomeClazz {
@Column("column")
private String column;
}
}
and the configs (application-it.yml):和配置(application-it.yml):
spring:
cloud:
gcp:
spanner:
project-id: emulator-config
r2dbc:
url: overwritten_in_tests
properties:
usePlainText: true
autoConfigEmulator: true
By setting the usePlainText
to the r2dbc URL in theory we should bypass the credentials issue.通过将
usePlainText
设置为 r2dbc URL 理论上我们应该绕过凭据问题。 The credentials provider is correctly configured to NoCredentials
( SpannerConnectionFactoryProvider#extractCredentials
).凭据提供程序已正确配置为
NoCredentials
( SpannerConnectionFactoryProvider#extractCredentials
)。
Github repo with the complete code: Github repo 完整代码:
https://github.com/magiccrafter/spanner-spring-boot-r2jdbc-app https://github.com/magiccrafter/spanner-spring-boot-r2jdbc-app
Here you can find a test container example of gcloud spanner:在这里您可以找到 gcloud spanner 的测试容器示例:
https://github.com/saturnism/testcontainers-gcloud-examples/blob/main/springboot/spanner-example/src/test/java/com/example/springboot/spanner/SpannerIntegrationTests.java https://github.com/saturnism/testcontainers-gcloud-examples/blob/main/springboot/spanner-example/src/test/java/com/example/springboot/spanner/SpannerIntegrationTests.java
and here:和这里:
https://www.testcontainers.org/modules/gcloud/#spanner https://www.testcontainers.org/modules/gcloud/#spanner
The error you are getting is actually hinting that your credentials options are working, but that something is trying to connect to Cloud Spanner (or some other Cloud product) without credentials.您收到的错误实际上是在暗示您的凭据选项正在运行,但有些东西正在尝试在没有凭据的情况下连接到 Cloud Spanner(或其他一些云产品)。 The emulator would normally not return an
Unauthenticated
error, as it does not expect any credentials.模拟器通常不会返回
Unauthenticated
错误,因为它不需要任何凭据。 Could you check:你能检查一下:
NoCredentials
.NoCredentials
访问其他一些云产品。Thanks to elefeint 's hint:感谢elefeint的提示:
You would also have to set up an environment variable export SPANNER_EMULATOR_HOST=localhost:9010, so that the Spanner client library picks up the non-production host, similar to jdbc driver.
您还必须设置环境变量 export SPANNER_EMULATOR_HOST=localhost:9010,以便 Spanner 客户端库选择非生产主机,类似于 jdbc 驱动程序。
Upvote #200 for allowing programmatic customization of emulator.
Upvote #200 允许以编程方式自定义模拟器。
for more details check the Github issue #200有关详细信息,请查看Github 问题 #200
Here is the workaround I came up with to bypass the requirement for SPANNER_EMULATOR_HOST env variable prior to the integration tests run:这是我想出的解决方法,可以在集成测试运行之前绕过对 SPANNER_EMULATOR_HOST 环境变量的要求:
@Testcontainers
@ExtendWith(SystemStubsExtension.class)
@ExtendWith(SpringExtension.class)
@SpringBootTest
@ActiveProfiles("it")
@DirtiesContext
public class SpannerIT {
static final String PROJECT_ID = "nv-local";
static final String INSTANCE_ID = "test-instance";
static final String DATABASE_NAME = "trades";
@Container
private static final SpannerEmulatorContainer spannerContainer =
new SpannerEmulatorContainer(
DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator").withTag("1.4.1"));
@SystemStub
private static EnvironmentVariables environmentVariables;
@Autowired
ConnectionFactory connectionFactory;
@DynamicPropertySource
static void properties(DynamicPropertyRegistry r) {
environmentVariables.set("SPANNER_EMULATOR_HOST", spannerContainer.getEmulatorGrpcEndpoint());
r.add("spring.r2dbc.url", () -> "r2dbc:cloudspanner://" +
"/projects/" + PROJECT_ID + "/instances/" + INSTANCE_ID + "/databases/" + DATABASE_NAME);
}
This way, we can have the Spanner emulator in Testcontainers without starting the spanner emulator separately and mapping a concrete port.这样,我们就可以在 Testcontainers 中拥有 Spanner 模拟器,而无需单独启动 Spanner 模拟器并映射具体端口。 The complete source code can be found here .
完整的源代码可以在这里找到。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.