Commit f233a0f6 authored by Kamil Trzciński's avatar Kamil Trzciński

Added helpers tests

parent 63b2cb01
......@@ -160,6 +160,7 @@ mocks: FORCE
go get github.com/vektra/mockery/.../
rm -rf mocks/
mockery -dir=$(GOPATH)/src/github.com/ayufan/golang-kardianos-service -name=Interface
mockery -dir=./common -name=Network
test-docker:
make test-docker-image IMAGE=centos:6 TYPE=rpm
......
package commands_helpers
import (
"archive/zip"
"github.com/stretchr/testify/assert"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
)
const UntrackedFileName = "some_fancy_untracked_file"
var currentDir, _ = os.Getwd()
func randomTempFile(t *testing.T, format string) string {
file, err := ioutil.TempFile("", "archive_")
assert.NoError(t, err)
defer file.Close()
defer os.Remove(file.Name())
return file.Name() + format
}
func createArchiveCommand(t *testing.T) *ArchiveCommand {
err := os.Chdir(filepath.Join(currentDir, "..", ".."))
assert.NoError(t, err)
return &ArchiveCommand{
File: randomTempFile(t, ".zip"),
Verbose: true,
}
}
func filesInFolder(path string) []string {
matches, _ := filepath.Glob(path)
return matches
}
func readArchiveContent(t *testing.T, c *ArchiveCommand) (resultMap map[string]bool) {
resultMap = make(map[string]bool)
archive, err := zip.OpenReader(c.File)
assert.NoError(t, err)
defer archive.Close()
for _, file := range archive.File {
resultMap[file.Name] = true
}
return
}
func verifyArchiveContent(t *testing.T, c *ArchiveCommand, files ...string) {
resultMap := readArchiveContent(t, c)
for _, file := range files {
assert.True(t, resultMap[file], "File should exist %q", file)
delete(resultMap, file)
}
assert.Len(t, resultMap, 0, "No extra file should exist")
}
func TestArchiveNotCreatingArchive(t *testing.T) {
cmd := createArchiveCommand(t)
defer os.Remove(cmd.File)
cmd.Execute(nil)
_, err := os.Stat(cmd.File)
assert.True(t, os.IsNotExist(err), "File should not exist", cmd.File, err)
}
func TestArchiveAddingSomeLocalFiles(t *testing.T) {
cmd := createArchiveCommand(t)
defer os.Remove(cmd.File)
cmd.Paths = []string{
"commands/helpers/*",
}
cmd.Execute(nil)
verifyArchiveContent(t, cmd, filesInFolder("commands/helpers/*")...)
}
func TestArchiveNotAddingDuplicateFiles(t *testing.T) {
cmd := createArchiveCommand(t)
defer os.Remove(cmd.File)
cmd.Paths = []string{
"commands/helpers/*",
"commands/helpers/archive.go",
}
cmd.Execute(nil)
verifyArchiveContent(t, cmd, filesInFolder("commands/helpers/*")...)
}
func TestArchiveAddingUntrackedFiles(t *testing.T) {
cmd := createArchiveCommand(t)
defer os.Remove(cmd.File)
err := ioutil.WriteFile(UntrackedFileName, []byte{}, 0700)
assert.NoError(t, err)
cmd.Untracked = true
cmd.Execute(nil)
files := readArchiveContent(t, cmd)
assert.NotEmpty(t, files)
assert.True(t, files[UntrackedFileName])
}
func TestArchiveUpdating(t *testing.T) {
tempFile := randomTempFile(t, ".zip")
defer os.Remove(tempFile)
err := ioutil.WriteFile(UntrackedFileName, []byte{}, 0700)
assert.NoError(t, err)
cmd := createArchiveCommand(t)
defer os.Remove(cmd.File)
cmd.Paths = []string{
"commands",
UntrackedFileName,
}
cmd.Execute(nil)
archive1, err := os.Stat(cmd.File)
assert.NoError(t, err, "Archive is created")
cmd.Execute(nil)
archive2, err := os.Stat(cmd.File)
assert.NoError(t, err, "Archive is created")
assert.Equal(t, archive1.ModTime(), archive2.ModTime(), "Archive should not be modified")
time.Sleep(time.Second)
err = ioutil.WriteFile(UntrackedFileName, []byte{}, 0700)
assert.NoError(t, err, "File is created")
cmd.Execute(nil)
archive3, err := os.Stat(cmd.File)
assert.NoError(t, err, "Archive is created")
assert.NotEqual(t, archive2.ModTime(), archive3.ModTime(), "File is added to archive")
time.Sleep(time.Second)
err = ioutil.WriteFile(UntrackedFileName, []byte{}, 0700)
assert.NoError(t, err, "File is updated")
cmd.Execute(nil)
archive4, err := os.Stat(cmd.File)
assert.NoError(t, err, "Archive is created")
assert.NotEqual(t, archive3.ModTime(), archive4.ModTime(), "File is updated in archive")
}
package commands_helpers
import (
"errors"
"io/ioutil"
"os"
"time"
......@@ -17,29 +16,23 @@ import (
type ArtifactsDownloaderCommand struct {
common.BuildCredentials
retryHelper
network common.Network
}
func (c *ArtifactsDownloaderCommand) download(file string) error {
gl := network.GitLabClient{}
// If the download fails, exit with a non-zero exit code to indicate an issue?
retry:
for i := 0; i < 3; i++ {
switch gl.DownloadArtifacts(c.BuildCredentials, file) {
case common.DownloadSucceeded:
return nil
case common.DownloadNotFound:
return os.ErrNotExist
case common.DownloadForbidden:
break retry
case common.DownloadFailed:
// wait one second to retry
logrus.Warningln("Retrying...")
time.Sleep(time.Second)
break
}
func (c *ArtifactsDownloaderCommand) download(file string) (bool, error) {
switch c.network.DownloadArtifacts(c.BuildCredentials, file) {
case common.DownloadSucceeded:
return false, nil
case common.DownloadNotFound:
return false, os.ErrNotExist
case common.DownloadForbidden:
return false, os.ErrPermission
case common.DownloadFailed:
return true, os.ErrInvalid
default:
return false, os.ErrInvalid
}
return errors.New("Failed to download artifacts")
}
func (c *ArtifactsDownloaderCommand) Execute(context *cli.Context) {
......@@ -61,7 +54,9 @@ func (c *ArtifactsDownloaderCommand) Execute(context *cli.Context) {
defer os.Remove(file.Name())
// Download artifacts file
err = c.download(file.Name())
err = c.doRetry(func() (bool, error) {
return c.download(file.Name())
})
if err != nil {
logrus.Fatalln(err)
}
......@@ -74,5 +69,11 @@ func (c *ArtifactsDownloaderCommand) Execute(context *cli.Context) {
}
func init() {
common.RegisterCommand2("artifacts-downloader", "download and extract build artifacts (internal)", &ArtifactsDownloaderCommand{})
common.RegisterCommand2("artifacts-downloader", "download and extract build artifacts (internal)", &ArtifactsDownloaderCommand{
network: &network.GitLabClient{},
retryHelper: retryHelper{
Retry: 2,
RetryTime: time.Second,
},
})
}
package commands_helpers
import (
"testing"
"github.com/stretchr/testify/assert"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
"os"
)
var downloaderCredentials = common.BuildCredentials{
ID: 1000,
Token: "test",
URL: "test",
}
func TestArtifactsDownloaderRequirements(t *testing.T) {
helpers.MakeFatalToPanic()
cmd := ArtifactsDownloaderCommand{}
assert.Panics(t, func() {
cmd.Execute(nil)
})
}
func TestArtifactsDownloaderNotFound(t *testing.T) {
network := &testNetwork{
downloadState: common.DownloadNotFound,
}
cmd := ArtifactsDownloaderCommand{
BuildCredentials: downloaderCredentials,
network: network,
}
assert.Panics(t, func() {
cmd.Execute(nil)
})
assert.Equal(t, 1, network.downloadCalled)
}
func TestArtifactsDownloaderForbidden(t *testing.T) {
network := &testNetwork{
downloadState: common.DownloadForbidden,
}
cmd := ArtifactsDownloaderCommand{
BuildCredentials: downloaderCredentials,
network: network,
}
assert.Panics(t, func() {
cmd.Execute(nil)
})
assert.Equal(t, 1, network.downloadCalled)
}
func TestArtifactsDownloaderRetry(t *testing.T) {
network := &testNetwork{
downloadState: common.DownloadFailed,
}
cmd := ArtifactsDownloaderCommand{
BuildCredentials: downloaderCredentials,
network: network,
retryHelper: retryHelper{
Retry: 2,
},
}
assert.Panics(t, func() {
cmd.Execute(nil)
})
assert.Equal(t, 3, network.downloadCalled)
}
func TestArtifactsDownloaderSucceeded(t *testing.T) {
network := &testNetwork{
downloadState: common.DownloadSucceeded,
}
cmd := ArtifactsDownloaderCommand{
BuildCredentials: downloaderCredentials,
network: network,
}
os.Remove(artifactsTestArchivedFile)
fi, _ := os.Stat(artifactsTestArchivedFile)
assert.Nil(t, fi)
cmd.Execute(nil)
assert.Equal(t, 1, network.downloadCalled)
fi, _ = os.Stat(artifactsTestArchivedFile)
assert.NotNil(t, fi)
}
package commands_helpers
import (
"archive/zip"
"bytes"
"github.com/Sirupsen/logrus"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/mocks"
"io"
"os"
)
const artifactsTestArchivedFile = "archive_file"
type testNetwork struct {
mocks.Network
downloadState common.DownloadState
downloadCalled int
uploadState common.UploadState
uploadCalled int
}
func (m *testNetwork) DownloadArtifacts(config common.BuildCredentials, artifactsFile string) common.DownloadState {
m.downloadCalled++
if m.downloadState == common.DownloadSucceeded {
file, err := os.Create(artifactsFile)
if err != nil {
logrus.Warningln(err)
return common.DownloadFailed
}
defer file.Close()
archive := zip.NewWriter(file)
archive.Create(artifactsTestArchivedFile)
archive.Close()
}
return m.downloadState
}
func (m *testNetwork) UploadRawArtifacts(config common.BuildCredentials, reader io.Reader, baseName string) common.UploadState {
m.uploadCalled++
if m.uploadState == common.UploadSucceeded {
var buffer bytes.Buffer
io.Copy(&buffer, reader)
archive, err := zip.NewReader(bytes.NewReader(buffer.Bytes()), int64(buffer.Len()))
if err != nil {
logrus.Warningln(err)
return common.UploadForbidden
}
if len(archive.File) != 1 || archive.File[0].Name != artifactsTestArchivedFile {
logrus.Warningln("Invalid archive:", len(archive.File))
return common.UploadForbidden
}
}
return m.uploadState
}
......@@ -8,6 +8,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
"errors"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/archives"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/formatter"
......@@ -16,10 +17,12 @@ import (
type ArtifactsUploaderCommand struct {
common.BuildCredentials
FileArchiver
fileArchiver
retryHelper
network common.Network
}
func (c *ArtifactsUploaderCommand) createAndUpload(network common.Network) common.UploadState {
func (c *ArtifactsUploaderCommand) createAndUpload() (bool, error) {
pr, pw := io.Pipe()
defer pr.Close()
......@@ -30,7 +33,18 @@ func (c *ArtifactsUploaderCommand) createAndUpload(network common.Network) commo
}()
// Upload the data
return network.UploadRawArtifacts(c.BuildCredentials, pr, "artifacts.zip")
switch c.network.UploadRawArtifacts(c.BuildCredentials, pr, "artifacts.zip") {
case common.UploadSucceeded:
return false, nil
case common.UploadForbidden:
return false, os.ErrPermission
case common.UploadTooLarge:
return false, errors.New("Too large")
case common.UploadFailed:
return true, os.ErrInvalid
default:
return false, os.ErrInvalid
}
}
func (c *ArtifactsUploaderCommand) Execute(*cli.Context) {
......@@ -49,28 +63,19 @@ func (c *ArtifactsUploaderCommand) Execute(*cli.Context) {
logrus.Fatalln(err)
}
gl := network.GitLabClient{}
// If the upload fails, exit with a non-zero exit code to indicate an issue?
retry:
for i := 0; i < 3; i++ {
switch c.createAndUpload(&gl) {
case common.UploadSucceeded:
return
case common.UploadForbidden:
break retry
case common.UploadTooLarge:
break retry
case common.UploadFailed:
// wait one second to retry
logrus.Warningln("Retrying...")
time.Sleep(time.Second)
break
}
err = c.doRetry(c.createAndUpload)
if err != nil {
logrus.Fatalln(err)
}
os.Exit(1)
}
func init() {
common.RegisterCommand2("artifacts-uploader", "create and upload build artifacts (internal)", &ArtifactsUploaderCommand{})
common.RegisterCommand2("artifacts-uploader", "create and upload build artifacts (internal)", &ArtifactsUploaderCommand{
network: &network.GitLabClient{},
retryHelper: retryHelper{
Retry: 2,
RetryTime: time.Second,
},
})
}
package commands_helpers
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
"io/ioutil"
)
var UploaderCredentials = common.BuildCredentials{
ID: 1000,
Token: "test",
URL: "test",
}
func TestArtifactsUploaderRequirements(t *testing.T) {
helpers.MakeFatalToPanic()
cmd := ArtifactsUploaderCommand{}
assert.Panics(t, func() {
cmd.Execute(nil)
})
}
func TestArtifactsUploaderTooLarge(t *testing.T) {
network := &testNetwork{
uploadState: common.UploadTooLarge,
}
cmd := ArtifactsUploaderCommand{
BuildCredentials: UploaderCredentials,
network: network,
}
assert.Panics(t, func() {
cmd.Execute(nil)
})
assert.Equal(t, 1, network.uploadCalled)
}
func TestArtifactsUploaderForbidden(t *testing.T) {
network := &testNetwork{
uploadState: common.UploadForbidden,
}
cmd := ArtifactsUploaderCommand{
BuildCredentials: UploaderCredentials,
network: network,
}
assert.Panics(t, func() {
cmd.Execute(nil)
})
assert.Equal(t, 1, network.uploadCalled)
}
func TestArtifactsUploaderRetry(t *testing.T) {
network := &testNetwork{
uploadState: common.UploadFailed,
}
cmd := ArtifactsUploaderCommand{
BuildCredentials: UploaderCredentials,
network: network,
retryHelper: retryHelper{
Retry: 2,
},
}
assert.Panics(t, func() {
cmd.Execute(nil)
})
assert.Equal(t, 3, network.uploadCalled)
}
func TestArtifactsUploaderSucceeded(t *testing.T) {
network := &testNetwork{
uploadState: common.UploadSucceeded,
}
cmd := ArtifactsUploaderCommand{
BuildCredentials: UploaderCredentials,
network: network,
fileArchiver: fileArchiver{
Paths: []string{artifactsTestArchivedFile},
},
}
ioutil.WriteFile(artifactsTestArchivedFile, nil, 0600)
defer os.Remove(artifactsTestArchivedFile)
cmd.Execute(nil)
assert.Equal(t, 1, network.uploadCalled)
fi, _ := os.Stat(artifactsTestArchivedFile)
assert.NotNil(t, fi)
}
......@@ -9,7 +9,7 @@ import (
)
type CacheArchiverCommand struct {
FileArchiver
fileArchiver
File string `long:"file" description:"The path to file"`
}
......
package commands_helpers
import (
"testing"
"github.com/stretchr/testify/assert"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
"io/ioutil"
"os"
"time"
)
const cacheArchiverArchive = "archive.zip"
const cacheArchiverTestArchivedFile = "archive_file"
func TestCacheArchiverIsUpToDate(t *testing.T) {
ioutil.WriteFile(cacheArchiverTestArchivedFile, nil, 0600)
defer os.Remove(cacheArchiverTestArchivedFile)
defer os.Remove(cacheArchiverArchive)
cmd := CacheArchiverCommand{
File: cacheArchiverArchive,
fileArchiver: fileArchiver{
Paths: []string{
cacheArchiverTestArchivedFile,
},
},
}
cmd.Execute(nil)
fi, _ := os.Stat(cacheArchiverArchive)
cmd.Execute(nil)
fi2, _ := os.Stat(cacheArchiverArchive)
assert.Equal(t, fi.ModTime(), fi2.ModTime())
os.Chtimes(cacheArchiverTestArchivedFile, time.Now(), time.Now())
cmd.Execute(nil)
fi3, _ := os.Stat(cacheArchiverArchive)
assert.Equal(t, fi.ModTime(), fi3.ModTime())
}
func TestCacheArchiverForIfNoFileDefined(t *testing.T) {
helpers.MakeFatalToPanic()
cmd := CacheArchiverCommand{}
assert.Panics(t, func() {
cmd.Execute(nil)
})
}
func TestCacheArchiverForNotExistingFile(t *testing.T) {
helpers.MakeFatalToPanic()
cmd := CacheArchiverCommand{
File: "/../../../test.zip",
}
assert.Panics(t, func() {
cmd.Execute(nil)
})
}
package commands_helpers
import (
"testing"
"archive/zip"
"github.com/stretchr/testify/assert"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
"io/ioutil"
"os"
)
const cacheExtractorArchive = "archive.zip"
const cacheExtractorTestArchivedFile = "archive_file"
func TestCacheExtractorValidArchive(t *testing.T) {
file, err := os.Create(cacheExtractorArchive)
assert.NoError(t, err)
defer file.Close()
defer os.Remove(file.Name())
defer os.Remove(cacheExtractorTestArchivedFile)
archive := zip.NewWriter(file)
archive.Create(cacheExtractorTestArchivedFile)
archive.Close()
_, err = os.Stat(cacheExtractorTestArchivedFile)
assert.Error(t, err)
cmd := CacheExtractorCommand{
File: cacheExtractorArchive,
}
assert.NotPanics(t, func() {
cmd.Execute(nil)
})
_, err = os.Stat(cacheExtractorTestArchivedFile)
assert.NoError(t, err)
}
func TestCacheExtractorForInvalidArchive(t *testing.T) {
helpers.MakeFatalToPanic()
ioutil.WriteFile(cacheExtractorArchive, nil, 0600)
defer os.Remove(cacheExtractorArchive)
cmd := CacheExtractorCommand{
File: cacheExtractorArchive,
}
assert.Panics(t, func() {
cmd.Execute(nil)
})
}
func TestCacheExtractorForIfNoFileDefined(t *testing.T) {
helpers.MakeFatalToPanic()
cmd := CacheExtractorCommand{}
assert.Panics(t, func() {
cmd.Execute(nil)
})
}
func TestCacheExtractorForNotExistingFile(t *testing.T) {
helpers.MakeFatalToPanic()
cmd := CacheExtractorCommand{
File: "/../../../test.zip",
}
assert.NotPanics(t, func() {
cmd.Execute(nil)
})
}
......@@ -16,7 +16,7 @@ import (
"github.com/Sirupsen/logrus"
)
type FileArchiver struct {
type fileArchiver struct {
Paths []string `long:"path" description:"Add paths to archive"`
Untracked bool `long:"untracked" description:"Add git untracked files"`
Verbose bool `long:"verbose" description:"Detailed information"`
......@@ -25,7 +25,7 @@ type FileArchiver struct {
files map[string]os.FileInfo
}
func (c *FileArchiver) isChanged(modTime time.Time) bool {
func (c *fileArchiver) isChanged(modTime time.Time) bool {