Add file transfer functions to SessionProvider 36/162036/18
authorAdam Malinowski <a.malinowsk2@partner.samsung.com>
Tue, 28 Nov 2017 14:31:28 +0000 (15:31 +0100)
committerAleksander Mistewicz <a.mistewicz@samsung.com>
Fri, 15 Jun 2018 10:50:12 +0000 (12:50 +0200)
Change-Id: Ief14d76d93bfd041bc9809d0599719859fde69dc
Signed-off-by: Adam Malinowski <a.malinowsk2@partner.samsung.com>
manager/dryad/dryad.go
manager/dryad/dryad_session_provider.go
manager/dryad/dryad_session_provider_test.go
manager/dryad_job_runner_test.go
manager/mock_dryad_test.go

index 3af47aa..3a3452a 100644 (file)
@@ -45,6 +45,12 @@ type SessionProvider interface {
 
        // Close terminates session to Dryad.
        Close() error
+
+       // SendFile sends file to Dryad.
+       SendFile(src, dst string) error
+
+       // ReceiveFile receives file from Dryad.
+       ReceiveFile(src, dst string) error
 }
 
 // Credentials are used to login to device.
index 19e2657..bdcc83b 100644 (file)
@@ -18,14 +18,15 @@ package dryad
 
 import (
        "bytes"
-       "time"
-
+       "fmt"
+       "io"
+       "os"
+       "path/filepath"
        "strings"
+       "time"
 
        "crypto/rsa"
 
-       "fmt"
-
        . "git.tizen.org/tools/weles"
        "golang.org/x/crypto/ssh"
 )
@@ -163,3 +164,100 @@ func (d *sessionProvider) Close() error {
        d.connection.client = nil
        return err
 }
+
+// SendFile is a part of SessionProvider interface.
+func (d *sessionProvider) SendFile(src, dst string) error {
+       f, err := os.Open(src)
+       if err != nil {
+               return err
+       }
+       defer f.Close()
+
+       s, err := f.Stat()
+       if err != nil {
+               return err
+       }
+
+       session, err := d.newSession()
+       if err != nil {
+               return err
+       }
+       defer session.Close()
+
+       filename := filepath.Base(dst)
+       directory := filepath.Dir(dst)
+
+       w, err := session.StdinPipe()
+       if err != nil {
+               return err
+       }
+       defer w.Close()
+
+       var stdout, stderr bytes.Buffer
+       session.Stdout = &stdout
+       session.Stderr = &stderr
+
+       // Trigger SCP sink mode
+       err = session.Start("scp -t " + directory)
+       if err != nil {
+               return err
+       }
+
+       _, err = fmt.Fprintln(w, "C0755", s.Size(), filename)
+       if err != nil {
+               return err
+       }
+
+       _, err = io.Copy(w, f)
+       if err != nil {
+               return err
+       }
+
+       _, err = fmt.Fprintln(w, "\x00")
+       if err != nil {
+               return err
+       }
+
+       err = session.Wait()
+
+       // FIXME: unexpected <newline> is reported by scp every time the transfer is finished properly. Needs to be solved.
+       // Bellow we have a very lousy trick. I hope it will be fixed in the future.
+       // I don't know what is the reason or how to fix it. Has to wait a little bit. Or maybe someone else will find the solution.
+       // First candidate sshfs -o slave
+       if strings.Contains(stdout.String(), "unexpected <newline>") {
+               return nil
+       }
+       return err
+}
+
+// ReceiveFile is a part of SessionProvider interface.
+func (d *sessionProvider) ReceiveFile(src, dst string) error {
+       session, err := d.newSession()
+       if err != nil {
+               return err
+       }
+       defer session.Close()
+
+       r, err := session.StdoutPipe()
+       if err != nil {
+               return err
+       }
+
+       file, err := os.Create(dst)
+       if err != nil {
+               return err
+       }
+       defer file.Close()
+
+       err = session.Start("scp " + src + " /dev/stdout")
+       if err != nil {
+               return err
+       }
+
+       _, err = io.Copy(file, r)
+       if err != nil {
+               return err
+       }
+
+       return session.Wait()
+}
index 48c30c6..2284451 100644 (file)
@@ -69,4 +69,24 @@ var _ = Describe("SessionProvider", func() {
        It("should switch to TS", func() {
                Expect(sp.TS()).ToNot(HaveOccurred())
        })
+
+       It("should transfer file to Dryad", func() {
+               err := sp.SendFile(keyFile, "/tmp/"+keyFile)
+               Expect(err).ToNot(HaveOccurred())
+       })
+
+       It("should not transfer file to Dryad - insufficient permissions", func() {
+               err := sp.SendFile(keyFile, "/root/"+keyFile)
+               Expect(err).To(HaveOccurred())
+       })
+
+       It("should transfer file from Dryad", func() {
+               err := sp.ReceiveFile("/tmp/"+keyFile, "/tmp/dl-"+keyFile)
+               Expect(err).ToNot(HaveOccurred())
+       })
+
+       It("should not transfer nonexistent file from Dryad", func() {
+               err := sp.ReceiveFile("/tmp/"+keyFile+"noway", "/tmp/dl-"+keyFile)
+               Expect(err).To(HaveOccurred())
+       })
 })
