mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
439a7ad82e
* added initializing empty repo * updated go.mod * updated go.mod * updated go.sum * updated go.mod * updated go.mod * updated go.mod --------- Co-authored-by: sumeet patil <sumeet.patil@sap.com>
428 lines
10 KiB
Go
428 lines
10 KiB
Go
package codeql
|
|
|
|
import (
|
|
"archive/zip"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/go-git/go-git/v5/plumbing"
|
|
"github.com/go-git/go-git/v5/plumbing/object"
|
|
"github.com/stretchr/testify/assert"
|
|
"gopkg.in/yaml.v2"
|
|
"k8s.io/utils/strings/slices"
|
|
)
|
|
|
|
const (
|
|
notExists = "not-exists"
|
|
exists = "exists"
|
|
refsHeads = "refs/heads/"
|
|
)
|
|
|
|
type gitMock struct {
|
|
ref string
|
|
url string
|
|
}
|
|
|
|
func newGitMock(ref, url string) *gitMock {
|
|
return &gitMock{ref: ref, url: url}
|
|
}
|
|
|
|
func (g *gitMock) listRemote() ([]reference, error) {
|
|
if g.url == notExists {
|
|
return nil, fmt.Errorf("repository not found")
|
|
}
|
|
list := []*referenceMock{
|
|
{
|
|
name: refsHeads + "ref1",
|
|
},
|
|
{
|
|
name: refsHeads + "ref2",
|
|
},
|
|
{
|
|
name: refsHeads + "ref3",
|
|
},
|
|
{
|
|
name: refsHeads + exists,
|
|
},
|
|
}
|
|
var convertedList []reference
|
|
for _, ref := range list {
|
|
convertedList = append(convertedList, ref)
|
|
}
|
|
return convertedList, nil
|
|
}
|
|
|
|
func (g *gitMock) cloneRepo(dir string, opts *git.CloneOptions) (*git.Repository, error) {
|
|
if opts.Auth == nil {
|
|
return nil, fmt.Errorf("error")
|
|
}
|
|
if opts.URL == notExists {
|
|
return nil, fmt.Errorf("error")
|
|
}
|
|
return &git.Repository{}, nil
|
|
}
|
|
|
|
func (g *gitMock) switchOrphan(branch string, repo *git.Repository) error {
|
|
return nil
|
|
}
|
|
|
|
func (g *gitMock) initRepo(dir string) (*git.Repository, error) {
|
|
return &git.Repository{}, nil
|
|
}
|
|
|
|
type referenceMock struct {
|
|
name string
|
|
}
|
|
|
|
func (r *referenceMock) Name() plumbing.ReferenceName {
|
|
return plumbing.ReferenceName(r.name)
|
|
}
|
|
|
|
type repoMock struct{}
|
|
|
|
func (r *repoMock) Worktree() (*git.Worktree, error) {
|
|
return &git.Worktree{}, nil
|
|
}
|
|
|
|
func (r *repoMock) CommitObject(commit plumbing.Hash) (*object.Commit, error) {
|
|
return &object.Commit{Hash: commit}, nil
|
|
}
|
|
|
|
func (r *repoMock) Push(opts *git.PushOptions) error {
|
|
if opts.Auth == nil {
|
|
return fmt.Errorf("error")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type worktreeMock struct{}
|
|
|
|
func (t *worktreeMock) RemoveGlob(pattern string) error {
|
|
return nil
|
|
}
|
|
|
|
func (t *worktreeMock) Clean(opts *git.CleanOptions) error {
|
|
return nil
|
|
}
|
|
|
|
func (t *worktreeMock) AddWithOptions(opts *git.AddOptions) error {
|
|
return nil
|
|
}
|
|
|
|
func (t *worktreeMock) Commit(msg string, opts *git.CommitOptions) (plumbing.Hash, error) {
|
|
if opts.Author == nil {
|
|
return plumbing.Hash{}, fmt.Errorf("error")
|
|
}
|
|
return plumbing.Hash{}, nil
|
|
}
|
|
|
|
func TestDoesRefExist(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Invalid repository", func(t *testing.T) {
|
|
ghUploader := newGitMock(refsHeads+notExists, notExists)
|
|
_, _, err := doesRefExist(ghUploader, refsHeads+notExists)
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
t.Run("Ref exists", func(t *testing.T) {
|
|
ghUploader := newGitMock(refsHeads+exists, exists)
|
|
ok, _, err := doesRefExist(ghUploader, refsHeads+exists)
|
|
assert.NoError(t, err)
|
|
assert.True(t, ok)
|
|
})
|
|
t.Run("Ref doesn't exist", func(t *testing.T) {
|
|
ghUploader := newGitMock(refsHeads+notExists, exists)
|
|
ok, _, err := doesRefExist(ghUploader, refsHeads+notExists)
|
|
assert.NoError(t, err)
|
|
assert.False(t, ok)
|
|
})
|
|
}
|
|
|
|
func TestClone(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Created new branch", func(t *testing.T) {
|
|
ghUploader := newGitMock(refsHeads+notExists, exists)
|
|
repo, err := clone(ghUploader, ghUploader.url, "", ghUploader.ref, "", false, false)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, repo)
|
|
})
|
|
t.Run("Target branch exists", func(t *testing.T) {
|
|
ghUploader := newGitMock(refsHeads+exists, exists)
|
|
repo, err := clone(ghUploader, ghUploader.url, "", ghUploader.ref, "", false, true)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, repo)
|
|
})
|
|
t.Run("Repo was empty", func(t *testing.T) {
|
|
ghUploader := newGitMock(refsHeads+exists, exists)
|
|
repo, err := clone(ghUploader, ghUploader.url, "", ghUploader.ref, "", true, false)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, repo)
|
|
})
|
|
}
|
|
|
|
func TestClean(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Success", func(t *testing.T) {
|
|
tree := &worktreeMock{}
|
|
err := cleanDir(tree)
|
|
assert.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestAdd(t *testing.T) {
|
|
t.Run("Success", func(t *testing.T) {
|
|
tree := &worktreeMock{}
|
|
err := add(tree)
|
|
assert.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestCommit(t *testing.T) {
|
|
t.Run("Success", func(t *testing.T) {
|
|
tree := &worktreeMock{}
|
|
repo := &repoMock{}
|
|
c, err := commit(repo, tree, "", "")
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, c)
|
|
})
|
|
}
|
|
|
|
func TestPush(t *testing.T) {
|
|
t.Run("Success", func(t *testing.T) {
|
|
repo := &repoMock{}
|
|
err := push(repo, "")
|
|
assert.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestUnzip(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("Success", func(t *testing.T) {
|
|
targetDir, err := os.MkdirTemp("", "tmp_target")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.RemoveAll(targetDir)
|
|
sourceDir, err := os.MkdirTemp("", "tmp_source")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.RemoveAll(sourceDir)
|
|
zipPath := filepath.Join(sourceDir, "src.zip")
|
|
|
|
srcFilenames := []string{
|
|
filepath.Join(sourceDir, "file1"),
|
|
filepath.Join(sourceDir, "file2"),
|
|
filepath.Join(sourceDir, "codeqlDB"),
|
|
filepath.Join(sourceDir, "subfolder1", "file1"),
|
|
filepath.Join(sourceDir, "subfolder1", "file2"),
|
|
filepath.Join(sourceDir, "subfolder2", "file1"),
|
|
}
|
|
err = createZIP(zipPath, srcFilenames)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
assert.NoError(t, unzip(zipPath, targetDir, sourceDir, "codeqlDB"))
|
|
targetFilenames := []string{
|
|
filepath.Join(targetDir, "file1"),
|
|
filepath.Join(targetDir, "file2"),
|
|
filepath.Join(targetDir, "subfolder1", "file1"),
|
|
filepath.Join(targetDir, "subfolder1", "file2"),
|
|
filepath.Join(targetDir, "subfolder2", "file1"),
|
|
}
|
|
checkExistedFiles(t, targetDir, targetFilenames)
|
|
})
|
|
|
|
t.Run("Empty zip", func(t *testing.T) {
|
|
targetDir, err := os.MkdirTemp("", "tmp_target")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.RemoveAll(targetDir)
|
|
sourceDir, err := os.MkdirTemp("", "tmp_source")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.RemoveAll(sourceDir)
|
|
zipPath := filepath.Join(sourceDir, "src.zip")
|
|
|
|
filenames := []string{}
|
|
err = createZIP(zipPath, filenames)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
assert.NoError(t, unzip(zipPath, targetDir, sourceDir, "codeqlDB"))
|
|
checkExistedFiles(t, targetDir, filenames)
|
|
})
|
|
|
|
t.Run("zip not found", func(t *testing.T) {
|
|
targetDir, err := os.MkdirTemp("", "tmp_target")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.RemoveAll(targetDir)
|
|
sourceDir, err := os.MkdirTemp("", "tmp_source")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.RemoveAll(sourceDir)
|
|
zipPath := filepath.Join(sourceDir, "src.zip")
|
|
|
|
assert.Error(t, unzip(zipPath, targetDir, sourceDir, "codeqlDB"))
|
|
})
|
|
|
|
t.Run("extra files in zip", func(t *testing.T) {
|
|
targetDir, err := os.MkdirTemp("", "tmp_target")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.RemoveAll(targetDir)
|
|
sourceDir, err := os.MkdirTemp("", "tmp_source")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.RemoveAll(sourceDir)
|
|
zipPath := filepath.Join(sourceDir, "src.zip")
|
|
|
|
srcFilenames := []string{
|
|
filepath.Join(sourceDir, "file1"),
|
|
filepath.Join(sourceDir, "file2"),
|
|
filepath.Join(sourceDir, "subfolder1", "file1"),
|
|
filepath.Join(sourceDir, "subfolder1", "file2"),
|
|
filepath.Join(sourceDir, "subfolder2", "file1"),
|
|
filepath.Join(targetDir, "extrafile1"),
|
|
filepath.Join(targetDir, "extrafile2"),
|
|
filepath.Join(targetDir, "subfolder1", "extrafile1"),
|
|
}
|
|
err = createZIP(zipPath, srcFilenames)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
assert.NoError(t, unzip(zipPath, targetDir, sourceDir, "codeqlDB"))
|
|
targetFilenames := []string{
|
|
filepath.Join(targetDir, "file1"),
|
|
filepath.Join(targetDir, "file2"),
|
|
filepath.Join(targetDir, "subfolder1", "file1"),
|
|
filepath.Join(targetDir, "subfolder1", "file2"),
|
|
filepath.Join(targetDir, "subfolder2", "file1"),
|
|
}
|
|
checkExistedFiles(t, targetDir, targetFilenames)
|
|
})
|
|
}
|
|
|
|
func TestGetSourceLocationPrefix(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("Success", func(t *testing.T) {
|
|
filename := "test-file.yml"
|
|
location := "/some/location"
|
|
err := createFile(filename, location, false)
|
|
assert.NoError(t, err)
|
|
defer os.Remove(filename)
|
|
srcLocationPrefix, err := getSourceLocationPrefix(filename)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, location, srcLocationPrefix)
|
|
})
|
|
|
|
t.Run("No file found", func(t *testing.T) {
|
|
filename := "test-file-2.yml"
|
|
_, err := getSourceLocationPrefix(filename)
|
|
assert.Error(t, err)
|
|
})
|
|
|
|
t.Run("Empty file", func(t *testing.T) {
|
|
filename := "test-file-3.yml"
|
|
err := createFile(filename, "", true)
|
|
assert.NoError(t, err)
|
|
defer os.Remove(filename)
|
|
srcLocationPrefix, err := getSourceLocationPrefix(filename)
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, srcLocationPrefix)
|
|
})
|
|
}
|
|
|
|
func checkExistedFiles(t *testing.T, dir string, filenames []string) {
|
|
counter := 0
|
|
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if path == dir || info.IsDir() {
|
|
return nil
|
|
}
|
|
assert.True(t, slices.Contains(filenames, path))
|
|
counter++
|
|
return nil
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, len(filenames), counter)
|
|
}
|
|
|
|
func createZIP(zipPath string, filenames []string) error {
|
|
archive, err := os.Create(zipPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer archive.Close()
|
|
|
|
zipWriter := zip.NewWriter(archive)
|
|
defer zipWriter.Close()
|
|
|
|
for _, filename := range filenames {
|
|
writer, err := zipWriter.Create(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
reader := strings.NewReader("test content\n")
|
|
if _, err := io.Copy(writer, reader); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func createFile(fileName, location string, isEmpty bool) error {
|
|
err := ensureBaseDir(fileName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
if isEmpty {
|
|
return nil
|
|
}
|
|
|
|
type codeqlDatabase struct {
|
|
SourceLocation string `yaml:"sourceLocationPrefix"`
|
|
OtherInfo string `yaml:"otherInfo"`
|
|
}
|
|
db := codeqlDatabase{SourceLocation: location, OtherInfo: "test"}
|
|
data, err := yaml.Marshal(db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = f.Write(data)
|
|
return err
|
|
}
|
|
|
|
func ensureBaseDir(fpath string) error {
|
|
baseDir := path.Dir(fpath)
|
|
info, err := os.Stat(baseDir)
|
|
if err == nil && info.IsDir() {
|
|
return nil
|
|
}
|
|
return os.MkdirAll(baseDir, 0755)
|
|
}
|