diff --git a/go.mod b/go.mod index ba73fac6296..c025253ce32 100644 --- a/go.mod +++ b/go.mod @@ -61,6 +61,7 @@ require ( golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e golang.org/x/tools v0.1.12 + gopkg.in/dnaeon/go-vcr.v3 v3.1.2 gopkg.in/yaml.v2 v2.4.0 syreclabs.com/go/faker v1.2.3 ) @@ -127,4 +128,5 @@ require ( google.golang.org/genproto v0.0.0-20200711021454-869866162049 // indirect google.golang.org/grpc v1.51.0 // indirect google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 1964fd289aa..91abba7603e 100644 --- a/go.sum +++ b/go.sum @@ -460,6 +460,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/dnaeon/go-vcr.v3 v3.1.2 h1:F1smfXBqQqwpVifDfUBQG6zzaGjzT+EnVZakrOdr5wA= +gopkg.in/dnaeon/go-vcr.v3 v3.1.2/go.mod h1:2IMOnnlx9I6u9x+YBsM3tAMx6AlOxnJ0pWxQAzZ79Ag= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/acctest/exports_test.go b/internal/acctest/exports_test.go new file mode 100644 index 00000000000..53e1a1cff14 --- /dev/null +++ b/internal/acctest/exports_test.go @@ -0,0 +1,6 @@ +package acctest + +// Exports for use in tests only. +var ( + CloseVCRRecorder = closeVCRRecorder +) diff --git a/internal/acctest/vcr.go b/internal/acctest/vcr.go new file mode 100644 index 00000000000..b1331235001 --- /dev/null +++ b/internal/acctest/vcr.go @@ -0,0 +1,456 @@ +package acctest + +import ( + "bytes" + "context" + "crypto/tls" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "math/rand" + "net/http" + "os" + "path/filepath" + "reflect" + "strconv" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + cleanhttp "github.com/hashicorp/go-cleanhttp" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/provider" + "gopkg.in/dnaeon/go-vcr.v3/cassette" + "gopkg.in/dnaeon/go-vcr.v3/recorder" +) + +const ( + envVarVCRMode = "VCR_MODE" + envVarVCRPath = "VCR_PATH" +) + +type randomnessSource struct { + seed int64 + source rand.Source +} + +type metaMap map[string]*conns.AWSClient + +func (m metaMap) Lock() { + conns.GlobalMutexKV.Lock(m.key()) +} + +func (m metaMap) Unlock() { + conns.GlobalMutexKV.Unlock(m.key()) +} + +func (m metaMap) key() string { + return "vcr-metas" +} + +type randomnessSourceMap map[string]*randomnessSource + +func (m randomnessSourceMap) Lock() { + conns.GlobalMutexKV.Lock(m.key()) +} + +func (m randomnessSourceMap) Unlock() { + conns.GlobalMutexKV.Unlock(m.key()) +} + +func (m randomnessSourceMap) key() string { + return "vcr-randomness-sources" +} + +var ( + providerMetas = metaMap(make(map[string]*conns.AWSClient, 0)) + randomnessSources = randomnessSourceMap(make(map[string]*randomnessSource, 0)) +) + +// ProviderMeta returns the current provider's state (AKA "meta" or "conns.AWSClient"). +func ProviderMeta(t *testing.T) *conns.AWSClient { + providerMetas.Lock() + meta, ok := providerMetas[t.Name()] + defer providerMetas.Unlock() + + if !ok { + meta = Provider.Meta().(*conns.AWSClient) + } + + return meta +} + +func isVCREnabled() bool { + return os.Getenv(envVarVCRMode) != "" && os.Getenv(envVarVCRPath) != "" +} + +func vcrMode() (recorder.Mode, error) { + switch v := os.Getenv(envVarVCRMode); v { + case "RECORDING": + return recorder.ModeRecordOnce, nil + case "REPLAYING": + return recorder.ModeReplayOnly, nil + default: + return recorder.ModePassthrough, fmt.Errorf("unsupported value for %s: %s", envVarVCRMode, v) + } +} + +// vcrEnabledProtoV5ProviderFactories returns ProtoV5ProviderFactories ready for use with VCR. +func vcrEnabledProtoV5ProviderFactories(t *testing.T, input map[string]func() (tfprotov5.ProviderServer, error)) map[string]func() (tfprotov5.ProviderServer, error) { + output := make(map[string]func() (tfprotov5.ProviderServer, error), len(input)) + + for name := range input { + output[name] = func() (tfprotov5.ProviderServer, error) { + providerServerFactory, primary, err := provider.ProtoV5ProviderServerFactory(context.Background()) + + if err != nil { + return nil, err + } + + primary.ConfigureContextFunc = vcrProviderConfigureContextFunc(primary, primary.ConfigureContextFunc, t.Name()) + + return providerServerFactory(), nil + } + } + + return output +} + +// vcrProviderConfigureContextFunc returns a provider configuration function returning cached provider instance state. +// This is necessary as ConfigureContextFunc is called multiple times for a given test, each time creating a new HTTP client. +// VCR requires a single HTTP client to handle all interactions. +func vcrProviderConfigureContextFunc(provider *schema.Provider, configureContextFunc schema.ConfigureContextFunc, testName string) schema.ConfigureContextFunc { + return func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) { + providerMetas.Lock() + meta, ok := providerMetas[testName] + defer providerMetas.Unlock() + + if ok { + return meta, nil + } + + vcrMode, err := vcrMode() + + if err != nil { + return nil, diag.FromErr(err) + } + + // Cribbed from aws-sdk-go-base. + httpClient := cleanhttp.DefaultPooledClient() + transport := httpClient.Transport.(*http.Transport) + transport.MaxIdleConnsPerHost = 10 + tlsConfig := transport.TLSClientConfig + if tlsConfig == nil { + tlsConfig = &tls.Config{} + transport.TLSClientConfig = tlsConfig + } + tlsConfig.MinVersion = tls.VersionTLS12 + + path := filepath.Join(os.Getenv(envVarVCRPath), vcrFileName(testName)) + + // Create a VCR recorder around a default HTTP client. + r, err := recorder.NewWithOptions(&recorder.Options{ + CassetteName: path, + Mode: vcrMode, + RealTransport: httpClient.Transport, + }) + + if err != nil { + return nil, diag.FromErr(err) + } + + // Remove sensitive HTTP headers. + r.AddHook(func(i *cassette.Interaction) error { + delete(i.Request.Headers, "Authorization") + delete(i.Request.Headers, "X-Amz-Security-Token") + + return nil + }, recorder.AfterCaptureHook) + + // Defines how VCR will match requests to responses. + r.SetMatcher(func(r *http.Request, i cassette.Request) bool { + // Default matcher compares method and URL only. + if !cassette.DefaultMatcher(r, i) { + return false + } + + if r.Body == nil { + return true + } + + var b bytes.Buffer + if _, err := b.ReadFrom(r.Body); err != nil { + tflog.Debug(ctx, "Failed to read request body from cassette", map[string]interface{}{ + "error": err, + }) + return false + } + + r.Body = io.NopCloser(&b) + body := b.String() + // If body matches identically, we are done. + if body == i.Body { + return true + } + + // https://awslabs.github.io/smithy/1.0/spec/aws/index.html#aws-protocols. + switch contentType := r.Header.Get("Content-Type"); contentType { + case "application/json", "application/x-amz-json-1.0", "application/x-amz-json-1.1": + // JSON might be the same, but reordered. Try parsing and comparing. + var requestJson, cassetteJson interface{} + + if err := json.Unmarshal([]byte(body), &requestJson); err != nil { + tflog.Debug(ctx, "Failed to unmarshal request JSON", map[string]interface{}{ + "error": err, + }) + return false + } + + if err := json.Unmarshal([]byte(i.Body), &cassetteJson); err != nil { + tflog.Debug(ctx, "Failed to unmarshal cassette JSON", map[string]interface{}{ + "error": err, + }) + return false + } + + return reflect.DeepEqual(requestJson, cassetteJson) + + case "application/xml": + // XML might be the same, but reordered. Try parsing and comparing. + var requestXml, cassetteXml interface{} + + if err := xml.Unmarshal([]byte(body), &requestXml); err != nil { + tflog.Debug(ctx, "Failed to unmarshal request XML", map[string]interface{}{ + "error": err, + }) + return false + } + + if err := xml.Unmarshal([]byte(i.Body), &cassetteXml); err != nil { + tflog.Debug(ctx, "Failed to unmarshal cassette XML", map[string]interface{}{ + "error": err, + }) + return false + } + + return reflect.DeepEqual(requestXml, cassetteXml) + } + + return false + }) + + // Use the wrapped HTTP Client for AWS APIs. + // As the HTTP client is used in the provider's ConfigureContextFunc + // we must do this setup before calling the ConfigureContextFunc. + httpClient.Transport = r + if v, ok := provider.Meta().(*conns.AWSClient); ok { + meta = v + } else { + meta = new(conns.AWSClient) + } + meta.SetHTTPClient(httpClient) + provider.SetMeta(meta) + + if v, diags := configureContextFunc(ctx, d); diags.HasError() { + return nil, diags + } else { + meta = v.(*conns.AWSClient) + } + + // Don't retry requests if a recorded interaction isn't found. + // TODO Need to loop through all API clients to do this. + // TODO Use []*client.Client? + // TODO AWS SDK for Go v2 API clients. + meta.LogsConn().Handlers.AfterRetry.PushFront(func(r *request.Request) { + // We have to use 'Contains' rather than 'errors.Is' because 'awserr.Error' doesn't implement 'Unwrap'. + if errs.Contains(r.Error, cassette.ErrInteractionNotFound.Error()) { + r.Retryable = aws.Bool(false) + } + }) + + providerMetas[testName] = meta + + return meta, nil + } +} + +// vcrRandomnessSource returns a rand.Source for VCR testing. +// In RECORDING mode, generates a new seed and saves it to a file, using the seed for the source. +// In REPLAYING mode, reads a seed from a file and creates a source from it. +func vcrRandomnessSource(t *testing.T) (*randomnessSource, error) { + testName := t.Name() + + randomnessSources.Lock() + s, ok := randomnessSources[testName] + defer randomnessSources.Unlock() + + if ok { + return s, nil + } + + vcrMode, err := vcrMode() + + if err != nil { + return nil, err + } + + switch vcrMode { + case recorder.ModeRecordOnce: + seed := rand.Int63() + s = &randomnessSource{ + seed: seed, + source: rand.NewSource(seed), + } + case recorder.ModeReplayOnly: + seed, err := readSeedFromFile(vcrSeedFile(os.Getenv(envVarVCRPath), testName)) + + if err != nil { + return nil, fmt.Errorf("no cassette found on disk for %s, please replay this testcase in recording mode - %w", testName, err) + } + + s = &randomnessSource{ + seed: seed, + source: rand.NewSource(seed), + } + default: + t.FailNow() + } + + randomnessSources[testName] = s + + return s, nil +} + +func vcrFileName(name string) string { + return strings.ReplaceAll(name, "/", "_") +} + +func vcrSeedFile(path, name string) string { + return filepath.Join(path, fmt.Sprintf("%s.seed", vcrFileName(name))) +} + +func readSeedFromFile(fileName string) (int64, error) { + // Max number of digits for int64 is 19. + data := make([]byte, 19) + f, err := os.Open(fileName) + + if err != nil { + return 0, err + } + + defer f.Close() + + _, err = f.Read(data) + + if err != nil { + return 0, err + } + + // Remove NULL characters from seed. + return strconv.ParseInt(string(bytes.Trim(data, "\x00")), 10, 64) +} + +func writeSeedToFile(seed int64, fileName string) error { + f, err := os.Create(fileName) + + if err != nil { + return err + } + + defer f.Close() + + _, err = f.WriteString(strconv.FormatInt(seed, 10)) + + return err +} + +// closeVCRRecorder closes the VCR recorder, saving the cassette and randomness seed. +func closeVCRRecorder(t *testing.T) { + // Don't close the recorder if we're running because of a panic. + if p := recover(); p != nil { + panic(p) + } + + testName := t.Name() + providerMetas.Lock() + meta, ok := providerMetas[testName] + defer providerMetas.Unlock() + + if ok { + if !t.Failed() { + if v, ok := meta.HTTPClient().Transport.(*recorder.Recorder); ok { + t.Log("stopping VCR recorder") + if err := v.Stop(); err != nil { + t.Error(err) + } + } + } + + delete(providerMetas, testName) + } + + // Save the randomness seed. + randomnessSources.Lock() + s, ok := randomnessSources[testName] + defer randomnessSources.Unlock() + + if ok { + if !t.Failed() { + t.Log("persisting randomness seed") + if err := writeSeedToFile(s.seed, vcrSeedFile(os.Getenv(envVarVCRPath), t.Name())); err != nil { + t.Error(err) + } + } + + delete(randomnessSources, testName) + } +} + +// ParallelTest wraps resource.ParallelTest, initializing VCR if enabled. +func ParallelTest(t *testing.T, c resource.TestCase) { + if isVCREnabled() { + c.ProtoV5ProviderFactories = vcrEnabledProtoV5ProviderFactories(t, c.ProtoV5ProviderFactories) + defer closeVCRRecorder(t) + } + + resource.ParallelTest(t, c) +} + +// Test wraps resource.Test, initializing VCR if enabled. +func Test(t *testing.T, c resource.TestCase) { + if isVCREnabled() { + c.ProtoV5ProviderFactories = vcrEnabledProtoV5ProviderFactories(t, c.ProtoV5ProviderFactories) + defer closeVCRRecorder(t) + } + + resource.Test(t, c) +} + +// RandInt is a VCR-friendly replacement for acctest.RandInt. +func RandInt(t *testing.T) int { + if !isVCREnabled() { + return sdkacctest.RandInt() + } + + s, err := vcrRandomnessSource(t) + + if err != nil { + t.Fatal(err) + } + + return rand.New(s.source).Int() +} + +// RandomWithPrefix is a VCR-friendly replacement for acctest.RandomWithPrefix. +func RandomWithPrefix(t *testing.T, prefix string) string { + return fmt.Sprintf("%s-%d", prefix, RandInt(t)) +} diff --git a/internal/acctest/vcr_test.go b/internal/acctest/vcr_test.go new file mode 100644 index 00000000000..5d5bc2824b6 --- /dev/null +++ b/internal/acctest/vcr_test.go @@ -0,0 +1,47 @@ +package acctest_test + +import ( + "testing" + + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func TestRandInt(t *testing.T) { //nolint:paralleltest + t.Setenv("VCR_PATH", t.TempDir()) + + t.Setenv("VCR_MODE", "RECORDING") + rec1 := acctest.RandInt(t) + rec2 := acctest.RandInt(t) + acctest.CloseVCRRecorder(t) + + t.Setenv("VCR_MODE", "REPLAYING") + rep1 := acctest.RandInt(t) + rep2 := acctest.RandInt(t) + + if rep1 != rec1 { + t.Errorf("REPLAYING: %d, RECORDING: %d", rep1, rec1) + } + if rep2 != rec2 { + t.Errorf("REPLAYING: %d, RECORDING: %d", rep2, rec2) + } +} + +func TestRandomWithPrefix(t *testing.T) { //nolint:paralleltest + t.Setenv("VCR_PATH", t.TempDir()) + + t.Setenv("VCR_MODE", "RECORDING") + rec1 := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + rec2 := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + acctest.CloseVCRRecorder(t) + + t.Setenv("VCR_MODE", "REPLAYING") + rep1 := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + rep2 := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + if rep1 != rec1 { + t.Errorf("REPLAYING: %s, RECORDING: %s", rep1, rec1) + } + if rep2 != rec2 { + t.Errorf("REPLAYING: %s, RECORDING: %s", rep2, rec2) + } +} diff --git a/internal/conns/awsclient.go b/internal/conns/awsclient.go index e44b8180d96..4f001a37d14 100644 --- a/internal/conns/awsclient.go +++ b/internal/conns/awsclient.go @@ -3,6 +3,7 @@ package conns import ( "context" "fmt" + "net/http" "github.com/aws/aws-sdk-go/service/s3" ) @@ -29,3 +30,16 @@ func (client *AWSClient) RegionalHostname(prefix string) string { func (client *AWSClient) S3ConnURICleaningDisabled() *s3.S3 { return client.s3ConnURICleaningDisabled } + +// SetHTTPClient sets the http.Client used for AWS API calls. +// To have effect it must be called before the AWS SDK v1 Session is created. +func (client *AWSClient) SetHTTPClient(httpClient *http.Client) { + if client.Session == nil { + client.httpClient = httpClient + } +} + +// HTTPClient returns the http.Client used for AWS API calls. +func (client *AWSClient) HTTPClient() *http.Client { + return client.httpClient +} diff --git a/internal/conns/awsclient_gen.go b/internal/conns/awsclient_gen.go index 713029d0fa6..51ef6d82d9e 100644 --- a/internal/conns/awsclient_gen.go +++ b/internal/conns/awsclient_gen.go @@ -2,6 +2,8 @@ package conns import ( + "net/http" + "github.com/aws/aws-sdk-go-v2/service/auditmanager" "github.com/aws/aws-sdk-go-v2/service/cloudcontrol" cloudwatchlogs_sdkv2 "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" @@ -333,7 +335,7 @@ type AWSClient struct { Session *session.Session TerraformVersion string - s3ConnURICleaningDisabled *s3.S3 + httpClient *http.Client ec2Client lazyClient[*ec2_sdkv2.Client] logsClient lazyClient[*cloudwatchlogs_sdkv2.Client] @@ -649,6 +651,8 @@ type AWSClient struct { workspacesConn *workspaces.WorkSpaces workspaceswebConn *workspacesweb.WorkSpacesWeb xrayConn *xray.XRay + + s3ConnURICleaningDisabled *s3.S3 } func (client *AWSClient) ACMConn() *acm.ACM { diff --git a/internal/conns/config.go b/internal/conns/config.go index 12240109bbf..d29ffab3863 100644 --- a/internal/conns/config.go +++ b/internal/conns/config.go @@ -88,6 +88,7 @@ func (c *Config) ConfigureProvider(ctx context.Context, client *AWSClient) (*AWS EC2MetadataServiceEnableState: c.EC2MetadataServiceEnableState, IamEndpoint: c.Endpoints[names.IAM], Insecure: c.Insecure, + HTTPClient: client.HTTPClient(), HTTPProxy: c.HTTPProxy, MaxRetries: c.MaxRetries, Profile: c.Profile, @@ -185,6 +186,7 @@ func (c *Config) ConfigureProvider(ctx context.Context, client *AWSClient) (*AWS client.Partition = partition client.Region = c.Region client.ReverseDNSPrefix = ReverseDNS(DNSSuffix) + client.SetHTTPClient(sess.Config.HTTPClient) // Must be called while client.Session is nil. client.Session = sess client.TerraformVersion = c.TerraformVersion diff --git a/internal/conns/mutexkv.go b/internal/conns/mutexkv.go index e33c626ccb2..c44e909d6b9 100644 --- a/internal/conns/mutexkv.go +++ b/internal/conns/mutexkv.go @@ -1,38 +1,33 @@ package conns import ( - "log" "sync" ) // GlobalMutexKV is a global MutexKV for use within this plugin. -var GlobalMutexKV = NewMutexKV() +var GlobalMutexKV = newMutexKV() -// MutexKV is a simple key/value store for arbitrary mutexes. It can be used to +// mutexKV is a simple key/value store for arbitrary mutexes. It can be used to // serialize changes across arbitrary collaborators that share knowledge of the // keys they must serialize on. -type MutexKV struct { +type mutexKV struct { lock sync.Mutex store map[string]*sync.Mutex } // Locks the mutex for the given key. Caller is responsible for calling Unlock // for the same key -func (m *MutexKV) Lock(key string) { - log.Printf("[DEBUG] Locking %q", key) +func (m *mutexKV) Lock(key string) { m.get(key).Lock() - log.Printf("[DEBUG] Locked %q", key) } // Unlock the mutex for the given key. Caller must have called Lock for the same key first -func (m *MutexKV) Unlock(key string) { - log.Printf("[DEBUG] Unlocking %q", key) +func (m *mutexKV) Unlock(key string) { m.get(key).Unlock() - log.Printf("[DEBUG] Unlocked %q", key) } // Returns a mutex for the given key, no guarantee of its lock status -func (m *MutexKV) get(key string) *sync.Mutex { +func (m *mutexKV) get(key string) *sync.Mutex { m.lock.Lock() defer m.lock.Unlock() mutex, ok := m.store[key] @@ -44,8 +39,8 @@ func (m *MutexKV) get(key string) *sync.Mutex { } // Returns a properly initialized MutexKV -func NewMutexKV() *MutexKV { - return &MutexKV{ +func newMutexKV() *mutexKV { + return &mutexKV{ store: make(map[string]*sync.Mutex), } } diff --git a/internal/conns/mutexkv_test.go b/internal/conns/mutexkv_test.go index 5e2390b5175..986f476224a 100644 --- a/internal/conns/mutexkv_test.go +++ b/internal/conns/mutexkv_test.go @@ -8,7 +8,7 @@ import ( func TestMutexKVLock(t *testing.T) { t.Parallel() - mkv := NewMutexKV() + mkv := newMutexKV() mkv.Lock("foo") @@ -30,7 +30,7 @@ func TestMutexKVLock(t *testing.T) { func TestMutexKVUnlock(t *testing.T) { t.Parallel() - mkv := NewMutexKV() + mkv := newMutexKV() mkv.Lock("foo") mkv.Unlock("foo") @@ -53,7 +53,7 @@ func TestMutexKVUnlock(t *testing.T) { func TestMutexKVDifferentKeys(t *testing.T) { t.Parallel() - mkv := NewMutexKV() + mkv := newMutexKV() mkv.Lock("foo") diff --git a/internal/errs/errs.go b/internal/errs/errs.go index 55486fa734c..ad97d780980 100644 --- a/internal/errs/errs.go +++ b/internal/errs/errs.go @@ -7,20 +7,33 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" ) -// Messager is a simple interface for types with ErrorMessage(). -type Messager interface { +// errorMessager is a simple interface for types with ErrorMessage(). +type errorMessager interface { ErrorMessage() string } func AsContains(err error, target any, message string) bool { if errors.As(err, target) { - if v, ok := target.(Messager); ok && strings.Contains(v.ErrorMessage(), message) { + if v, ok := target.(errorMessager); ok && strings.Contains(v.ErrorMessage(), message) { return true } } return false } +// IsAErrorMessageContains returns whether or not the specified error is of the specified type +// and its ErrorMessage() value contains the specified needle. +func IsAErrorMessageContains[T interface { + error + errorMessager +}](err error, needle string) bool { + as, ok := As[T](err) + if ok { + return strings.Contains(as.ErrorMessage(), needle) + } + return false +} + // Contains returns true if the error matches all these conditions: // - err as string contains needle func Contains(err error, needle string) bool { diff --git a/internal/errs/errs_test.go b/internal/errs/errs_test.go new file mode 100644 index 00000000000..f4f05d45e67 --- /dev/null +++ b/internal/errs/errs_test.go @@ -0,0 +1,50 @@ +package errs_test + +import ( + "testing" + + "github.com/hashicorp/terraform-provider-aws/internal/errs" +) + +type Error1 struct{} + +func (e Error1) Error() string { + return "Error1 Error" +} + +func (e Error1) ErrorMessage() string { + return "Error1 ErrorMessage" +} + +type Error2 struct{} + +func (e *Error2) Error() string { + return "Error2 Error" +} + +func (e *Error2) ErrorMessage() string { + return "Error2 ErrorMessage" +} + +func TestIsAErrorMessageContains(t *testing.T) { + t.Parallel() + + var e1 Error1 + var e2 Error2 + + if !errs.IsAErrorMessageContains[Error1](e1, "Error1") { + t.Error("unexpected false") + } + + if errs.IsAErrorMessageContains[Error1](e1, "Error2") { + t.Error("unexpected true") + } + + if errs.IsAErrorMessageContains[*Error2](e1, "Error1") { + t.Error("unexpected true") + } + + if !errs.IsAErrorMessageContains[*Error2](&e2, "Error2") { + t.Error("unexpected false") + } +} diff --git a/internal/generate/awsclient/file.tmpl b/internal/generate/awsclient/file.tmpl index b881be08843..e4d183ffa41 100644 --- a/internal/generate/awsclient/file.tmpl +++ b/internal/generate/awsclient/file.tmpl @@ -2,6 +2,8 @@ package conns import ( + "net/http" + {{ range .Services }} {{- if eq .SDKVersion "1" }} "github.com/aws/aws-sdk-go/service/{{ .GoV1Package }}" @@ -30,7 +32,7 @@ type AWSClient struct { Session *session.Session TerraformVersion string - s3ConnURICleaningDisabled *s3.S3 + httpClient *http.Client {{ range .Services }} {{- if ne .SDKVersion "1,2" }}{{continue}}{{- end }} @@ -44,6 +46,8 @@ type AWSClient struct { {{ .ProviderPackage }}Client *{{ .GoV2Package }}.{{ .ClientTypeName }} {{- end }} {{- end }} + + s3ConnURICleaningDisabled *s3.S3 } {{ range .Services }} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 5a6e18ae7e6..f8d463cef74 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -2033,7 +2033,6 @@ func New(ctx context.Context) (*schema.Provider, error) { "aws_sagemaker_workforce": sagemaker.ResourceWorkforce(), "aws_sagemaker_workteam": sagemaker.ResourceWorkteam(), - "aws_scheduler_schedule": scheduler.ResourceSchedule(), "aws_scheduler_schedule_group": scheduler.ResourceScheduleGroup(), "aws_schemas_discoverer": schemas.ResourceDiscoverer(), @@ -2297,9 +2296,14 @@ func New(ctx context.Context) (*schema.Provider, error) { // Set the provider Meta (instance data) here. // It will be overwritten by the result of the call to ConfigureContextFunc, // but can be used pre-configuration by other (non-primary) provider servers. - provider.SetMeta(&conns.AWSClient{ - ServicePackages: servicePackages, - }) + var meta *conns.AWSClient + if v, ok := provider.Meta().(*conns.AWSClient); ok { + meta = v + } else { + meta = new(conns.AWSClient) + } + meta.ServicePackages = servicePackages + provider.SetMeta(meta) return provider, nil } @@ -2395,7 +2399,13 @@ func configure(ctx context.Context, provider *schema.Provider, d *schema.Resourc } } - meta, diags := config.ConfigureProvider(ctx, provider.Meta().(*conns.AWSClient)) + var meta *conns.AWSClient + if v, ok := provider.Meta().(*conns.AWSClient); ok { + meta = v + } else { + meta = new(conns.AWSClient) + } + meta, diags := config.ConfigureProvider(ctx, meta) if diags.HasError() { return nil, diags diff --git a/internal/service/logs/group_test.go b/internal/service/logs/group_test.go index 9de08fbf1ce..fc8297c72ed 100644 --- a/internal/service/logs/group_test.go +++ b/internal/service/logs/group_test.go @@ -6,30 +6,28 @@ import ( "testing" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" - sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" - "github.com/hashicorp/terraform-provider-aws/internal/conns" tflogs "github.com/hashicorp/terraform-provider-aws/internal/service/logs" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccLogsGroup_basic(t *testing.T) { - var lg cloudwatchlogs.LogGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var v cloudwatchlogs.LogGroup + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_cloudwatch_log_group.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupDestroy, + CheckDestroy: testAccCheckGroupDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "logs", fmt.Sprintf("log-group:%s", rName)), resource.TestCheckResourceAttr(resourceName, "kms_key_id", ""), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -50,19 +48,19 @@ func TestAccLogsGroup_basic(t *testing.T) { } func TestAccLogsGroup_nameGenerate(t *testing.T) { - var lg cloudwatchlogs.LogGroup + var v cloudwatchlogs.LogGroup resourceName := "aws_cloudwatch_log_group.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupDestroy, + CheckDestroy: testAccCheckGroupDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_nameGenerated(), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), acctest.CheckResourceAttrNameGenerated(resourceName, "name"), resource.TestCheckResourceAttr(resourceName, "name_prefix", resource.UniqueIdPrefix), ), @@ -78,19 +76,19 @@ func TestAccLogsGroup_nameGenerate(t *testing.T) { } func TestAccLogsGroup_namePrefix(t *testing.T) { - var lg cloudwatchlogs.LogGroup + var v cloudwatchlogs.LogGroup resourceName := "aws_cloudwatch_log_group.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupDestroy, + CheckDestroy: testAccCheckGroupDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_namePrefix("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), acctest.CheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), ), @@ -106,20 +104,20 @@ func TestAccLogsGroup_namePrefix(t *testing.T) { } func TestAccLogsGroup_disappears(t *testing.T) { - var lg cloudwatchlogs.LogGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var v cloudwatchlogs.LogGroup + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_cloudwatch_log_group.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupDestroy, + CheckDestroy: testAccCheckGroupDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), acctest.CheckResourceDisappears(acctest.Provider, tflogs.ResourceGroup(), resourceName), ), ExpectNonEmptyPlan: true, @@ -129,20 +127,20 @@ func TestAccLogsGroup_disappears(t *testing.T) { } func TestAccLogsGroup_tags(t *testing.T) { - var lg cloudwatchlogs.LogGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var v cloudwatchlogs.LogGroup + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_cloudwatch_log_group.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupDestroy, + CheckDestroy: testAccCheckGroupDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_tags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), @@ -156,7 +154,7 @@ func TestAccLogsGroup_tags(t *testing.T) { { Config: testAccGroupConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), @@ -165,7 +163,7 @@ func TestAccLogsGroup_tags(t *testing.T) { { Config: testAccGroupConfig_tags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), @@ -175,22 +173,22 @@ func TestAccLogsGroup_tags(t *testing.T) { } func TestAccLogsGroup_kmsKey(t *testing.T) { - var lg cloudwatchlogs.LogGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var v cloudwatchlogs.LogGroup + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_cloudwatch_log_group.test" kmsKey1ResourceName := "aws_kms_key.test.0" kmsKey2ResourceName := "aws_kms_key.test.1" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupDestroy, + CheckDestroy: testAccCheckGroupDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_kmsKey(rName, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttrPair(resourceName, "kms_key_id", kmsKey1ResourceName, "arn"), ), }, @@ -203,14 +201,14 @@ func TestAccLogsGroup_kmsKey(t *testing.T) { { Config: testAccGroupConfig_kmsKey(rName, 1), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttrPair(resourceName, "kms_key_id", kmsKey2ResourceName, "arn"), ), }, { Config: testAccGroupConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "kms_key_id", ""), ), }, @@ -219,20 +217,20 @@ func TestAccLogsGroup_kmsKey(t *testing.T) { } func TestAccLogsGroup_retentionPolicy(t *testing.T) { - var lg cloudwatchlogs.LogGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var v cloudwatchlogs.LogGroup + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_cloudwatch_log_group.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupDestroy, + CheckDestroy: testAccCheckGroupDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_retentionPolicy(rName, 365), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "retention_in_days", "365"), ), }, @@ -245,7 +243,7 @@ func TestAccLogsGroup_retentionPolicy(t *testing.T) { { Config: testAccGroupConfig_retentionPolicy(rName, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "retention_in_days", "0"), ), }, @@ -254,24 +252,24 @@ func TestAccLogsGroup_retentionPolicy(t *testing.T) { } func TestAccLogsGroup_multiple(t *testing.T) { - var lg cloudwatchlogs.LogGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var v1, v2, v3 cloudwatchlogs.LogGroup + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resource1Name := "aws_cloudwatch_log_group.test.0" resource2Name := "aws_cloudwatch_log_group.test.1" resource3Name := "aws_cloudwatch_log_group.test.2" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupDestroy, + CheckDestroy: testAccCheckGroupDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_multiple(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resource1Name, &lg), - testAccCheckGroupExists(resource2Name, &lg), - testAccCheckGroupExists(resource3Name, &lg), + testAccCheckGroupExists(t, resource1Name, &v1), + testAccCheckGroupExists(t, resource2Name, &v2), + testAccCheckGroupExists(t, resource3Name, &v3), ), }, }, @@ -279,20 +277,20 @@ func TestAccLogsGroup_multiple(t *testing.T) { } func TestAccLogsGroup_skipDestroy(t *testing.T) { - var lg cloudwatchlogs.LogGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + var v cloudwatchlogs.LogGroup + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_cloudwatch_log_group.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, ErrorCheck: acctest.ErrorCheck(t, cloudwatchlogs.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckGroupNoDestroy, + CheckDestroy: testAccCheckGroupNoDestroy(t), Steps: []resource.TestStep{ { Config: testAccGroupConfig_skipDestroy(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckGroupExists(resourceName, &lg), + testAccCheckGroupExists(t, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "skip_destroy", "true"), ), }, @@ -300,7 +298,7 @@ func TestAccLogsGroup_skipDestroy(t *testing.T) { }) } -func testAccCheckGroupExists(n string, v *cloudwatchlogs.LogGroup) resource.TestCheckFunc { +func testAccCheckGroupExists(t *testing.T, n string, v *cloudwatchlogs.LogGroup) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -311,7 +309,7 @@ func testAccCheckGroupExists(n string, v *cloudwatchlogs.LogGroup) resource.Test return fmt.Errorf("No CloudWatch Logs Log Group ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).LogsConn() + conn := acctest.ProviderMeta(t).LogsConn() output, err := tflogs.FindLogGroupByName(context.Background(), conn, rs.Primary.ID) @@ -325,44 +323,48 @@ func testAccCheckGroupExists(n string, v *cloudwatchlogs.LogGroup) resource.Test } } -func testAccCheckGroupDestroy(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).LogsConn() +func testAccCheckGroupDestroy(t *testing.T) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.ProviderMeta(t).LogsConn() - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_cloudwatch_log_group" { - continue - } + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudwatch_log_group" { + continue + } - _, err := tflogs.FindLogGroupByName(context.Background(), conn, rs.Primary.ID) + _, err := tflogs.FindLogGroupByName(context.Background(), conn, rs.Primary.ID) - if tfresource.NotFound(err) { - continue - } + if tfresource.NotFound(err) { + continue + } - if err != nil { - return err + if err != nil { + return err + } + + return fmt.Errorf("CloudWatch Logs Log Group still exists: %s", rs.Primary.ID) } - return fmt.Errorf("CloudWatch Logs Log Group still exists: %s", rs.Primary.ID) + return nil } - - return nil } -func testAccCheckGroupNoDestroy(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).LogsConn() +func testAccCheckGroupNoDestroy(t *testing.T) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.ProviderMeta(t).LogsConn() - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_cloudwatch_log_group" { - continue - } + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_cloudwatch_log_group" { + continue + } - _, err := tflogs.FindLogGroupByName(context.Background(), conn, rs.Primary.ID) + _, err := tflogs.FindLogGroupByName(context.Background(), conn, rs.Primary.ID) - return err - } + return err + } - return nil + return nil + } } func testAccGroupConfig_basic(rName string) string { diff --git a/internal/service/logs/stream_test.go b/internal/service/logs/stream_test.go index 31fcff6df91..fbf989e8967 100644 --- a/internal/service/logs/stream_test.go +++ b/internal/service/logs/stream_test.go @@ -67,7 +67,6 @@ func TestAccLogsStream_disappears(t *testing.T) { func TestAccLogsStream_Disappears_logGroup(t *testing.T) { var ls cloudwatchlogs.LogStream - var lg cloudwatchlogs.LogGroup resourceName := "aws_cloudwatch_log_stream.test" logGroupResourceName := "aws_cloudwatch_log_group.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -82,7 +81,6 @@ func TestAccLogsStream_Disappears_logGroup(t *testing.T) { Config: testAccStreamConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckStreamExists(resourceName, &ls), - testAccCheckGroupExists(logGroupResourceName, &lg), acctest.CheckResourceDisappears(acctest.Provider, tflogs.ResourceGroup(), logGroupResourceName), ), ExpectNonEmptyPlan: true, diff --git a/internal/service/logs/subscription_filter_test.go b/internal/service/logs/subscription_filter_test.go index 0d298405738..a419bb761c0 100644 --- a/internal/service/logs/subscription_filter_test.go +++ b/internal/service/logs/subscription_filter_test.go @@ -92,7 +92,6 @@ func TestAccLogsSubscriptionFilter_disappears(t *testing.T) { func TestAccLogsSubscriptionFilter_Disappears_logGroup(t *testing.T) { var filter cloudwatchlogs.SubscriptionFilter - var logGroup cloudwatchlogs.LogGroup logGroupResourceName := "aws_cloudwatch_log_group.test" resourceName := "aws_cloudwatch_log_subscription_filter.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -107,7 +106,6 @@ func TestAccLogsSubscriptionFilter_Disappears_logGroup(t *testing.T) { Config: testAccSubscriptionFilterConfig_destinationARNLambda(rName), Check: resource.ComposeTestCheckFunc( testAccCheckSubscriptionFilterExists(resourceName, &filter), - testAccCheckGroupExists(logGroupResourceName, &logGroup), acctest.CheckResourceDisappears(acctest.Provider, tflogs.ResourceGroup(), logGroupResourceName), ), ExpectNonEmptyPlan: true, diff --git a/internal/service/scheduler/exports_test.go b/internal/service/scheduler/exports_test.go new file mode 100644 index 00000000000..56dacaccb30 --- /dev/null +++ b/internal/service/scheduler/exports_test.go @@ -0,0 +1,7 @@ +package scheduler + +// Exports for use in tests only. +var ( + FindScheduleByTwoPartKey = findScheduleByTwoPartKey + ResourceSchedule = resourceSchedule +) diff --git a/internal/service/scheduler/find.go b/internal/service/scheduler/find.go index 1c04e08f350..da4873c97f4 100644 --- a/internal/service/scheduler/find.go +++ b/internal/service/scheduler/find.go @@ -11,31 +11,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -func findScheduleByGroupAndName(ctx context.Context, conn *scheduler.Client, groupName, scheduleName string) (*scheduler.GetScheduleOutput, error) { - in := &scheduler.GetScheduleInput{ - Name: aws.String(scheduleName), - GroupName: aws.String(groupName), - } - out, err := conn.GetSchedule(ctx, in) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil, &resource.NotFoundError{ - LastError: err, - LastRequest: in, - } - } - - return nil, err - } - - if out == nil || out.Arn == nil { - return nil, tfresource.NewEmptyResultError(in) - } - - return out, nil -} - func findScheduleGroupByName(ctx context.Context, conn *scheduler.Client, name string) (*scheduler.GetScheduleGroupOutput, error) { in := &scheduler.GetScheduleGroupInput{ Name: aws.String(name), diff --git a/internal/service/scheduler/retry.go b/internal/service/scheduler/retry.go index 48dd54fa136..7435e8b35c6 100644 --- a/internal/service/scheduler/retry.go +++ b/internal/service/scheduler/retry.go @@ -2,11 +2,10 @@ package scheduler import ( "context" - "errors" - "strings" "time" "github.com/aws/aws-sdk-go-v2/service/scheduler/types" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) @@ -22,13 +21,7 @@ func retryWhenIAMNotPropagated[T any](ctx context.Context, f func() (T, error)) return f() }, func(err error) (bool, error) { - var ex *types.ValidationException - - if !errors.As(err, &ex) { - return false, err - } - - if strings.Contains(ex.ErrorMessage(), "The execution role you provide must allow AWS EventBridge Scheduler to assume the role.") { + if errs.IsAErrorMessageContains[*types.ValidationException](err, "The execution role you provide must allow AWS EventBridge Scheduler to assume the role.") { return true, err } diff --git a/internal/service/scheduler/schedule.go b/internal/service/scheduler/schedule.go index 68ba483afcc..b7eaa3b29f8 100644 --- a/internal/service/scheduler/schedule.go +++ b/internal/service/scheduler/schedule.go @@ -21,13 +21,18 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) -func ResourceSchedule() *schema.Resource { +func init() { + _sp.registerSDKResourceFactory("aws_scheduler_schedule", resourceSchedule) +} + +func resourceSchedule() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceScheduleCreate, ReadWithoutTimeout: resourceScheduleRead, @@ -512,7 +517,7 @@ func resourceScheduleRead(ctx context.Context, d *schema.ResourceData, meta inte return create.DiagError(names.Scheduler, create.ErrActionReading, ResNameSchedule, d.Id(), fmt.Errorf("invalid resource id: %w", err)) } - out, err := findScheduleByGroupAndName(ctx, conn, groupName, scheduleName) + out, err := findScheduleByTwoPartKey(ctx, conn, groupName, scheduleName) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] EventBridge Scheduler Schedule (%s) not found, removing from state", d.Id()) @@ -637,6 +642,32 @@ func resourceScheduleDelete(ctx context.Context, d *schema.ResourceData, meta in return nil } +func findScheduleByTwoPartKey(ctx context.Context, conn *scheduler.Client, groupName, scheduleName string) (*scheduler.GetScheduleOutput, error) { + in := &scheduler.GetScheduleInput{ + GroupName: aws.String(groupName), + Name: aws.String(scheduleName), + } + + out, err := conn.GetSchedule(ctx, in) + + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + if err != nil { + return nil, err + } + + if out == nil || out.Arn == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out, nil +} + // ResourceScheduleIDFromARN constructs a string of the form "group_name/schedule_name" // from the given Schedule ARN. func ResourceScheduleIDFromARN(arn string) (id string, err error) { diff --git a/internal/service/scheduler/schedule_test.go b/internal/service/scheduler/schedule_test.go index 362dae64043..a1bcc95cc78 100644 --- a/internal/service/scheduler/schedule_test.go +++ b/internal/service/scheduler/schedule_test.go @@ -5,19 +5,15 @@ import ( "errors" "fmt" "regexp" - "strings" "testing" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/scheduler" - "github.com/aws/aws-sdk-go-v2/service/scheduler/types" - sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" - "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" tfscheduler "github.com/hashicorp/terraform-provider-aws/internal/service/scheduler" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -183,10 +179,10 @@ func TestAccSchedulerSchedule_basic(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -194,12 +190,12 @@ func TestAccSchedulerSchedule_basic(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "scheduler", regexp.MustCompile(regexp.QuoteMeta(`schedule/default/`+name))), resource.TestCheckResourceAttr(resourceName, "description", ""), resource.TestCheckResourceAttr(resourceName, "end_date", ""), @@ -241,10 +237,10 @@ func TestAccSchedulerSchedule_disappears(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -252,12 +248,12 @@ func TestAccSchedulerSchedule_disappears(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), acctest.CheckResourceDisappears(acctest.Provider, tfscheduler.ResourceSchedule(), resourceName), ), ExpectNonEmptyPlan: true, @@ -272,10 +268,10 @@ func TestAccSchedulerSchedule_description(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -283,12 +279,12 @@ func TestAccSchedulerSchedule_description(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_description(name, "test 1"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "description", "test 1"), ), }, @@ -300,7 +296,7 @@ func TestAccSchedulerSchedule_description(t *testing.T) { { Config: testAccScheduleConfig_description(name, "test 2"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "description", "test 2"), ), }, @@ -312,7 +308,7 @@ func TestAccSchedulerSchedule_description(t *testing.T) { { Config: testAccScheduleConfig_description(name, ""), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "description", ""), ), }, @@ -331,10 +327,10 @@ func TestAccSchedulerSchedule_endDate(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -342,12 +338,12 @@ func TestAccSchedulerSchedule_endDate(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_endDate(name, "2100-01-01T01:02:03Z"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "end_date", "2100-01-01T01:02:03Z"), ), }, @@ -359,7 +355,7 @@ func TestAccSchedulerSchedule_endDate(t *testing.T) { { Config: testAccScheduleConfig_endDate(name, "2099-01-01T01:00:00Z"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "end_date", "2099-01-01T01:00:00Z"), ), }, @@ -371,7 +367,7 @@ func TestAccSchedulerSchedule_endDate(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "end_date", ""), ), }, @@ -390,10 +386,10 @@ func TestAccSchedulerSchedule_flexibleTimeWindow(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -401,12 +397,12 @@ func TestAccSchedulerSchedule_flexibleTimeWindow(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_flexibleTimeWindow(name, 10), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "flexible_time_window.0.maximum_window_in_minutes", "10"), resource.TestCheckResourceAttr(resourceName, "flexible_time_window.0.mode", "FLEXIBLE"), ), @@ -419,7 +415,7 @@ func TestAccSchedulerSchedule_flexibleTimeWindow(t *testing.T) { { Config: testAccScheduleConfig_flexibleTimeWindow(name, 20), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "flexible_time_window.0.maximum_window_in_minutes", "20"), resource.TestCheckResourceAttr(resourceName, "flexible_time_window.0.mode", "FLEXIBLE"), ), @@ -432,7 +428,7 @@ func TestAccSchedulerSchedule_flexibleTimeWindow(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "flexible_time_window.0.maximum_window_in_minutes", "0"), resource.TestCheckResourceAttr(resourceName, "flexible_time_window.0.mode", "OFF"), ), @@ -452,10 +448,10 @@ func TestAccSchedulerSchedule_groupName(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -463,12 +459,12 @@ func TestAccSchedulerSchedule_groupName(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_groupName(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "group_name", "aws_scheduler_schedule_group.test", "name"), ), }, @@ -487,10 +483,10 @@ func TestAccSchedulerSchedule_kmsKeyARN(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -498,12 +494,12 @@ func TestAccSchedulerSchedule_kmsKeyARN(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_kmsKeyARN(name, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "kms_key_arn", "aws_kms_key.test.0", "arn"), ), }, @@ -515,7 +511,7 @@ func TestAccSchedulerSchedule_kmsKeyARN(t *testing.T) { { Config: testAccScheduleConfig_kmsKeyARN(name, 1), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "kms_key_arn", "aws_kms_key.test.1", "arn"), ), }, @@ -527,7 +523,7 @@ func TestAccSchedulerSchedule_kmsKeyARN(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "kms_key_arn", ""), ), }, @@ -548,7 +544,7 @@ func TestAccSchedulerSchedule_nameGenerated(t *testing.T) { var schedule scheduler.GetScheduleOutput resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -556,12 +552,12 @@ func TestAccSchedulerSchedule_nameGenerated(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_nameGenerated(), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), acctest.CheckResourceAttrNameGenerated(resourceName, "name"), resource.TestCheckResourceAttr(resourceName, "name_prefix", resource.UniqueIdPrefix), ), @@ -583,7 +579,7 @@ func TestAccSchedulerSchedule_namePrefix(t *testing.T) { var schedule scheduler.GetScheduleOutput resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -591,12 +587,12 @@ func TestAccSchedulerSchedule_namePrefix(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_namePrefix("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), acctest.CheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), ), @@ -616,10 +612,10 @@ func TestAccSchedulerSchedule_scheduleExpression(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -627,12 +623,12 @@ func TestAccSchedulerSchedule_scheduleExpression(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_scheduleExpression(name, "rate(1 hour)"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "schedule_expression", "rate(1 hour)"), ), }, @@ -644,7 +640,7 @@ func TestAccSchedulerSchedule_scheduleExpression(t *testing.T) { { Config: testAccScheduleConfig_scheduleExpression(name, "rate(1 day)"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "schedule_expression", "rate(1 day)"), ), }, @@ -663,10 +659,10 @@ func TestAccSchedulerSchedule_scheduleExpressionTimezone(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -674,12 +670,12 @@ func TestAccSchedulerSchedule_scheduleExpressionTimezone(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_scheduleExpressionTimezone(name, "Europe/Paris"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "schedule_expression_timezone", "Europe/Paris"), ), }, @@ -691,7 +687,7 @@ func TestAccSchedulerSchedule_scheduleExpressionTimezone(t *testing.T) { { Config: testAccScheduleConfig_scheduleExpressionTimezone(name, "Australia/Sydney"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "schedule_expression_timezone", "Australia/Sydney"), ), }, @@ -703,7 +699,7 @@ func TestAccSchedulerSchedule_scheduleExpressionTimezone(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "schedule_expression_timezone", "UTC"), ), }, @@ -722,10 +718,10 @@ func TestAccSchedulerSchedule_startDate(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -733,12 +729,12 @@ func TestAccSchedulerSchedule_startDate(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_startDate(name, "2100-01-01T01:02:03Z"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "start_date", "2100-01-01T01:02:03Z"), ), }, @@ -750,7 +746,7 @@ func TestAccSchedulerSchedule_startDate(t *testing.T) { { Config: testAccScheduleConfig_startDate(name, "2099-01-01T01:00:00Z"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "start_date", "2099-01-01T01:00:00Z"), ), }, @@ -762,7 +758,7 @@ func TestAccSchedulerSchedule_startDate(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "start_date", ""), ), }, @@ -781,10 +777,10 @@ func TestAccSchedulerSchedule_state(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -792,12 +788,12 @@ func TestAccSchedulerSchedule_state(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_state(name, "ENABLED"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "state", "ENABLED"), ), }, @@ -809,7 +805,7 @@ func TestAccSchedulerSchedule_state(t *testing.T) { { Config: testAccScheduleConfig_state(name, "DISABLED"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "state", "DISABLED"), ), }, @@ -821,7 +817,7 @@ func TestAccSchedulerSchedule_state(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "state", "ENABLED"), ), }, @@ -840,10 +836,10 @@ func TestAccSchedulerSchedule_targetARN(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -851,12 +847,12 @@ func TestAccSchedulerSchedule_targetARN(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetARN(name, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "target.0.arn", "aws_sqs_queue.test.0", "arn"), ), }, @@ -868,7 +864,7 @@ func TestAccSchedulerSchedule_targetARN(t *testing.T) { { Config: testAccScheduleConfig_targetARN(name, 1), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "target.0.arn", "aws_sqs_queue.test.1", "arn"), ), }, @@ -887,10 +883,10 @@ func TestAccSchedulerSchedule_targetDeadLetterConfig(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -898,12 +894,12 @@ func TestAccSchedulerSchedule_targetDeadLetterConfig(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetDeadLetterConfig(name, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "target.0.dead_letter_config.0.arn", "aws_sqs_queue.dlq.0", "arn"), ), }, @@ -915,7 +911,7 @@ func TestAccSchedulerSchedule_targetDeadLetterConfig(t *testing.T) { { Config: testAccScheduleConfig_targetDeadLetterConfig(name, 1), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "target.0.dead_letter_config.0.arn", "aws_sqs_queue.dlq.1", "arn"), ), }, @@ -927,7 +923,7 @@ func TestAccSchedulerSchedule_targetDeadLetterConfig(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.dead_letter_config.#", "0"), ), }, @@ -946,10 +942,10 @@ func TestAccSchedulerSchedule_targetECSParameters(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -957,12 +953,12 @@ func TestAccSchedulerSchedule_targetECSParameters(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetECSParameters1(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.0.capacity_provider_strategy.#", "0"), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.0.enable_ecs_managed_tags", "false"), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.0.enable_execute_command", "false"), @@ -987,7 +983,7 @@ func TestAccSchedulerSchedule_targetECSParameters(t *testing.T) { { Config: testAccScheduleConfig_targetECSParameters2(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.0.capacity_provider_strategy.#", "2"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "target.0.ecs_parameters.0.capacity_provider_strategy.*", map[string]string{ "base": "2", @@ -1034,7 +1030,7 @@ func TestAccSchedulerSchedule_targetECSParameters(t *testing.T) { { Config: testAccScheduleConfig_targetECSParameters3(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.0.capacity_provider_strategy.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "target.0.ecs_parameters.0.capacity_provider_strategy.*", map[string]string{ "base": "3", @@ -1076,7 +1072,7 @@ func TestAccSchedulerSchedule_targetECSParameters(t *testing.T) { { Config: testAccScheduleConfig_targetECSParameters4(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.0.capacity_provider_strategy.#", "0"), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.0.enable_ecs_managed_tags", "false"), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.0.enable_execute_command", "false"), @@ -1101,7 +1097,7 @@ func TestAccSchedulerSchedule_targetECSParameters(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.ecs_parameters.#", "0"), ), }, @@ -1120,11 +1116,11 @@ func TestAccSchedulerSchedule_targetEventBridgeParameters(t *testing.T) { } var schedule scheduler.GetScheduleOutput - scheduleName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - eventBusName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + scheduleName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + eventBusName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -1132,12 +1128,12 @@ func TestAccSchedulerSchedule_targetEventBridgeParameters(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetEventBridgeParameters(scheduleName, eventBusName, "test-1", "tf.test.1"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.eventbridge_parameters.0.detail_type", "test-1"), resource.TestCheckResourceAttr(resourceName, "target.0.eventbridge_parameters.0.source", "tf.test.1"), ), @@ -1150,7 +1146,7 @@ func TestAccSchedulerSchedule_targetEventBridgeParameters(t *testing.T) { { Config: testAccScheduleConfig_targetEventBridgeParameters(scheduleName, eventBusName, "test-2", "tf.test.2"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.eventbridge_parameters.0.detail_type", "test-2"), resource.TestCheckResourceAttr(resourceName, "target.0.eventbridge_parameters.0.source", "tf.test.2"), ), @@ -1163,7 +1159,7 @@ func TestAccSchedulerSchedule_targetEventBridgeParameters(t *testing.T) { { Config: testAccScheduleConfig_basic(scheduleName), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.eventbridge_parameters.#", "0"), ), }, @@ -1182,11 +1178,11 @@ func TestAccSchedulerSchedule_targetInput(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" var queueUrl string - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -1194,12 +1190,12 @@ func TestAccSchedulerSchedule_targetInput(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetInput(name, "test1"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrWith("aws_sqs_queue.test", "url", func(value string) error { queueUrl = value return nil @@ -1221,7 +1217,7 @@ func TestAccSchedulerSchedule_targetInput(t *testing.T) { { Config: testAccScheduleConfig_targetInput(name, "test2"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), func(s *terraform.State) error { return acctest.CheckResourceAttrEquivalentJSON( resourceName, @@ -1246,11 +1242,11 @@ func TestAccSchedulerSchedule_targetKinesisParameters(t *testing.T) { } var schedule scheduler.GetScheduleOutput - scheduleName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - streamName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + scheduleName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + streamName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -1258,12 +1254,12 @@ func TestAccSchedulerSchedule_targetKinesisParameters(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetKinesisParameters(scheduleName, streamName, "test-1"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.kinesis_parameters.0.partition_key", "test-1"), ), }, @@ -1275,7 +1271,7 @@ func TestAccSchedulerSchedule_targetKinesisParameters(t *testing.T) { { Config: testAccScheduleConfig_targetKinesisParameters(scheduleName, streamName, "test-2"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.kinesis_parameters.0.partition_key", "test-2"), ), }, @@ -1287,7 +1283,7 @@ func TestAccSchedulerSchedule_targetKinesisParameters(t *testing.T) { { Config: testAccScheduleConfig_basic(scheduleName), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.kinesis_parameters.#", "0"), ), }, @@ -1306,10 +1302,10 @@ func TestAccSchedulerSchedule_targetRetryPolicy(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -1317,12 +1313,12 @@ func TestAccSchedulerSchedule_targetRetryPolicy(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetRetryPolicy(name, 60, 1), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.retry_policy.0.maximum_event_age_in_seconds", "60"), resource.TestCheckResourceAttr(resourceName, "target.0.retry_policy.0.maximum_retry_attempts", "1"), ), @@ -1335,7 +1331,7 @@ func TestAccSchedulerSchedule_targetRetryPolicy(t *testing.T) { { Config: testAccScheduleConfig_targetRetryPolicy(name, 61, 0), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.retry_policy.0.maximum_event_age_in_seconds", "61"), resource.TestCheckResourceAttr(resourceName, "target.0.retry_policy.0.maximum_retry_attempts", "0"), ), @@ -1348,7 +1344,7 @@ func TestAccSchedulerSchedule_targetRetryPolicy(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.retry_policy.0.maximum_event_age_in_seconds", "86400"), resource.TestCheckResourceAttr(resourceName, "target.0.retry_policy.0.maximum_retry_attempts", "185"), ), @@ -1368,10 +1364,10 @@ func TestAccSchedulerSchedule_targetRoleARN(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -1379,12 +1375,12 @@ func TestAccSchedulerSchedule_targetRoleARN(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetRoleARN(name, "test"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "target.0.role_arn", "aws_iam_role.test", "arn"), ), }, @@ -1396,7 +1392,7 @@ func TestAccSchedulerSchedule_targetRoleARN(t *testing.T) { { Config: testAccScheduleConfig_targetRoleARN(name, "test1"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttrPair(resourceName, "target.0.role_arn", "aws_iam_role.test1", "arn"), ), }, @@ -1415,10 +1411,10 @@ func TestAccSchedulerSchedule_targetSageMakerPipelineParameters(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -1426,12 +1422,12 @@ func TestAccSchedulerSchedule_targetSageMakerPipelineParameters(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetSageMakerPipelineParameters1(name, "key1", "value1"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.sagemaker_pipeline_parameters.0.pipeline_parameter.#", "1"), resource.TestCheckTypeSetElemNestedAttrs( resourceName, "target.0.sagemaker_pipeline_parameters.0.pipeline_parameter.*", @@ -1449,7 +1445,7 @@ func TestAccSchedulerSchedule_targetSageMakerPipelineParameters(t *testing.T) { { Config: testAccScheduleConfig_targetSageMakerPipelineParameters2(name, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.sagemaker_pipeline_parameters.0.pipeline_parameter.#", "2"), resource.TestCheckTypeSetElemNestedAttrs( resourceName, "target.0.sagemaker_pipeline_parameters.0.pipeline_parameter.*", @@ -1473,7 +1469,7 @@ func TestAccSchedulerSchedule_targetSageMakerPipelineParameters(t *testing.T) { { Config: testAccScheduleConfig_targetSageMakerPipelineParameters1(name, "key2", "value2"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.sagemaker_pipeline_parameters.0.pipeline_parameter.#", "1"), resource.TestCheckTypeSetElemNestedAttrs( resourceName, "target.0.sagemaker_pipeline_parameters.0.pipeline_parameter.*", @@ -1491,7 +1487,7 @@ func TestAccSchedulerSchedule_targetSageMakerPipelineParameters(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.sagemaker_pipeline_parameters.#", "0"), ), }, @@ -1510,10 +1506,10 @@ func TestAccSchedulerSchedule_targetSQSParameters(t *testing.T) { } var schedule scheduler.GetScheduleOutput - name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + name := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) resourceName := "aws_scheduler_schedule.test" - resource.ParallelTest(t, resource.TestCase{ + acctest.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) acctest.PreCheckPartitionHasService(names.SchedulerEndpointID, t) @@ -1521,12 +1517,12 @@ func TestAccSchedulerSchedule_targetSQSParameters(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.SchedulerEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckScheduleDestroy, + CheckDestroy: testAccCheckScheduleDestroy(t), Steps: []resource.TestStep{ { Config: testAccScheduleConfig_targetSQSParameters(name, "test1"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.sqs_parameters.0.message_group_id", "test1"), ), }, @@ -1538,7 +1534,7 @@ func TestAccSchedulerSchedule_targetSQSParameters(t *testing.T) { { Config: testAccScheduleConfig_targetSQSParameters(name, "test2"), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.sqs_parameters.0.message_group_id", "test2"), ), }, @@ -1550,7 +1546,7 @@ func TestAccSchedulerSchedule_targetSQSParameters(t *testing.T) { { Config: testAccScheduleConfig_basic(name), Check: resource.ComposeTestCheckFunc( - testAccCheckScheduleExists(resourceName, &schedule), + testAccCheckScheduleExists(t, resourceName, &schedule), resource.TestCheckResourceAttr(resourceName, "target.0.sqs_parameters.#", "0"), ), }, @@ -1563,37 +1559,40 @@ func TestAccSchedulerSchedule_targetSQSParameters(t *testing.T) { }) } -func testAccCheckScheduleDestroy(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).SchedulerClient() - ctx := context.Background() +func testAccCheckScheduleDestroy(t *testing.T) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.ProviderMeta(t).SchedulerClient() + ctx := context.Background() - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_scheduler_schedule" { - continue - } + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_scheduler_schedule" { + continue + } - parts := strings.Split(rs.Primary.ID, "/") + groupName, scheduleName, err := tfscheduler.ResourceScheduleParseID(rs.Primary.ID) - input := &scheduler.GetScheduleInput{ - GroupName: aws.String(parts[0]), - Name: aws.String(parts[1]), - } - _, err := conn.GetSchedule(ctx, input) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil + if err != nil { + return err } - return err + + _, err = tfscheduler.FindScheduleByTwoPartKey(ctx, conn, groupName, scheduleName) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("%s %s %s still exists", names.Scheduler, tfscheduler.ResNameSchedule, rs.Primary.ID) } - return create.Error(names.Scheduler, create.ErrActionCheckingDestroyed, tfscheduler.ResNameSchedule, rs.Primary.ID, errors.New("not destroyed")) + return nil } - - return nil } -func testAccCheckScheduleExists(name string, schedule *scheduler.GetScheduleOutput) resource.TestCheckFunc { +func testAccCheckScheduleExists(t *testing.T, name string, v *scheduler.GetScheduleOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] if !ok { @@ -1604,20 +1603,22 @@ func testAccCheckScheduleExists(name string, schedule *scheduler.GetScheduleOutp return create.Error(names.Scheduler, create.ErrActionCheckingExistence, tfscheduler.ResNameSchedule, name, errors.New("not set")) } - parts := strings.Split(rs.Primary.ID, "/") + groupName, scheduleName, err := tfscheduler.ResourceScheduleParseID(rs.Primary.ID) - conn := acctest.Provider.Meta().(*conns.AWSClient).SchedulerClient() + if err != nil { + return err + } + + conn := acctest.ProviderMeta(t).SchedulerClient() ctx := context.Background() - resp, err := conn.GetSchedule(ctx, &scheduler.GetScheduleInput{ - Name: aws.String(parts[1]), - GroupName: aws.String(parts[0]), - }) + + output, err := tfscheduler.FindScheduleByTwoPartKey(ctx, conn, groupName, scheduleName) if err != nil { - return create.Error(names.Scheduler, create.ErrActionCheckingExistence, tfscheduler.ResNameSchedule, rs.Primary.ID, err) + return err } - *schedule = *resp + *v = *output return nil } diff --git a/internal/service/scheduler/sweep.go b/internal/service/scheduler/sweep.go index c0ac40d1228..857e4cad369 100644 --- a/internal/service/scheduler/sweep.go +++ b/internal/service/scheduler/sweep.go @@ -105,7 +105,7 @@ func sweepSchedules(region string) error { groupName := aws.ToString(it.GroupName) scheduleName := aws.ToString(it.Name) - r := ResourceSchedule() + r := resourceSchedule() d := r.Data(nil) d.SetId(fmt.Sprintf("%s/%s", groupName, scheduleName))