github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/plugins_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "reflect" 8 "testing" 9 10 "github.com/hashicorp/terraform/addrs" 11 "github.com/hashicorp/terraform/configs/configschema" 12 "github.com/hashicorp/terraform/plugin/discovery" 13 "github.com/hashicorp/terraform/providers" 14 "github.com/hashicorp/terraform/terraform" 15 "github.com/hashicorp/terraform/tfdiags" 16 ) 17 18 func TestMultiVersionProviderResolver(t *testing.T) { 19 available := make(discovery.PluginMetaSet) 20 available.Add(discovery.PluginMeta{ 21 Name: "plugin", 22 Version: "1.0.0", 23 Path: "testdata/empty-file", 24 }) 25 26 resolver := &multiVersionProviderResolver{ 27 Internal: map[addrs.Provider]providers.Factory{ 28 addrs.NewLegacyProvider("internal"): providers.FactoryFixed( 29 &terraform.MockProvider{ 30 GetSchemaReturn: &terraform.ProviderSchema{ 31 ResourceTypes: map[string]*configschema.Block{ 32 "internal_foo": {}, 33 }, 34 }, 35 }, 36 ), 37 }, 38 Available: available, 39 } 40 41 t.Run("plugin matches", func(t *testing.T) { 42 reqd := discovery.PluginRequirements{ 43 "plugin": &discovery.PluginConstraints{ 44 Versions: discovery.ConstraintStr("1.0.0").MustParse(), 45 }, 46 } 47 got, err := resolver.ResolveProviders(reqd) 48 if err != nil { 49 t.Fatalf("unexpected error: %s", err) 50 } 51 if ct := len(got); ct != 1 { 52 t.Errorf("wrong number of results %d; want 1", ct) 53 } 54 if _, exists := got[addrs.NewLegacyProvider("plugin")]; !exists { 55 t.Errorf("provider \"plugin\" not in result") 56 } 57 }) 58 t.Run("plugin doesn't match", func(t *testing.T) { 59 reqd := discovery.PluginRequirements{ 60 "plugin": &discovery.PluginConstraints{ 61 Versions: discovery.ConstraintStr("2.0.0").MustParse(), 62 }, 63 } 64 _, err := resolver.ResolveProviders(reqd) 65 if err == nil { 66 t.Errorf("resolved successfully, but want error") 67 } 68 }) 69 t.Run("internal matches", func(t *testing.T) { 70 reqd := discovery.PluginRequirements{ 71 "internal": &discovery.PluginConstraints{ 72 Versions: discovery.AllVersions, 73 }, 74 } 75 got, err := resolver.ResolveProviders(reqd) 76 if err != nil { 77 t.Fatalf("unexpected error: %s", err) 78 } 79 if ct := len(got); ct != 1 { 80 t.Errorf("wrong number of results %d; want 1", ct) 81 } 82 if _, exists := got[addrs.NewLegacyProvider("internal")]; !exists { 83 t.Errorf("provider \"internal\" not in result") 84 } 85 }) 86 t.Run("internal with version constraint", func(t *testing.T) { 87 // Version constraints are not permitted for internal providers 88 reqd := discovery.PluginRequirements{ 89 "internal": &discovery.PluginConstraints{ 90 Versions: discovery.ConstraintStr("2.0.0").MustParse(), 91 }, 92 } 93 _, err := resolver.ResolveProviders(reqd) 94 if err == nil { 95 t.Errorf("resolved successfully, but want error") 96 } 97 }) 98 } 99 100 func TestPluginPath(t *testing.T) { 101 td := testTempDir(t) 102 defer os.RemoveAll(td) 103 defer testChdir(t, td)() 104 105 pluginPath := []string{"a", "b", "c"} 106 107 m := Meta{} 108 if err := m.storePluginPath(pluginPath); err != nil { 109 t.Fatal(err) 110 } 111 112 restoredPath, err := m.loadPluginPath() 113 if err != nil { 114 t.Fatal(err) 115 } 116 117 if !reflect.DeepEqual(pluginPath, restoredPath) { 118 t.Fatalf("expected plugin path %#v, got %#v", pluginPath, restoredPath) 119 } 120 } 121 122 func TestInternalProviders(t *testing.T) { 123 m := Meta{} 124 internal := m.internalProviders() 125 tfProvider, err := internal[addrs.NewLegacyProvider("terraform")]() 126 if err != nil { 127 t.Fatal(err) 128 } 129 130 schema := tfProvider.GetSchema() 131 _, found := schema.DataSources["terraform_remote_state"] 132 if !found { 133 t.Errorf("didn't find terraform_remote_state in internal \"terraform\" provider") 134 } 135 } 136 137 // mockProviderInstaller is a discovery.PluginInstaller implementation that 138 // is a mock for discovery.ProviderInstaller. 139 type mockProviderInstaller struct { 140 // A map of provider names to available versions. 141 // The tests expect the versions to be in order from newest to oldest. 142 Providers map[string][]string 143 144 Dir string 145 PurgeUnusedCalled bool 146 } 147 148 func (i *mockProviderInstaller) FileName(provider, version string) string { 149 return fmt.Sprintf("terraform-provider-%s_v%s_x4", provider, version) 150 } 151 152 func (i *mockProviderInstaller) Get(provider addrs.Provider, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) { 153 var diags tfdiags.Diagnostics 154 noMeta := discovery.PluginMeta{} 155 versions := i.Providers[provider.Type] 156 if len(versions) == 0 { 157 return noMeta, diags, fmt.Errorf("provider %q not found", provider) 158 } 159 160 err := os.MkdirAll(i.Dir, 0755) 161 if err != nil { 162 return noMeta, diags, fmt.Errorf("error creating plugins directory: %s", err) 163 } 164 165 for _, v := range versions { 166 version, err := discovery.VersionStr(v).Parse() 167 if err != nil { 168 panic(err) 169 } 170 171 if req.Allows(version) { 172 // provider filename 173 name := i.FileName(provider.Type, v) 174 path := filepath.Join(i.Dir, name) 175 f, err := os.Create(path) 176 if err != nil { 177 return noMeta, diags, fmt.Errorf("error fetching provider: %s", err) 178 } 179 f.Close() 180 return discovery.PluginMeta{ 181 Name: provider.Type, 182 Version: discovery.VersionStr(v), 183 Path: path, 184 }, diags, nil 185 } 186 } 187 188 return noMeta, diags, fmt.Errorf("no suitable version for provider %q found with constraints %s", provider, req) 189 } 190 191 func (i *mockProviderInstaller) PurgeUnused(map[string]discovery.PluginMeta) (discovery.PluginMetaSet, error) { 192 i.PurgeUnusedCalled = true 193 ret := make(discovery.PluginMetaSet) 194 ret.Add(discovery.PluginMeta{ 195 Name: "test", 196 Version: "0.0.0", 197 Path: "mock-test", 198 }) 199 return ret, nil 200 } 201 202 type callbackPluginInstaller func(provider string, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) 203 204 func (cb callbackPluginInstaller) Get(provider addrs.Provider, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) { 205 return cb(provider.Type, req) 206 } 207 208 func (cb callbackPluginInstaller) PurgeUnused(map[string]discovery.PluginMeta) (discovery.PluginMetaSet, error) { 209 // does nothing 210 return make(discovery.PluginMetaSet), nil 211 }