blob: d8d2d7b94f828201563606898f11dc95d4ffdefb [file] [log] [blame]
// Copyright 2015 The LUCI Authors.
//
// 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 isolate
import (
"io"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
. "github.com/smartystreets/goconvey/convey"
"go.chromium.org/luci/common/system/filesystem"
)
func init() {
log.SetOutput(io.Discard)
}
func TestReplaceVars(t *testing.T) {
t.Parallel()
Convey(`Variables replacement should be supported in isolate files.`, t, func() {
opts := &ArchiveOptions{PathVariables: map[string]string{"VAR": "wonderful"}}
// Single replacement.
r, err := ReplaceVariables("hello <(VAR) world", opts)
So(err, ShouldBeNil)
So(r, ShouldResemble, "hello wonderful world")
// Multiple replacement.
r, err = ReplaceVariables("hello <(VAR) <(VAR) world", opts)
So(err, ShouldBeNil)
So(r, ShouldResemble, "hello wonderful wonderful world")
// Replacement of missing variable.
r, err = ReplaceVariables("hello <(MISSING) world", opts)
So(err.Error(), ShouldResemble, "no value for variable 'MISSING'")
})
}
func TestIgnoredPathsRegexp(t *testing.T) {
t.Parallel()
Convey(`Ignored file extensions`, t, func() {
regexStr := genExtensionsRegex("pyc", "swp")
re, err := regexp.Compile(regexStr)
So(err, ShouldBeNil)
So(re.MatchString("a.pyc"), ShouldBeTrue)
So(re.MatchString("foo/a.pyc"), ShouldBeTrue)
So(re.MatchString("/b.swp"), ShouldBeTrue)
So(re.MatchString(`foo\b.swp`), ShouldBeTrue)
So(re.MatchString("a.py"), ShouldBeFalse)
So(re.MatchString("b.swppp"), ShouldBeFalse)
})
Convey(`Ignored directories`, t, func() {
regexStr := genDirectoriesRegex("\\.git", "\\.hg", "\\.svn")
re, err := regexp.Compile(regexStr)
So(err, ShouldBeNil)
So(re.MatchString(".git"), ShouldBeTrue)
So(re.MatchString(".git/"), ShouldBeTrue)
So(re.MatchString("/.git/"), ShouldBeTrue)
So(re.MatchString("/.hg"), ShouldBeTrue)
So(re.MatchString("foo/.svn"), ShouldBeTrue)
So(re.MatchString(`.hg\`), ShouldBeTrue)
So(re.MatchString(`foo\.svn`), ShouldBeTrue)
So(re.MatchString(".get"), ShouldBeFalse)
So(re.MatchString("foo.git"), ShouldBeFalse)
So(re.MatchString(".svnnnn"), ShouldBeFalse)
})
}
func TestProcessIsolateFile(t *testing.T) {
t.Parallel()
Convey(`Directory deps should end with osPathSeparator`, t, func() {
tmpDir := t.TempDir()
baseDir := filepath.Join(tmpDir, "baseDir")
secondDir := filepath.Join(tmpDir, "secondDir")
So(os.Mkdir(baseDir, 0700), ShouldBeNil)
So(os.Mkdir(secondDir, 0700), ShouldBeNil)
So(os.WriteFile(filepath.Join(baseDir, "foo"), []byte("foo"), 0600), ShouldBeNil)
// Note that for "secondDir", its separator is omitted intentionally.
isolate := `{
'variables': {
'files': [
'../baseDir/',
'../secondDir',
'../baseDir/foo',
],
},
}`
outDir := filepath.Join(tmpDir, "out")
So(os.Mkdir(outDir, 0700), ShouldBeNil)
isolatePath := filepath.Join(outDir, "my.isolate")
So(os.WriteFile(isolatePath, []byte(isolate), 0600), ShouldBeNil)
opts := &ArchiveOptions{
Isolate: isolatePath,
}
deps, _, err := ProcessIsolate(opts)
So(err, ShouldBeNil)
for _, dep := range deps {
isDir, err := filesystem.IsDir(dep)
So(err, ShouldBeNil)
So(strings.HasSuffix(dep, osPathSeparator), ShouldEqual, isDir)
}
})
Convey(`Allow missing files and dirs`, t, func() {
tmpDir := t.TempDir()
dir1 := filepath.Join(tmpDir, "dir1")
So(os.Mkdir(dir1, 0700), ShouldBeNil)
dir2 := filepath.Join(tmpDir, "dir2")
So(os.Mkdir(dir2, 0700), ShouldBeNil)
So(os.WriteFile(filepath.Join(dir2, "foo"), []byte("foo"), 0600), ShouldBeNil)
isolate := `{
'variables': {
'files': [
'../dir1/',
'../dir2/foo',
'../nodir1/',
'../nodir2/nofile',
],
},
}`
outDir := filepath.Join(tmpDir, "out")
So(os.Mkdir(outDir, 0700), ShouldBeNil)
isolatePath := filepath.Join(outDir, "my.isolate")
So(os.WriteFile(isolatePath, []byte(isolate), 0600), ShouldBeNil)
opts := &ArchiveOptions{
Isolate: isolatePath,
AllowMissingFileDir: false,
}
_, _, err := ProcessIsolate(opts)
So(err, ShouldNotBeNil)
opts = &ArchiveOptions{
Isolate: isolatePath,
AllowMissingFileDir: true,
}
deps, _, err := ProcessIsolate(opts)
So(err, ShouldBeNil)
So(deps, ShouldResemble, []string{dir1 + osPathSeparator, filepath.Join(dir2, "foo")})
})
Convey(`Process isolate for CAS`, t, func() {
tmpDir := t.TempDir()
dir1 := filepath.Join(tmpDir, "dir1")
So(os.Mkdir(dir1, 0700), ShouldBeNil)
isolDir := filepath.Join(tmpDir, "out")
So(os.Mkdir(isolDir, 0700), ShouldBeNil)
dir2 := filepath.Join(isolDir, "dir2")
So(os.Mkdir(dir2, 0700), ShouldBeNil)
So(os.WriteFile(filepath.Join(dir1, "foo"), []byte("foo"), 0600), ShouldBeNil)
So(os.WriteFile(filepath.Join(dir2, "bar"), []byte("bar"), 0600), ShouldBeNil)
isolate := `{
'variables': {
'files': [
'../dir1/',
'../dir1/foo',
'dir2/bar',
],
},
}`
isolatePath := filepath.Join(isolDir, "my.isolate")
So(os.WriteFile(isolatePath, []byte(isolate), 0600), ShouldBeNil)
opts := &ArchiveOptions{
Isolate: isolatePath,
AllowMissingFileDir: false,
}
relDeps, rootDir, err := ProcessIsolateForCAS(opts)
So(err, ShouldBeNil)
So(rootDir, ShouldResemble, filepath.Dir(isolDir))
So(relDeps, ShouldResemble, []string{"dir1" + osPathSeparator, filepath.Join("dir1", "foo"), filepath.Join("out", "dir2", "bar")})
})
}