mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 13:50:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			326 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2016 The Kubernetes 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 main
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"math/rand"
 | |
| 	"os"
 | |
| 	"path"
 | |
| 	"path/filepath"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// seed for rand.Source to generate data for files
 | |
| 	seed int64 = 42
 | |
| 
 | |
| 	// 1K binary file
 | |
| 	binLen = 1024
 | |
| 
 | |
| 	// Directory of the test package relative to $GOPATH
 | |
| 	testImportDir = "example.com/proj/pkg"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	pastHour = time.Now().Add(-1 * time.Hour)
 | |
| 
 | |
| 	// The test package we are testing against
 | |
| 	testPkg = path.Join(testImportDir, "test")
 | |
| )
 | |
| 
 | |
| // fakegolist implements the `golist` interface providing fake package information for testing.
 | |
| type fakegolist struct {
 | |
| 	dir       string
 | |
| 	importMap map[string]pkg
 | |
| 	testFiles []string
 | |
| 	binfile   string
 | |
| }
 | |
| 
 | |
| func newFakegolist() (*fakegolist, error) {
 | |
| 	dir, err := ioutil.TempDir("", "teststale")
 | |
| 	if err != nil {
 | |
| 		// test can't proceed without a temp directory.
 | |
| 		return nil, fmt.Errorf("failed to create a temp directory for testing: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Set the temp directory as the $GOPATH
 | |
| 	if err := os.Setenv("GOPATH", dir); err != nil {
 | |
| 		// can't proceed without pointing the $GOPATH to the temp directory.
 | |
| 		return nil, fmt.Errorf("failed to set \"$GOPATH\" pointing to %q: %v", dir, err)
 | |
| 	}
 | |
| 
 | |
| 	// Setup $GOPATH directory layout.
 | |
| 	// Yeah! I am bored of repeatedly writing "if err != nil {}"!
 | |
| 	if os.MkdirAll(filepath.Join(dir, "bin"), 0750) != nil ||
 | |
| 		os.MkdirAll(filepath.Join(dir, "pkg", "linux_amd64"), 0750) != nil ||
 | |
| 		os.MkdirAll(filepath.Join(dir, "src"), 0750) != nil {
 | |
| 		return nil, fmt.Errorf("failed to setup the $GOPATH directory structure")
 | |
| 	}
 | |
| 
 | |
| 	// Create a temp file to represent the test binary.
 | |
| 	binfile, err := ioutil.TempFile("", "testbin")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("failed to create the temp file to represent the test binary: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Could have used crypto/rand instead, but it doesn't matter.
 | |
| 	rr := rand.New(rand.NewSource(42))
 | |
| 	bin := make([]byte, binLen)
 | |
| 	if _, err = rr.Read(bin); err != nil {
 | |
| 		return nil, fmt.Errorf("couldn't read from the random source: %v", err)
 | |
| 	}
 | |
| 	if _, err := binfile.Write(bin); err != nil {
 | |
| 		return nil, fmt.Errorf("couldn't write to the binary file %q: %v", binfile.Name(), err)
 | |
| 	}
 | |
| 	if err := binfile.Close(); err != nil {
 | |
| 		// It is arguable whether this should be fatal.
 | |
| 		return nil, fmt.Errorf("failed to close the binary file %q: %v", binfile.Name(), err)
 | |
| 	}
 | |
| 
 | |
| 	if err := os.Chtimes(binfile.Name(), time.Now(), time.Now()); err != nil {
 | |
| 		return nil, fmt.Errorf("failed to modify the mtime of the binary file %q: %v", binfile.Name(), err)
 | |
| 	}
 | |
| 
 | |
| 	// Create test source files directory.
 | |
| 	testdir := filepath.Join(dir, "src", testPkg)
 | |
| 	if err := os.MkdirAll(testdir, 0750); err != nil {
 | |
| 		return nil, fmt.Errorf("failed to create test source directory %q: %v", testdir, err)
 | |
| 	}
 | |
| 
 | |
| 	fgl := &fakegolist{
 | |
| 		dir: dir,
 | |
| 		importMap: map[string]pkg{
 | |
| 			"example.com/proj/pkg/test": {
 | |
| 				Dir:        path.Join(dir, "src", testPkg),
 | |
| 				ImportPath: testPkg,
 | |
| 				Target:     path.Join(dir, "pkg", "linux_amd64", testImportDir, "test.a"),
 | |
| 				Stale:      false,
 | |
| 				TestGoFiles: []string{
 | |
| 					"foo_test.go",
 | |
| 					"bar_test.go",
 | |
| 				},
 | |
| 				TestImports: []string{
 | |
| 					"example.com/proj/pkg/p1",
 | |
| 					"example.com/proj/pkg/p1/c11",
 | |
| 					"example.com/proj/pkg/p2",
 | |
| 					"example.com/proj/cmd/p3/c12/c23",
 | |
| 					"strings",
 | |
| 					"testing",
 | |
| 				},
 | |
| 				XTestGoFiles: []string{
 | |
| 					"xfoo_test.go",
 | |
| 					"xbar_test.go",
 | |
| 					"xbaz_test.go",
 | |
| 				},
 | |
| 				XTestImports: []string{
 | |
| 					"example.com/proj/pkg/test",
 | |
| 					"example.com/proj/pkg/p1",
 | |
| 					"example.com/proj/cmd/p3/c12/c23",
 | |
| 					"os",
 | |
| 					"testing",
 | |
| 				},
 | |
| 			},
 | |
| 			"example.com/proj/pkg/p1":         {Stale: false},
 | |
| 			"example.com/proj/pkg/p1/c11":     {Stale: false},
 | |
| 			"example.com/proj/pkg/p2":         {Stale: false},
 | |
| 			"example.com/proj/cmd/p3/c12/c23": {Stale: false},
 | |
| 			"strings":                         {Stale: false},
 | |
| 			"testing":                         {Stale: false},
 | |
| 			"os":                              {Stale: false},
 | |
| 		},
 | |
| 		testFiles: []string{
 | |
| 			"foo_test.go",
 | |
| 			"bar_test.go",
 | |
| 			"xfoo_test.go",
 | |
| 			"xbar_test.go",
 | |
| 			"xbaz_test.go",
 | |
| 		},
 | |
| 		binfile: binfile.Name(),
 | |
| 	}
 | |
| 
 | |
| 	// Create test source files.
 | |
| 	for _, fn := range fgl.testFiles {
 | |
| 		fp := filepath.Join(testdir, fn)
 | |
| 		if _, err := os.Create(fp); err != nil {
 | |
| 			return nil, fmt.Errorf("failed to create the test file %q: %v", fp, err)
 | |
| 		}
 | |
| 		if err := os.Chtimes(fp, time.Now(), pastHour); err != nil {
 | |
| 			return nil, fmt.Errorf("failed to modify the mtime of the test file %q: %v", binfile.Name(), err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return fgl, nil
 | |
| }
 | |
| 
 | |
| func (fgl *fakegolist) pkgInfo(pkgPaths []string) ([]pkg, error) {
 | |
| 	var pkgs []pkg
 | |
| 	for _, path := range pkgPaths {
 | |
| 		p, ok := fgl.importMap[path]
 | |
| 		if !ok {
 | |
| 			return nil, fmt.Errorf("package %q not found", path)
 | |
| 		}
 | |
| 		pkgs = append(pkgs, p)
 | |
| 	}
 | |
| 	return pkgs, nil
 | |
| }
 | |
| 
 | |
| func (fgl *fakegolist) chMtime(filename string, mtime time.Time) error {
 | |
| 	for _, fn := range fgl.testFiles {
 | |
| 		if fn == filename {
 | |
| 			fp := filepath.Join(fgl.dir, "src", testPkg, fn)
 | |
| 			if err := os.Chtimes(fp, time.Now(), mtime); err != nil {
 | |
| 				return fmt.Errorf("failed to modify the mtime of %q: %v", filename, err)
 | |
| 			}
 | |
| 			return nil
 | |
| 		}
 | |
| 	}
 | |
| 	return fmt.Errorf("file %q not found", filename)
 | |
| }
 | |
| 
 | |
| func (fgl *fakegolist) chStale(pkg string, stale bool) error {
 | |
| 	if p, ok := fgl.importMap[pkg]; ok {
 | |
| 		p.Stale = stale
 | |
| 		fgl.importMap[pkg] = p
 | |
| 		return nil
 | |
| 	}
 | |
| 	return fmt.Errorf("package %q not found", pkg)
 | |
| }
 | |
| 
 | |
| func (fgl *fakegolist) cleanup() {
 | |
| 	os.RemoveAll(fgl.dir)
 | |
| 	os.Remove(fgl.binfile)
 | |
| }
 | |
| 
 | |
| func TestIsTestStale(t *testing.T) {
 | |
| 	cases := []struct {
 | |
| 		fileMtime    map[string]time.Time
 | |
| 		pkgStaleness map[string]bool
 | |
| 		result       bool
 | |
| 	}{
 | |
| 		// Basic test: binary is fresh, all modifications were before the binary was built.
 | |
| 		{
 | |
| 			result: false,
 | |
| 		},
 | |
| 		// A local test file is new, hence binary must be stale.
 | |
| 		{
 | |
| 			fileMtime: map[string]time.Time{
 | |
| 				"foo_test.go": time.Now().Add(1 * time.Hour),
 | |
| 			},
 | |
| 			result: true,
 | |
| 		},
 | |
| 		// Test package is new, so binary must be stale.
 | |
| 		{
 | |
| 			pkgStaleness: map[string]bool{
 | |
| 				"example.com/proj/pkg/test": true,
 | |
| 			},
 | |
| 			result: true,
 | |
| 		},
 | |
| 		// Test package dependencies are new, so binary must be stale.
 | |
| 		{
 | |
| 			pkgStaleness: map[string]bool{
 | |
| 				"example.com/proj/cmd/p3/c12/c23": true,
 | |
| 				"strings":                         true,
 | |
| 			},
 | |
| 			result: true,
 | |
| 		},
 | |
| 		// External test files are new, hence binary must be stale.
 | |
| 		{
 | |
| 			fileMtime: map[string]time.Time{
 | |
| 				"xfoo_test.go": time.Now().Add(1 * time.Hour),
 | |
| 				"xbar_test.go": time.Now().Add(2 * time.Hour),
 | |
| 			},
 | |
| 			result: true,
 | |
| 		},
 | |
| 		// External test dependency is new, so binary must be stale.
 | |
| 		{
 | |
| 			pkgStaleness: map[string]bool{
 | |
| 				"os": true,
 | |
| 			},
 | |
| 			result: true,
 | |
| 		},
 | |
| 		// Multiple source files and dependencies are new, so binary must be stale.
 | |
| 		{
 | |
| 			fileMtime: map[string]time.Time{
 | |
| 				"foo_test.go":  time.Now().Add(1 * time.Hour),
 | |
| 				"xfoo_test.go": time.Now().Add(2 * time.Hour),
 | |
| 				"xbar_test.go": time.Now().Add(3 * time.Hour),
 | |
| 			},
 | |
| 			pkgStaleness: map[string]bool{
 | |
| 				"example.com/proj/pkg/p1":         true,
 | |
| 				"example.com/proj/pkg/p1/c11":     true,
 | |
| 				"example.com/proj/pkg/p2":         true,
 | |
| 				"example.com/proj/cmd/p3/c12/c23": true,
 | |
| 				"strings":                         true,
 | |
| 				"os":                              true,
 | |
| 			},
 | |
| 			result: true,
 | |
| 		},
 | |
| 		// Everything is new, so binary must be stale.
 | |
| 		{
 | |
| 			fileMtime: map[string]time.Time{
 | |
| 				"foo_test.go":  time.Now().Add(3 * time.Hour),
 | |
| 				"bar_test.go":  time.Now().Add(1 * time.Hour),
 | |
| 				"xfoo_test.go": time.Now().Add(2 * time.Hour),
 | |
| 				"xbar_test.go": time.Now().Add(1 * time.Hour),
 | |
| 				"xbaz_test.go": time.Now().Add(2 * time.Hour),
 | |
| 			},
 | |
| 			pkgStaleness: map[string]bool{
 | |
| 				"example.com/proj/pkg/p1":         true,
 | |
| 				"example.com/proj/pkg/p1/c11":     true,
 | |
| 				"example.com/proj/pkg/p2":         true,
 | |
| 				"example.com/proj/cmd/p3/c12/c23": true,
 | |
| 				"example.com/proj/pkg/test":       true,
 | |
| 				"strings":                         true,
 | |
| 				"testing":                         true,
 | |
| 				"os":                              true,
 | |
| 			},
 | |
| 			result: true,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tc := range cases {
 | |
| 		fgl, err := newFakegolist()
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("failed to setup the test: %v", err)
 | |
| 		}
 | |
| 		defer fgl.cleanup()
 | |
| 
 | |
| 		for fn, mtime := range tc.fileMtime {
 | |
| 			if err := fgl.chMtime(fn, mtime); err != nil {
 | |
| 				t.Fatalf("failed to change the mtime of %q: %v", fn, err)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		for pkg, stale := range tc.pkgStaleness {
 | |
| 			if err := fgl.chStale(pkg, stale); err != nil {
 | |
| 				t.Fatalf("failed to change the staleness of %q: %v", pkg, err)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if tc.result != isTestStale(fgl, fgl.binfile, testPkg) {
 | |
| 			if tc.result {
 | |
| 				t.Errorf("Expected test package %q to be stale", testPkg)
 | |
| 			} else {
 | |
| 				t.Errorf("Expected test package %q to be not stale", testPkg)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |