255 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|    Copyright The containerd 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 testing
 | |
| 
 | |
| import (
 | |
| 	"os"
 | |
| 	"sync"
 | |
| 
 | |
| 	containerdmount "github.com/containerd/containerd/mount"
 | |
| 
 | |
| 	osInterface "github.com/containerd/containerd/pkg/os"
 | |
| )
 | |
| 
 | |
| // CalledDetail is the struct contains called function name and arguments.
 | |
| type CalledDetail struct {
 | |
| 	// Name of the function called.
 | |
| 	Name string
 | |
| 	// Arguments of the function called.
 | |
| 	Arguments []interface{}
 | |
| }
 | |
| 
 | |
| // FakeOS mocks out certain OS calls to avoid perturbing the filesystem
 | |
| // If a member of the form `*Fn` is set, that function will be called in place
 | |
| // of the real call.
 | |
| type FakeOS struct {
 | |
| 	sync.Mutex
 | |
| 	MkdirAllFn             func(string, os.FileMode) error
 | |
| 	RemoveAllFn            func(string) error
 | |
| 	StatFn                 func(string) (os.FileInfo, error)
 | |
| 	ResolveSymbolicLinkFn  func(string) (string, error)
 | |
| 	FollowSymlinkInScopeFn func(string, string) (string, error)
 | |
| 	CopyFileFn             func(string, string, os.FileMode) error
 | |
| 	WriteFileFn            func(string, []byte, os.FileMode) error
 | |
| 	MountFn                func(source string, target string, fstype string, flags uintptr, data string) error
 | |
| 	UnmountFn              func(target string) error
 | |
| 	LookupMountFn          func(path string) (containerdmount.Info, error)
 | |
| 	HostnameFn             func() (string, error)
 | |
| 	calls                  []CalledDetail
 | |
| 	errors                 map[string]error
 | |
| }
 | |
| 
 | |
| var _ osInterface.OS = &FakeOS{}
 | |
| 
 | |
| // getError get error for call
 | |
