github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/hooks/hooks_test.go (about)

     1  package hooks
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"testing"
    11  
    12  	current "github.com/containers/libpod/pkg/hooks/1.0.0"
    13  	rspec "github.com/opencontainers/runtime-spec/specs-go"
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  // path is the path to an example hook executable.
    18  var path string
    19  
    20  func TestGoodNew(t *testing.T) {
    21  	ctx := context.Background()
    22  
    23  	dir, err := ioutil.TempDir("", "hooks-test-")
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  	defer os.RemoveAll(dir)
    28  
    29  	for i, name := range []string{
    30  		"01-my-hook.json",
    31  		"01-UPPERCASE.json",
    32  		"02-another-hook.json",
    33  	} {
    34  		jsonPath := filepath.Join(dir, name)
    35  		var extraStages string
    36  		if i == 0 {
    37  			extraStages = ", \"poststart\", \"poststop\""
    38  		}
    39  		err = ioutil.WriteFile(jsonPath, []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\", \"timeout\": %d}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"%s]}", path, i+1, extraStages)), 0644)
    40  		if err != nil {
    41  			t.Fatal(err)
    42  		}
    43  	}
    44  
    45  	manager, err := New(ctx, []string{dir}, []string{})
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	config := &rspec.Spec{}
    51  	extensionStageHooks, err := manager.Hooks(config, map[string]string{}, false)
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  
    56  	one := 1
    57  	two := 2
    58  	three := 3
    59  	assert.Equal(t, &rspec.Hooks{
    60  		Prestart: []rspec.Hook{
    61  			{
    62  				Path:    path,
    63  				Timeout: &one,
    64  			},
    65  			{
    66  				Path:    path,
    67  				Timeout: &two,
    68  			},
    69  			{
    70  				Path:    path,
    71  				Timeout: &three,
    72  			},
    73  		},
    74  		Poststart: []rspec.Hook{
    75  			{
    76  				Path:    path,
    77  				Timeout: &one,
    78  			},
    79  		},
    80  		Poststop: []rspec.Hook{
    81  			{
    82  				Path:    path,
    83  				Timeout: &one,
    84  			},
    85  		},
    86  	}, config.Hooks)
    87  
    88  	var nilExtensionStageHooks map[string][]rspec.Hook
    89  	assert.Equal(t, nilExtensionStageHooks, extensionStageHooks)
    90  }
    91  
    92  func TestBadNew(t *testing.T) {
    93  	ctx := context.Background()
    94  
    95  	dir, err := ioutil.TempDir("", "hooks-test-")
    96  	if err != nil {
    97  		t.Fatal(err)
    98  	}
    99  	defer os.RemoveAll(dir)
   100  
   101  	jsonPath := filepath.Join(dir, "a.json")
   102  	err = ioutil.WriteFile(jsonPath, []byte("{\"version\": \"-1\"}"), 0644)
   103  	if err != nil {
   104  		t.Fatal(err)
   105  	}
   106  
   107  	_, err = New(ctx, []string{dir}, []string{})
   108  	if err == nil {
   109  		t.Fatal("unexpected success")
   110  	}
   111  	assert.Regexp(t, "^parsing hook \"[^\"]*a.json\": unrecognized hook version: \"-1\"$", err.Error())
   112  }
   113  
   114  func TestBrokenMatch(t *testing.T) {
   115  	manager := Manager{
   116  		hooks: map[string]*current.Hook{
   117  			"a.json": {
   118  				Version: current.Version,
   119  				Hook: rspec.Hook{
   120  					Path: "/a/b/c",
   121  				},
   122  				When: current.When{
   123  					Commands: []string{"["},
   124  				},
   125  				Stages: []string{"prestart"},
   126  			},
   127  		},
   128  	}
   129  	config := &rspec.Spec{
   130  		Process: &rspec.Process{
   131  			Args: []string{"/bin/sh"},
   132  		},
   133  	}
   134  	extensionStageHooks, err := manager.Hooks(config, map[string]string{}, false)
   135  	if err == nil {
   136  		t.Fatal("unexpected success")
   137  	}
   138  	assert.Regexp(t, "^matching hook \"a\\.json\": command: error parsing regexp: .*", err.Error())
   139  
   140  	var nilExtensionStageHooks map[string][]rspec.Hook
   141  	assert.Equal(t, nilExtensionStageHooks, extensionStageHooks)
   142  }
   143  
   144  func TestInvalidStage(t *testing.T) {
   145  	always := true
   146  	manager := Manager{
   147  		hooks: map[string]*current.Hook{
   148  			"a.json": {
   149  				Version: current.Version,
   150  				Hook: rspec.Hook{
   151  					Path: "/a/b/c",
   152  				},
   153  				When: current.When{
   154  					Always: &always,
   155  				},
   156  				Stages: []string{"does-not-exist"},
   157  			},
   158  		},
   159  	}
   160  	extensionStageHooks, err := manager.Hooks(&rspec.Spec{}, map[string]string{}, false)
   161  	if err == nil {
   162  		t.Fatal("unexpected success")
   163  	}
   164  	assert.Regexp(t, "^hook \"a\\.json\": unknown stage \"does-not-exist\"$", err.Error())
   165  
   166  	var nilExtensionStageHooks map[string][]rspec.Hook
   167  	assert.Equal(t, nilExtensionStageHooks, extensionStageHooks)
   168  }
   169  
   170  func TestExtensionStage(t *testing.T) {
   171  	always := true
   172  	manager := Manager{
   173  		hooks: map[string]*current.Hook{
   174  			"a.json": {
   175  				Version: current.Version,
   176  				Hook: rspec.Hook{
   177  					Path: "/a/b/c",
   178  				},
   179  				When: current.When{
   180  					Always: &always,
   181  				},
   182  				Stages: []string{"prestart", "poststop", "a", "b"},
   183  			},
   184  		},
   185  		extensionStages: []string{"poststop", "a", "b", "c"},
   186  	}
   187  
   188  	config := &rspec.Spec{}
   189  	extensionStageHooks, err := manager.Hooks(config, map[string]string{}, false)
   190  	if err != nil {
   191  		t.Fatal(err)
   192  	}
   193  
   194  	assert.Equal(t, &rspec.Hooks{
   195  		Prestart: []rspec.Hook{
   196  			{
   197  				Path: "/a/b/c",
   198  			},
   199  		},
   200  	}, config.Hooks)
   201  
   202  	assert.Equal(t, map[string][]rspec.Hook{
   203  		"poststop": {
   204  			{
   205  				Path: "/a/b/c",
   206  			},
   207  		},
   208  		"a": {
   209  			{
   210  				Path: "/a/b/c",
   211  			},
   212  		},
   213  		"b": {
   214  			{
   215  				Path: "/a/b/c",
   216  			},
   217  		},
   218  	}, extensionStageHooks)
   219  }
   220  
   221  func init() {
   222  	if runtime.GOOS != "windows" {
   223  		path = "/bin/sh"
   224  	} else {
   225  		panic("we need a reliable executable path on Windows")
   226  	}
   227  }