github.com/opencontainers/umoci@v0.4.8-0.20240508124516-656e4836fb0d/oci/layer/generate_test.go (about)

     1  /*
     2   * umoci: Umoci Modifies Open Containers' Images
     3   * Copyright (C) 2016-2020 SUSE LLC
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *    http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package layer
    19  
    20  import (
    21  	"archive/tar"
    22  	"bytes"
    23  	"io"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  	"testing"
    28  
    29  	"github.com/vbatts/go-mtree"
    30  )
    31  
    32  func TestGenerate(t *testing.T) {
    33  	dir, err := ioutil.TempDir("", "umoci-TestGenerate")
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	defer os.RemoveAll(dir)
    38  
    39  	// Create some files and other fun things.
    40  	if err := os.MkdirAll(filepath.Join(dir, "some", "parents"), 0755); err != nil {
    41  		t.Fatal(err)
    42  	}
    43  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "fileunchanged"), []byte("unchanged"), 0644); err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("changed"), 0644); err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "deleted"), []byte("deleted"), 0644); err != nil {
    50  		t.Fatal(err)
    51  	}
    52  
    53  	// Get initial.
    54  	initDh, err := mtree.Walk(dir, nil, append(mtree.DefaultKeywords, "sha256digest"), nil)
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  
    59  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("new contents"), 0644); err != nil {
    60  		t.Fatal(err)
    61  	}
    62  	if err := os.Remove(filepath.Join(dir, "some", "parents", "deleted")); err != nil {
    63  		t.Fatal(err)
    64  	}
    65  
    66  	// Get post.
    67  	postDh, err := mtree.Walk(dir, nil, initDh.UsedKeywords(), nil)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  
    72  	diffs, err := mtree.Compare(initDh, postDh, initDh.UsedKeywords())
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  
    77  	reader, err := GenerateLayer(dir, diffs, &RepackOptions{})
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	defer reader.Close()
    82  
    83  	var (
    84  		gotDeleted bool
    85  		gotChanged bool
    86  		gotDir     bool
    87  	)
    88  
    89  	tr := tar.NewReader(reader)
    90  	for {
    91  		hdr, err := tr.Next()
    92  		if err == io.EOF {
    93  			break
    94  		}
    95  		if err != nil {
    96  			t.Errorf("unexpected error: %s", err)
    97  			break
    98  		}
    99  		switch hdr.Name {
   100  		case filepath.Join("some", "parents") + "/":
   101  			if hdr.Typeflag != tar.TypeDir {
   102  				t.Errorf("directory suddenly stopped being a directory")
   103  			}
   104  			gotDir = true
   105  		case filepath.Join("some", "parents", ".wh.deleted"):
   106  			if hdr.Size != 0 {
   107  				t.Errorf("whiteout file has non-zero size: %d", hdr.Size)
   108  			}
   109  			gotDeleted = true
   110  		case filepath.Join("some", "parents", "filechanged"):
   111  			contents, err := ioutil.ReadAll(tr)
   112  			if err != nil {
   113  				t.Errorf("unexpected error reading changed file: %s", err)
   114  			}
   115  			if !bytes.Equal(contents, []byte("new contents")) {
   116  				t.Errorf("did not get expected contents: %s", contents)
   117  			}
   118  			gotChanged = true
   119  		case filepath.Join("some", "fileunchanged"):
   120  			t.Errorf("got unchanged file in diff layer!")
   121  		default:
   122  			t.Errorf("got unexpected file: %s", hdr.Name)
   123  		}
   124  	}
   125  
   126  	if !gotDeleted {
   127  		t.Errorf("did not get deleted file!")
   128  	}
   129  	if !gotChanged {
   130  		t.Errorf("did not get changed file!")
   131  	}
   132  	if !gotDir {
   133  		// This for some reason happen on Travis even though it shouldn't. It's
   134  		// probably caused by some AUFS fun times that I don't want to debug.
   135  		t.Logf("did not get directory!")
   136  	}
   137  }
   138  
   139  // Make sure that opencontainers/umoci#33 doesn't regress.
   140  func TestGenerateMissingFileError(t *testing.T) {
   141  	dir, err := ioutil.TempDir("", "umoci-TestGenerateError")
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	defer os.RemoveAll(dir)
   146  
   147  	// Create some files and other fun things.
   148  	if err := os.MkdirAll(filepath.Join(dir, "some", "parents"), 0755); err != nil {
   149  		t.Fatal(err)
   150  	}
   151  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "fileunchanged"), []byte("unchanged"), 0644); err != nil {
   152  		t.Fatal(err)
   153  	}
   154  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("changed"), 0644); err != nil {
   155  		t.Fatal(err)
   156  	}
   157  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "deleted"), []byte("deleted"), 0644); err != nil {
   158  		t.Fatal(err)
   159  	}
   160  
   161  	// Get initial from the main directory.
   162  	initDh, err := mtree.Walk(dir, nil, append(mtree.DefaultKeywords, "sha256digest"), nil)
   163  	if err != nil {
   164  		t.Fatal(err)
   165  	}
   166  
   167  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("new contents"), 0644); err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	if err := os.Remove(filepath.Join(dir, "some", "parents", "deleted")); err != nil {
   171  		t.Fatal(err)
   172  	}
   173  
   174  	// Get post.
   175  	postDh, err := mtree.Walk(dir, nil, initDh.UsedKeywords(), nil)
   176  	if err != nil {
   177  		t.Fatal(err)
   178  	}
   179  
   180  	diffs, err := mtree.Compare(initDh, postDh, initDh.UsedKeywords())
   181  	if err != nil {
   182  		t.Fatal(err)
   183  	}
   184  
   185  	// Remove the changed file after getting the diffs. This will cause an error.
   186  	if err := os.Remove(filepath.Join(dir, "some", "parents", "filechanged")); err != nil {
   187  		t.Fatal(err)
   188  	}
   189  
   190  	// Generate a layer where the changed file is missing after the diff.
   191  	reader, err := GenerateLayer(dir, diffs, &RepackOptions{})
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	defer reader.Close()
   196  
   197  	tr := tar.NewReader(reader)
   198  	for {
   199  		_, err := tr.Next()
   200  		if err == io.EOF {
   201  			t.Errorf("got EOF, not a proper error!")
   202  		}
   203  		if err != nil {
   204  			break
   205  		}
   206  	}
   207  }
   208  
   209  // Make sure that opencontainers/umoci#33 doesn't regress.
   210  func TestGenerateWrongRootError(t *testing.T) {
   211  	dir, err := ioutil.TempDir("", "umoci-TestGenerateError")
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  	defer os.RemoveAll(dir)
   216  
   217  	// Create some files and other fun things.
   218  	if err := os.MkdirAll(filepath.Join(dir, "some", "parents"), 0755); err != nil {
   219  		t.Fatal(err)
   220  	}
   221  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "fileunchanged"), []byte("unchanged"), 0644); err != nil {
   222  		t.Fatal(err)
   223  	}
   224  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("changed"), 0644); err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "deleted"), []byte("deleted"), 0644); err != nil {
   228  		t.Fatal(err)
   229  	}
   230  
   231  	// Get initial from the main directory.
   232  	initDh, err := mtree.Walk(dir, nil, append(mtree.DefaultKeywords, "sha256digest"), nil)
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  
   237  	if err := ioutil.WriteFile(filepath.Join(dir, "some", "parents", "filechanged"), []byte("new contents"), 0644); err != nil {
   238  		t.Fatal(err)
   239  	}
   240  	if err := os.Remove(filepath.Join(dir, "some", "parents", "deleted")); err != nil {
   241  		t.Fatal(err)
   242  	}
   243  
   244  	// Get post.
   245  	postDh, err := mtree.Walk(dir, nil, initDh.UsedKeywords(), nil)
   246  	if err != nil {
   247  		t.Fatal(err)
   248  	}
   249  
   250  	diffs, err := mtree.Compare(initDh, postDh, initDh.UsedKeywords())
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  
   255  	// Generate a layer with the wrong root directory.
   256  	reader, err := GenerateLayer(filepath.Join(dir, "some"), diffs, &RepackOptions{})
   257  	if err != nil {
   258  		t.Fatal(err)
   259  	}
   260  	defer reader.Close()
   261  
   262  	tr := tar.NewReader(reader)
   263  	for {
   264  		_, err := tr.Next()
   265  		if err == io.EOF {
   266  			t.Errorf("got EOF, not a proper error!")
   267  		}
   268  		if err != nil {
   269  			break
   270  		}
   271  	}
   272  }