| func (f *FakeOS) getError(op string) error {
 | |
| 	f.Lock()
 | |
| 	defer f.Unlock()
 | |
| 	err, ok := f.errors[op]
 | |
| 	if ok {
 | |
| 		delete(f.errors, op)
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // InjectError inject error for call
 | |
| func (f *FakeOS) InjectError(fn string, err error) {
 | |
| 	f.Lock()
 | |
| 	defer f.Unlock()
 | |
| 	f.errors[fn] = err
 | |
| }
 | |
| 
 | |
| // InjectErrors inject errors for calls
 | |
| func (f *FakeOS) InjectErrors(errs map[string]error) {
 | |
| 	f.Lock()
 | |
| 	defer f.Unlock()
 | |
| 	for fn, err := range errs {
 | |
| 		f.errors[fn] = err
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // ClearErrors clear errors for call
 | |
| func (f *FakeOS) ClearErrors() {
 | |
| 	f.Lock()
 | |
| 	defer f.Unlock()
 | |
| 	f.errors = make(map[string]error)
 | |
| }
 | |
| 
 | |
| func (f *FakeOS) appendCalls(name string, args ...interface{}) {
 | |
| 	f.Lock()
 | |
| 	defer f.Unlock()
 | |
| 	f.calls = append(f.calls, CalledDetail{Name: name, Arguments: args})
 | |
| }
 | |
| 
 | |
| // GetCalls get detail of calls.
 | |
| func (f *FakeOS) GetCalls() []CalledDetail {
 | |
| 	f.Lock()
 | |
| 	defer f.Unlock()
 | |
| 	return append([]CalledDetail{}, f.calls...)
 | |
| }
 | |
| 
 | |
| // NewFakeOS creates a FakeOS.
 | |
| func NewFakeOS() *FakeOS {
 | |
| 	return &FakeOS{
 | |
| 		errors: make(map[string]error),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // MkdirAll is a fake call that invokes MkdirAllFn or just returns nil.
 | |
| func (f *FakeOS) MkdirAll(path string, perm os.FileMode) error {
 | |
| 	f.appendCalls("MkdirAll", path, perm)
 | |
| 	if err := f.getError("MkdirAll"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if f.MkdirAllFn != nil {
 | |
| 		return f.MkdirAllFn(path, perm)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // RemoveAll is a fake call that invokes RemoveAllFn or just returns nil.
 | |
| func (f *FakeOS) RemoveAll(path string) error {
 | |
| 	f.appendCalls("RemoveAll", path)
 | |
| 	if err := f.getError("RemoveAll"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if f.RemoveAllFn != nil {
 | |
| 		return f.RemoveAllFn(path)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Stat is a fake call that invokes StatFn or just return nil.
 | |
| func (f *FakeOS) Stat(name string) (os.FileInfo, error) {
 | |
| 	f.appendCalls("Stat", name)
 | |
| 	if err := f.getError("Stat"); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if f.StatFn != nil {
 | |
| 		return f.StatFn(name)
 | |
| 	}
 | |
| 	return nil, nil
 | |
| }
 | |
| 
 | |
| // ResolveSymbolicLink is a fake call that invokes ResolveSymbolicLinkFn or returns its input
 | |
| func (f *FakeOS) ResolveSymbolicLink(path string) (string, error) {
 | |
| 	f.appendCalls("ResolveSymbolicLink", path)
 | |
| 	if err := f.getError("ResolveSymbolicLink"); err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	if f.ResolveSymbolicLinkFn != nil {
 | |
| 		return f.ResolveSymbolicLinkFn(path)
 | |
| 	}
 | |
| 	return path, nil
 | |
| }
 | |
| 
 | |
| // FollowSymlinkInScope is a fake call that invokes FollowSymlinkInScope or returns its input
 | |
| func (f *FakeOS) FollowSymlinkInScope(path, scope string) (string, error) {
 | |
| 	f.appendCalls("FollowSymlinkInScope", path, scope)
 | |
| 	if err := f.getError("FollowSymlinkInScope"); err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	if f.FollowSymlinkInScopeFn != nil {
 | |
| 		return f.FollowSymlinkInScopeFn(path, scope)
 | |
| 	}
 | |
| 	return path, nil
 | |
| }
 | |
| 
 | |
| // CopyFile is a fake call that invokes CopyFileFn or just return nil.
 | |
| func (f *FakeOS) CopyFile(src, dest string, perm os.FileMode) error {
 | |
| 	f.appendCalls("CopyFile", src, dest, perm)
 | |
| 	if err := f.getError("CopyFile"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if f.CopyFileFn != nil {
 | |
| 		return f.CopyFileFn(src, dest, perm)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // WriteFile is a fake call that invokes WriteFileFn or just return nil.
 | |
| func (f *FakeOS) WriteFile(filename string, data []byte, perm os.FileMode) error {
 | |
| 	f.appendCalls("WriteFile", filename, data, perm)
 | |
| 	if err := f.getError("WriteFile"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if f.WriteFileFn != nil {
 | |
| 		return f.WriteFileFn(filename, data, perm)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Mount is a fake call that invokes MountFn or just return nil.
 | |
| func (f *FakeOS) Mount(source string, target string, fstype string, flags uintptr, data string) error {
 | |
| 	f.appendCalls("Mount", source, target, fstype, flags, data)
 | |
| 	if err := f.getError("Mount"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if f.MountFn != nil {
 | |
| 		return f.MountFn(source, target, fstype, flags, data)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Unmount is a fake call that invokes UnmountFn or just return nil.
 | |
| func (f *FakeOS) Unmount(target string) error {
 | |
| 	f.appendCalls("Unmount", target)
 | |
| 	if err := f.getError("Unmount"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if f.UnmountFn != nil {
 | |
| 		return f.UnmountFn(target)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // LookupMount is a fake call that invokes LookupMountFn or just return nil.
 | |
| func (f *FakeOS) LookupMount(path string) (containerdmount.Info, error) {
 | |
| 	f.appendCalls("LookupMount", path)
 | |
| 	if err := f.getError("LookupMount"); err != nil {
 | |
| 		return containerdmount.Info{}, err
 | |
| 	}
 | |
| 
 | |
| 	if f.LookupMountFn != nil {
 | |
| 		return f.LookupMountFn(path)
 | |
| 	}
 | |
| 	return containerdmount.Info{}, nil
 | |
| }
 | |
| 
 | |
| // Hostname is a fake call that invokes HostnameFn or just return nil.
 | |
| func (f *FakeOS) Hostname() (string, error) {
 | |
| 	f.appendCalls("Hostname")
 | |
| 	if err := f.getError("Hostname"); err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	if f.HostnameFn != nil {
 | |
| 		return f.HostnameFn()
 | |
| 	}
 | |
| 	return "", nil
 | |
| }
 | 
