当前位置: 首页 > 知识库问答 >
问题:

如何解析GOOGLE_APPLICATION_CREDENTIALS时运行应用程序在测试,Spring引导?

孙海
2023-03-14

我有一个Spring Boot应用程序依赖于谷歌PubSub。我想用谷歌云PubSub模拟器运行它。如何解析google_application_credentials,以便应用程序启动并使用来自本地模拟器而不是外部项目的消息?

目前,如果我将GOOGLE_APPLICATION_CREDENTIALS设置为dev.json,则不会调用PubSub,如果我不设置变量,则测试崩溃。我怎样才能克服它?我不会拼图。

注意:我正在编写一个完整的Spring boot启动的集成测试。

我的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()
        }
    }

}

共有1个答案

屠君墨
2023-03-14

我找不到有人问我的问题的答案。

我发现了Junit5的一个变通方法,junit-pioneer可以在实际测试运行之前将env变量设置为某个值。

因此,代码将与前面相同,但使用@SetEnvironmentVariable注释

@SetEnvironmentVariable(key="GOOGLE_APPLICATION_CREDENTIALS", value="dev.json")
class PubSubTestServer {
  ...
}

JUnit-Pioneer:Maven Central。

 类似资料:
  • 我有一个Spring boot应用程序,希望在Eclipse中作为服务器应用程序运行。因此,该应用程序将被识别为Tomcat web应用程序,并可以在更新facet时添加: 当我运行web应用程序时,找不到我的rest服务。spring boot应用程序包含的文件夹结构与spring boot发布前的spring应用程序不同。spring boot应用程序可以从配置了eclipse的tomcat上

  • 我不明白在springboot应用程序中如何正确地编写websocket测试用例。我有一个实现的类,我在中添加了这个处理程序: 但是当我写下下面的测试用例时,我得到了一个例外: 异常::发起WebSocket连接的HTTP请求失败 如果我将(结尾斜杠)它可以工作,但不工作。 我做错了什么?

  • 我有一个SpringBoot批处理应用程序,我正在针对它编写集成测试。当我执行测试时,整个批处理应用程序都会运行。如何仅执行测试中的应用程序代码? 这是我的测试代码。当它执行时,整个批处理作业步骤将运行(读卡器、处理器和写入器)。然后,测试运行。

  • 我在一个项目中工作,所以我有下面的代码: 但问题是,我得到了这个错误: 处理命令时发生未知的服务器端错误。原始错误:执行adbexec时出错。原始错误:“command”c:\users\dnkos\appdata\local\android\sdk\platform-tools\adb.exe-p 5037-s emulator-5554 install-r c:\users\dnkos\app

  • 尝试完成Spring Boot教程:https://Spring.io/guides/gs/spring-boot/#initial 以下是我的课程: 和pom.xml: 当我尝试使用以下命令运行它时:“mvn package&&java-jar target/gs-spring-boot-0.1.0.jar”,我得到的是: “-dmaven.home=C:\program files\jetbr