1package cmd_test
2
3import (
4	"errors"
5	"fmt"
6	"io"
7	"os"
8	"path/filepath"
9	"syscall"
10	"time"
11
12	"code.cloudfoundry.org/clock"
13	"code.cloudfoundry.org/clock/fakeclock"
14	fakeui "github.com/cloudfoundry/bosh-cli/ui/fakes"
15	fakesys "github.com/cloudfoundry/bosh-utils/system/fakes"
16	. "github.com/onsi/ginkgo"
17	. "github.com/onsi/gomega"
18
19	. "github.com/cloudfoundry/bosh-cli/cmd"
20	fakedir "github.com/cloudfoundry/bosh-cli/director/directorfakes"
21)
22
23var _ = Describe("UIDownloader", func() {
24	var (
25		director    *fakedir.FakeDirector
26		fs          *fakesys.FakeFileSystem
27		timeService clock.Clock
28		ui          *fakeui.FakeUI
29		downloader  UIDownloader
30	)
31
32	BeforeEach(func() {
33		director = &fakedir.FakeDirector{}
34		timeService = fakeclock.NewFakeClock(time.Date(2009, time.November, 10, 23, 1, 2, 333, time.UTC))
35		fs = fakesys.NewFakeFileSystem()
36		ui = &fakeui.FakeUI{}
37		downloader = NewUIDownloader(director, timeService, fs, ui)
38	})
39
40	Describe("Download", func() {
41		var expectedPath string
42
43		BeforeEach(func() {
44			expectedPath = filepath.Join("/", "fake-dst-dir", "prefix-20091110-230102-000000333.tgz")
45
46			err := fs.MkdirAll("/fake-dst-dir", os.ModePerm)
47			Expect(err).ToNot(HaveOccurred())
48		})
49
50		itReturnsErrs := func(act func() error) {
51			It("returns error if downloading resource fails", func() {
52				err := fs.MkdirAll("/fake-dst-dir", os.ModePerm)
53				Expect(err).ToNot(HaveOccurred())
54
55				fs.ReturnTempFile = fakesys.NewFakeFile("/some-tmp-file", fs)
56
57				director.DownloadResourceUncheckedStub = func(_ string, _ io.Writer) error {
58					return errors.New("fake-err")
59				}
60
61				err = act()
62				Expect(err).To(HaveOccurred())
63				Expect(err.Error()).To(ContainSubstring("fake-err"))
64
65				Expect(fs.FileExists("/some-tmp-file")).To(BeFalse())
66				Expect(fs.FileExists(expectedPath)).To(BeFalse())
67			})
68
69			It("returns error if temp file cannot be created", func() {
70				fs.TempFileError = errors.New("fake-err")
71
72				err := act()
73				Expect(err).To(HaveOccurred())
74				Expect(err.Error()).To(ContainSubstring("fake-err"))
75
76				Expect(director.DownloadResourceUncheckedCallCount()).To(Equal(0))
77				Expect(fs.FileExists(expectedPath)).To(BeFalse())
78			})
79		}
80
81		Context("when SHA1 is provided", func() {
82			act := func() error {
83				return downloader.Download("fake-blob-id", "a2511842a89119b9da922f9528307b7f8f55b798", "prefix", "/fake-dst-dir")
84			}
85
86			It("downloads specified blob to a specific destination", func() {
87				fakeFile := fakesys.NewFakeFile("/some-tmp-file", fs)
88				fakeFile.Write([]byte("file-contents"))
89				fs.ReturnTempFile = fakeFile
90
91				director.DownloadResourceUncheckedStub = func(_ string, out io.Writer) error {
92					out.Write([]byte("file-contents"))
93					return nil
94				}
95
96				err := act()
97				Expect(err).ToNot(HaveOccurred())
98
99				Expect(fs.FileExists("/some-tmp-file")).To(BeFalse())
100				Expect(fs.FileExists(expectedPath)).To(BeTrue())
101				Expect(fs.ReadFileString(expectedPath)).To(Equal("file-contents"))
102
103				blobID, _ := director.DownloadResourceUncheckedArgsForCall(0)
104				Expect(blobID).To(Equal("fake-blob-id"))
105
106				Expect(ui.Said).To(Equal([]string{
107					fmt.Sprintf("Downloading resource 'fake-blob-id' to '%s'...", expectedPath)}))
108			})
109
110			It("returns error if sha1 does not match expected sha1", func() {
111				fakeFile := fakesys.NewFakeFile("/some-tmp-file", fs)
112				fakeFile.Write([]byte("file-contents-that-were-corrupted"))
113				fs.ReturnTempFile = fakeFile
114
115				err := act()
116				Expect(err).To(HaveOccurred())
117				Expect(err.Error()).To(Equal("Expected stream to have digest 'a2511842a89119b9da922f9528307b7f8f55b798' but was '93135ede4065c7d5958ab7e328d501f8d4d9e2aa'"))
118
119				Expect(fs.FileExists(expectedPath)).To(BeFalse())
120			})
121
122			It("returns error if sha1 check fails", func() {
123				fakeFile := fakesys.NewFakeFile("/some-tmp-file", fs)
124				fakeFile.Write([]byte("file-contents-that-were-corrupted"))
125				fs.ReturnTempFile = fakeFile
126				fs.OpenFileErr = errors.New("fake-err")
127
128				err := act()
129				Expect(err).To(HaveOccurred())
130				Expect(err.Error()).To(ContainSubstring("fake-err"))
131
132				Expect(fs.FileExists(expectedPath)).To(BeFalse())
133			})
134
135			itReturnsErrs(act)
136		})
137
138		Context("when SHA1 is not provided", func() {
139			act := func() error { return downloader.Download("fake-blob-id", "", "prefix", "/fake-dst-dir") }
140
141			It("downloads specified blob to a specific destination without checking SHA1", func() {
142				fs.ReturnTempFile = fakesys.NewFakeFile("/some-tmp-file", fs)
143
144				director.DownloadResourceUncheckedStub = func(_ string, out io.Writer) error {
145					out.Write([]byte("content"))
146					return nil
147				}
148
149				err := act()
150				Expect(err).ToNot(HaveOccurred())
151
152				Expect(fs.FileExists("/some-tmp-file")).To(BeFalse())
153				Expect(fs.FileExists(expectedPath)).To(BeTrue())
154				Expect(fs.ReadFileString(expectedPath)).To(Equal("content"))
155
156				blobID, _ := director.DownloadResourceUncheckedArgsForCall(0)
157				Expect(blobID).To(Equal("fake-blob-id"))
158
159				Expect(ui.Said).To(Equal([]string{
160					fmt.Sprintf("Downloading resource 'fake-blob-id' to '%s'...", expectedPath)}))
161			})
162
163			itReturnsErrs(act)
164		})
165
166		Context("when downloading across devices", func() {
167			BeforeEach(func() {
168				fs.RenameError = &os.LinkError{
169					Err: syscall.Errno(0x12),
170				}
171			})
172
173			act := func() error { return downloader.Download("fake-blob-id", "", "prefix", "/fake-dst-dir") }
174
175			It("downloads specified blob to a specific destination without checking SHA1", func() {
176				fs.ReturnTempFile = fakesys.NewFakeFile("/some-tmp-file", fs)
177
178				director.DownloadResourceUncheckedStub = func(_ string, out io.Writer) error {
179					out.Write([]byte("content"))
180					return nil
181				}
182
183				err := act()
184				Expect(err).ToNot(HaveOccurred())
185
186				Expect(fs.FileExists("/some-tmp-file")).To(BeFalse())
187				Expect(fs.FileExists(expectedPath)).To(BeTrue())
188				Expect(fs.ReadFileString(expectedPath)).To(Equal("content"))
189
190				blobID, _ := director.DownloadResourceUncheckedArgsForCall(0)
191				Expect(blobID).To(Equal("fake-blob-id"))
192
193				Expect(ui.Said).To(Equal([]string{
194					fmt.Sprintf("Downloading resource 'fake-blob-id' to '%s'...", expectedPath)}))
195			})
196
197			itReturnsErrs(act)
198		})
199	})
200})
201