blob: 63f494be3d8a825480bb4ba8c168e4dff5d61993 [file] [log] [blame]
// Copyright 2016 Google Inc. 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 main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"syscall"
"testing"
)
const attr = "user.gitsha1"
const checksum = "3f75526aa8f01eea5d76cee10722195dc73676de"
func createFSTree(names []string) (string, error) {
dir, err := ioutil.TempDir("", "")
if err != nil {
return dir, err
}
for _, f := range names {
p := filepath.Join(dir, f)
if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
return dir, err
}
if err := ioutil.WriteFile(p, []byte{42}, 0644); err != nil {
return dir, err
}
if err := syscall.Setxattr(p, attr, []byte(checksum), 0); err != nil {
return dir, fmt.Errorf("Setxattr: %v", err)
}
}
return dir, nil
}
func TestConstruct(t *testing.T) {
dir, err := createFSTree([]string{
"toplevel",
"build/core/.git/HEAD",
"build/core/subdir/core.h",
"build/core/song/.git/HEAD",
"build/core/song/song.mp3",
"build/core/top",
"build/subfile",
})
if err != nil {
t.Fatal(err)
}
parent := newRepoTree(dir)
construct(dir, "", parent)
songT := &repoTree{
children: map[string]*repoTree{},
entries: []string{"song.mp3"},
}
coreT := &repoTree{
children: map[string]*repoTree{"song": songT},
entries: []string{"subdir/core.h",
"top",
},
}
topT := &repoTree{
children: map[string]*repoTree{
"build/core": coreT,
},
entries: []string{
"build/subfile",
"toplevel",
},
}
if !reflect.DeepEqual(topT, parent) {
t.Errorf("got %#v want %#v", parent, topT)
}
all := topT.allChildren()
want := map[string]*repoTree{
"": topT,
"build/core": coreT,
"build/core/song": songT,
}
if !reflect.DeepEqual(all, want) {
t.Errorf("got %#v want %#v", all, want)
}
}
func TestPopulate(t *testing.T) {
dir, err := createFSTree([]string{
"ro/toplevel",
"ro/build/core/.gitid",
"ro/build/core/subdir/core.h",
"ro/build/core/song/.gitid",
"ro/build/core/song/song.mp3",
"ro/build/core/top",
"ro/build/subfile",
"ro/platform/art/.gitid",
"ro/platform/art/art.c",
"ro/platform/art/art.h",
"ro/platform/art/painting/.gitid",
"ro/platform/art/painting/picasso.c",
"rw/build/core/.git/head",
"rw/build/core/newdir/bla",
})
if err != nil {
t.Fatal("createFSTree:", err)
}
if err := os.Symlink(filepath.Join(dir, "ro/obsolete"), filepath.Join(dir, "rw/obsolete")); err != nil {
t.Errorf("Symlink: %v", err)
}
if err := populateCheckout(filepath.Join(dir, "ro"), filepath.Join(dir, "rw")); err != nil {
t.Errorf("populateCheckout: %v", err)
}
for _, f := range []string{
"build/core/newdir/bla",
"build/core/song/song.mp3",
"platform/art/art.c",
"platform/art/art.h",
"platform/art/painting/picasso.c",
} {
fn := filepath.Join(dir, "rw", f)
fi, err := os.Stat(fn)
if err != nil || fi.Size() != 1 {
t.Errorf("Stat(%s): %v, %v", fn, fi, err)
}
}
// The following files are in repo that has a r/w checkout, so
// they should not appear in the populated tree.
for _, f := range []string{
"ro/build/core/subdir/core.h",
"ro/build/core/top",
} {
fn := filepath.Join(dir, "rw", f)
_, err := os.Stat(fn)
if err == nil {
t.Errorf("file %s exists", fn)
}
}
if fi, err := os.Lstat(filepath.Join(dir, "rw/obsolete")); err == nil {
t.Fatalf("obsolete symlink still there: %v", fi)
}
}
func TestChangedFiles(t *testing.T) {
dir, err := createFSTree([]string{
"r1/manifest.xml",
"r1/a",
"r1/b",
"r2/manifest.xml",
"r2/a",
"r2/b",
"r2/c",
})
if err != nil {
t.Fatalf("createFSTree: %v", err)
}
ck2 := "3f75526aa8f01eea5d76cee10722195dc73676df"
for _, changed := range []string{"r2/b", "r2/manifest.xml"} {
if err := syscall.Setxattr(filepath.Join(dir, changed), attr, []byte(ck2), 0); err != nil {
t.Fatalf("Setxattr: %v", err)
}
}
got, err := changedFiles(filepath.Join(dir, "r1"), filepath.Join(dir, "r2"))
if err != nil {
t.Fatalf("changedFiles: %v", err)
}
if want := []string{"b", "c"}; !reflect.DeepEqual(want, got) {
t.Errorf("got %v, want %v", got, want)
}
}
func TestClearEmptyDirs(t *testing.T) {
dir, err := createFSTree([]string{
"ro/build/sub/sub2/p1/.gitid",
"ro/build/sub/sub2/p1/build.mk",
"rw/build/proj/.git/HEAD",
"rw/build/proj/build.mk",
"r3/toplevel",
})
if err != nil {
t.Fatal("createFSTree:", err)
}
dest := filepath.Join(dir, "rw", "build/sub/sub2/p1")
if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
t.Errorf("MkdirAll: %v", err)
}
if err := os.Symlink(filepath.Join(dir, "ro", "build/sub/sub2/p1"), dest); err != nil {
t.Errorf("Symlink(%s): %v", dest, err)
}
if err := populateCheckout(filepath.Join(dir, "r3"), filepath.Join(dir, "rw")); err != nil {
t.Errorf("populateCheckout: %v", err)
}
gone := filepath.Join(dir, "rw", "build", "sub")
if fi, err := os.Lstat(gone); err == nil {
t.Errorf("directory %s still there: %v", gone, fi)
}
}