github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/pkg/platform/runtime/envdef/environment_test.go (about)

     1  package envdef_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/ActiveState/cli/internal/testhelpers/suite"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/ActiveState/cli/internal/fileutils"
    14  	"github.com/ActiveState/cli/pkg/platform/runtime/envdef"
    15  )
    16  
    17  type EnvironmentTestSuite struct {
    18  	suite.Suite
    19  }
    20  
    21  func (suite *EnvironmentTestSuite) TestMergeVariables() {
    22  
    23  	ev1 := envdef.EnvironmentVariable{}
    24  	err := json.Unmarshal([]byte(`{
    25  		"env_name": "V",
    26  		"values": ["a", "b"]
    27  		}`), &ev1)
    28  	require.NoError(suite.T(), err)
    29  	ev2 := envdef.EnvironmentVariable{}
    30  	err = json.Unmarshal([]byte(`{
    31  		"env_name": "V",
    32  		"values": ["b", "c"]
    33  		}`), &ev2)
    34  	require.NoError(suite.T(), err)
    35  
    36  	expected := &envdef.EnvironmentVariable{}
    37  	err = json.Unmarshal([]byte(`{
    38  		"env_name": "V",
    39  		"values": ["b", "c", "a"],
    40  		"join": "prepend"
    41  		}`), expected)
    42  	require.NoError(suite.T(), err)
    43  
    44  	suite.Assert().True(expected.Inherit, "inherit should be true")
    45  	suite.Assert().Equal(":", expected.Separator)
    46  
    47  	res, err := ev1.Merge(ev2)
    48  	suite.Assert().NoError(err)
    49  	suite.Assert().Equal(expected, res)
    50  }
    51  
    52  func (suite *EnvironmentTestSuite) TestMerge() {
    53  	ed1 := &envdef.EnvironmentDefinition{}
    54  
    55  	err := json.Unmarshal([]byte(`{
    56  			"env": [{"env_name": "V", "values": ["a", "b"]}],
    57  			"installdir": "abc"
    58  		}`), ed1)
    59  	require.NoError(suite.T(), err)
    60  
    61  	ed2 := envdef.EnvironmentDefinition{}
    62  	err = json.Unmarshal([]byte(`{
    63  			"env": [{"env_name": "V", "values": ["c", "d"]}],
    64  			"installdir": "abc"
    65  		}`), &ed2)
    66  	require.NoError(suite.T(), err)
    67  
    68  	expected := envdef.EnvironmentDefinition{}
    69  	err = json.Unmarshal([]byte(`{
    70  			"env": [{"env_name": "V", "values": ["c", "d", "a", "b"]}],
    71  			"installdir": "abc"
    72  		}`), &expected)
    73  	require.NoError(suite.T(), err)
    74  
    75  	ed1, err = ed1.Merge(&ed2)
    76  	suite.Assert().NoError(err)
    77  	require.NotNil(suite.T(), ed1)
    78  	suite.Assert().Equal(expected, *ed1)
    79  }
    80  
    81  func (suite *EnvironmentTestSuite) TestInheritPath() {
    82  	ed1 := &envdef.EnvironmentDefinition{}
    83  
    84  	err := json.Unmarshal([]byte(`{
    85  			"env": [{"env_name": "PATH", "values": ["NEWVALUE"]}],
    86  			"join": "prepend",
    87  			"inherit": true,
    88  			"separator": ":"
    89  		}`), ed1)
    90  	require.NoError(suite.T(), err)
    91  
    92  	env, err := ed1.GetEnvBasedOn(func(k string) (string, bool) {
    93  		return "OLDVALUE", true
    94  	})
    95  	require.NoError(suite.T(), err)
    96  	suite.True(strings.HasPrefix(env["PATH"], "NEWVALUE"), "%s does not start with NEWVALUE", env["PATH"])
    97  	suite.True(strings.HasSuffix(env["PATH"], "OLDVALUE"), "%s does not end with OLDVALUE", env["PATH"])
    98  }
    99  
   100  func (suite *EnvironmentTestSuite) TestSharedTests() {
   101  
   102  	type testCase struct {
   103  		Name        string                         `json:"name"`
   104  		Definitions []envdef.EnvironmentDefinition `json:"definitions"`
   105  		BaseEnv     map[string]string              `json:"base_env"`
   106  		Expected    map[string]string              `json:"result"`
   107  		IsError     bool                           `json:"error"`
   108  	}
   109  
   110  	td, err := os.ReadFile("runtime_test_cases.json")
   111  	require.NoError(suite.T(), err)
   112  
   113  	cases := &[]testCase{}
   114  
   115  	err = json.Unmarshal(td, cases)
   116  	require.NoError(suite.T(), err, "unmarshal the test cases")
   117  
   118  	for _, tc := range *cases {
   119  		suite.Run(tc.Name, func() {
   120  			ed := &tc.Definitions[0]
   121  			for i, med := range tc.Definitions[1:] {
   122  				ed, err = ed.Merge(&med)
   123  				if tc.IsError {
   124  					suite.Assert().Error(err)
   125  					return
   126  				}
   127  				suite.Assert().NoError(err, "error merging %d-th definition", i)
   128  			}
   129  
   130  			lookupEnv := func(k string) (string, bool) {
   131  				res, ok := tc.BaseEnv[k]
   132  				return res, ok
   133  			}
   134  
   135  			res, err := ed.GetEnvBasedOn(lookupEnv)
   136  			if tc.IsError {
   137  				suite.Assert().Error(err)
   138  				return
   139  			}
   140  			suite.Assert().NoError(err)
   141  			suite.Assert().Equal(tc.Expected, res)
   142  		})
   143  	}
   144  
   145  }
   146  
   147  func (suite *EnvironmentTestSuite) TestValueString() {
   148  	ev1 := envdef.EnvironmentVariable{}
   149  	err := json.Unmarshal([]byte(`{
   150  		"env_name": "V",
   151  		"values": ["a", "b"]
   152  		}`), &ev1)
   153  	require.NoError(suite.T(), err)
   154  
   155  	res := ev1.ValueString()
   156  	suite.Assert().Equal("a:b", res)
   157  }
   158  
   159  func (suite *EnvironmentTestSuite) TestGetEnv() {
   160  	ed1 := envdef.EnvironmentDefinition{}
   161  	err := json.Unmarshal([]byte(`{
   162  			"env": [{"env_name": "V", "values": ["a", "b"]}],
   163  			"installdir": "abc"
   164  		}`), &ed1)
   165  	require.NoError(suite.T(), err)
   166  
   167  	res := ed1.GetEnv(true)
   168  	suite.Assert().Equal(map[string]string{
   169  		"V": "a:b",
   170  	}, res)
   171  }
   172  
   173  func (suite *EnvironmentTestSuite) TestFindBinPathFor() {
   174  	tmpDir, err := os.MkdirTemp("", "")
   175  	require.NoError(suite.T(), err, "creating temporary directory")
   176  	defer os.RemoveAll(tmpDir)
   177  
   178  	ed1 := envdef.EnvironmentDefinition{}
   179  	err = json.Unmarshal([]byte(`{
   180  			"env": [{"env_name": "PATH", "values": ["${INSTALLDIR}/bin", "${INSTALLDIR}/bin2"]}],
   181  			"installdir": "abc"
   182  		}`), &ed1)
   183  	require.NoError(suite.T(), err, "un-marshaling test json blob")
   184  
   185  	tmpDir, err = fileutils.GetLongPathName(tmpDir)
   186  	require.NoError(suite.T(), err)
   187  
   188  	constants, err := envdef.NewConstants(tmpDir)
   189  	require.NoError(suite.T(), err)
   190  	// expand variables
   191  	ed1.ExpandVariables(constants)
   192  
   193  	suite.Assert().Equal("", ed1.FindBinPathFor("executable"), "executable should not exist")
   194  
   195  	err = fileutils.Touch(filepath.Join(tmpDir, "bin2", "executable"))
   196  	require.NoError(suite.T(), err, "creating dummy file")
   197  	suite.Assert().Equal(filepath.Join(tmpDir, "bin2"), ed1.FindBinPathFor("executable"), "executable should be found")
   198  }
   199  
   200  func TestEnvironmentTestSuite(t *testing.T) {
   201  	suite.Run(t, new(EnvironmentTestSuite))
   202  }
   203  
   204  func TestFilterPATH(t *testing.T) {
   205  	s := string(os.PathListSeparator)
   206  	type args struct {
   207  		env      map[string]string
   208  		excludes []string
   209  	}
   210  	tests := []struct {
   211  		name string
   212  		args args
   213  		want string
   214  	}{
   215  		{
   216  			"Filters out matching path",
   217  			args{
   218  				map[string]string{"PATH": "/path/to/key1" + s + "/path/to/key2" + s + "/path/to/key3"},
   219  				[]string{"/path/to/key2"},
   220  			},
   221  			"/path/to/key1" + s + "/path/to/key3",
   222  		},
   223  		{
   224  			"Filters out matching path despite malformed paths",
   225  			args{
   226  				map[string]string{"PATH": "/path/to/key1" + s + "/path//to/key2" + s + "/path/to/key3"},
   227  				[]string{"/path/to//key2"},
   228  			},
   229  			"/path/to/key1" + s + "/path/to/key3",
   230  		},
   231  		{
   232  			"Preserve original version of PATH, even if it's malformed",
   233  			args{
   234  				map[string]string{"PATH": "/path//to/key1" + s + "/path//to/key2" + s + "/path/to//key3"},
   235  				[]string{"/path/to//key2"},
   236  			},
   237  			"/path//to/key1" + s + "/path/to//key3",
   238  		},
   239  		{
   240  			"Does not filter any paths",
   241  			args{
   242  				map[string]string{"PATH": "/path/to/key1"},
   243  				[]string{"/path/to/key2", "/path/to/key3"},
   244  			},
   245  			"/path/to/key1",
   246  		},
   247  	}
   248  	for _, tt := range tests {
   249  		t.Run(tt.name, func(t *testing.T) {
   250  			envdef.FilterPATH(tt.args.env, tt.args.excludes...)
   251  			require.Equal(t, tt.want, tt.args.env["PATH"])
   252  		})
   253  	}
   254  }