go - 如何将模拟服务器的 URL 注入 terraform 的验收测试?
问题描述
官方网站上有一整节关于 terraform 提供者的验收测试,假设我将在真实基础设施上使用测试帐户运行它。
也就是说,在我的情况下,我不能使用我的真实基础设施,并且计划使用模拟服务器而不是我想让 tf 提供者/客户端与之交谈,并且我确实有一个特定的变量:
provider "foo" {
endpoint = var.endpoint
}
variable "endpoint" {
type = string
description = "Endpoint to talk to"
default = "https://realinfra.com" % want to use "localhost:9090" (mock server's address) in tests instead
}
我可以在验收测试中以某种方式设置/通过它吗?这是我的测试的最小工作示例:
package example
// example.Widget represents a concrete Go type that represents an API resource
func TestAccExampleWidget_basic(t *testing.T) {
var widgetBefore, widgetAfter example.Widget
rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckExampleResourceDestroy,
Steps: []resource.TestStep{
{
Config: testAccExampleResource(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckExampleResourceExists("example_widget.foo", &widgetBefore),
),
},
{
Config: testAccExampleResource_removedPolicy(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckExampleResourceExists("example_widget.foo", &widgetAfter),
),
},
},
})
}
换句话说(或者像一个更一般的问题),你将如何在 tf provider 中设置变量的值,因为你有:
func Provider() *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
...,
"endpoint": {
Type: schema.TypeString,
Optional: true,
Default: "https://realinfra.com",
},
"email": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("FOO_USERNAME", ""),
},
解决方案
有几种方法可以做到这一点:
1.环境变量
允许通过 env 变量设置提供者端点:
"endpoint": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("FOO_ENDPOINT", "https://realinfra.com")
},
并要求将此环境变量设置为testAccPreCheck
:
func testAccPreCheck(t *testing.T) {
if v := os.Getenv("FOO_ENDPOINT"); v == "" {
t.Fatal("FOO_ENDPOINT env must be set for acceptance tests")
}
}
然后你可以在你的 Makefile 中导出这个 env var
2.在测试用例中提供配置
您可以在测试用例配置中设置您的提供者配置:
// define mock address
const mockServer = "http://localhost:9090"
func TestAccExampleWidget_basic(t *testing.T) {
...
resource.Test(t, resource.TestCase{
...
Steps: []resource.TestStep{
{
// pass mock server to configs
Config: testAccExampleResource(rName, mockServer),
...
},
},
})
}
func testAccExampleResource(resourceName, server string) string {
return fmt.Sprintf(`
# use mock serer address to configure your provider inside test case config
provider "myprovider" {
endpoint = "%s"
}
myresource "myprovider_something" "foo" {
name = "%s"
}`, server, resourceName)
}
请注意,您需要为每个测试配置执行此操作。
3. 构建mock API客户端并传递给测试提供者
允许将 api 客户端传递给提供者构造函数:
provider.go
func New(client *myApiClient) *schema.Provider {
provider := &schema.Provider{...}
provider.ConfigureContextFunc = func(_ context.Context, data *schema.ResourceData) (interface{}, diag.Diagnostics) {
// return mock client if provided
if client != nil {
return client, nil
}
// existing client config here
...
return client, nil
}
}
使用空客户端更新提供程序入口点:
main.go
func main() {
plugin.Serve(&plugin.ServeOpts{
ProviderFunc: func() *schema.Provider {
return provider.New(nil)
},
})
}
根据您的 API 客户端的初始化方式,创建模拟并将其传递给测试内部的提供者:
provider_test.go
var testAccProviderFactories map[string]func() (*schema.Provider, error)
var testAccProvider *schema.Provider
var client *myApiClient
func init() {
client = &myApiClient{Endpoint: "http://localhost:9000"}
testAccProvider = New(client)
testAccProviderFactories = map[string]func() (*schema.Provider, error){
"myprovider": func() (*schema.Provider, error) {
return testAccProvider, nil
},
}
}
这种方法的灵感来自于keycloak 提供者测试
推荐阅读
- c - 如何将麦克风输入作为标准输入提供给 C 程序
- python - 如何按位置删除数据框列中的值?
- sql - 如何选择填充多列的数据
- matrix - ggcorrplot - 如何使圆圈变小?
- reactjs - Material-UI:悬停时选择边框颜色
- python - 每当启动“for循环”时告诉python,自行实现进度条
- java - 如何在 Android Studio 的 Firebase 实时数据库中添加多个文本视图
- django - 在视图上调用 transaction.set_rollback() 时删除上传的文件
- python - Python 脚本无法检索 HttpOnly cookie
- php - laravel 中基于角色的路由访问