From e00d5626f60668bd3b0d2b94e3d4ccbbd7fbb24a Mon Sep 17 00:00:00 2001 From: Adam Malinowski Date: Mon, 27 Nov 2017 06:01:15 +0100 Subject: [PATCH] Add DeviceCommunicationProvider implementation Change-Id: I0b98831d3ee53de05831caf7564363fdf289fcf8 Signed-off-by: Adam Malinowski Signed-off-by: Aleksander Mistewicz --- manager/dryad/device_communication_provider.go | 78 +++++++++++- .../dryad/device_communication_provider_test.go | 132 +++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 manager/dryad/device_communication_provider_test.go diff --git a/manager/dryad/device_communication_provider.go b/manager/dryad/device_communication_provider.go index f870f14..2fa09a6 100644 --- a/manager/dryad/device_communication_provider.go +++ b/manager/dryad/device_communication_provider.go @@ -16,7 +16,83 @@ package dryad -// NewDeviceCommunicationProvider is a stub. +import ( + "path/filepath" + "strings" + "time" +) + +// deviceCommunicationProvider implements DeviceCommunicationProvider interface. +type deviceCommunicationProvider struct { + DeviceCommunicationProvider + credentials Credentials + sessionProvider SessionProvider +} + +// NewDeviceCommunicationProvider returns new instance of DeviceCommunicationProvider. func NewDeviceCommunicationProvider(session SessionProvider) DeviceCommunicationProvider { + return &deviceCommunicationProvider{ + sessionProvider: session, + } +} + +// Login is a part of DeviceCommunicationProvider interface. +func (d *deviceCommunicationProvider) Login(credentials Credentials) error { + d.credentials = credentials + _, _, err := d.sessionProvider.Exec([]string{"dut_login.sh", d.credentials.Username, d.credentials.Password}) + return err +} + +// CopyFilesTo function is a part of DeviceCommunicationProvider interface. +// It uses tmpfs of MuxPi so caller must take into consideration size of all files that are to be copied. +func (d *deviceCommunicationProvider) CopyFilesTo(src []string, dest string) error { + if !strings.HasSuffix(dest, "/") { + dest += "/" + } + + for _, path := range src { + fileName := filepath.Base(path) + tmpDst := "/tmp/weles_cft_" + fileName + + err := d.sessionProvider.SendFile(path, tmpDst) + if err != nil { + return err + } + + _, _, err = d.sessionProvider.Exec([]string{"dut_copyto.sh", tmpDst, dest + fileName}) + if err != nil { + return err + } + } return nil } + +// CopyFilesFrom function is a part of DeviceCommunicationProvider interface. +// It uses tmpfs of MuxPi so caller must take into consideration size of all files that are to be copied. +func (d *deviceCommunicationProvider) CopyFilesFrom(src []string, dest string) error { + for _, path := range src { + fileName := filepath.Base(path) + tmpDst := "/tmp/weles_cff_" + fileName + + _, _, err := d.sessionProvider.Exec([]string{"dut_copyfrom.sh", path, tmpDst}) + if err != nil { + return err + } + + err = d.sessionProvider.ReceiveFile(tmpDst, dest+fileName) + if err != nil { + return err + } + } + return nil +} + +// Exec function is a part of DeviceCommunicationProvider interface. +func (d *deviceCommunicationProvider) Exec(cmd []string, timeout time.Duration) (stdout, stderr []byte, err error) { + return d.sessionProvider.Exec(append([]string{"dut_exec.sh"}, cmd...)) +} + +// Close function is a part of DeviceCommunicationProvider interface. +func (d *deviceCommunicationProvider) Close() error { + return nil // Nothing to do for the time. +} diff --git a/manager/dryad/device_communication_provider_test.go b/manager/dryad/device_communication_provider_test.go new file mode 100644 index 0000000..134a4a3 --- /dev/null +++ b/manager/dryad/device_communication_provider_test.go @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package dryad + +import ( + "io/ioutil" + "strconv" + "time" + + "os" + "path/filepath" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("DeviceCommunicationProvider", func() { + var dcp DeviceCommunicationProvider + timeout := time.Second * 30 + onelineCows := `Cows called Daisy Are often lazy. But cows called Brian They be flyin Up in the air And out into space Because of the grass And the gasses it makes!` + + var testFiles []string + for i := 1; i < 6; i++ { + buff := make([]byte, i*1024*1024) + fileName := "/tmp/weles_test_file_" + strconv.FormatUint(uint64(i), 10) + ".bin" + ioutil.WriteFile(fileName, buff, 0644) + testFiles = append(testFiles, fileName) + } + + BeforeEach(func() { + if !accessInfoGiven { + Skip("No valid access info to Dryad") + } + sp := NewSessionProvider(dryadInfo) + dcp = NewDeviceCommunicationProvider(sp) + sp.DUT() + time.Sleep(2 * time.Second) + for t := 0; t < 3; t++ { // Try to boot DUT 3 times. For some reason Odroid U3 won't boot every time. + sp.PowerTick() + for i := 0; i < 10; i++ { + time.Sleep(10 * time.Second) + if dcp.Login(Credentials{"", ""}) == nil { + return + } + } + } + + Skip("Target device (DUT) not available.") + }) + + AfterEach(func() { + dcp.Close() + }) + + It("should 'login' to DUT", func() { + err := dcp.Login(Credentials{"", ""}) + Expect(err).ToNot(HaveOccurred()) + }) + + It("should list / dir", func() { + stdout, stderr, err := dcp.Exec([]string{"ls", "-al", "/"}, timeout) + Expect(err).ToNot(HaveOccurred()) + Expect(stdout).ToNot(BeEmpty()) + Expect(stderr).To(BeEmpty()) + }) + + It("should write and read poem from a file", func() { + By("Writing poem to a file") + stdout, stderr, err := dcp.Exec([]string{"echo", onelineCows, " \">\" ", flyingCowsPath}, timeout) + Expect(err).ToNot(HaveOccurred()) + Expect(stdout).To(BeEmpty()) + Expect(stderr).To(BeEmpty()) + + By("Reading poem from a file") + stdout, stderr, err = dcp.Exec([]string{"cat", flyingCowsPath}, timeout) + Expect(err).ToNot(HaveOccurred()) + Expect(string(stdout[:len(stdout)-2])).To(BeIdenticalTo(onelineCows)) + Expect(stderr).To(BeEmpty()) + }) + + It("should not read poem from nonexistent file", func() { + stdout, stderr, err := dcp.Exec([]string{"cat", flyingCowsPath + ".txt"}, timeout) + Expect(err).ToNot(HaveOccurred()) // When sdb is used no error is returned. + Expect(stdout).To(ContainSubstring("No such file")) // And stderr are redirected to stdout. + Expect(stderr).To(BeEmpty()) + }) + + It("should transfer files to and from DUT", func() { + os.Mkdir("/tmp/dl", 0755) + + By("Sending files to DUT") + err := dcp.CopyFilesTo(testFiles, "/tmp/") + Expect(err).ToNot(HaveOccurred()) + + By("Receiving files from DUT") + err = dcp.CopyFilesFrom(testFiles, "/tmp/dl/") + Expect(err).ToNot(HaveOccurred()) + for _, path := range testFiles { + fl, _ := os.Open(path) + ls, _ := fl.Stat() + fr, _ := os.Open("/tmp/dl/" + filepath.Base(path)) + rs, _ := fr.Stat() + Expect(ls.Size()).To(BeIdenticalTo(rs.Size())) + fl.Close() + fr.Close() + } + }) + + It("should not transfer files to Dryad's nonexistent directory", func() { + err := dcp.CopyFilesTo(testFiles, "/nonexistent_dir/") + Expect(err).To(HaveOccurred()) + }) + + It("should not transfer nonexistent file from Dryad's", func() { + err := dcp.CopyFilesFrom([]string{"/nonexistent_dir/nonexistent_file"}, "/tmp/dl/") + Expect(err).To(HaveOccurred()) + }) +}) -- 2.7.4