2014-08-17 23:45:43 +02:00
|
|
|
package schema
|
|
|
|
|
|
|
|
import (
|
2014-08-18 00:01:27 +02:00
|
|
|
"fmt"
|
2014-08-18 00:07:01 +02:00
|
|
|
"reflect"
|
2018-11-05 13:21:37 +01:00
|
|
|
"strings"
|
2014-08-17 23:45:43 +02:00
|
|
|
"testing"
|
2016-10-24 03:07:17 +02:00
|
|
|
"time"
|
2014-08-17 23:45:43 +02:00
|
|
|
|
2018-07-12 02:59:32 +02:00
|
|
|
"github.com/google/go-cmp/cmp"
|
2017-10-14 03:43:08 +02:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
|
2014-08-17 23:45:43 +02:00
|
|
|
"github.com/hashicorp/terraform/config"
|
2018-07-05 19:33:29 +02:00
|
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
2014-08-17 23:45:43 +02:00
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
|
|
)
|
|
|
|
|
2014-08-18 05:23:25 +02:00
|
|
|
func TestProvider_impl(t *testing.T) {
|
|
|
|
var _ terraform.ResourceProvider = new(Provider)
|
|
|
|
}
|
|
|
|
|
2017-10-14 03:43:08 +02:00
|
|
|
func TestProviderGetSchema(t *testing.T) {
|
|
|
|
// This functionality is already broadly tested in core_schema_test.go,
|
|
|
|
// so this is just to ensure that the call passes through correctly.
|
|
|
|
p := &Provider{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"bar": {
|
|
|
|
Type: TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"foo": &Resource{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"bar": {
|
|
|
|
Type: TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DataSourcesMap: map[string]*Resource{
|
|
|
|
"baz": &Resource{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"bur": {
|
|
|
|
Type: TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
want := &terraform.ProviderSchema{
|
|
|
|
Provider: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": &configschema.Attribute{
|
|
|
|
Type: cty.String,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
|
|
|
},
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
2018-07-12 02:59:32 +02:00
|
|
|
"foo": testResource(&configschema.Block{
|
2017-10-14 03:43:08 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": &configschema.Attribute{
|
|
|
|
Type: cty.String,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
2018-07-12 02:59:32 +02:00
|
|
|
}),
|
2017-10-14 03:43:08 +02:00
|
|
|
},
|
|
|
|
DataSources: map[string]*configschema.Block{
|
2018-07-12 02:59:32 +02:00
|
|
|
"baz": testResource(&configschema.Block{
|
2017-10-14 03:43:08 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bur": &configschema.Attribute{
|
|
|
|
Type: cty.String,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
2018-07-12 02:59:32 +02:00
|
|
|
}),
|
2017-10-14 03:43:08 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
got, err := p.GetSchema(&terraform.ProviderSchemaRequest{
|
|
|
|
ResourceTypes: []string{"foo", "bar"},
|
|
|
|
DataSources: []string{"baz", "bar"},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error %s", err)
|
|
|
|
}
|
|
|
|
|
2018-07-12 04:34:39 +02:00
|
|
|
if !cmp.Equal(got, want, equateEmpty, typeComparer) {
|
|
|
|
t.Error("wrong result:\n", cmp.Diff(got, want, equateEmpty, typeComparer))
|
2017-10-14 03:43:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-18 00:01:27 +02:00
|
|
|
func TestProviderConfigure(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
P *Provider
|
|
|
|
Config map[string]interface{}
|
|
|
|
Err bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
P: &Provider{},
|
|
|
|
Config: nil,
|
|
|
|
Err: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
P: &Provider{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"foo": &Schema{
|
|
|
|
Type: TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2014-08-18 04:45:26 +02:00
|
|
|
ConfigureFunc: func(d *ResourceData) (interface{}, error) {
|
2014-08-18 00:01:27 +02:00
|
|
|
if d.Get("foo").(int) == 42 {
|
2014-08-18 04:45:26 +02:00
|
|
|
return nil, nil
|
2014-08-18 00:01:27 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 04:45:26 +02:00
|
|
|
return nil, fmt.Errorf("nope")
|
2014-08-18 00:01:27 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"foo": 42,
|
|
|
|
},
|
|
|
|
Err: false,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
P: &Provider{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"foo": &Schema{
|
|
|
|
Type: TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2014-08-18 04:45:26 +02:00
|
|
|
ConfigureFunc: func(d *ResourceData) (interface{}, error) {
|
2014-08-18 00:01:27 +02:00
|
|
|
if d.Get("foo").(int) == 42 {
|
2014-08-18 04:45:26 +02:00
|
|
|
return nil, nil
|
2014-08-18 00:01:27 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 04:45:26 +02:00
|
|
|
return nil, fmt.Errorf("nope")
|
2014-08-18 00:01:27 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"foo": 52,
|
|
|
|
},
|
|
|
|
Err: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tc := range cases {
|
|
|
|
c, err := config.NewRawConfig(tc.Config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = tc.P.Configure(terraform.NewResourceConfig(c))
|
2015-10-08 14:48:04 +02:00
|
|
|
if err != nil != tc.Err {
|
2014-08-18 00:01:27 +02:00
|
|
|
t.Fatalf("%d: %s", i, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-18 00:07:01 +02:00
|
|
|
func TestProviderResources(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
P *Provider
|
|
|
|
Result []terraform.ResourceType
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
P: &Provider{},
|
|
|
|
Result: []terraform.ResourceType{},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
P: &Provider{
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"foo": nil,
|
|
|
|
"bar": nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Result: []terraform.ResourceType{
|
2017-10-14 03:43:08 +02:00
|
|
|
terraform.ResourceType{Name: "bar", SchemaAvailable: true},
|
|
|
|
terraform.ResourceType{Name: "foo", SchemaAvailable: true},
|
2014-08-18 00:07:01 +02:00
|
|
|
},
|
|
|
|
},
|
2016-04-26 18:39:39 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
P: &Provider{
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"foo": nil,
|
|
|
|
"bar": &Resource{Importer: &ResourceImporter{}},
|
|
|
|
"baz": nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Result: []terraform.ResourceType{
|
2017-10-14 03:43:08 +02:00
|
|
|
terraform.ResourceType{Name: "bar", Importable: true, SchemaAvailable: true},
|
|
|
|
terraform.ResourceType{Name: "baz", SchemaAvailable: true},
|
|
|
|
terraform.ResourceType{Name: "foo", SchemaAvailable: true},
|
2016-04-26 18:39:39 +02:00
|
|
|
},
|
|
|
|
},
|
2014-08-18 00:07:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, tc := range cases {
|
|
|
|
actual := tc.P.Resources()
|
|
|
|
if !reflect.DeepEqual(actual, tc.Result) {
|
|
|
|
t.Fatalf("%d: %#v", i, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
core: New ResourceProvider methods for data resources
This is a breaking change to the ResourceProvider interface that adds the
new operations relating to data sources.
DataSources, ValidateDataSource, ReadDataDiff and ReadDataApply are the
data source equivalents of Resources, Validate, Diff and Apply (respectively)
for managed resources.
The diff/apply model seems at first glance a rather strange workflow for
read-only resources, but implementing data resources in this way allows them
to fit cleanly into the standard plan/apply lifecycle in cases where the
configuration contains computed arguments and thus the read must be deferred
until apply time.
Along with breaking the interface, we also fix up the plugin client/server
and helper/schema implementations of it, which are all of the callers
used when provider plugins use helper/schema. This would be a breaking
change for any provider plugin that directly implements the provider
interface, but no known plugins do this and it is not recommended.
At the helper/schema layer the implementer sees ReadDataApply as a "Read",
as opposed to "Create" or "Update" as in the managed resource Apply
implementation. The planning mechanics are handled entirely within
helper/schema, so that complexity is hidden from the provider implementation
itself.
2016-05-08 06:55:32 +02:00
|
|
|
func TestProviderDataSources(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
P *Provider
|
|
|
|
Result []terraform.DataSource
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
P: &Provider{},
|
|
|
|
Result: []terraform.DataSource{},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
P: &Provider{
|
|
|
|
DataSourcesMap: map[string]*Resource{
|
|
|
|
"foo": nil,
|
|
|
|
"bar": nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Result: []terraform.DataSource{
|
2017-10-14 03:43:08 +02:00
|
|
|
terraform.DataSource{Name: "bar", SchemaAvailable: true},
|
|
|
|
terraform.DataSource{Name: "foo", SchemaAvailable: true},
|
core: New ResourceProvider methods for data resources
This is a breaking change to the ResourceProvider interface that adds the
new operations relating to data sources.
DataSources, ValidateDataSource, ReadDataDiff and ReadDataApply are the
data source equivalents of Resources, Validate, Diff and Apply (respectively)
for managed resources.
The diff/apply model seems at first glance a rather strange workflow for
read-only resources, but implementing data resources in this way allows them
to fit cleanly into the standard plan/apply lifecycle in cases where the
configuration contains computed arguments and thus the read must be deferred
until apply time.
Along with breaking the interface, we also fix up the plugin client/server
and helper/schema implementations of it, which are all of the callers
used when provider plugins use helper/schema. This would be a breaking
change for any provider plugin that directly implements the provider
interface, but no known plugins do this and it is not recommended.
At the helper/schema layer the implementer sees ReadDataApply as a "Read",
as opposed to "Create" or "Update" as in the managed resource Apply
implementation. The planning mechanics are handled entirely within
helper/schema, so that complexity is hidden from the provider implementation
itself.
2016-05-08 06:55:32 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tc := range cases {
|
|
|
|
actual := tc.P.DataSources()
|
|
|
|
if !reflect.DeepEqual(actual, tc.Result) {
|
|
|
|
t.Fatalf("%d: got %#v; want %#v", i, actual, tc.Result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-24 01:52:04 +02:00
|
|
|
func TestProviderValidate(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
P *Provider
|
|
|
|
Config map[string]interface{}
|
|
|
|
Err bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
P: &Provider{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"foo": &Schema{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Config: nil,
|
|
|
|
Err: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tc := range cases {
|
|
|
|
c, err := config.NewRawConfig(tc.Config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, es := tc.P.Validate(terraform.NewResourceConfig(c))
|
2015-10-08 14:48:04 +02:00
|
|
|
if len(es) > 0 != tc.Err {
|
2015-06-24 01:52:04 +02:00
|
|
|
t.Fatalf("%d: %#v", i, es)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-30 22:10:17 +01:00
|
|
|
func TestProviderDiff_legacyTimeoutType(t *testing.T) {
|
2018-11-05 13:21:37 +01:00
|
|
|
p := &Provider{
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"blah": &Resource{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"foo": {
|
|
|
|
Type: TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Timeouts: &ResourceTimeout{
|
|
|
|
Create: DefaultTimeout(10 * time.Minute),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidCfg := map[string]interface{}{
|
|
|
|
"foo": 42,
|
|
|
|
"timeouts": []map[string]interface{}{
|
|
|
|
map[string]interface{}{
|
|
|
|
"create": "40m",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
ic, err := config.NewRawConfig(invalidCfg)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
2019-01-30 22:10:17 +01:00
|
|
|
_, err = p.Diff(
|
|
|
|
&terraform.InstanceInfo{
|
|
|
|
Type: "blah",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
terraform.NewResourceConfig(ic),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProviderDiff_invalidTimeoutType(t *testing.T) {
|
|
|
|
p := &Provider{
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"blah": &Resource{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"foo": {
|
|
|
|
Type: TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Timeouts: &ResourceTimeout{
|
|
|
|
Create: DefaultTimeout(10 * time.Minute),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidCfg := map[string]interface{}{
|
|
|
|
"foo": 42,
|
|
|
|
"timeouts": []interface{}{
|
|
|
|
map[string]interface{}{
|
|
|
|
"create": "40m",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
ic, err := config.NewRawConfig(invalidCfg)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
2018-11-05 13:21:37 +01:00
|
|
|
_, err = p.Diff(
|
|
|
|
&terraform.InstanceInfo{
|
|
|
|
Type: "blah",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
terraform.NewResourceConfig(ic),
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Expected provider.Diff to fail with invalid timeout type")
|
|
|
|
}
|
|
|
|
expectedErrMsg := "Invalid Timeout structure"
|
|
|
|
if !strings.Contains(err.Error(), expectedErrMsg) {
|
|
|
|
t.Fatalf("Unexpected error message: %q\nExpected message to contain %q",
|
|
|
|
err.Error(),
|
|
|
|
expectedErrMsg)
|
2018-11-05 13:16:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProviderDiff_timeoutInvalidValue(t *testing.T) {
|
|
|
|
p := &Provider{
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"blah": &Resource{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"foo": {
|
|
|
|
Type: TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Timeouts: &ResourceTimeout{
|
|
|
|
Create: DefaultTimeout(10 * time.Minute),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidCfg := map[string]interface{}{
|
|
|
|
"foo": 42,
|
|
|
|
"timeouts": map[string]interface{}{
|
|
|
|
"create": "invalid",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
ic, err := config.NewRawConfig(invalidCfg)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = p.Diff(
|
|
|
|
&terraform.InstanceInfo{
|
|
|
|
Type: "blah",
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
terraform.NewResourceConfig(ic),
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Expected provider.Diff to fail with invalid timeout value")
|
|
|
|
}
|
|
|
|
expectedErrMsg := "time: invalid duration invalid"
|
|
|
|
if !strings.Contains(err.Error(), expectedErrMsg) {
|
|
|
|
t.Fatalf("Unexpected error message: %q\nExpected message to contain %q",
|
|
|
|
err.Error(),
|
|
|
|
expectedErrMsg)
|
2018-11-05 13:21:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-17 23:45:43 +02:00
|
|
|
func TestProviderValidateResource(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
P *Provider
|
|
|
|
Type string
|
|
|
|
Config map[string]interface{}
|
|
|
|
Err bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
P: &Provider{},
|
|
|
|
Type: "foo",
|
|
|
|
Config: nil,
|
|
|
|
Err: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
P: &Provider{
|
2014-08-18 00:07:01 +02:00
|
|
|
ResourcesMap: map[string]*Resource{
|
2014-08-17 23:45:43 +02:00
|
|
|
"foo": &Resource{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Type: "foo",
|
|
|
|
Config: nil,
|
|
|
|
Err: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tc := range cases {
|
|
|
|
c, err := config.NewRawConfig(tc.Config)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, es := tc.P.ValidateResource(tc.Type, terraform.NewResourceConfig(c))
|
2015-10-08 14:48:04 +02:00
|
|
|
if len(es) > 0 != tc.Err {
|
2014-08-17 23:45:43 +02:00
|
|
|
t.Fatalf("%d: %#v", i, es)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-08-20 00:26:31 +02:00
|
|
|
|
2016-05-04 21:56:45 +02:00
|
|
|
func TestProviderImportState_default(t *testing.T) {
|
|
|
|
p := &Provider{
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"foo": &Resource{
|
|
|
|
Importer: &ResourceImporter{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
states, err := p.ImportState(&terraform.InstanceInfo{
|
|
|
|
Type: "foo",
|
|
|
|
}, "bar")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(states) != 1 {
|
|
|
|
t.Fatalf("bad: %#v", states)
|
|
|
|
}
|
|
|
|
if states[0].ID != "bar" {
|
|
|
|
t.Fatalf("bad: %#v", states)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-04 20:18:45 +02:00
|
|
|
func TestProviderImportState_setsId(t *testing.T) {
|
|
|
|
var val string
|
|
|
|
stateFunc := func(d *ResourceData, meta interface{}) ([]*ResourceData, error) {
|
|
|
|
val = d.Id()
|
|
|
|
return []*ResourceData{d}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
p := &Provider{
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"foo": &Resource{
|
|
|
|
Importer: &ResourceImporter{
|
|
|
|
State: stateFunc,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := p.ImportState(&terraform.InstanceInfo{
|
|
|
|
Type: "foo",
|
2016-05-04 21:42:02 +02:00
|
|
|
}, "bar")
|
2016-05-04 20:18:45 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if val != "bar" {
|
|
|
|
t.Fatal("should set id")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-01 01:36:31 +02:00
|
|
|
func TestProviderImportState_setsType(t *testing.T) {
|
|
|
|
var tVal string
|
|
|
|
stateFunc := func(d *ResourceData, meta interface{}) ([]*ResourceData, error) {
|
|
|
|
d.SetId("foo")
|
|
|
|
tVal = d.State().Ephemeral.Type
|
|
|
|
return []*ResourceData{d}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
p := &Provider{
|
|
|
|
ResourcesMap: map[string]*Resource{
|
|
|
|
"foo": &Resource{
|
|
|
|
Importer: &ResourceImporter{
|
|
|
|
State: stateFunc,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := p.ImportState(&terraform.InstanceInfo{
|
|
|
|
Type: "foo",
|
2016-05-04 21:42:02 +02:00
|
|
|
}, "bar")
|
2016-05-01 01:36:31 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if tVal != "foo" {
|
|
|
|
t.Fatal("should set type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 00:26:31 +02:00
|
|
|
func TestProviderMeta(t *testing.T) {
|
|
|
|
p := new(Provider)
|
|
|
|
if v := p.Meta(); v != nil {
|
|
|
|
t.Fatalf("bad: %#v", v)
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := 42
|
|
|
|
p.SetMeta(42)
|
|
|
|
if v := p.Meta(); !reflect.DeepEqual(v, expected) {
|
2014-08-25 06:50:35 +02:00
|
|
|
t.Fatalf("bad: %#v", v)
|
2014-08-20 00:26:31 +02:00
|
|
|
}
|
|
|
|
}
|
2016-10-24 03:07:17 +02:00
|
|
|
|
|
|
|
func TestProviderStop(t *testing.T) {
|
|
|
|
var p Provider
|
|
|
|
|
|
|
|
if p.Stopped() {
|
|
|
|
t.Fatal("should not be stopped")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify stopch blocks
|
2016-10-25 20:29:24 +02:00
|
|
|
ch := p.StopContext().Done()
|
2016-10-24 03:07:17 +02:00
|
|
|
select {
|
|
|
|
case <-ch:
|
|
|
|
t.Fatal("should not be stopped")
|
|
|
|
case <-time.After(10 * time.Millisecond):
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop it
|
|
|
|
if err := p.Stop(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify
|
|
|
|
if !p.Stopped() {
|
|
|
|
t.Fatal("should be stopped")
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-ch:
|
|
|
|
case <-time.After(10 * time.Millisecond):
|
|
|
|
t.Fatal("should be stopped")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProviderStop_stopFirst(t *testing.T) {
|
|
|
|
var p Provider
|
|
|
|
|
|
|
|
// Stop it
|
|
|
|
if err := p.Stop(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify
|
|
|
|
if !p.Stopped() {
|
|
|
|
t.Fatal("should be stopped")
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
2016-10-25 20:29:24 +02:00
|
|
|
case <-p.StopContext().Done():
|
2016-10-24 03:07:17 +02:00
|
|
|
case <-time.After(10 * time.Millisecond):
|
|
|
|
t.Fatal("should be stopped")
|
|
|
|
}
|
|
|
|
}
|
2017-03-07 15:19:02 +01:00
|
|
|
|
|
|
|
func TestProviderReset(t *testing.T) {
|
|
|
|
var p Provider
|
|
|
|
stopCtx := p.StopContext()
|
|
|
|
p.MetaReset = func() error {
|
|
|
|
stopCtx = p.StopContext()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// cancel the current context
|
|
|
|
p.Stop()
|
|
|
|
|
|
|
|
if err := p.TestReset(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// the first context should have been replaced
|
|
|
|
if err := stopCtx.Err(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// we should not get a canceled context here either
|
|
|
|
if err := p.StopContext().Err(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2017-07-11 06:51:55 +02:00
|
|
|
|
|
|
|
func TestProvider_InternalValidate(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
P *Provider
|
|
|
|
ExpectedErr error
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
P: &Provider{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"foo": {
|
|
|
|
Type: TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedErr: nil,
|
|
|
|
},
|
|
|
|
{ // Reserved resource fields should be allowed in provider block
|
|
|
|
P: &Provider{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"provisioner": {
|
|
|
|
Type: TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"count": {
|
|
|
|
Type: TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedErr: nil,
|
|
|
|
},
|
|
|
|
{ // Reserved provider fields should not be allowed
|
|
|
|
P: &Provider{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"alias": {
|
|
|
|
Type: TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedErr: fmt.Errorf("%s is a reserved field name for a provider", "alias"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tc := range cases {
|
|
|
|
err := tc.P.InternalValidate()
|
|
|
|
if tc.ExpectedErr == nil {
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("%d: Error returned (expected no error): %s", i, err)
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if tc.ExpectedErr != nil && err == nil {
|
|
|
|
t.Fatalf("%d: Expected error (%s), but no error returned", i, tc.ExpectedErr)
|
|
|
|
}
|
|
|
|
if err.Error() != tc.ExpectedErr.Error() {
|
|
|
|
t.Fatalf("%d: Errors don't match. Expected: %#v Given: %#v", i, tc.ExpectedErr, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|