fix: abstract OS file functions (#6)
Signed-off-by: matttrach <matt.trachier@suse.com>
This commit is contained in:
parent
31c5a03e8f
commit
3ad0663037
|
|
@ -34,7 +34,7 @@ resource "file_local" "example" {
|
||||||
- `directory` (String) The directory where the file will be placed, defaults to the current working directory.
|
- `directory` (String) The directory where the file will be placed, defaults to the current working directory.
|
||||||
- `hmac_secret_key` (String, Sensitive) A string used to generate the file identifier, you can pass this value in the environment variable `TF_FILE_HMAC_SECRET_KEY`.The provider will use a hard coded value as the secret key for unprotected files.
|
- `hmac_secret_key` (String, Sensitive) A string used to generate the file identifier, you can pass this value in the environment variable `TF_FILE_HMAC_SECRET_KEY`.The provider will use a hard coded value as the secret key for unprotected files.
|
||||||
- `id` (String) Identifier derived from sha256+HMAC hash of file contents. When setting 'protected' to true this argument is required. However, when 'protected' is false then this should be left empty (computed by the provider).
|
- `id` (String) Identifier derived from sha256+HMAC hash of file contents. When setting 'protected' to true this argument is required. However, when 'protected' is false then this should be left empty (computed by the provider).
|
||||||
- `mode` (String) The file permissions to assign to the file, defaults to '0600'.
|
- `permissions` (String) The file permissions to assign to the file, defaults to '0600'.
|
||||||
- `protected` (Boolean) Whether or not to fail update or create if the calculated id doesn't match the given id.When this is true, the 'id' field is required and must match what we calculate as the hash at both create and update times.If the 'id' configured doesn't match what we calculate then the provider will error rather than updating or creating the file.When setting this to true, you will need to either set the `TF_FILE_HMAC_SECRET_KEY` environment variable or set the hmac_secret_key argument.
|
- `protected` (Boolean) Whether or not to fail update or create if the calculated id doesn't match the given id.When this is true, the 'id' field is required and must match what we calculate as the hash at both create and update times.If the 'id' configured doesn't match what we calculate then the provider will error rather than updating or creating the file.When setting this to true, you will need to either set the `TF_FILE_HMAC_SECRET_KEY` environment variable or set the hmac_secret_key argument.
|
||||||
|
|
||||||
## Import
|
## Import
|
||||||
|
|
|
||||||
|
|
@ -34,20 +34,73 @@ import (
|
||||||
var _ resource.Resource = &LocalResource{}
|
var _ resource.Resource = &LocalResource{}
|
||||||
var _ resource.ResourceWithImportState = &LocalResource{}
|
var _ resource.ResourceWithImportState = &LocalResource{}
|
||||||
|
|
||||||
// type FileClient struct{}
|
// An interface for defining custom file managers.
|
||||||
|
type fileClient interface {
|
||||||
|
Create(directory string, name string, data string, permissions string) error
|
||||||
|
// If file isn't found the error message must have err.Error() == "file not found"
|
||||||
|
Read(directory string, name string) (string, string, error) // permissions, contents, error
|
||||||
|
Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error
|
||||||
|
Delete(directory string, name string) error
|
||||||
|
}
|
||||||
|
|
||||||
// func (f *FileClient) Create() {}
|
// The default fileClient, using the os package.
|
||||||
// func (f *FileClient) Read() {}
|
type osFileClient struct{}
|
||||||
// func (f *FileClient) Update() {}
|
|
||||||
// func (f *FileClient) Delete() {}
|
var _ fileClient = &osFileClient{} // make sure the osFileClient implements the fileClient
|
||||||
|
func (c *osFileClient) Create(directory string, name string, data string, permissions string) error {
|
||||||
|
path := filepath.Join(directory, name)
|
||||||
|
modeInt, err := strconv.ParseUint(permissions, 8, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.WriteFile(path, []byte(data), os.FileMode(modeInt))
|
||||||
|
}
|
||||||
|
func (c *osFileClient) Read(directory string, name string) (string, string, error) {
|
||||||
|
path := filepath.Join(directory, name)
|
||||||
|
info, err := os.Stat(path)
|
||||||
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
return "", "", fmt.Errorf("file not found")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
mode := fmt.Sprintf("%#o", info.Mode().Perm())
|
||||||
|
contents, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return mode, string(contents), nil
|
||||||
|
}
|
||||||
|
func (c *osFileClient) Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error {
|
||||||
|
currentPath := filepath.Join(currentDirectory, currentName)
|
||||||
|
newPath := filepath.Join(newDirectory, newName)
|
||||||
|
if currentPath != newPath {
|
||||||
|
err := os.Rename(currentPath, newPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modeInt, err := strconv.ParseUint(permissions, 8, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = os.WriteFile(newPath, []byte(data), os.FileMode(modeInt)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *osFileClient) Delete(directory string, name string) error {
|
||||||
|
path := filepath.Join(directory, name)
|
||||||
|
return os.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
func NewLocalResource() resource.Resource {
|
func NewLocalResource() resource.Resource {
|
||||||
return &LocalResource{}
|
return &LocalResource{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalResource defines the resource implementation.
|
type LocalResource struct {
|
||||||
// This facilitates the LocalResource class, it can now be used in functions with *LocalResource.
|
client fileClient
|
||||||
type LocalResource struct{}
|
}
|
||||||
|
|
||||||
// LocalResourceModel describes the resource data model.
|
// LocalResourceModel describes the resource data model.
|
||||||
type LocalResourceModel struct {
|
type LocalResourceModel struct {
|
||||||
|
|
@ -55,10 +108,9 @@ type LocalResourceModel struct {
|
||||||
Name types.String `tfsdk:"name"`
|
Name types.String `tfsdk:"name"`
|
||||||
Contents types.String `tfsdk:"contents"`
|
Contents types.String `tfsdk:"contents"`
|
||||||
Directory types.String `tfsdk:"directory"`
|
Directory types.String `tfsdk:"directory"`
|
||||||
Mode types.String `tfsdk:"mode"`
|
Permissions types.String `tfsdk:"permissions"`
|
||||||
HmacSecretKey types.String `tfsdk:"hmac_secret_key"`
|
HmacSecretKey types.String `tfsdk:"hmac_secret_key"`
|
||||||
Protected types.Bool `tfsdk:"protected"`
|
Protected types.Bool `tfsdk:"protected"`
|
||||||
// Fake types.Bool `tfsdk:"fake"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LocalResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
func (r *LocalResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
||||||
|
|
@ -84,7 +136,7 @@ func (r *LocalResource) Schema(ctx context.Context, req resource.SchemaRequest,
|
||||||
Computed: true, // whenever an argument has a default value it should have Computed: true
|
Computed: true, // whenever an argument has a default value it should have Computed: true
|
||||||
Default: stringdefault.StaticString("."),
|
Default: stringdefault.StaticString("."),
|
||||||
},
|
},
|
||||||
"mode": schema.StringAttribute{
|
"permissions": schema.StringAttribute{
|
||||||
MarkdownDescription: "The file permissions to assign to the file, defaults to '0600'.",
|
MarkdownDescription: "The file permissions to assign to the file, defaults to '0600'.",
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
|
|
@ -141,6 +193,10 @@ func (r *LocalResource) Configure(ctx context.Context, req resource.ConfigureReq
|
||||||
if req.ProviderData == nil {
|
if req.ProviderData == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Allow the ability to inject a file client, but use the osFileClient by default.
|
||||||
|
if r.client == nil {
|
||||||
|
r.client = &osFileClient{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should:
|
// We should:
|
||||||
|
|
@ -161,7 +217,7 @@ func (r *LocalResource) Create(ctx context.Context, req resource.CreateRequest,
|
||||||
name := plan.Name.ValueString()
|
name := plan.Name.ValueString()
|
||||||
directory := plan.Directory.ValueString()
|
directory := plan.Directory.ValueString()
|
||||||
contents := plan.Contents.ValueString()
|
contents := plan.Contents.ValueString()
|
||||||
modeString := plan.Mode.ValueString()
|
permString := plan.Permissions.ValueString()
|
||||||
hmacSecretKey := plan.HmacSecretKey.ValueString()
|
hmacSecretKey := plan.HmacSecretKey.ValueString()
|
||||||
protected := plan.Protected.ValueBool()
|
protected := plan.Protected.ValueBool()
|
||||||
|
|
||||||
|
|
@ -190,14 +246,8 @@ func (r *LocalResource) Create(ctx context.Context, req resource.CreateRequest,
|
||||||
plan.HmacSecretKey = types.StringValue("")
|
plan.HmacSecretKey = types.StringValue("")
|
||||||
}
|
}
|
||||||
|
|
||||||
localFilePath := filepath.Join(directory, name)
|
if err = r.client.Create(directory, name, contents, permString); err != nil {
|
||||||
modeInt, err := strconv.ParseUint(modeString, 8, 32)
|
resp.Diagnostics.AddError("Error creating file: ", err.Error())
|
||||||
if err != nil {
|
|
||||||
resp.Diagnostics.AddError("Error reading file mode from config: ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = os.WriteFile(localFilePath, []byte(contents), os.FileMode(modeInt)); err != nil {
|
|
||||||
resp.Diagnostics.AddError("Error writing file: ", err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -220,28 +270,24 @@ func (r *LocalResource) Read(ctx context.Context, req resource.ReadRequest, resp
|
||||||
sName := state.Name.ValueString()
|
sName := state.Name.ValueString()
|
||||||
sDirectory := state.Directory.ValueString()
|
sDirectory := state.Directory.ValueString()
|
||||||
sContents := state.Contents.ValueString()
|
sContents := state.Contents.ValueString()
|
||||||
sMode := state.Mode.ValueString()
|
sPerm := state.Permissions.ValueString()
|
||||||
sHmacSecretKey := state.HmacSecretKey.ValueString()
|
sHmacSecretKey := state.HmacSecretKey.ValueString()
|
||||||
|
|
||||||
sFilePath := filepath.Join(sDirectory, sName)
|
|
||||||
|
|
||||||
// If Possible, we should avoid reading the file into memory
|
// If Possible, we should avoid reading the file into memory
|
||||||
|
|
||||||
// The "real" (non-calculated) parts of the file are the path, the contents, and the mode
|
// The "real" (non-calculated) parts of the file are the path, the contents, and the mode
|
||||||
|
|
||||||
// If the file doesn't exist at the path, then we need to (re)create it
|
// If the file doesn't exist at the path, then we need to (re)create it
|
||||||
if _, err := os.Stat(sFilePath); os.IsNotExist(err) {
|
perm, contents, err := r.client.Read(sDirectory, sName)
|
||||||
|
if err != nil && err.Error() == "File not found." {
|
||||||
resp.State.RemoveResource(ctx)
|
resp.State.RemoveResource(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the file's contents have changed, then we need to update the state
|
|
||||||
c, err := os.ReadFile(sFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics.AddError("Error reading file: ", err.Error())
|
resp.Diagnostics.AddError("Error reading file: ", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
contents := string(c)
|
|
||||||
if contents != sContents {
|
if contents != sContents {
|
||||||
// update state with actual contents
|
// update state with actual contents
|
||||||
state.Contents = types.StringValue(contents)
|
state.Contents = types.StringValue(contents)
|
||||||
|
|
@ -260,16 +306,9 @@ func (r *LocalResource) Read(ctx context.Context, req resource.ReadRequest, resp
|
||||||
state.Id = types.StringValue(id)
|
state.Id = types.StringValue(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the file's mode has changed, then we need to update the state
|
if perm != sPerm {
|
||||||
inf, err := os.Stat(sFilePath)
|
|
||||||
if err != nil {
|
|
||||||
resp.Diagnostics.AddError("Error reading file stat: ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mode := fmt.Sprintf("%#o", inf.Mode().Perm())
|
|
||||||
if mode != sMode {
|
|
||||||
// update the state with the actual mode
|
// update the state with the actual mode
|
||||||
state.Mode = types.StringValue(mode)
|
state.Permissions = types.StringValue(perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
||||||
|
|
@ -292,12 +331,10 @@ func (r *LocalResource) Update(ctx context.Context, req resource.UpdateRequest,
|
||||||
cName := config.Name.ValueString()
|
cName := config.Name.ValueString()
|
||||||
cContents := config.Contents.ValueString()
|
cContents := config.Contents.ValueString()
|
||||||
cDirectory := config.Directory.ValueString()
|
cDirectory := config.Directory.ValueString()
|
||||||
cMode := config.Mode.ValueString()
|
cPerm := config.Permissions.ValueString()
|
||||||
cHmacSecretKey := config.HmacSecretKey.ValueString()
|
cHmacSecretKey := config.HmacSecretKey.ValueString()
|
||||||
cProtected := config.Protected.ValueBool()
|
cProtected := config.Protected.ValueBool()
|
||||||
|
|
||||||
cFilePath := filepath.Join(cDirectory, cName)
|
|
||||||
|
|
||||||
cKey := cHmacSecretKey
|
cKey := cHmacSecretKey
|
||||||
if cKey == "" {
|
if cKey == "" {
|
||||||
cKey = os.Getenv("TF_FILE_HMAC_SECRET_KEY")
|
cKey = os.Getenv("TF_FILE_HMAC_SECRET_KEY")
|
||||||
|
|
@ -318,6 +355,7 @@ func (r *LocalResource) Update(ctx context.Context, req resource.UpdateRequest,
|
||||||
config.HmacSecretKey = types.StringValue("")
|
config.HmacSecretKey = types.StringValue("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read updates state with reality, so state = reality
|
||||||
var reality LocalResourceModel
|
var reality LocalResourceModel
|
||||||
resp.Diagnostics.Append(req.State.Get(ctx, &reality)...)
|
resp.Diagnostics.Append(req.State.Get(ctx, &reality)...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -325,47 +363,13 @@ func (r *LocalResource) Update(ctx context.Context, req resource.UpdateRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
rName := reality.Name.ValueString()
|
rName := reality.Name.ValueString()
|
||||||
rContents := reality.Contents.ValueString()
|
|
||||||
rDirectory := reality.Directory.ValueString()
|
rDirectory := reality.Directory.ValueString()
|
||||||
rMode := reality.Mode.ValueString()
|
|
||||||
|
|
||||||
rFilePath := filepath.Join(rDirectory, rName)
|
err := r.client.Update(rDirectory, rName, cDirectory, cName, cContents, cPerm)
|
||||||
|
if err != nil {
|
||||||
if rFilePath != cFilePath {
|
resp.Diagnostics.AddError("Error updating file: ", err.Error())
|
||||||
// config is changing the file path, we need to move the file
|
return
|
||||||
err := os.Rename(rFilePath, cFilePath)
|
}
|
||||||
if err != nil {
|
|
||||||
resp.Diagnostics.AddError("Error moving file: ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} // the config's file path (cFilePath) is now accurate
|
|
||||||
|
|
||||||
if rMode != cMode {
|
|
||||||
// the config is changing the mode
|
|
||||||
modeInt, err := strconv.ParseUint(cMode, 8, 32)
|
|
||||||
if err != nil {
|
|
||||||
resp.Diagnostics.AddError("Error reading file mode from config: ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = os.Chmod(cFilePath, os.FileMode(modeInt))
|
|
||||||
if err != nil {
|
|
||||||
resp.Diagnostics.AddError("Error changing file mode: ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} // the config's mode (cMode) is now accurate
|
|
||||||
|
|
||||||
if cContents != rContents {
|
|
||||||
// config is changing the contents
|
|
||||||
modeInt, err := strconv.ParseUint(cMode, 8, 32)
|
|
||||||
if err != nil {
|
|
||||||
resp.Diagnostics.AddError("Error reading file mode from config: ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = os.WriteFile(cFilePath, []byte(cContents), os.FileMode(modeInt)); err != nil {
|
|
||||||
resp.Diagnostics.AddError("Error writing file: ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} // the config's contents (cContents) are now accurate
|
|
||||||
|
|
||||||
// the path, mode, and contents are all of the "real" parts of the file
|
// the path, mode, and contents are all of the "real" parts of the file
|
||||||
// the id is calculated from the secret key and contents,
|
// the id is calculated from the secret key and contents,
|
||||||
|
|
@ -396,8 +400,6 @@ func (r *LocalResource) Delete(ctx context.Context, req resource.DeleteRequest,
|
||||||
}
|
}
|
||||||
contents := state.Contents.ValueString()
|
contents := state.Contents.ValueString()
|
||||||
|
|
||||||
localFilePath := filepath.Join(directory, name)
|
|
||||||
|
|
||||||
// we need to validate the id before we can delete a protected file
|
// we need to validate the id before we can delete a protected file
|
||||||
if protected {
|
if protected {
|
||||||
err := validateProtected(protected, id, key, contents)
|
err := validateProtected(protected, id, key, contents)
|
||||||
|
|
@ -407,7 +409,7 @@ func (r *LocalResource) Delete(ctx context.Context, req resource.DeleteRequest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Remove(localFilePath); err != nil {
|
if err := r.client.Delete(directory, name); err != nil {
|
||||||
tflog.Error(ctx, "Failed to delete file: "+err.Error())
|
tflog.Error(ctx, "Failed to delete file: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@ package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"fmt"
|
||||||
"path/filepath"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -19,7 +18,7 @@ import (
|
||||||
const (
|
const (
|
||||||
defaultId = ""
|
defaultId = ""
|
||||||
defaultDirectory = "."
|
defaultDirectory = "."
|
||||||
defaultMode = "0600"
|
defaultPerm = "0600"
|
||||||
defaultProtected = "false"
|
defaultProtected = "false"
|
||||||
defaultHmacSecretKey = ""
|
defaultHmacSecretKey = ""
|
||||||
)
|
)
|
||||||
|
|
@ -73,21 +72,20 @@ func TestLocalSchema(t *testing.T) {
|
||||||
func TestLocalResourceCreate(t *testing.T) {
|
func TestLocalResourceCreate(t *testing.T) {
|
||||||
t.Run("Create function", func(t *testing.T) {
|
t.Run("Create function", func(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
fit LocalResource
|
fit LocalResource
|
||||||
have resource.CreateRequest
|
have resource.CreateRequest
|
||||||
want resource.CreateResponse
|
want resource.CreateResponse
|
||||||
tearDownPath string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"Basic",
|
"Basic",
|
||||||
LocalResource{},
|
LocalResource{client: &memoryFileClient{}},
|
||||||
// have
|
// have
|
||||||
getCreateRequest(t, map[string]string{
|
getCreateRequest(t, map[string]string{
|
||||||
"id": defaultId,
|
"id": defaultId,
|
||||||
"name": "test_basic.tmp",
|
"name": "test_basic.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a basic test",
|
"contents": "this is a basic test",
|
||||||
"protected": defaultProtected,
|
"protected": defaultProtected,
|
||||||
"hmac_secret_key": defaultHmacSecretKey, // this should use the hard coded hmac secret key for unprotected files
|
"hmac_secret_key": defaultHmacSecretKey, // this should use the hard coded hmac secret key for unprotected files
|
||||||
|
|
@ -97,22 +95,21 @@ func TestLocalResourceCreate(t *testing.T) {
|
||||||
"id": "3de642fb91d2fb0ce02fe66c3d19ebdf44cbc6a2ebcc2dad22f1950b67c1217f",
|
"id": "3de642fb91d2fb0ce02fe66c3d19ebdf44cbc6a2ebcc2dad22f1950b67c1217f",
|
||||||
"name": "test_basic.tmp",
|
"name": "test_basic.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a basic test",
|
"contents": "this is a basic test",
|
||||||
"protected": defaultProtected,
|
"protected": defaultProtected,
|
||||||
"hmac_secret_key": defaultHmacSecretKey,
|
"hmac_secret_key": defaultHmacSecretKey,
|
||||||
}),
|
}),
|
||||||
filepath.Join(defaultDirectory, "test_basic.tmp"),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Protected",
|
"Protected",
|
||||||
LocalResource{},
|
LocalResource{client: &osFileClient{}},
|
||||||
// have
|
// have
|
||||||
getCreateRequest(t, map[string]string{
|
getCreateRequest(t, map[string]string{
|
||||||
"id": "4ccd8ec7ea24e0524c8aba459fbf3a2649ec3cd96a1c8f9dfb326cc57a9d3127",
|
"id": "4ccd8ec7ea24e0524c8aba459fbf3a2649ec3cd96a1c8f9dfb326cc57a9d3127",
|
||||||
"name": "test_protected.tmp",
|
"name": "test_protected.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a test",
|
"contents": "this is a test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": "this-is-a-test-key",
|
"hmac_secret_key": "this-is-a-test-key",
|
||||||
|
|
@ -122,22 +119,21 @@ func TestLocalResourceCreate(t *testing.T) {
|
||||||
"id": "4ccd8ec7ea24e0524c8aba459fbf3a2649ec3cd96a1c8f9dfb326cc57a9d3127",
|
"id": "4ccd8ec7ea24e0524c8aba459fbf3a2649ec3cd96a1c8f9dfb326cc57a9d3127",
|
||||||
"name": "test_protected.tmp",
|
"name": "test_protected.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a test",
|
"contents": "this is a test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": "this-is-a-test-key",
|
"hmac_secret_key": "this-is-a-test-key",
|
||||||
}),
|
}),
|
||||||
filepath.Join(defaultDirectory, "test_protected.tmp"),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Protected using key from environment",
|
"Protected using key from environment",
|
||||||
LocalResource{},
|
LocalResource{client: &memoryFileClient{}},
|
||||||
// have
|
// have
|
||||||
getCreateRequest(t, map[string]string{
|
getCreateRequest(t, map[string]string{
|
||||||
"id": "59fed8691a76c7693fc9dcd4fda28390a1fd3090114bc64f3e5a3abe312a92f5",
|
"id": "59fed8691a76c7693fc9dcd4fda28390a1fd3090114bc64f3e5a3abe312a92f5",
|
||||||
"name": "test_protected.tmp",
|
"name": "test_protected.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a test",
|
"contents": "this is a test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": defaultHmacSecretKey, // this relies on TF_FILE_HMAC_SECRET_KEY=thisisasupersecretkey in your environment
|
"hmac_secret_key": defaultHmacSecretKey, // this relies on TF_FILE_HMAC_SECRET_KEY=thisisasupersecretkey in your environment
|
||||||
|
|
@ -147,12 +143,11 @@ func TestLocalResourceCreate(t *testing.T) {
|
||||||
"id": "59fed8691a76c7693fc9dcd4fda28390a1fd3090114bc64f3e5a3abe312a92f5",
|
"id": "59fed8691a76c7693fc9dcd4fda28390a1fd3090114bc64f3e5a3abe312a92f5",
|
||||||
"name": "test_protected.tmp",
|
"name": "test_protected.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a test",
|
"contents": "this is a test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": defaultHmacSecretKey,
|
"hmac_secret_key": defaultHmacSecretKey,
|
||||||
}),
|
}),
|
||||||
filepath.Join(defaultDirectory, "test_protected.tmp"),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|
@ -163,12 +158,18 @@ func TestLocalResourceCreate(t *testing.T) {
|
||||||
}
|
}
|
||||||
plannedProtected := plannedState.Protected.ValueBool()
|
plannedProtected := plannedState.Protected.ValueBool()
|
||||||
plannedHmacSecretKey := plannedState.HmacSecretKey.ValueString()
|
plannedHmacSecretKey := plannedState.HmacSecretKey.ValueString()
|
||||||
|
plannedDirectory := plannedState.Directory.ValueString()
|
||||||
|
plannedName := plannedState.Name.ValueString()
|
||||||
if plannedProtected && plannedHmacSecretKey == "" {
|
if plannedProtected && plannedHmacSecretKey == "" {
|
||||||
t.Setenv("TF_FILE_HMAC_SECRET_KEY", "thisisasupersecretkey")
|
t.Setenv("TF_FILE_HMAC_SECRET_KEY", "thisisasupersecretkey")
|
||||||
}
|
}
|
||||||
r := getCreateResponseContainer()
|
r := getCreateResponseContainer()
|
||||||
tc.fit.Create(context.Background(), tc.have, &r)
|
tc.fit.Create(context.Background(), tc.have, &r)
|
||||||
defer teardown(tc.tearDownPath)
|
defer func() {
|
||||||
|
if err := tc.fit.client.Delete(plannedDirectory, plannedName); err != nil {
|
||||||
|
t.Errorf("Error cleaning up: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
got := r
|
got := r
|
||||||
if diff := cmp.Diff(tc.want, got); diff != "" {
|
if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||||
t.Errorf("Create() mismatch (-want +got):\n%s", diff)
|
t.Errorf("Create() mismatch (-want +got):\n%s", diff)
|
||||||
|
|
@ -181,22 +182,21 @@ func TestLocalResourceCreate(t *testing.T) {
|
||||||
func TestLocalResourceRead(t *testing.T) {
|
func TestLocalResourceRead(t *testing.T) {
|
||||||
t.Run("Read function", func(t *testing.T) {
|
t.Run("Read function", func(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
fit LocalResource
|
fit LocalResource
|
||||||
have resource.ReadRequest
|
have resource.ReadRequest
|
||||||
want resource.ReadResponse
|
want resource.ReadResponse
|
||||||
setup map[string]string
|
setup map[string]string
|
||||||
tearDownPath string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"Unprotected",
|
"Unprotected",
|
||||||
LocalResource{},
|
LocalResource{client: &memoryFileClient{}},
|
||||||
// have
|
// have
|
||||||
getReadRequest(t, map[string]string{
|
getReadRequest(t, map[string]string{
|
||||||
"id": "60cef95046105ff4522c0c1f1aeeeba43d0d729dbcabdd8846c317c98cac60a2",
|
"id": "60cef95046105ff4522c0c1f1aeeeba43d0d729dbcabdd8846c317c98cac60a2",
|
||||||
"name": "read.tmp",
|
"name": "read.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is an unprotected read test",
|
"contents": "this is an unprotected read test",
|
||||||
"protected": defaultProtected,
|
"protected": defaultProtected,
|
||||||
"hmac_secret_key": defaultHmacSecretKey,
|
"hmac_secret_key": defaultHmacSecretKey,
|
||||||
|
|
@ -206,27 +206,27 @@ func TestLocalResourceRead(t *testing.T) {
|
||||||
"id": "60cef95046105ff4522c0c1f1aeeeba43d0d729dbcabdd8846c317c98cac60a2",
|
"id": "60cef95046105ff4522c0c1f1aeeeba43d0d729dbcabdd8846c317c98cac60a2",
|
||||||
"name": "read.tmp",
|
"name": "read.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is an unprotected read test",
|
"contents": "this is an unprotected read test",
|
||||||
"protected": defaultProtected,
|
"protected": defaultProtected,
|
||||||
"hmac_secret_key": defaultHmacSecretKey,
|
"hmac_secret_key": defaultHmacSecretKey,
|
||||||
}),
|
}),
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"mode": defaultMode,
|
"mode": defaultPerm,
|
||||||
"path": filepath.Join(defaultDirectory, "read.tmp"),
|
"directory": defaultDirectory,
|
||||||
"contents": "this is an unprotected read test",
|
"name": "read.tmp",
|
||||||
|
"contents": "this is an unprotected read test",
|
||||||
},
|
},
|
||||||
filepath.Join(defaultDirectory, "read.tmp"),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Protected",
|
"Protected",
|
||||||
LocalResource{},
|
LocalResource{client: &memoryFileClient{}},
|
||||||
// have
|
// have
|
||||||
getReadRequest(t, map[string]string{
|
getReadRequest(t, map[string]string{
|
||||||
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
||||||
"name": "read_protected.tmp",
|
"name": "read_protected.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a protected read test",
|
"contents": "this is a protected read test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": "this-is-a-test-key",
|
"hmac_secret_key": "this-is-a-test-key",
|
||||||
|
|
@ -236,28 +236,28 @@ func TestLocalResourceRead(t *testing.T) {
|
||||||
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
||||||
"name": "read_protected.tmp",
|
"name": "read_protected.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a protected read test",
|
"contents": "this is a protected read test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": "this-is-a-test-key",
|
"hmac_secret_key": "this-is-a-test-key",
|
||||||
}),
|
}),
|
||||||
// reality
|
// reality
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"mode": defaultMode,
|
"mode": defaultPerm,
|
||||||
"path": filepath.Join(defaultDirectory, "read_protected.tmp"),
|
"directory": defaultDirectory,
|
||||||
"contents": "this is a protected read test",
|
"name": "read_protected.tmp",
|
||||||
|
"contents": "this is a protected read test",
|
||||||
},
|
},
|
||||||
filepath.Join(defaultDirectory, "read_protected.tmp"),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Protected with content update",
|
"Protected with content update",
|
||||||
LocalResource{},
|
LocalResource{client: &memoryFileClient{}},
|
||||||
// have
|
// have
|
||||||
getReadRequest(t, map[string]string{
|
getReadRequest(t, map[string]string{
|
||||||
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
||||||
"name": "read_protected_content.tmp",
|
"name": "read_protected_content.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a protected read test",
|
"contents": "this is a protected read test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": "this-is-a-test-key",
|
"hmac_secret_key": "this-is-a-test-key",
|
||||||
|
|
@ -267,28 +267,28 @@ func TestLocalResourceRead(t *testing.T) {
|
||||||
"id": "84326116e261654e44ca3cb73fa026580853794062d472bc817b7ec2c82ff648",
|
"id": "84326116e261654e44ca3cb73fa026580853794062d472bc817b7ec2c82ff648",
|
||||||
"name": "read_protected_content.tmp",
|
"name": "read_protected_content.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a change in contents in the real file",
|
"contents": "this is a change in contents in the real file",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": "this-is-a-test-key",
|
"hmac_secret_key": "this-is-a-test-key",
|
||||||
}),
|
}),
|
||||||
// reality
|
// reality
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"mode": defaultMode,
|
"mode": defaultPerm,
|
||||||
"path": filepath.Join(defaultDirectory, "read_protected_content.tmp"),
|
"directory": defaultDirectory,
|
||||||
"contents": "this is a change in contents in the real file",
|
"name": "read_protected_content.tmp",
|
||||||
|
"contents": "this is a change in contents in the real file",
|
||||||
},
|
},
|
||||||
filepath.Join(defaultDirectory, "read_protected_content.tmp"),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Protected with mode update",
|
"Protected with mode update",
|
||||||
LocalResource{},
|
LocalResource{client: &memoryFileClient{}},
|
||||||
// have
|
// have
|
||||||
getReadRequest(t, map[string]string{
|
getReadRequest(t, map[string]string{
|
||||||
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
||||||
"name": "read_protected_mode.tmp",
|
"name": "read_protected_mode.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a protected read test",
|
"contents": "this is a protected read test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": "this-is-a-test-key",
|
"hmac_secret_key": "this-is-a-test-key",
|
||||||
|
|
@ -298,24 +298,30 @@ func TestLocalResourceRead(t *testing.T) {
|
||||||
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
"id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1",
|
||||||
"name": "read_protected_mode.tmp",
|
"name": "read_protected_mode.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": "0755",
|
"permissions": "0755",
|
||||||
"contents": "this is a protected read test",
|
"contents": "this is a protected read test",
|
||||||
"protected": "true",
|
"protected": "true",
|
||||||
"hmac_secret_key": "this-is-a-test-key",
|
"hmac_secret_key": "this-is-a-test-key",
|
||||||
}),
|
}),
|
||||||
// reality
|
// reality
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"mode": "0755",
|
"mode": "0755",
|
||||||
"path": filepath.Join(defaultDirectory, "read_protected_mode.tmp"),
|
"directory": defaultDirectory,
|
||||||
"contents": "this is a protected read test",
|
"name": "read_protected_mode.tmp",
|
||||||
|
"contents": "this is a protected read test",
|
||||||
},
|
},
|
||||||
filepath.Join(defaultDirectory, "read_protected_mode.tmp"),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
setup(tc.setup)
|
if err := tc.fit.client.Create(tc.setup["directory"], tc.setup["name"], tc.setup["contents"], tc.setup["mode"]); err != nil {
|
||||||
defer teardown(tc.tearDownPath)
|
t.Errorf("Error setting up: %v", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := tc.fit.client.Delete(tc.setup["directory"], tc.setup["name"]); err != nil {
|
||||||
|
t.Errorf("Error tearing down: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
r := getReadResponseContainer()
|
r := getReadResponseContainer()
|
||||||
tc.fit.Read(context.Background(), tc.have, &r)
|
tc.fit.Read(context.Background(), tc.have, &r)
|
||||||
got := r
|
got := r
|
||||||
|
|
@ -326,27 +332,25 @@ func TestLocalResourceRead(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocalResourceUpdate(t *testing.T) {
|
func TestLocalResourceUpdate(t *testing.T) {
|
||||||
t.Run("Update function", func(t *testing.T) {
|
t.Run("Update function", func(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
fit LocalResource
|
fit LocalResource
|
||||||
have resource.UpdateRequest
|
have resource.UpdateRequest
|
||||||
want resource.UpdateResponse
|
want resource.UpdateResponse
|
||||||
setup map[string]string
|
setup map[string]string
|
||||||
tearDownPath string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"Basic test",
|
"Basic test",
|
||||||
LocalResource{},
|
LocalResource{client: &memoryFileClient{}},
|
||||||
// have
|
// have
|
||||||
getUpdateRequest(t, map[string]map[string]string{
|
getUpdateRequest(t, map[string]map[string]string{
|
||||||
"priorState": {
|
"priorState": {
|
||||||
"id": defaultId,
|
"id": defaultId,
|
||||||
"name": "update_basic.tmp",
|
"name": "update_basic.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is an update test",
|
"contents": "this is an update test",
|
||||||
"protected": defaultProtected,
|
"protected": defaultProtected,
|
||||||
"hmac_secret_key": defaultHmacSecretKey,
|
"hmac_secret_key": defaultHmacSecretKey,
|
||||||
|
|
@ -355,7 +359,7 @@ func TestLocalResourceUpdate(t *testing.T) {
|
||||||
"id": defaultId,
|
"id": defaultId,
|
||||||
"name": "update_basic.tmp",
|
"name": "update_basic.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a basic update test",
|
"contents": "this is a basic update test",
|
||||||
"protected": defaultProtected,
|
"protected": defaultProtected,
|
||||||
"hmac_secret_key": defaultHmacSecretKey,
|
"hmac_secret_key": defaultHmacSecretKey,
|
||||||
|
|
@ -366,24 +370,30 @@ func TestLocalResourceUpdate(t *testing.T) {
|
||||||
"id": "0ec41eee6c157a3f7e50b78d586ee2ddb4d6e93b6de8bdf6d9354cf720e89549",
|
"id": "0ec41eee6c157a3f7e50b78d586ee2ddb4d6e93b6de8bdf6d9354cf720e89549",
|
||||||
"name": "update_basic.tmp",
|
"name": "update_basic.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a basic update test",
|
"contents": "this is a basic update test",
|
||||||
"protected": defaultProtected,
|
"protected": defaultProtected,
|
||||||
"hmac_secret_key": defaultHmacSecretKey,
|
"hmac_secret_key": defaultHmacSecretKey,
|
||||||
}),
|
}),
|
||||||
// setup
|
// setup
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"mode": defaultMode,
|
"mode": defaultPerm,
|
||||||
"path": filepath.Join(defaultDirectory, "update_basic.tmp"),
|
"directory": defaultDirectory,
|
||||||
"contents": "this is an update test",
|
"name": "update_basic.tmp",
|
||||||
|
"contents": "this is an update test",
|
||||||
},
|
},
|
||||||
filepath.Join(defaultDirectory, "update_basic.tmp"),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
setup(tc.setup)
|
if err := tc.fit.client.Create(tc.setup["directory"], tc.setup["name"], tc.setup["contents"], tc.setup["mode"]); err != nil {
|
||||||
defer teardown(tc.tearDownPath)
|
t.Errorf("Error setting up: %v", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := tc.fit.client.Delete(tc.setup["directory"], tc.setup["name"]); err != nil {
|
||||||
|
t.Errorf("Error tearing down: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
r := getUpdateResponseContainer()
|
r := getUpdateResponseContainer()
|
||||||
tc.fit.Update(context.Background(), tc.have, &r)
|
tc.fit.Update(context.Background(), tc.have, &r)
|
||||||
got := r
|
got := r
|
||||||
|
|
@ -392,13 +402,12 @@ func TestLocalResourceUpdate(t *testing.T) {
|
||||||
t.Errorf("Failed to get planned state: %v", diags)
|
t.Errorf("Failed to get planned state: %v", diags)
|
||||||
}
|
}
|
||||||
plannedContents := plannedState.Contents.ValueString()
|
plannedContents := plannedState.Contents.ValueString()
|
||||||
plannedFilePath := filepath.Join(plannedState.Directory.ValueString(), plannedState.Name.ValueString())
|
_, contentsAfterUpdate, err := tc.fit.client.Read(plannedState.Directory.ValueString(), plannedState.Name.ValueString())
|
||||||
contentsAfterUpdate, err := os.ReadFile(plannedFilePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to read file for update verification: %s", err)
|
t.Errorf("Failed to read file for update verification: %s", err)
|
||||||
}
|
}
|
||||||
if string(contentsAfterUpdate) != plannedContents {
|
if contentsAfterUpdate != plannedContents {
|
||||||
t.Errorf("File content was not updated correctly. Got %q, want %q", string(contentsAfterUpdate), plannedContents)
|
t.Errorf("File content was not updated correctly. Got %q, want %q", contentsAfterUpdate, plannedContents)
|
||||||
}
|
}
|
||||||
if diff := cmp.Diff(tc.want, got); diff != "" {
|
if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||||
t.Errorf("Update() mismatch (-want +got):\n%s", diff)
|
t.Errorf("Update() mismatch (-want +got):\n%s", diff)
|
||||||
|
|
@ -411,22 +420,21 @@ func TestLocalResourceUpdate(t *testing.T) {
|
||||||
func TestLocalResourceDelete(t *testing.T) {
|
func TestLocalResourceDelete(t *testing.T) {
|
||||||
t.Run("Delete function", func(t *testing.T) {
|
t.Run("Delete function", func(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
fit LocalResource
|
fit LocalResource
|
||||||
have resource.DeleteRequest
|
have resource.DeleteRequest
|
||||||
want resource.DeleteResponse
|
want resource.DeleteResponse
|
||||||
setup map[string]string
|
setup map[string]string
|
||||||
tearDownPath string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"Basic test",
|
"Basic test",
|
||||||
LocalResource{},
|
LocalResource{client: &memoryFileClient{}},
|
||||||
// have
|
// have
|
||||||
getDeleteRequest(t, map[string]string{
|
getDeleteRequest(t, map[string]string{
|
||||||
"id": "fd6fb8621c4850c228190f4d448ce30881a32609d6b4c7341d48d0027e597567",
|
"id": "fd6fb8621c4850c228190f4d448ce30881a32609d6b4c7341d48d0027e597567",
|
||||||
"name": "delete.tmp",
|
"name": "delete.tmp",
|
||||||
"directory": defaultDirectory,
|
"directory": defaultDirectory,
|
||||||
"mode": defaultMode,
|
"permissions": defaultPerm,
|
||||||
"contents": "this is a delete test",
|
"contents": "this is a delete test",
|
||||||
"protected": defaultProtected,
|
"protected": defaultProtected,
|
||||||
"hmac_secret_key": defaultHmacSecretKey,
|
"hmac_secret_key": defaultHmacSecretKey,
|
||||||
|
|
@ -435,22 +443,27 @@ func TestLocalResourceDelete(t *testing.T) {
|
||||||
getDeleteResponse(),
|
getDeleteResponse(),
|
||||||
// setup
|
// setup
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"mode": defaultMode,
|
"mode": defaultPerm,
|
||||||
"path": filepath.Join(defaultDirectory, "delete.tmp"),
|
"directory": defaultDirectory,
|
||||||
"contents": "this is a delete test",
|
"name": "delete.tmp",
|
||||||
|
"contents": "this is a delete test",
|
||||||
},
|
},
|
||||||
filepath.Join(defaultDirectory, "delete.tmp"),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
setup(tc.setup)
|
if err := tc.fit.client.Create(tc.setup["directory"], tc.setup["name"], tc.setup["contents"], tc.setup["mode"]); err != nil {
|
||||||
|
t.Errorf("Error setting up: %v", err)
|
||||||
|
}
|
||||||
r := getDeleteResponseContainer()
|
r := getDeleteResponseContainer()
|
||||||
tc.fit.Delete(context.Background(), tc.have, &r)
|
tc.fit.Delete(context.Background(), tc.have, &r)
|
||||||
got := r
|
got := r
|
||||||
// Verify the file was actually deleted from disk
|
// Verify the file was actually deleted from disk
|
||||||
if _, err := os.Stat(tc.setup["path"]); !os.IsNotExist(err) {
|
if _, c, err := tc.fit.client.Read(tc.setup["directory"], tc.setup["name"]); err == nil || err.Error() != "file not found" {
|
||||||
t.Errorf("Expected file to be deleted, but it still exists.")
|
if err == nil {
|
||||||
|
t.Errorf("Expected file to be delete, but it still exists. File contents: %s", c)
|
||||||
|
}
|
||||||
|
t.Errorf("Expected file to be deleted, but it still exists. Error: %s", err.Error())
|
||||||
}
|
}
|
||||||
// verify that the file was removed from state
|
// verify that the file was removed from state
|
||||||
if diff := cmp.Diff(tc.want, got); diff != "" {
|
if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||||
|
|
@ -682,7 +695,7 @@ func getObjectAttributeTypes() tftypes.Object {
|
||||||
"id": tftypes.String,
|
"id": tftypes.String,
|
||||||
"name": tftypes.String,
|
"name": tftypes.String,
|
||||||
"directory": tftypes.String,
|
"directory": tftypes.String,
|
||||||
"mode": tftypes.String,
|
"permissions": tftypes.String,
|
||||||
"contents": tftypes.String,
|
"contents": tftypes.String,
|
||||||
"hmac_secret_key": tftypes.String,
|
"hmac_secret_key": tftypes.String,
|
||||||
"protected": tftypes.Bool,
|
"protected": tftypes.Bool,
|
||||||
|
|
@ -697,11 +710,42 @@ func getLocalResourceSchema() *resource.SchemaResponse {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup(data map[string]string) {
|
// type fileClient interface {
|
||||||
modeInt, _ := strconv.ParseUint(data["mode"], 8, 32)
|
// Create(directory string, name string, data string, permissions string) error
|
||||||
_ = os.WriteFile(data["path"], []byte(data["contents"]), os.FileMode(modeInt))
|
// // If file isn't found the error message must have err.Error() == "File not found."
|
||||||
|
// Read(directory string, name string) (string, string, error)// permissions, contents, error
|
||||||
|
// Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error
|
||||||
|
// Delete(directory string, name string) error
|
||||||
|
// }
|
||||||
|
|
||||||
|
type memoryFileClient struct {
|
||||||
|
file map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func teardown(path string) {
|
var _ fileClient = &memoryFileClient{} // make sure the memoryFileClient implements the fileClient
|
||||||
os.Remove(path)
|
func (c *memoryFileClient) Create(directory string, name string, data string, permissions string) error {
|
||||||
|
|
||||||
|
c.file = make(map[string]string)
|
||||||
|
c.file["directory"] = directory
|
||||||
|
c.file["name"] = name
|
||||||
|
c.file["contents"] = data
|
||||||
|
c.file["permissions"] = permissions
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *memoryFileClient) Read(directory string, name string) (string, string, error) {
|
||||||
|
if c.file["directory"] == "" || c.file["name"] == "" {
|
||||||
|
return "", "", fmt.Errorf("file not found")
|
||||||
|
}
|
||||||
|
return c.file["permissions"], c.file["contents"], nil
|
||||||
|
}
|
||||||
|
func (c *memoryFileClient) Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error {
|
||||||
|
c.file["directory"] = newDirectory
|
||||||
|
c.file["name"] = newName
|
||||||
|
c.file["contents"] = data
|
||||||
|
c.file["permissions"] = permissions
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *memoryFileClient) Delete(directory string, name string) error {
|
||||||
|
c.file = nil
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue