From e4834afe167fedac0ee8171b2d6880d18dd1cf1c Mon Sep 17 00:00:00 2001 From: Javier Aliaga Date: Mon, 22 Sep 2025 11:08:11 +0200 Subject: [PATCH 1/2] chore: Close file after write Signed-off-by: Javier Aliaga --- bindings/sftp/sftp.go | 7 +++ bindings/sftp/sftp_integration_test.go | 82 ++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 bindings/sftp/sftp_integration_test.go diff --git a/bindings/sftp/sftp.go b/bindings/sftp/sftp.go index 960294a44a..e794ef4032 100644 --- a/bindings/sftp/sftp.go +++ b/bindings/sftp/sftp.go @@ -173,6 +173,13 @@ func (sftp *Sftp) create(_ context.Context, req *bindings.InvokeRequest) (*bindi return nil, fmt.Errorf("sftp binding error: error create file %s: %w", path, err) } + defer func() { + closeErr := file.Close() + if closeErr != nil { + sftp.logger.Errorf("sftp binding error: error close file: %s", closeErr) + } + }() + _, err = file.Write(req.Data) if err != nil { return nil, fmt.Errorf("sftp binding error: error write file: %w", err) diff --git a/bindings/sftp/sftp_integration_test.go b/bindings/sftp/sftp_integration_test.go new file mode 100644 index 0000000000..178c7535db --- /dev/null +++ b/bindings/sftp/sftp_integration_test.go @@ -0,0 +1,82 @@ +package sftp + +import ( + "encoding/json" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/dapr/components-contrib/bindings" +) + +var connectionStringEnvKey = "DAPR_TEST_SFTP_CONNSTRING" + +// Run docker from the file location as the upload folder is relative to the test +// docker run -v ./upload:/home/foo/upload -p 2222:22 -d atmoz/sftp foo:pass:1001 +func TestIntegrationCases(t *testing.T) { + connectionString := os.Getenv(connectionStringEnvKey) + if connectionString == "" { + t.Skipf(`sftp binding integration tests skipped. To enable this test, define the connection string using environment variable '%[1]s' (example 'export %[1]s="localhost:2222")'`, connectionStringEnvKey) + } + + t.Run("List operation", testListOperation) + t.Run("Create operation", testCreateOperation) +} + +func testListOperation(t *testing.T) { + c := Sftp{} + m := bindings.Metadata{} + m.Properties = map[string]string{ + "rootPath": "/upload", + "address": os.Getenv(connectionStringEnvKey), + "username": "foo", + "password": "pass", + "insecureIgnoreHostKey": "true", + } + err := c.Init(t.Context(), m) + require.NoError(t, err) + + r, err := c.Invoke(t.Context(), &bindings.InvokeRequest{Operation: bindings.ListOperation}) + require.NoError(t, err) + assert.NotNil(t, r.Data) + + var d []listResponse + err = json.Unmarshal(r.Data, &d) + require.NoError(t, err) +} + +func testCreateOperation(t *testing.T) { + c := Sftp{} + m := bindings.Metadata{} + m.Properties = map[string]string{ + "rootPath": "/upload", + "address": os.Getenv(connectionStringEnvKey), + "username": "foo", + "password": "pass", + "insecureIgnoreHostKey": "true", + } + + err := os.Remove("./upload/test.txt") + if err != nil && !os.IsNotExist(err) { + require.NoError(t, err) + } + + err = c.Init(t.Context(), m) + require.NoError(t, err) + + r, err := c.Invoke(t.Context(), &bindings.InvokeRequest{ + Operation: bindings.CreateOperation, + Data: []byte("test data 1"), + Metadata: map[string]string{ + "fileName": "test.txt", + }, + }) + require.NoError(t, err) + assert.NotNil(t, r.Data) + + file, err := os.Stat("./upload/test.txt") + require.NoError(t, err) + assert.Equal(t, "test.txt", file.Name()) +} From ef87b3a0f37c3fe16adc64da99007286840b05eb Mon Sep 17 00:00:00 2001 From: Javier Aliaga Date: Mon, 22 Sep 2025 17:31:12 +0200 Subject: [PATCH 2/2] Update bindings/sftp/sftp.go Co-authored-by: Sam Signed-off-by: Javier Aliaga --- bindings/sftp/sftp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/sftp/sftp.go b/bindings/sftp/sftp.go index e794ef4032..211cce85d3 100644 --- a/bindings/sftp/sftp.go +++ b/bindings/sftp/sftp.go @@ -176,7 +176,7 @@ func (sftp *Sftp) create(_ context.Context, req *bindings.InvokeRequest) (*bindi defer func() { closeErr := file.Close() if closeErr != nil { - sftp.logger.Errorf("sftp binding error: error close file: %s", closeErr) + sftp.logger.Errorf("sftp binding error: error close file: %w", closeErr) } }()