...

Source file src/github.com/containerd/continuity/fs/du_test.go

Documentation: github.com/containerd/continuity/fs

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package fs
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"io"
    23  	"math/rand"
    24  	"os"
    25  	"path/filepath"
    26  	"runtime"
    27  	"testing"
    28  
    29  	"github.com/containerd/continuity/fs/fstest"
    30  )
    31  
    32  var errNotImplemented = errors.New("check not implemented")
    33  
    34  func TestUsage(t *testing.T) {
    35  	align, dirs, err := getTmpAlign(t)
    36  	if err != nil {
    37  		t.Fatal(err)
    38  	}
    39  
    40  	type testCase struct {
    41  		name string
    42  		fs   fstest.Applier
    43  		size int64
    44  	}
    45  	testCases := []testCase{
    46  		{
    47  			name: "SingleSmallFile",
    48  			fs: fstest.Apply(
    49  				fstest.CreateDir("/dir", 0o755),
    50  				fstest.CreateRandomFile("/dir/file", 1, 5, 0o644),
    51  			),
    52  			size: dirs(2) + align(5),
    53  		},
    54  		{
    55  			name: "MultipleSmallFile",
    56  			fs: fstest.Apply(
    57  				fstest.CreateDir("/dir", 0o755),
    58  				fstest.CreateRandomFile("/dir/file1", 2, 5, 0o644),
    59  				fstest.CreateRandomFile("/dir/file2", 3, 5, 0o644),
    60  			),
    61  			size: dirs(2) + align(5)*2,
    62  		},
    63  		{
    64  			name: "BiggerFiles",
    65  			fs: fstest.Apply(
    66  				fstest.CreateDir("/dir", 0o755),
    67  				fstest.CreateRandomFile("/dir/file1", 4, 5, 0o644),
    68  				fstest.CreateRandomFile("/dir/file2", 5, 1024, 0o644),
    69  				fstest.CreateRandomFile("/dir/file3", 6, 50*1024, 0o644),
    70  			),
    71  			size: dirs(2) + align(5) + align(1024) + align(50*1024),
    72  		},
    73  	}
    74  	if runtime.GOOS != "windows" {
    75  		testCases = append(testCases, []testCase{
    76  			{
    77  				name: "Hardlinks",
    78  				fs: fstest.Apply(
    79  					fstest.CreateDir("/dir", 0o755),
    80  					fstest.CreateRandomFile("/dir/file1", 11, 60*1024, 0o644),
    81  					fstest.Link("/dir/file1", "/dir/link1"),
    82  				),
    83  				size: dirs(2) + align(60*1024),
    84  			},
    85  			{
    86  				name: "HardlinkSparefile",
    87  				fs: fstest.Apply(
    88  					fstest.CreateDir("/dir", 0o755),
    89  					createSparseFile("/dir/file1", 10, 0o644, 30*1024, 1024*1024*1024, 30*1024),
    90  					fstest.Link("/dir/file1", "/dir/link1"),
    91  				),
    92  				size: dirs(2) + align(30*1024)*2,
    93  			},
    94  		}...)
    95  	}
    96  	if runtime.GOOS != "windows" && runtime.GOOS != "darwin" {
    97  		testCases = append(testCases, []testCase{
    98  			{
    99  				name: "SparseFiles",
   100  				fs: fstest.Apply(
   101  					fstest.CreateDir("/dir", 0o755),
   102  					fstest.CreateRandomFile("/dir/file1", 7, 5, 0o644),
   103  					createSparseFile("/dir/sparse1", 8, 0o644, 5, 1024*1024, 5),
   104  					createSparseFile("/dir/sparse2", 9, 0o644, 0, 1024*1024),
   105  					createSparseFile("/dir/sparse2", 10, 0o644, 0, 1024*1024*1024, 1024),
   106  				),
   107  				size: dirs(2) + align(5)*3 + align(1024),
   108  			},
   109  		}...)
   110  	}
   111  
   112  	for i := range testCases {
   113  		tc := testCases[i]
   114  		t.Run(tc.name, func(t *testing.T) {
   115  			t.Parallel()
   116  
   117  			t1 := t.TempDir()
   118  			if err := tc.fs.Apply(t1); err != nil {
   119  				t.Fatal("Failed to apply base filesystem:", err)
   120  			}
   121  
   122  			usage, err := DiskUsage(context.Background(), t1)
   123  			if err != nil {
   124  				t.Fatal(err)
   125  			}
   126  			if usage.Size != tc.size {
   127  				t.Fatalf("Wrong usage size %d, expected %d", usage.Size, tc.size)
   128  			}
   129  
   130  			du, err := duCheck(t1)
   131  			if err != nil && err != errNotImplemented {
   132  				t.Fatal("Failed calling du:", err)
   133  			}
   134  			if err == nil && usage.Size != du {
   135  				t.Fatalf("Wrong usage size %d, du reported %d", usage.Size, du)
   136  			}
   137  		})
   138  	}
   139  }
   140  
   141  // createSparseFile creates a sparse file filled with random
   142  // bytes for data parts
   143  // The parse alternate data length, hole length, data length, ....
   144  // To start a file as sparse, give an initial data length of 0
   145  func createSparseFile(name string, seed int64, perm os.FileMode, parts ...int64) fstest.Applier {
   146  	return sparseFile{
   147  		name:  name,
   148  		seed:  seed,
   149  		parts: parts,
   150  		perm:  perm,
   151  	}
   152  }
   153  
   154  type sparseFile struct {
   155  	name  string
   156  	seed  int64
   157  	parts []int64
   158  	perm  os.FileMode
   159  }
   160  
   161  func (sf sparseFile) Apply(root string) (retErr error) {
   162  	fullPath := filepath.Join(root, sf.name)
   163  	f, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, sf.perm)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	defer func() {
   168  		err := f.Close()
   169  		if err != nil && retErr == nil {
   170  			retErr = err
   171  		}
   172  	}()
   173  
   174  	rr := rand.New(rand.NewSource(sf.seed))
   175  
   176  	parts := sf.parts
   177  	for len(parts) > 0 {
   178  		// Write content
   179  		if parts[0] > 0 {
   180  			_, err = io.Copy(f, io.LimitReader(rr, parts[0]))
   181  			if err != nil {
   182  				return err
   183  			}
   184  		}
   185  		parts = parts[1:]
   186  
   187  		if len(parts) > 0 {
   188  			if parts[0] != 0 {
   189  				f.Seek(parts[0], io.SeekCurrent)
   190  			}
   191  			parts = parts[1:]
   192  		}
   193  	}
   194  	return os.Chmod(fullPath, sf.perm)
   195  }
   196  

View as plain text