github.com/apptainer/singularity@v3.1.1+incompatible/pkg/image/image_test.go (about)

     1  // Copyright (c) 2019, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package image
     7  
     8  import (
     9  	"encoding/json"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"testing"
    17  
    18  	"github.com/sylabs/singularity/internal/pkg/util/fs"
    19  
    20  	imageSpecs "github.com/opencontainers/image-spec/specs-go/v1"
    21  	"github.com/sylabs/singularity/pkg/image/unpacker"
    22  )
    23  
    24  func downloadImage(t *testing.T) string {
    25  	sexec, err := exec.LookPath("singularity")
    26  	if err != nil {
    27  		t.SkipNow()
    28  	}
    29  	f, err := ioutil.TempFile("", "image-")
    30  	if err != nil {
    31  		t.Fatal(err)
    32  	}
    33  	name := f.Name()
    34  	f.Close()
    35  
    36  	cmd := exec.Command(sexec, "build", "-F", name, "docker://busybox")
    37  	if err := cmd.Run(); err != nil {
    38  		t.Fatal(err)
    39  	}
    40  	return name
    41  }
    42  
    43  func checkPartition(reader io.Reader) error {
    44  	extracted := "/bin/busybox"
    45  	dir, err := ioutil.TempDir("", "extract-")
    46  	if err != nil {
    47  		return err
    48  	}
    49  	defer os.RemoveAll(dir)
    50  
    51  	s := unpacker.NewSquashfs()
    52  	if s.HasUnsquashfs() {
    53  		if err := s.ExtractFiles([]string{extracted}, reader, dir); err != nil {
    54  			return fmt.Errorf("extraction failed: %s", err)
    55  		}
    56  		if !fs.IsExec(filepath.Join(dir, extracted)) {
    57  			return fmt.Errorf("%s extraction failed", extracted)
    58  		}
    59  	}
    60  	return nil
    61  }
    62  
    63  func checkSection(reader io.Reader) error {
    64  	dec := json.NewDecoder(reader)
    65  	imgSpec := &imageSpecs.ImageConfig{}
    66  	if err := dec.Decode(imgSpec); err != nil {
    67  		return fmt.Errorf("failed to decode oci image config")
    68  	}
    69  	if len(imgSpec.Cmd) == 0 {
    70  		return fmt.Errorf("no command found")
    71  	}
    72  	if imgSpec.Cmd[0] != "sh" {
    73  		return fmt.Errorf("unexpected value: %s instead of sh", imgSpec.Cmd[0])
    74  	}
    75  	return nil
    76  }
    77  
    78  func TestReader(t *testing.T) {
    79  	filename := downloadImage(t)
    80  	defer os.Remove(filename)
    81  
    82  	for _, e := range []struct {
    83  		fn       func(*Image, string, int) (io.Reader, error)
    84  		fnCheck  func(io.Reader) error
    85  		errCheck error
    86  		name     string
    87  		index    int
    88  	}{
    89  		{
    90  			fn:       NewPartitionReader,
    91  			fnCheck:  checkPartition,
    92  			errCheck: ErrNoPartition,
    93  			name:     RootFs,
    94  			index:    -1,
    95  		},
    96  		{
    97  			fn:       NewPartitionReader,
    98  			fnCheck:  checkPartition,
    99  			errCheck: ErrNoPartition,
   100  			index:    0,
   101  		},
   102  		{
   103  			fn:       NewSectionReader,
   104  			fnCheck:  checkSection,
   105  			errCheck: ErrNoSection,
   106  			name:     "oci-config.json",
   107  			index:    -1,
   108  		},
   109  	} {
   110  		// test with nil image parameter
   111  		if _, err := e.fn(nil, "", -1); err == nil {
   112  			t.Errorf("unexpected success with nil image parameter")
   113  		}
   114  		// test with non opened file
   115  		if _, err := e.fn(&Image{}, "", -1); err == nil {
   116  			t.Errorf("unexpected success with non opened file")
   117  		}
   118  
   119  		img, err := Init(filename, false)
   120  		if err != nil {
   121  			t.Fatal(err)
   122  		}
   123  
   124  		if img.Type != SIF {
   125  			t.Errorf("unexpected image format: %v", img.Type)
   126  		}
   127  		// test without match criteria
   128  		if _, err := e.fn(img, "", -1); err == nil {
   129  			t.Errorf("unexpected success without match criteria")
   130  		}
   131  		// test with large index
   132  		if _, err := e.fn(img, "", 999999); err == nil {
   133  			t.Errorf("unexpected success with large index")
   134  		}
   135  		// test with unknown name
   136  		if _, err := e.fn(img, "fakefile.name", -1); err != e.errCheck {
   137  			t.Errorf("unexpected error with unknown name")
   138  		}
   139  		// test with match criteria
   140  		if r, err := e.fn(img, e.name, e.index); err == e.errCheck {
   141  			t.Error(err)
   142  		} else {
   143  			if err := e.fnCheck(r); err != nil {
   144  				t.Error(err)
   145  			}
   146  		}
   147  		img.File.Close()
   148  	}
   149  }