如何解决 GOOGLE_APPLICATION_CREDENTIALS 当 运行 app in test, Spring Boot?
How to resolve GOOGLE_APPLICATION_CREDENTIALS when running app in test, Spring Boot?
我有一个 Spring 依赖于 Google PubSub 的启动应用程序。我想 运行 使用 Google Cloud PubSub 模拟器。我如何解决 GOOGLE_APPLICATION_CREDENTIALS
,以便应用程序启动并使用来自本地模拟器而不是外部项目的消息?
目前,如果我将 GOOGLE_APPLICATION_CREDENTIALS 设置为 dev.json,如果我不设置变量,则不会调用 PubSub,测试会崩溃。我怎样才能克服它?我不会拼图。
注意:我正在编写一个完整的 Spring 引导启动的集成测试。
我的 PubSub 实现:
import com.github.dockerjava.api.exception.DockerClientException
import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.api.gax.rpc.TransportChannelProvider
import com.google.cloud.pubsub.v1.*
import com.google.cloud.pubsub.v1.stub.GrpcSubscriberStub
import com.google.cloud.pubsub.v1.stub.SubscriberStubSettings
import com.google.protobuf.ByteString
import com.google.pubsub.v1.*
import com.greenbird.server.contracts.TestServer
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName
import java.util.concurrent.TimeUnit
class PubSubTestServer(private val projectName: ProjectName, private val ports: Array<Int> = arrayOf(8085)) :
TestServer {
constructor(projectId: String): this(ProjectName.of(projectId))
private val projectId = projectName.project
var emulator: PubSubEmulatorContainer = PubSubEmulatorContainer(
DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:latest")
)
private var channels: MutableList<ManagedChannel> = mutableListOf()
private fun channel(): ManagedChannel {
return if (channels.isEmpty()) {
val endpoint = emulator.emulatorEndpoint
val channel = ManagedChannelBuilder
.forTarget(endpoint)
.usePlaintext()
.build()
channels.add(channel)
channel
} else {
channels.first()
}
}
private val channelProvider: TransportChannelProvider
get() {
return FixedTransportChannelProvider
.create(
GrpcTransportChannel.create(channel())
)
}
private val credentialsProvider: NoCredentialsProvider = NoCredentialsProvider.create()
private val topicAdminSettings: TopicAdminSettings
get() {
when {
emulator.isRunning -> {
return buildTopicAdminSettings()
}
else -> {
throw DockerClientException("Topic admin settings attempted to initialize before starting PubSub emulator")
}
}
}
private fun buildTopicAdminSettings(): TopicAdminSettings {
return TopicAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
}
private val subscriptionAdminSettings: SubscriptionAdminSettings
get() {
when {
emulator.isRunning -> {
return buildSubscriptionAdminSettings()
}
else -> {
throw DockerClientException("Subscription admin settings attempted to initialize before starting PubSub emulator")
}
}
}
private fun buildSubscriptionAdminSettings(): SubscriptionAdminSettings {
return SubscriptionAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
}
override fun start() {
emulator.withExposedPorts(*ports).start()
}
override fun stop() {
terminate()
emulator.stop()
}
private fun terminate() {
for (channel in channels) {
channel.shutdownNow()
channel.awaitTermination(5, TimeUnit.SECONDS)
}
}
fun createTopic(topicId: String) {
TopicAdminClient.create(topicAdminSettings).use { topicAdminClient ->
val topicName = TopicName.of(projectId, topicId)
topicAdminClient.createTopic(topicName)
}
}
fun listTopics(): List<String> {
return TopicAdminClient.create(topicAdminSettings)
.listTopics(projectName)
.iterateAll()
.map { it.name }
.toList()
}
fun createSubscription(subscriptionId: String, topicId: String) {
val subscriptionName = ProjectSubscriptionName.of(projectId, subscriptionId)
SubscriptionAdminClient.create(subscriptionAdminSettings).createSubscription(
subscriptionName,
TopicName.of(projectId, topicId),
PushConfig.getDefaultInstance(),
10
)
}
fun listSubscriptions(): List<String> {
return SubscriptionAdminClient.create(subscriptionAdminSettings)
.listSubscriptions(projectName)
.iterateAll()
.map { it.name }
.toList()
}
fun push(topicId: String, message: String) {
val publisher: Publisher = Publisher.newBuilder(TopicName.of(projectId, topicId))
.setChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
val pubsubMessage: PubsubMessage = PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8(message)).build()
publisher.publish(pubsubMessage).get()
}
fun poll(size: Int, subscriptionId: String): List<String> {
val subscriberStubSettings: SubscriberStubSettings = SubscriberStubSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
GrpcSubscriberStub.create(subscriberStubSettings).use { subscriber ->
val pullRequest: PullRequest = PullRequest.newBuilder()
.setMaxMessages(size)
.setSubscription(ProjectSubscriptionName.format(projectId, subscriptionId))
.build()
val pullResponse: PullResponse = subscriber.pullCallable().call(pullRequest)
return pullResponse.receivedMessagesList
.map { it.message.data.toStringUtf8() }
.toList()
}
}
}
我找不到问题的答案。
我找到了 Junit5 的解决方法 junit-pioneer
可以在实际测试之前将 env 变量设置为某个值 运行。
因此,代码将与以前相同,但注释为 @SetEnvironmentVariable
@SetEnvironmentVariable(key="GOOGLE_APPLICATION_CREDENTIALS", value="dev.json")
class PubSubTestServer {
...
}
JUnit 先锋:Maven central.
我有一个 Spring 依赖于 Google PubSub 的启动应用程序。我想 运行 使用 Google Cloud PubSub 模拟器。我如何解决 GOOGLE_APPLICATION_CREDENTIALS
,以便应用程序启动并使用来自本地模拟器而不是外部项目的消息?
目前,如果我将 GOOGLE_APPLICATION_CREDENTIALS 设置为 dev.json,如果我不设置变量,则不会调用 PubSub,测试会崩溃。我怎样才能克服它?我不会拼图。
注意:我正在编写一个完整的 Spring 引导启动的集成测试。
我的 PubSub 实现:
import com.github.dockerjava.api.exception.DockerClientException
import com.google.api.gax.core.NoCredentialsProvider
import com.google.api.gax.grpc.GrpcTransportChannel
import com.google.api.gax.rpc.FixedTransportChannelProvider
import com.google.api.gax.rpc.TransportChannelProvider
import com.google.cloud.pubsub.v1.*
import com.google.cloud.pubsub.v1.stub.GrpcSubscriberStub
import com.google.cloud.pubsub.v1.stub.SubscriberStubSettings
import com.google.protobuf.ByteString
import com.google.pubsub.v1.*
import com.greenbird.server.contracts.TestServer
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
import org.testcontainers.containers.PubSubEmulatorContainer
import org.testcontainers.utility.DockerImageName
import java.util.concurrent.TimeUnit
class PubSubTestServer(private val projectName: ProjectName, private val ports: Array<Int> = arrayOf(8085)) :
TestServer {
constructor(projectId: String): this(ProjectName.of(projectId))
private val projectId = projectName.project
var emulator: PubSubEmulatorContainer = PubSubEmulatorContainer(
DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:latest")
)
private var channels: MutableList<ManagedChannel> = mutableListOf()
private fun channel(): ManagedChannel {
return if (channels.isEmpty()) {
val endpoint = emulator.emulatorEndpoint
val channel = ManagedChannelBuilder
.forTarget(endpoint)
.usePlaintext()
.build()
channels.add(channel)
channel
} else {
channels.first()
}
}
private val channelProvider: TransportChannelProvider
get() {
return FixedTransportChannelProvider
.create(
GrpcTransportChannel.create(channel())
)
}
private val credentialsProvider: NoCredentialsProvider = NoCredentialsProvider.create()
private val topicAdminSettings: TopicAdminSettings
get() {
when {
emulator.isRunning -> {
return buildTopicAdminSettings()
}
else -> {
throw DockerClientException("Topic admin settings attempted to initialize before starting PubSub emulator")
}
}
}
private fun buildTopicAdminSettings(): TopicAdminSettings {
return TopicAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
}
private val subscriptionAdminSettings: SubscriptionAdminSettings
get() {
when {
emulator.isRunning -> {
return buildSubscriptionAdminSettings()
}
else -> {
throw DockerClientException("Subscription admin settings attempted to initialize before starting PubSub emulator")
}
}
}
private fun buildSubscriptionAdminSettings(): SubscriptionAdminSettings {
return SubscriptionAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
}
override fun start() {
emulator.withExposedPorts(*ports).start()
}
override fun stop() {
terminate()
emulator.stop()
}
private fun terminate() {
for (channel in channels) {
channel.shutdownNow()
channel.awaitTermination(5, TimeUnit.SECONDS)
}
}
fun createTopic(topicId: String) {
TopicAdminClient.create(topicAdminSettings).use { topicAdminClient ->
val topicName = TopicName.of(projectId, topicId)
topicAdminClient.createTopic(topicName)
}
}
fun listTopics(): List<String> {
return TopicAdminClient.create(topicAdminSettings)
.listTopics(projectName)
.iterateAll()
.map { it.name }
.toList()
}
fun createSubscription(subscriptionId: String, topicId: String) {
val subscriptionName = ProjectSubscriptionName.of(projectId, subscriptionId)
SubscriptionAdminClient.create(subscriptionAdminSettings).createSubscription(
subscriptionName,
TopicName.of(projectId, topicId),
PushConfig.getDefaultInstance(),
10
)
}
fun listSubscriptions(): List<String> {
return SubscriptionAdminClient.create(subscriptionAdminSettings)
.listSubscriptions(projectName)
.iterateAll()
.map { it.name }
.toList()
}
fun push(topicId: String, message: String) {
val publisher: Publisher = Publisher.newBuilder(TopicName.of(projectId, topicId))
.setChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
val pubsubMessage: PubsubMessage = PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8(message)).build()
publisher.publish(pubsubMessage).get()
}
fun poll(size: Int, subscriptionId: String): List<String> {
val subscriberStubSettings: SubscriberStubSettings = SubscriberStubSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build()
GrpcSubscriberStub.create(subscriberStubSettings).use { subscriber ->
val pullRequest: PullRequest = PullRequest.newBuilder()
.setMaxMessages(size)
.setSubscription(ProjectSubscriptionName.format(projectId, subscriptionId))
.build()
val pullResponse: PullResponse = subscriber.pullCallable().call(pullRequest)
return pullResponse.receivedMessagesList
.map { it.message.data.toStringUtf8() }
.toList()
}
}
}
我找不到问题的答案。
我找到了 Junit5 的解决方法 junit-pioneer
可以在实际测试之前将 env 变量设置为某个值 运行。
因此,代码将与以前相同,但注释为 @SetEnvironmentVariable
@SetEnvironmentVariable(key="GOOGLE_APPLICATION_CREDENTIALS", value="dev.json")
class PubSubTestServer {
...
}
JUnit 先锋:Maven central.