index e91ae57..d74a027 100644 (file)
@@ -16,6 +16,8 @@
 
 package manager
 
+//go:generate mockgen -package=manager -destination=mock_dryad_test.go git.tizen.org/tools/weles/manager/dryad SessionProvider,DeviceCommunicationProvider
+
 import (
        "context"
        "errors"
index c650111..3309594 100644 (file)
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: manager/dryad/dryad.go
+// Source: git.tizen.org/tools/weles/manager/dryad (interfaces: SessionProvider,DeviceCommunicationProvider)
 
 // Package manager is a generated GoMock package.
 package manager
@@ -34,18 +34,16 @@ func (m *MockSessionProvider) EXPECT() *MockSessionProviderMockRecorder {
        return m.recorder
 }
 
-// Exec mocks base method
-func (m *MockSessionProvider) Exec(cmd []string) ([]byte, []byte, error) {
-       ret := m.ctrl.Call(m, "Exec", cmd)
-       ret0, _ := ret[0].([]byte)
-       ret1, _ := ret[1].([]byte)
-       ret2, _ := ret[2].(error)
-       return ret0, ret1, ret2
+// Close mocks base method
+func (m *MockSessionProvider) Close() error {
+       ret := m.ctrl.Call(m, "Close")
+       ret0, _ := ret[0].(error)
+       return ret0
 }
 
-// Exec indicates an expected call of Exec
-func (mr *MockSessionProviderMockRecorder) Exec(cmd interface{}) *gomock.Call {
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockSessionProvider)(nil).Exec), cmd)
+// Close indicates an expected call of Close
+func (mr *MockSessionProviderMockRecorder) Close() *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSessionProvider)(nil).Close))
 }
 
 // DUT mocks base method
@@ -60,16 +58,18 @@ func (mr *MockSessionProviderMockRecorder) DUT() *gomock.Call {
        return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DUT", reflect.TypeOf((*MockSessionProvider)(nil).DUT))
 }
 
-// TS mocks base method
-func (m *MockSessionProvider) TS() error {
-       ret := m.ctrl.Call(m, "TS")
-       ret0, _ := ret[0].(error)
-       return ret0
+// Exec mocks base method
+func (m *MockSessionProvider) Exec(arg0 []string) ([]byte, []byte, error) {
+       ret := m.ctrl.Call(m, "Exec", arg0)
+       ret0, _ := ret[0].([]byte)
+       ret1, _ := ret[1].([]byte)
+       ret2, _ := ret[2].(error)
+       return ret0, ret1, ret2
 }
 
-// TS indicates an expected call of TS
-func (mr *MockSessionProviderMockRecorder) TS() *gomock.Call {
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TS", reflect.TypeOf((*MockSessionProvider)(nil).TS))
+// Exec indicates an expected call of Exec
+func (mr *MockSessionProviderMockRecorder) Exec(arg0 interface{}) *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockSessionProvider)(nil).Exec), arg0)
 }
 
 // PowerTick mocks base method
@@ -84,16 +84,40 @@ func (mr *MockSessionProviderMockRecorder) PowerTick() *gomock.Call {
        return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PowerTick", reflect.TypeOf((*MockSessionProvider)(nil).PowerTick))
 }
 
-// Close mocks base method
-func (m *MockSessionProvider) Close() error {
-       ret := m.ctrl.Call(m, "Close")
+// ReceiveFile mocks base method
+func (m *MockSessionProvider) ReceiveFile(arg0, arg1 string) error {
+       ret := m.ctrl.Call(m, "ReceiveFile", arg0, arg1)
        ret0, _ := ret[0].(error)
        return ret0
 }
 
-// Close indicates an expected call of Close
-func (mr *MockSessionProviderMockRecorder) Close() *gomock.Call {
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSessionProvider)(nil).Close))
+// ReceiveFile indicates an expected call of ReceiveFile
+func (mr *MockSessionProviderMockRecorder) ReceiveFile(arg0, arg1 interface{}) *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceiveFile", reflect.TypeOf((*MockSessionProvider)(nil).ReceiveFile), arg0, arg1)
+}
+
+// SendFile mocks base method
+func (m *MockSessionProvider) SendFile(arg0, arg1 string) error {
+       ret := m.ctrl.Call(m, "SendFile", arg0, arg1)
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// SendFile indicates an expected call of SendFile
+func (mr *MockSessionProviderMockRecorder) SendFile(arg0, arg1 interface{}) *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendFile", reflect.TypeOf((*MockSessionProvider)(nil).SendFile), arg0, arg1)
+}
+
+// TS mocks base method
+func (m *MockSessionProvider) TS() error {
+       ret := m.ctrl.Call(m, "TS")
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// TS indicates an expected call of TS
+func (mr *MockSessionProviderMockRecorder) TS() *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TS", reflect.TypeOf((*MockSessionProvider)(nil).TS))
 }
 
 // MockDeviceCommunicationProvider is a mock of DeviceCommunicationProvider interface
