github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/daemon/graphdriver/graphtest/testutil.go (about)

     1  package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphtest"
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/fs"
     7  	"math/rand"
     8  	"os"
     9  	"path/filepath"
    10  	"sort"
    11  
    12  	"github.com/docker/docker/daemon/graphdriver"
    13  	"github.com/docker/docker/pkg/archive"
    14  	"github.com/docker/docker/pkg/stringid"
    15  )
    16  
    17  func randomContent(size int, seed int64) []byte {
    18  	s := rand.NewSource(seed)
    19  	content := make([]byte, size)
    20  
    21  	for i := 0; i < len(content); i += 7 {
    22  		val := s.Int63()
    23  		for j := 0; i+j < len(content) && j < 7; j++ {
    24  			content[i+j] = byte(val)
    25  			val >>= 8
    26  		}
    27  	}
    28  
    29  	return content
    30  }
    31  
    32  func addFiles(drv graphdriver.Driver, layer string, seed int64) error {
    33  	root, err := drv.Get(layer, "")
    34  	if err != nil {
    35  		return err
    36  	}
    37  	defer drv.Put(layer)
    38  
    39  	if err := os.WriteFile(filepath.Join(root, "file-a"), randomContent(64, seed), 0o755); err != nil {
    40  		return err
    41  	}
    42  	if err := os.MkdirAll(filepath.Join(root, "dir-b"), 0o755); err != nil {
    43  		return err
    44  	}
    45  	if err := os.WriteFile(filepath.Join(root, "dir-b", "file-b"), randomContent(128, seed+1), 0o755); err != nil {
    46  		return err
    47  	}
    48  
    49  	return os.WriteFile(filepath.Join(root, "file-c"), randomContent(128*128, seed+2), 0o755)
    50  }
    51  
    52  func checkFile(drv graphdriver.Driver, layer, filename string, content []byte) error {
    53  	root, err := drv.Get(layer, "")
    54  	if err != nil {
    55  		return err
    56  	}
    57  	defer drv.Put(layer)
    58  
    59  	fileContent, err := os.ReadFile(filepath.Join(root, filename))
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	if !bytes.Equal(fileContent, content) {
    65  		return fmt.Errorf("mismatched file content %v, expecting %v", fileContent, content)
    66  	}
    67  
    68  	return nil
    69  }
    70  
    71  func addFile(drv graphdriver.Driver, layer, filename string, content []byte) error {
    72  	root, err := drv.Get(layer, "")
    73  	if err != nil {
    74  		return err
    75  	}
    76  	defer drv.Put(layer)
    77  
    78  	return os.WriteFile(filepath.Join(root, filename), content, 0o755)
    79  }
    80  
    81  func addDirectory(drv graphdriver.Driver, layer, dir string) error {
    82  	root, err := drv.Get(layer, "")
    83  	if err != nil {
    84  		return err
    85  	}
    86  	defer drv.Put(layer)
    87  
    88  	return os.MkdirAll(filepath.Join(root, dir), 0o755)
    89  }
    90  
    91  func removeAll(drv graphdriver.Driver, layer string, names ...string) error {
    92  	root, err := drv.Get(layer, "")
    93  	if err != nil {
    94  		return err
    95  	}
    96  	defer drv.Put(layer)
    97  
    98  	for _, filename := range names {
    99  		if err := os.RemoveAll(filepath.Join(root, filename)); err != nil {
   100  			return err
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  func checkFileRemoved(drv graphdriver.Driver, layer, filename string) error {
   107  	root, err := drv.Get(layer, "")
   108  	if err != nil {
   109  		return err
   110  	}
   111  	defer drv.Put(layer)
   112  
   113  	if _, err := os.Stat(filepath.Join(root, filename)); err == nil {
   114  		return fmt.Errorf("file still exists: %s", filepath.Join(root, filename))
   115  	} else if !os.IsNotExist(err) {
   116  		return err
   117  	}
   118  
   119  	return nil
   120  }
   121  
   122  func addManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) error {
   123  	root, err := drv.Get(layer, "")
   124  	if err != nil {
   125  		return err
   126  	}
   127  	defer drv.Put(layer)
   128  
   129  	for i := 0; i < count; i += 100 {
   130  		dir := filepath.Join(root, fmt.Sprintf("directory-%d", i))
   131  		if err := os.MkdirAll(dir, 0o755); err != nil {
   132  			return err
   133  		}
   134  		for j := 0; i+j < count && j < 100; j++ {
   135  			file := filepath.Join(dir, fmt.Sprintf("file-%d", i+j))
   136  			if err := os.WriteFile(file, randomContent(64, seed+int64(i+j)), 0o755); err != nil {
   137  				return err
   138  			}
   139  		}
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  func changeManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) ([]archive.Change, error) {
   146  	root, err := drv.Get(layer, "")
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	defer drv.Put(layer)
   151  
   152  	var changes []archive.Change
   153  	for i := 0; i < count; i += 100 {
   154  		archiveRoot := fmt.Sprintf("/directory-%d", i)
   155  		if err := os.MkdirAll(filepath.Join(root, archiveRoot), 0o755); err != nil {
   156  			return nil, err
   157  		}
   158  		for j := 0; i+j < count && j < 100; j++ {
   159  			if j == 0 {
   160  				changes = append(changes, archive.Change{
   161  					Path: archiveRoot,
   162  					Kind: archive.ChangeModify,
   163  				})
   164  			}
   165  			var change archive.Change
   166  			switch j % 3 {
   167  			// Update file
   168  			case 0:
   169  				change.Path = filepath.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
   170  				change.Kind = archive.ChangeModify
   171  				if err := os.WriteFile(filepath.Join(root, change.Path), randomContent(64, seed+int64(i+j)), 0o755); err != nil {
   172  					return nil, err
   173  				}
   174  			// Add file
   175  			case 1:
   176  				change.Path = filepath.Join(archiveRoot, fmt.Sprintf("file-%d-%d", seed, i+j))
   177  				change.Kind = archive.ChangeAdd
   178  				if err := os.WriteFile(filepath.Join(root, change.Path), randomContent(64, seed+int64(i+j)), 0o755); err != nil {
   179  					return nil, err
   180  				}
   181  			// Remove file
   182  			case 2:
   183  				change.Path = filepath.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
   184  				change.Kind = archive.ChangeDelete
   185  				if err := os.Remove(filepath.Join(root, change.Path)); err != nil {
   186  					return nil, err
   187  				}
   188  			}
   189  			changes = append(changes, change)
   190  		}
   191  	}
   192  
   193  	return changes, nil
   194  }
   195  
   196  func checkManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) error {
   197  	root, err := drv.Get(layer, "")
   198  	if err != nil {
   199  		return err
   200  	}
   201  	defer drv.Put(layer)
   202  
   203  	for i := 0; i < count; i += 100 {
   204  		dir := filepath.Join(root, fmt.Sprintf("directory-%d", i))
   205  		for j := 0; i+j < count && j < 100; j++ {
   206  			file := filepath.Join(dir, fmt.Sprintf("file-%d", i+j))
   207  			fileContent, err := os.ReadFile(file)
   208  			if err != nil {
   209  				return err
   210  			}
   211  
   212  			content := randomContent(64, seed+int64(i+j))
   213  
   214  			if !bytes.Equal(fileContent, content) {
   215  				return fmt.Errorf("mismatched file content %v, expecting %v", fileContent, content)
   216  			}
   217  		}
   218  	}
   219  
   220  	return nil
   221  }
   222  
   223  type changeList []archive.Change
   224  
   225  func (c changeList) Less(i, j int) bool {
   226  	if c[i].Path == c[j].Path {
   227  		return c[i].Kind < c[j].Kind
   228  	}
   229  	return c[i].Path < c[j].Path
   230  }
   231  func (c changeList) Len() int      { return len(c) }
   232  func (c changeList) Swap(i, j int) { c[j], c[i] = c[i], c[j] }
   233  
   234  func checkChanges(expected, actual []archive.Change) error {
   235  	if len(expected) != len(actual) {
   236  		return fmt.Errorf("unexpected number of changes, expected %d, got %d", len(expected), len(actual))
   237  	}
   238  	sort.Sort(changeList(expected))
   239  	sort.Sort(changeList(actual))
   240  
   241  	for i := range expected {
   242  		if expected[i] != actual[i] {
   243  			return fmt.Errorf("unexpected change, expecting %v, got %v", expected[i], actual[i])
   244  		}
   245  	}
   246  
   247  	return nil
   248  }
   249  
   250  func addLayerFiles(drv graphdriver.Driver, layer, parent string, i int) error {
   251  	root, err := drv.Get(layer, "")
   252  	if err != nil {
   253  		return err
   254  	}
   255  	defer drv.Put(layer)
   256  
   257  	if err := os.WriteFile(filepath.Join(root, "top-id"), []byte(layer), 0o755); err != nil {
   258  		return err
   259  	}
   260  	layerDir := filepath.Join(root, fmt.Sprintf("layer-%d", i))
   261  	if err := os.MkdirAll(layerDir, 0o755); err != nil {
   262  		return err
   263  	}
   264  	if err := os.WriteFile(filepath.Join(layerDir, "layer-id"), []byte(layer), 0o755); err != nil {
   265  		return err
   266  	}
   267  	return os.WriteFile(filepath.Join(layerDir, "parent-id"), []byte(parent), 0o755)
   268  }
   269  
   270  func addManyLayers(drv graphdriver.Driver, baseLayer string, count int) (string, error) {
   271  	lastLayer := baseLayer
   272  	for i := 1; i <= count; i++ {
   273  		nextLayer := stringid.GenerateRandomID()
   274  		if err := drv.Create(nextLayer, lastLayer, nil); err != nil {
   275  			return "", err
   276  		}
   277  		if err := addLayerFiles(drv, nextLayer, lastLayer, i); err != nil {
   278  			return "", err
   279  		}
   280  
   281  		lastLayer = nextLayer
   282  	}
   283  	return lastLayer, nil
   284  }
   285  
   286  func checkManyLayers(drv graphdriver.Driver, layer string, count int) error {
   287  	root, err := drv.Get(layer, "")
   288  	if err != nil {
   289  		return err
   290  	}
   291  	defer drv.Put(layer)
   292  
   293  	layerIDBytes, err := os.ReadFile(filepath.Join(root, "top-id"))
   294  	if err != nil {
   295  		return err
   296  	}
   297  
   298  	if !bytes.Equal(layerIDBytes, []byte(layer)) {
   299  		return fmt.Errorf("mismatched file content %v, expecting %v", layerIDBytes, []byte(layer))
   300  	}
   301  
   302  	for i := count; i > 0; i-- {
   303  		layerDir := filepath.Join(root, fmt.Sprintf("layer-%d", i))
   304  
   305  		thisLayerIDBytes, err := os.ReadFile(filepath.Join(layerDir, "layer-id"))
   306  		if err != nil {
   307  			return err
   308  		}
   309  		if !bytes.Equal(thisLayerIDBytes, layerIDBytes) {
   310  			return fmt.Errorf("mismatched file content %v, expecting %v", thisLayerIDBytes, layerIDBytes)
   311  		}
   312  		layerIDBytes, err = os.ReadFile(filepath.Join(layerDir, "parent-id"))
   313  		if err != nil {
   314  			return err
   315  		}
   316  	}
   317  	return nil
   318  }
   319  
   320  // readDir reads a directory just like os.ReadDir()
   321  // then hides specific files (currently "lost+found")
   322  // so the tests don't "see" it
   323  func readDir(dir string) ([]fs.DirEntry, error) {
   324  	a, err := os.ReadDir(dir)
   325  	if err != nil {
   326  		return nil, err
   327  	}
   328  
   329  	b := a[:0]
   330  	for _, x := range a {
   331  		if x.Name() != "lost+found" { // ext4 always have this dir
   332  			b = append(b, x)
   333  		}
   334  	}
   335  
   336  	return b, nil
   337  }