@@ -119,45 +143,45 @@ func (m *MockDeviceCommunicationProvider) EXPECT() *MockDeviceCommunicationProvi
        return m.recorder
 }
 
-// Login mocks base method
-func (m *MockDeviceCommunicationProvider) Login(arg0 dryad.Credentials) error {
-       ret := m.ctrl.Call(m, "Login", arg0)
+// Close mocks base method
+func (m *MockDeviceCommunicationProvider) Close() error {
+       ret := m.ctrl.Call(m, "Close")
        ret0, _ := ret[0].(error)
        return ret0
 }
 
-// Login indicates an expected call of Login
-func (mr *MockDeviceCommunicationProviderMockRecorder) Login(arg0 interface{}) *gomock.Call {
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Login", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).Login), arg0)
+// Close indicates an expected call of Close
+func (mr *MockDeviceCommunicationProviderMockRecorder) Close() *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).Close))
 }
 
-// CopyFilesTo mocks base method
-func (m *MockDeviceCommunicationProvider) CopyFilesTo(src []string, dest string) error {
-       ret := m.ctrl.Call(m, "CopyFilesTo", src, dest)
+// CopyFilesFrom mocks base method
+func (m *MockDeviceCommunicationProvider) CopyFilesFrom(arg0 []string, arg1 string) error {
+       ret := m.ctrl.Call(m, "CopyFilesFrom", arg0, arg1)
        ret0, _ := ret[0].(error)
        return ret0
 }
 
-// CopyFilesTo indicates an expected call of CopyFilesTo
-func (mr *MockDeviceCommunicationProviderMockRecorder) CopyFilesTo(src, dest interface{}) *gomock.Call {
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyFilesTo", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).CopyFilesTo), src, dest)
+// CopyFilesFrom indicates an expected call of CopyFilesFrom
+func (mr *MockDeviceCommunicationProviderMockRecorder) CopyFilesFrom(arg0, arg1 interface{}) *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyFilesFrom", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).CopyFilesFrom), arg0, arg1)
 }
 
-// CopyFilesFrom mocks base method
-func (m *MockDeviceCommunicationProvider) CopyFilesFrom(src []string, dest string) error {
-       ret := m.ctrl.Call(m, "CopyFilesFrom", src, dest)
+// CopyFilesTo mocks base method
+func (m *MockDeviceCommunicationProvider) CopyFilesTo(arg0 []string, arg1 string) error {
+       ret := m.ctrl.Call(m, "CopyFilesTo", arg0, arg1)
        ret0, _ := ret[0].(error)
        return ret0
 }
 
-// CopyFilesFrom indicates an expected call of CopyFilesFrom
-func (mr *MockDeviceCommunicationProviderMockRecorder) CopyFilesFrom(src, dest interface{}) *gomock.Call {
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyFilesFrom", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).CopyFilesFrom), src, dest)
+// CopyFilesTo indicates an expected call of CopyFilesTo
+func (mr *MockDeviceCommunicationProviderMockRecorder) CopyFilesTo(arg0, arg1 interface{}) *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyFilesTo", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).CopyFilesTo), arg0, arg1)
 }
 
 // Exec mocks base method
-func (m *MockDeviceCommunicationProvider) Exec(cmd []string, timeout time.Duration) ([]byte, []byte, error) {
-       ret := m.ctrl.Call(m, "Exec", cmd, timeout)
+func (m *MockDeviceCommunicationProvider) Exec(arg0 []string, arg1 time.Duration) ([]byte, []byte, error) {
+       ret := m.ctrl.Call(m, "Exec", arg0, arg1)
        ret0, _ := ret[0].([]byte)
        ret1, _ := ret[1].([]byte)
        ret2, _ := ret[2].(error)
@@ -165,18 +189,18 @@ func (m *MockDeviceCommunicationProvider) Exec(cmd []string, timeout time.Durati
 }
 
 // Exec indicates an expected call of Exec
-func (mr *MockDeviceCommunicationProviderMockRecorder) Exec(cmd, timeout interface{}) *gomock.Call {
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).Exec), cmd, timeout)
+func (mr *MockDeviceCommunicationProviderMockRecorder) Exec(arg0, arg1 interface{}) *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).Exec), arg0, arg1)
 }
 
-// Close mocks base method
-func (m *MockDeviceCommunicationProvider) Close() error {
-       ret := m.ctrl.Call(m, "Close")
+// Login mocks base method
+func (m *MockDeviceCommunicationProvider) Login(arg0 dryad.Credentials) error {
+       ret := m.ctrl.Call(m, "Login", arg0)
        ret0, _ := ret[0].(error)
        return ret0
 }
 
-// Close indicates an expected call of Close
-func (mr *MockDeviceCommunicationProviderMockRecorder) Close() *gomock.Call {
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).Close))
+// Login indicates an expected call of Login
+func (mr *MockDeviceCommunicationProviderMockRecorder) Login(arg0 interface{}) *gomock.Call {
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Login", reflect.TypeOf((*MockDeviceCommunicationProvider)(nil).Login), arg0)
 }