...

Source file src/github.com/redhat-developer/odo/pkg/util/util_test.go

Documentation: github.com/redhat-developer/odo/pkg/util

     1  package util
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"os"
    12  	"os/user"
    13  	"path/filepath"
    14  	"regexp"
    15  	"runtime"
    16  	"strconv"
    17  	"strings"
    18  	"testing"
    19  
    20  	"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
    21  	dfutil "github.com/devfile/library/v2/pkg/util"
    22  	"github.com/go-git/go-git/v5"
    23  	"github.com/go-git/go-git/v5/config"
    24  	"github.com/google/go-cmp/cmp"
    25  	corev1 "k8s.io/api/core/v1"
    26  
    27  	"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
    28  )
    29  
    30  // TODO(feloy) Move tests to devfile library
    31  
    32  func TestNamespaceOpenShiftObject(t *testing.T) {
    33  
    34  	tests := []struct {
    35  		testName        string
    36  		componentName   string
    37  		applicationName string
    38  		want            string
    39  		wantErr         bool
    40  	}{
    41  		{
    42  			testName:        "Test namespacing",
    43  			componentName:   "foo",
    44  			applicationName: "bar",
    45  			want:            "foo-bar",
    46  		},
    47  		{
    48  			testName:        "Blank applicationName with namespacing",
    49  			componentName:   "foo",
    50  			applicationName: "",
    51  			wantErr:         true,
    52  		},
    53  		{
    54  			testName:        "Blank componentName with namespacing",
    55  			componentName:   "",
    56  			applicationName: "bar",
    57  			wantErr:         true,
    58  		},
    59  	}
    60  
    61  	// Test that it "joins"
    62  
    63  	for _, tt := range tests {
    64  		t.Log("Running test: ", tt.testName)
    65  		t.Run(tt.testName, func(t *testing.T) {
    66  			name, err := dfutil.NamespaceOpenShiftObject(tt.componentName, tt.applicationName)
    67  
    68  			if tt.wantErr && err == nil {
    69  				t.Errorf("Expected an error, got success")
    70  			} else if tt.wantErr == false && err != nil {
    71  				t.Errorf("Error with namespacing: %s", err)
    72  			}
    73  
    74  			if tt.want != name {
    75  				t.Errorf("Expected %s, got %s", tt.want, name)
    76  			}
    77  		})
    78  	}
    79  
    80  }
    81  
    82  func TestExtractComponentType(t *testing.T) {
    83  
    84  	tests := []struct {
    85  		testName      string
    86  		componentType string
    87  		want          string
    88  		wantErr       bool
    89  	}{
    90  		{
    91  			testName:      "Test namespacing and versioning",
    92  			componentType: "myproject/foo:3.5",
    93  			want:          "foo",
    94  		},
    95  		{
    96  			testName:      "Test versioning",
    97  			componentType: "foo:3.5",
    98  			want:          "foo",
    99  		},
   100  		{
   101  			testName:      "Test plain component type",
   102  			componentType: "foo",
   103  			want:          "foo",
   104  		},
   105  	}
   106  
   107  	// Test that it "joins"
   108  
   109  	for _, tt := range tests {
   110  		t.Log("Running test: ", tt.testName)
   111  		t.Run(tt.testName, func(t *testing.T) {
   112  			name := dfutil.ExtractComponentType(tt.componentType)
   113  			if tt.want != name {
   114  				t.Errorf("Expected %s, got %s", tt.want, name)
   115  			}
   116  		})
   117  	}
   118  
   119  }
   120  
   121  func TestGetDNS1123Name(t *testing.T) {
   122  
   123  	tests := []struct {
   124  		testName string
   125  		param    string
   126  		want     string
   127  	}{
   128  		{
   129  			testName: "Case 1: Test get DNS-1123 name for namespace and version qualified imagestream",
   130  			param:    "myproject/foo:3.5",
   131  			want:     "myproject-foo-3-5",
   132  		},
   133  		{
   134  			testName: "Case 2: Test get DNS-1123 name for doubly hyphenated string",
   135  			param:    "nodejs--myproject-foo-3.5",
   136  			want:     "nodejs-myproject-foo-3-5",
   137  		},
   138  		{
   139  			testName: "Case 3: Test get DNS-1123 name for string starting with underscore",
   140  			param:    "_nodejs--myproject-foo-3.5",
   141  			want:     "nodejs-myproject-foo-3-5",
   142  		},
   143  		{
   144  			testName: "Case 4: Test get DNS-1123 name for string ending with underscore",
   145  			param:    "nodejs--myproject-foo-3.5_",
   146  			want:     "nodejs-myproject-foo-3-5",
   147  		},
   148  		{
   149  			testName: "Case 5: Test get DNS-1123 name for string having multiple non alpha-numeric chars as prefix",
   150  			param:    "_#*nodejs--myproject-foo-3.5",
   151  			want:     "nodejs-myproject-foo-3-5",
   152  		},
   153  		{
   154  			testName: "Case 6: Test get DNS-1123 name for string having multiple non alpha-numeric chars as suffix",
   155  			param:    "nodejs--myproject-foo-3.5=_@",
   156  			want:     "nodejs-myproject-foo-3-5",
   157  		},
   158  		{
   159  			testName: "Case 7: Test get DNS-1123 name for string having with multiple non alpha-numeric chars as prefix and suffix",
   160  			param:    " _#*nodejs--myproject-foo-3.5=_@ ",
   161  			want:     "nodejs-myproject-foo-3-5",
   162  		},
   163  		{
   164  			testName: "Case 8: Test get DNS-1123 should remove invalid chars",
   165  			param:    "myproject/$foo@@:3.5",
   166  			want:     "myproject-foo-3-5",
   167  		},
   168  		{
   169  			testName: "Case 9: Test get DNS-1123 should remove invalid chars with sufix and prefix",
   170  			param:    "54myproject/$foo@@:3.5",
   171  			want:     "myproject-foo-3-5",
   172  		},
   173  		{
   174  			testName: "Case 9: Test get DNS-1123 should add x as a prefix for all numerics",
   175  			param:    "54453443",
   176  			want:     "x54453443",
   177  		},
   178  	}
   179  
   180  	// Test that it "joins"
   181  
   182  	for _, tt := range tests {
   183  		t.Log("Running test: ", tt.testName)
   184  		t.Run(tt.testName, func(t *testing.T) {
   185  			name := GetDNS1123Name(tt.param)
   186  			if tt.want != name {
   187  				t.Errorf("Expected %s, got %s", tt.want, name)
   188  			}
   189  		})
   190  	}
   191  
   192  }
   193  
   194  func TestGetRandomName(t *testing.T) {
   195  	type args struct {
   196  		prefix    string
   197  		existList []string
   198  	}
   199  	tests := []struct {
   200  		testName string
   201  		args     args
   202  		// want is regexp if expectConflictResolution is true else its a full name
   203  		want string
   204  	}{
   205  		{
   206  			testName: "Case: Optional suffix passed and prefix-suffix as a name is not already used",
   207  			args: args{
   208  				prefix: "odo",
   209  				existList: []string{
   210  					"odo-auth",
   211  					"odo-pqrs",
   212  				},
   213  			},
   214  			want: "odo-[a-z]{4}",
   215  		},
   216  		{
   217  			testName: "Case: Optional suffix passed and prefix-suffix as a name is already used",
   218  			args: args{
   219  				prefix: "nodejs-ex-nodejs",
   220  				existList: []string{
   221  					"nodejs-ex-nodejs-yvrp",
   222  					"nodejs-ex-nodejs-abcd",
   223  				},
   224  			},
   225  			want: "nodejs-ex-nodejs-[a-z]{4}",
   226  		},
   227  	}
   228  
   229  	for _, tt := range tests {
   230  		t.Log("Running test: ", tt.testName)
   231  		t.Run(tt.testName, func(t *testing.T) {
   232  			name, err := dfutil.GetRandomName(tt.args.prefix, -1, tt.args.existList, 3)
   233  			if err != nil {
   234  				t.Errorf("failed to generate a random name. Error %v", err)
   235  			}
   236  
   237  			r, _ := regexp.Compile(tt.want)
   238  			match := r.MatchString(name)
   239  			if !match {
   240  				t.Errorf("Received name %s which does not match %s", name, tt.want)
   241  			}
   242  		})
   243  	}
   244  }
   245  
   246  func TestTruncateString(t *testing.T) {
   247  	tests := []struct {
   248  		testName  string
   249  		str       string
   250  		strLength int
   251  		appendStr bool
   252  		appendArr []string
   253  		want      string
   254  	}{
   255  		{
   256  			testName:  "Case: Truncate string to greater length",
   257  			str:       "qw",
   258  			strLength: 4,
   259  			appendStr: false,
   260  			want:      "qw",
   261  		},
   262  		{
   263  			testName:  "Case: Truncate string to lesser length",
   264  			str:       "rtyu",
   265  			strLength: 3,
   266  			appendStr: false,
   267  			want:      "rty",
   268  		},
   269  		{
   270  			testName:  "Case: Truncate string to -1 length",
   271  			str:       "Odo",
   272  			strLength: -1,
   273  			appendStr: false,
   274  			want:      "Odo",
   275  		},
   276  		{
   277  			testName:  "Case: Trunicate string with 3 dots appended",
   278  			str:       "rtyu",
   279  			strLength: 3,
   280  			appendStr: true,
   281  			appendArr: []string{"..."},
   282  			want:      "rty...",
   283  		},
   284  		{
   285  			testName:  "Case: Appends multiple if multiple args are provided",
   286  			str:       "rtyu",
   287  			strLength: 3,
   288  			appendStr: true,
   289  			appendArr: []string{".", ".", "."},
   290  			want:      "rty...",
   291  		},
   292  		{
   293  			testName:  "Case: Does not append if length is lesser than max length",
   294  			str:       "qw",
   295  			strLength: 4,
   296  			appendStr: true,
   297  			appendArr: []string{"..."},
   298  			want:      "qw",
   299  		},
   300  		{
   301  			testName:  "Case: Does not append if maxlength is -1",
   302  			str:       "rtyu",
   303  			strLength: -1,
   304  			appendStr: true,
   305  			appendArr: []string{"..."},
   306  			want:      "rtyu",
   307  		},
   308  	}
   309  
   310  	for _, tt := range tests {
   311  		t.Log("Running test: ", tt.testName)
   312  		t.Run(tt.testName, func(t *testing.T) {
   313  			var receivedStr string
   314  			if tt.appendStr {
   315  				receivedStr = TruncateString(tt.str, tt.strLength, tt.appendArr...)
   316  			} else {
   317  				receivedStr = TruncateString(tt.str, tt.strLength)
   318  			}
   319  			if tt.want != receivedStr {
   320  				t.Errorf("Truncated string %s is not same as %s", receivedStr, tt.want)
   321  			}
   322  		})
   323  	}
   324  }
   325  
   326  func TestGenerateRandomString(t *testing.T) {
   327  	tests := []struct {
   328  		testName  string
   329  		strLength int
   330  	}{
   331  		{
   332  			testName:  "Case: Generate random string of length 4",
   333  			strLength: 4,
   334  		},
   335  		{
   336  			testName:  "Case: Generate random string of length 3",
   337  			strLength: 3,
   338  		},
   339  	}
   340  
   341  	for _, tt := range tests {
   342  		t.Log("Running test: ", tt.testName)
   343  		t.Run(tt.testName, func(t *testing.T) {
   344  			name := dfutil.GenerateRandomString(tt.strLength)
   345  			r, _ := regexp.Compile(fmt.Sprintf("[a-z]{%d}", tt.strLength))
   346  			match := r.MatchString(name)
   347  			if !match {
   348  				t.Errorf("Randomly generated string %s which does not match regexp %s", name, fmt.Sprintf("[a-z]{%d}", tt.strLength))
   349  			}
   350  		})
   351  	}
   352  }
   353  
   354  func TestGetAbsPath(t *testing.T) {
   355  	tests := []struct {
   356  		name    string
   357  		path    string
   358  		absPath string
   359  		wantErr bool
   360  	}{
   361  		{
   362  			name:    "Case 1: Valid abs path resolution of `~`",
   363  			path:    "~",
   364  			wantErr: false,
   365  		},
   366  		{
   367  			name:    "Case 2: Valid abs path resolution of `.`",
   368  			path:    ".",
   369  			wantErr: false,
   370  		},
   371  	}
   372  	for _, tt := range tests {
   373  		t.Log("Running test: ", tt.name)
   374  		t.Run(tt.name, func(t *testing.T) {
   375  			switch tt.path {
   376  			case "~":
   377  				if len(customHomeDir) > 0 {
   378  					tt.absPath = customHomeDir
   379  				} else {
   380  					usr, err := user.Current()
   381  					if err != nil {
   382  						t.Errorf("Failed to get absolute path corresponding to `~`. Error %v", err)
   383  						return
   384  					}
   385  					tt.absPath = usr.HomeDir
   386  				}
   387  
   388  			case ".":
   389  				absPath, err := os.Getwd()
   390  				if err != nil {
   391  					t.Errorf("Failed to get absolute path corresponding to `.`. Error %v", err)
   392  					return
   393  				}
   394  				tt.absPath = absPath
   395  			}
   396  			result, err := dfutil.GetAbsPath(tt.path)
   397  			if result != tt.absPath {
   398  				t.Errorf("Expected %v, got %v", tt.absPath, result)
   399  			}
   400  			if !tt.wantErr == (err != nil) {
   401  				t.Errorf("Expected error: %v got error %v", tt.wantErr, err)
   402  			}
   403  		})
   404  	}
   405  }
   406  
   407  func TestCheckPathExists(t *testing.T) {
   408  	tests := []struct {
   409  		fsProvider func() (filesystem.Filesystem, error)
   410  		fileName   string
   411  		wantBool   bool
   412  	}{
   413  		{
   414  			fsProvider: func() (filesystem.Filesystem, error) {
   415  				fakeFs := filesystem.NewFakeFs()
   416  				_, err := fakeFs.Create("my-file")
   417  				if err != nil {
   418  					return nil, err
   419  				}
   420  				return fakeFs, nil
   421  			},
   422  			fileName: "my-file",
   423  			wantBool: true,
   424  		},
   425  		{
   426  			fsProvider: func() (filesystem.Filesystem, error) {
   427  				return filesystem.NewFakeFs(), nil
   428  			},
   429  			fileName: "some-file-blah",
   430  			wantBool: false,
   431  		},
   432  	}
   433  
   434  	for _, tt := range tests {
   435  		fsys, err := tt.fsProvider()
   436  		if err != nil {
   437  			t.Fatal(err)
   438  		}
   439  		exists := CheckPathExists(fsys, tt.fileName)
   440  		if tt.wantBool != exists {
   441  			t.Errorf("the expected value of TestCheckPathExists function is different : %v, got: %v", tt.wantBool, exists)
   442  		}
   443  	}
   444  }
   445  
   446  func TestGetHostWithPort(t *testing.T) {
   447  
   448  	tests := []struct {
   449  		inputURL string
   450  		want     string
   451  		wantErr  bool
   452  	}{
   453  		{
   454  			inputURL: "https://example.com",
   455  			want:     "example.com:443",
   456  			wantErr:  false,
   457  		},
   458  		{
   459  			inputURL: "https://example.com:8443",
   460  			want:     "example.com:8443",
   461  			wantErr:  false,
   462  		},
   463  		{
   464  			inputURL: "http://example.com",
   465  			want:     "example.com:80",
   466  			wantErr:  false,
   467  		},
   468  		{
   469  			inputURL: "notexisting://example.com",
   470  			want:     "",
   471  			wantErr:  true,
   472  		},
   473  		{
   474  			inputURL: "http://127.0.0.1",
   475  			want:     "127.0.0.1:80",
   476  			wantErr:  false,
   477  		},
   478  		{
   479  			inputURL: "example.com:1234",
   480  			want:     "",
   481  			wantErr:  true,
   482  		},
   483  	}
   484  	for _, tt := range tests {
   485  		t.Run(fmt.Sprintf("Testing inputURL: %s", tt.inputURL), func(t *testing.T) {
   486  			got, err := dfutil.GetHostWithPort(tt.inputURL)
   487  			if (err != nil) != tt.wantErr {
   488  				t.Errorf("getHostWithPort() error = %v, wantErr %v", err, tt.wantErr)
   489  				return
   490  			}
   491  			if got != tt.want {
   492  				t.Errorf("getHostWithPort() = %v, want %v", got, tt.want)
   493  			}
   494  		})
   495  	}
   496  }
   497  
   498  // MakeFileWithContent creates file with a given name in the given directory and writes the content to it
   499  // dir is the name of the directory
   500  // fileName is the name of the file to be created
   501  // content is the string to be written to the file
   502  func MakeFileWithContent(dir string, fileName string, content string) error {
   503  	file, err := os.Create(dir + string(os.PathSeparator) + fileName)
   504  	if err != nil {
   505  		return fmt.Errorf("error while creating file: %w", err)
   506  	}
   507  	defer file.Close()
   508  	_, err = file.WriteString(content)
   509  	if err != nil {
   510  		return fmt.Errorf("error while writing to file: %w", err)
   511  	}
   512  	return nil
   513  }
   514  
   515  // RemoveContentsFromDir removes content from the given directory
   516  // dir is the name of the directory
   517  func RemoveContentsFromDir(dir string) error {
   518  	files, err := filepath.Glob(filepath.Join(dir, "*"))
   519  	if err != nil {
   520  		return err
   521  	}
   522  	for _, file := range files {
   523  		err = os.RemoveAll(file)
   524  		if err != nil {
   525  			return err
   526  		}
   527  	}
   528  	return nil
   529  }
   530  
   531  func TestGetIgnoreRulesFromDirectory(t *testing.T) {
   532  	testDir := t.TempDir()
   533  	tests := []struct {
   534  		name             string
   535  		directoryName    string
   536  		filesToCreate    []string
   537  		rulesOnGitIgnore string
   538  		rulesOnOdoIgnore string
   539  		wantRules        []string
   540  		wantErr          bool
   541  	}{
   542  		{
   543  			name:             "test case 1: no odoignore and no gitignore",
   544  			directoryName:    testDir,
   545  			filesToCreate:    []string{""},
   546  			rulesOnGitIgnore: "",
   547  			rulesOnOdoIgnore: "",
   548  			wantRules:        []string{".git"},
   549  			wantErr:          false,
   550  		},
   551  		{
   552  			name:             "test case 2: no odoignore but gitignore exists with no rules",
   553  			directoryName:    testDir,
   554  			filesToCreate:    []string{DotGitIgnoreFile},
   555  			rulesOnGitIgnore: "",
   556  			rulesOnOdoIgnore: "",
   557  			wantRules:        []string{".git"},
   558  			wantErr:          false,
   559  		},
   560  		{
   561  			name:             "test case 3: no odoignore but gitignore exists with rules",
   562  			directoryName:    testDir,
   563  			filesToCreate:    []string{DotGitIgnoreFile},
   564  			rulesOnGitIgnore: "*.js\n\n/openshift/**/*.json\n/tests",
   565  			rulesOnOdoIgnore: "",
   566  			wantRules:        []string{".git", "*.js", "/openshift/**/*.json", "/tests"},
   567  			wantErr:          false,
   568  		},
   569  		{
   570  			name:             "test case 4: odoignore exists with no rules",
   571  			directoryName:    testDir,
   572  			filesToCreate:    []string{".odoignore"},
   573  			rulesOnGitIgnore: "",
   574  			rulesOnOdoIgnore: "",
   575  			wantRules:        []string{".git"},
   576  			wantErr:          false,
   577  		},
   578  		{
   579  			name:             "test case 5: odoignore exists with rules",
   580  			directoryName:    testDir,
   581  			filesToCreate:    []string{".odoignore"},
   582  			rulesOnGitIgnore: "",
   583  			rulesOnOdoIgnore: "*.json\n\n/openshift/**/*.js",
   584  			wantRules:        []string{".git", "*.json", "/openshift/**/*.js"},
   585  			wantErr:          false,
   586  		},
   587  		{
   588  			name:             "test case 6: odoignore and gitignore both exists with rules",
   589  			directoryName:    testDir,
   590  			filesToCreate:    []string{DotGitIgnoreFile, ".odoignore"},
   591  			rulesOnGitIgnore: "/tests",
   592  			rulesOnOdoIgnore: "*.json\n\n/openshift/**/*.js",
   593  			wantRules:        []string{".git", "*.json", "/openshift/**/*.js"},
   594  			wantErr:          false,
   595  		},
   596  		{
   597  			name:             "test case 7: no odoignore but gitignore exists with rules and comments",
   598  			directoryName:    testDir,
   599  			filesToCreate:    []string{DotGitIgnoreFile},
   600  			rulesOnGitIgnore: "*.js\n\n/openshift/**/*.json\n\n\n#/tests",
   601  			rulesOnOdoIgnore: "",
   602  			wantRules:        []string{".git", "*.js", "/openshift/**/*.json"},
   603  			wantErr:          false,
   604  		},
   605  		{
   606  			name:             "test case 8: odoignore exists exists with rules and comments",
   607  			directoryName:    testDir,
   608  			filesToCreate:    []string{".odoignore"},
   609  			rulesOnOdoIgnore: "*.js\n\n\n/openshift/**/*.json\n\n\n#/tests\n/bin",
   610  			rulesOnGitIgnore: "",
   611  			wantRules:        []string{".git", "*.js", "/openshift/**/*.json", "/bin"},
   612  			wantErr:          false,
   613  		},
   614  	}
   615  
   616  	for _, tt := range tests {
   617  		for _, fileName := range tt.filesToCreate {
   618  			var err error
   619  			if fileName == DotGitIgnoreFile {
   620  				err = MakeFileWithContent(testDir, fileName, tt.rulesOnGitIgnore)
   621  			} else if fileName == ".odoignore" {
   622  				err = MakeFileWithContent(testDir, fileName, tt.rulesOnOdoIgnore)
   623  			}
   624  			if err != nil {
   625  				t.Fatal(err)
   626  			}
   627  		}
   628  
   629  		gotRules, err := dfutil.GetIgnoreRulesFromDirectory(testDir)
   630  
   631  		if err == nil && !tt.wantErr {
   632  			if diff := cmp.Diff(tt.wantRules, gotRules); diff != "" {
   633  				t.Errorf("dfutil.GetIgnoreRulesFromDirectory() wantRules mismatch (-want +got):\n%s", diff)
   634  			}
   635  		} else if err == nil && tt.wantErr {
   636  			t.Error("error was expected, but no error was returned")
   637  		} else if err != nil && !tt.wantErr {
   638  			t.Errorf("test failed, no error was expected, but got unexpected error: %s", err)
   639  		}
   640  		err = RemoveContentsFromDir(testDir)
   641  		if err != nil {
   642  			t.Fatal(err)
   643  		}
   644  	}
   645  }
   646  
   647  func TestGetAbsGlobExps(t *testing.T) {
   648  	tests := []struct {
   649  		testName              string
   650  		directoryName         string
   651  		inputRelativeGlobExps []string
   652  		expectedGlobExps      []string
   653  	}{
   654  		{
   655  			testName:      "test case 1: with a filename",
   656  			directoryName: "/home/redhat/nodejs-ex/",
   657  			inputRelativeGlobExps: []string{
   658  				"example.txt",
   659  			},
   660  			expectedGlobExps: []string{
   661  				"/home/redhat/nodejs-ex/example.txt",
   662  			},
   663  		},
   664  		{
   665  			testName:      "test case 2: with a folder name",
   666  			directoryName: "/home/redhat/nodejs-ex/",
   667  			inputRelativeGlobExps: []string{
   668  				"example/",
   669  			},
   670  			expectedGlobExps: []string{
   671  				"/home/redhat/nodejs-ex/example",
   672  			},
   673  		},
   674  	}
   675  
   676  	for _, tt := range tests {
   677  		t.Run(tt.testName, func(t *testing.T) {
   678  			resultExps := dfutil.GetAbsGlobExps(tt.directoryName, tt.inputRelativeGlobExps)
   679  			if runtime.GOOS == "windows" {
   680  				for index, element := range resultExps {
   681  					resultExps[index] = filepath.ToSlash(element)
   682  				}
   683  			}
   684  
   685  			if diff := cmp.Diff(tt.expectedGlobExps, resultExps); diff != "" {
   686  				t.Errorf("dfutil.GetAbsGlobExps() expectedGlobExps mismatch (-want +got):\n%s", diff)
   687  			}
   688  		})
   689  	}
   690  }
   691  
   692  func TestGetSortedKeys(t *testing.T) {
   693  	tests := []struct {
   694  		testName string
   695  		input    map[string]string
   696  		expected []string
   697  	}{
   698  		{
   699  			testName: "default",
   700  			input:    map[string]string{"a": "av", "c": "cv", "b": "bv"},
   701  			expected: []string{"a", "b", "c"},
   702  		},
   703  	}
   704  
   705  	for _, tt := range tests {
   706  		t.Log("Running test: ", tt.testName)
   707  		t.Run(tt.testName, func(t *testing.T) {
   708  			actual := dfutil.GetSortedKeys(tt.input)
   709  			if diff := cmp.Diff(tt.expected, actual); diff != "" {
   710  				t.Errorf("dfutil.GetSortedKeys() mismatch (-want +got):\n%s", diff)
   711  			}
   712  		})
   713  	}
   714  }
   715  
   716  func TestGetSplitValuesFromStr(t *testing.T) {
   717  	tests := []struct {
   718  		testName string
   719  		input    string
   720  		expected []string
   721  	}{
   722  		{
   723  			testName: "Empty string",
   724  			input:    "",
   725  			expected: []string{},
   726  		},
   727  		{
   728  			testName: "Single value",
   729  			input:    "s1",
   730  			expected: []string{"s1"},
   731  		},
   732  		{
   733  			testName: "Multiple values",
   734  			input:    "s1, s2, s3 ",
   735  			expected: []string{"s1", "s2", "s3"},
   736  		},
   737  	}
   738  
   739  	for _, tt := range tests {
   740  		t.Log("Running test: ", tt.testName)
   741  		t.Run(tt.testName, func(t *testing.T) {
   742  			actual := dfutil.GetSplitValuesFromStr(tt.input)
   743  			if diff := cmp.Diff(tt.expected, actual); diff != "" {
   744  				t.Errorf("dfutil.GetSplitValuesFromStr() mismatch (-want +got):\n%s", diff)
   745  			}
   746  		})
   747  	}
   748  }
   749  
   750  func TestGetContainerPortsFromStrings(t *testing.T) {
   751  	tests := []struct {
   752  		name           string
   753  		ports          []string
   754  		containerPorts []corev1.ContainerPort
   755  		wantErr        bool
   756  	}{
   757  		{
   758  			name:  "with normal port values and normal protocol values in lowercase",
   759  			ports: []string{"8080/tcp", "9090/udp"},
   760  			containerPorts: []corev1.ContainerPort{
   761  				{
   762  					Name:          "8080-tcp",
   763  					ContainerPort: 8080,
   764  					Protocol:      corev1.ProtocolTCP,
   765  				},
   766  				{
   767  					Name:          "9090-udp",
   768  					ContainerPort: 9090,
   769  					Protocol:      corev1.ProtocolUDP,
   770  				},
   771  			},
   772  			wantErr: false,
   773  		},
   774  		{
   775  			name:  "with normal port values and normal protocol values in mixed case",
   776  			ports: []string{"8080/TcP", "9090/uDp"},
   777  			containerPorts: []corev1.ContainerPort{
   778  				{
   779  					Name:          "8080-tcp",
   780  					ContainerPort: 8080,
   781  					Protocol:      corev1.ProtocolTCP,
   782  				},
   783  				{
   784  					Name:          "9090-udp",
   785  					ContainerPort: 9090,
   786  					Protocol:      corev1.ProtocolUDP,
   787  				},
   788  			},
   789  			wantErr: false,
   790  		},
   791  		{
   792  			name:  "with normal port values and with one protocol value not mentioned",
   793  			ports: []string{"8080", "9090/Udp"},
   794  			containerPorts: []corev1.ContainerPort{
   795  				{
   796  					Name:          "8080-tcp",
   797  					ContainerPort: 8080,
   798  					Protocol:      corev1.ProtocolTCP,
   799  				},
   800  				{
   801  					Name:          "9090-udp",
   802  					ContainerPort: 9090,
   803  					Protocol:      corev1.ProtocolUDP,
   804  				},
   805  			},
   806  			wantErr: false,
   807  		},
   808  		{
   809  			name:    "with normal port values and with one invalid protocol value",
   810  			ports:   []string{"8080/blah", "9090/Udp"},
   811  			wantErr: true,
   812  		},
   813  		{
   814  			name:    "with invalid port values and normal protocol",
   815  			ports:   []string{"ads/Tcp", "9090/Udp"},
   816  			wantErr: true,
   817  		},
   818  		{
   819  			name:    "with invalid port values and one missing protocol value",
   820  			ports:   []string{"ads", "9090/Udp"},
   821  			wantErr: true,
   822  		},
   823  	}
   824  	for _, tt := range tests {
   825  		t.Run(tt.name, func(t *testing.T) {
   826  			ports, err := dfutil.GetContainerPortsFromStrings(tt.ports)
   827  			if err == nil && !tt.wantErr {
   828  				if diff := cmp.Diff(tt.containerPorts, ports); diff != "" {
   829  					t.Errorf("dfutil.GetContainerPortsFromStrings() containerPorts mismatch (-want +got):\n%s", diff)
   830  				}
   831  			} else if err == nil && tt.wantErr {
   832  				t.Error("error was expected, but no error was returned")
   833  			} else if err != nil && !tt.wantErr {
   834  				t.Errorf("test failed, no error was expected, but got unexpected error: %s", err)
   835  			}
   836  		})
   837  	}
   838  }
   839  
   840  func TestIsGlobExpMatch(t *testing.T) {
   841  
   842  	tests := []struct {
   843  		testName   string
   844  		strToMatch string
   845  		globExps   []string
   846  		want       bool
   847  		wantErr    bool
   848  	}{
   849  		{
   850  			testName:   "Test glob matches",
   851  			strToMatch: "/home/redhat/nodejs-ex/.git",
   852  			globExps:   []string{"/home/redhat/nodejs-ex/.git", "/home/redhat/nodejs-ex/tests/"},
   853  			want:       true,
   854  			wantErr:    false,
   855  		},
   856  		{
   857  			testName:   "Test glob does not match",
   858  			strToMatch: "/home/redhat/nodejs-ex/gimmt.gimmt",
   859  			globExps:   []string{"/home/redhat/nodejs-ex/.git/", "/home/redhat/nodejs-ex/tests/"},
   860  			want:       false,
   861  			wantErr:    false,
   862  		},
   863  		{
   864  			testName:   "Test glob match files",
   865  			strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
   866  			globExps:   []string{"/home/redhat/nodejs-ex/*.json", "/home/redhat/nodejs-ex/tests/"},
   867  			want:       true,
   868  			wantErr:    false,
   869  		},
   870  		{
   871  			testName:   "Test '**' glob matches",
   872  			strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
   873  			globExps:   []string{"/home/redhat/nodejs-ex/openshift/**/*.json"},
   874  			want:       true,
   875  			wantErr:    false,
   876  		},
   877  		{
   878  			testName:   "Test '!' in glob matches",
   879  			strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
   880  			globExps:   []string{"/home/redhat/nodejs-ex/!*.json", "/home/redhat/nodejs-ex/tests/"},
   881  			want:       false,
   882  			wantErr:    false,
   883  		},
   884  		{
   885  			testName:   "Test [ in glob matches",
   886  			strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
   887  			globExps:   []string{"/home/redhat/nodejs-ex/["},
   888  			want:       false,
   889  			wantErr:    true,
   890  		},
   891  		{
   892  			testName:   "Test '#' comment glob matches",
   893  			strToMatch: "/home/redhat/nodejs-ex/openshift/templates/example.json",
   894  			globExps:   []string{"#/home/redhat/nodejs-ex/openshift/**/*.json"},
   895  			want:       false,
   896  			wantErr:    false,
   897  		},
   898  	}
   899  
   900  	for _, tt := range tests {
   901  		t.Run(tt.testName, func(t *testing.T) {
   902  			matched, err := dfutil.IsGlobExpMatch(tt.strToMatch, tt.globExps)
   903  
   904  			if !tt.wantErr == (err != nil) {
   905  				t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
   906  				return
   907  			}
   908  
   909  			if tt.want != matched {
   910  				t.Errorf("expected %v, got %v", tt.want, matched)
   911  			}
   912  		})
   913  	}
   914  }
   915  
   916  func TestRemoveRelativePathFromFiles(t *testing.T) {
   917  	type args struct {
   918  		path   string
   919  		input  []string
   920  		output []string
   921  	}
   922  	tests := []struct {
   923  		name    string
   924  		args    args
   925  		wantErr bool
   926  	}{
   927  		{
   928  			name: "Case 1 - Remove the relative path from a list of files",
   929  			args: args{
   930  				path:   "/foo/bar",
   931  				input:  []string{"/foo/bar/1", "/foo/bar/2", "/foo/bar/3/", "/foo/bar/4/5/foo/bar"},
   932  				output: []string{"1", "2", "3", "4/5/foo/bar"},
   933  			},
   934  			wantErr: false,
   935  		},
   936  		{
   937  			name: "Case 2 - Fail on purpose with an invalid path",
   938  			args: args{
   939  				path:   `..`,
   940  				input:  []string{"foo", "bar"},
   941  				output: []string{},
   942  			},
   943  			wantErr: true,
   944  		},
   945  	}
   946  	for _, tt := range tests {
   947  		t.Run(tt.name, func(t *testing.T) {
   948  
   949  			// Run function RemoveRelativePathFromFiles
   950  			output, err := dfutil.RemoveRelativePathFromFiles(tt.args.input, tt.args.path)
   951  			if runtime.GOOS == "windows" {
   952  				for index, element := range output {
   953  					output[index] = filepath.ToSlash(element)
   954  				}
   955  			}
   956  
   957  			// Check for error
   958  			if !tt.wantErr == (err != nil) {
   959  				t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
   960  				return
   961  			}
   962  
   963  			if diff := cmp.Diff(tt.args.output, output); diff != "" {
   964  				t.Errorf("dfutil.RemoveRelativePathFromFiles() output mismatch (-want +got):\n%s", diff)
   965  			}
   966  
   967  		})
   968  	}
   969  }
   970  
   971  func TestHTTPGetFreePort(t *testing.T) {
   972  	tests := []struct {
   973  		name    string
   974  		wantErr bool
   975  	}{
   976  		{
   977  			name:    "case 1: get a valid free port",
   978  			wantErr: false,
   979  		},
   980  	}
   981  	for _, tt := range tests {
   982  		t.Run(tt.name, func(t *testing.T) {
   983  			got, err := dfutil.HTTPGetFreePort()
   984  			if (err != nil) != tt.wantErr {
   985  				t.Errorf("HTTPGetFreePort() error = %v, wantErr %v", err, tt.wantErr)
   986  				return
   987  			}
   988  			addressLook := "localhost:" + strconv.Itoa(got)
   989  			listener, err := net.Listen("tcp", addressLook)
   990  			if err != nil {
   991  				t.Errorf("expected a free port, but listening failed cause: %v", err)
   992  			} else {
   993  				_ = listener.Close()
   994  			}
   995  		})
   996  	}
   997  }
   998  
   999  func TestGetRemoteFilesMarkedForDeletion(t *testing.T) {
  1000  	tests := []struct {
  1001  		name       string
  1002  		files      []string
  1003  		remotePath string
  1004  		want       []string
  1005  	}{
  1006  		{
  1007  			name:       "case 1: no files",
  1008  			files:      []string{},
  1009  			remotePath: "/projects",
  1010  			want:       nil,
  1011  		},
  1012  		{
  1013  			name:       "case 2: one file",
  1014  			files:      []string{"abc.txt"},
  1015  			remotePath: "/projects",
  1016  			want:       []string{"/projects/abc.txt"},
  1017  		},
  1018  		{
  1019  			name:       "case 3: multiple files",
  1020  			files:      []string{"abc.txt", "def.txt", "hello.txt"},
  1021  			remotePath: "/projects",
  1022  			want:       []string{"/projects/abc.txt", "/projects/def.txt", "/projects/hello.txt"},
  1023  		},
  1024  		{
  1025  			name:       "case 4: remote path multiple folders",
  1026  			files:      []string{"abc.txt", "def.txt", "hello.txt"},
  1027  			remotePath: "/test/folder",
  1028  			want:       []string{"/test/folder/abc.txt", "/test/folder/def.txt", "/test/folder/hello.txt"},
  1029  		},
  1030  	}
  1031  	for _, tt := range tests {
  1032  		t.Run(tt.name, func(t *testing.T) {
  1033  			remoteFiles := dfutil.GetRemoteFilesMarkedForDeletion(tt.files, tt.remotePath)
  1034  			if diff := cmp.Diff(tt.want, remoteFiles); diff != "" {
  1035  				t.Errorf("dfutil.GetRemoteFilesMarkedForDeletion() mismatch (-want +got):\n%s", diff)
  1036  			}
  1037  		})
  1038  	}
  1039  }
  1040  
  1041  func TestHTTPGetRequest(t *testing.T) {
  1042  	// Start a local HTTP server
  1043  	server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
  1044  		// Send response to be tested
  1045  		_, err := rw.Write([]byte("OK"))
  1046  		if err != nil {
  1047  			t.Error(err)
  1048  		}
  1049  	}))
  1050  	// Close the server when test finishes
  1051  	defer server.Close()
  1052  
  1053  	tests := []struct {
  1054  		name string
  1055  		url  string
  1056  		want []byte
  1057  	}{
  1058  		{
  1059  			name: "Case 1: Input url is valid",
  1060  			url:  server.URL,
  1061  			// Want(Expected) result is "OK"
  1062  			// According to Unicode table: O == 79, K == 75
  1063  			want: []byte{79, 75},
  1064  		},
  1065  		{
  1066  			name: "Case 2: Input url is invalid",
  1067  			url:  "invalid",
  1068  			want: nil,
  1069  		},
  1070  	}
  1071  
  1072  	for _, tt := range tests {
  1073  		t.Run(tt.name, func(t *testing.T) {
  1074  			request := dfutil.HTTPRequestParams{
  1075  				URL: tt.url,
  1076  			}
  1077  			got, err := dfutil.HTTPGetRequest(request, 0)
  1078  
  1079  			if diff := cmp.Diff(tt.want, got); diff != "" {
  1080  				t.Errorf("dfutil.HTTPGetRequest() mismatch (-want +got):\n%s", diff)
  1081  				t.Logf("Error message is: %v", err)
  1082  			}
  1083  		})
  1084  	}
  1085  }
  1086  
  1087  func TestFilterIgnores(t *testing.T) {
  1088  	tests := []struct {
  1089  		name             string
  1090  		changedFiles     []string
  1091  		deletedFiles     []string
  1092  		ignoredFiles     []string
  1093  		wantChangedFiles []string
  1094  		wantDeletedFiles []string
  1095  	}{
  1096  		{
  1097  			name:             "Case 1: No ignored files",
  1098  			changedFiles:     []string{"hello.txt", "test.abc"},
  1099  			deletedFiles:     []string{"one.txt", "two.txt"},
  1100  			ignoredFiles:     []string{},
  1101  			wantChangedFiles: []string{"hello.txt", "test.abc"},
  1102  			wantDeletedFiles: []string{"one.txt", "two.txt"},
  1103  		},
  1104  		{
  1105  			name:             "Case 2: One ignored file",
  1106  			changedFiles:     []string{"hello.txt", "test.abc"},
  1107  			deletedFiles:     []string{"one.txt", "two.txt"},
  1108  			ignoredFiles:     []string{"hello.txt"},
  1109  			wantChangedFiles: []string{"test.abc"},
  1110  			wantDeletedFiles: []string{"one.txt", "two.txt"},
  1111  		},
  1112  		{
  1113  			name:             "Case 3: Multiple ignored file",
  1114  			changedFiles:     []string{"hello.txt", "test.abc"},
  1115  			deletedFiles:     []string{"one.txt", "two.txt"},
  1116  			ignoredFiles:     []string{"hello.txt", "two.txt"},
  1117  			wantChangedFiles: []string{"test.abc"},
  1118  			wantDeletedFiles: []string{"one.txt"},
  1119  		},
  1120  		{
  1121  			name:             "Case 4: No changed or deleted files",
  1122  			changedFiles:     []string{""},
  1123  			deletedFiles:     []string{""},
  1124  			ignoredFiles:     []string{"hello.txt", "two.txt"},
  1125  			wantChangedFiles: []string{""},
  1126  			wantDeletedFiles: []string{""},
  1127  		},
  1128  	}
  1129  
  1130  	for _, tt := range tests {
  1131  		t.Run(tt.name, func(t *testing.T) {
  1132  			filterChanged, filterDeleted := dfutil.FilterIgnores(tt.changedFiles, tt.deletedFiles, tt.ignoredFiles)
  1133  
  1134  			if diff := cmp.Diff(tt.wantChangedFiles, filterChanged); diff != "" {
  1135  				t.Errorf("dfutil.FilterIgnores() wantChangedFiles mismatch (-want +got):\n%s", diff)
  1136  			}
  1137  
  1138  			if diff := cmp.Diff(tt.wantDeletedFiles, filterDeleted); diff != "" {
  1139  				t.Errorf("dfutil.FilterIgnores() wantDeletedFiles mismatch (-want +got):\n%s", diff)
  1140  			}
  1141  		})
  1142  	}
  1143  }
  1144  
  1145  func TestDownloadFile(t *testing.T) {
  1146  	// Start a local HTTP server
  1147  	server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
  1148  		// Send response to be tested
  1149  		_, err := rw.Write([]byte("OK"))
  1150  		if err != nil {
  1151  			t.Error(err)
  1152  		}
  1153  	}))
  1154  	// Close the server when test finishes
  1155  	defer server.Close()
  1156  
  1157  	tests := []struct {
  1158  		name     string
  1159  		url      string
  1160  		filepath string
  1161  		want     []byte
  1162  		wantErr  bool
  1163  	}{
  1164  		{
  1165  			name:     "Case 1: Input url is valid",
  1166  			url:      server.URL,
  1167  			filepath: "./test.yaml",
  1168  			// Want(Expected) result is "OK"
  1169  			// According to Unicode table: O == 79, K == 75
  1170  			want:    []byte{79, 75},
  1171  			wantErr: false,
  1172  		},
  1173  		{
  1174  			name:     "Case 2: Input url is invalid",
  1175  			url:      "invalid",
  1176  			filepath: "./test.yaml",
  1177  			want:     []byte{},
  1178  			wantErr:  true,
  1179  		},
  1180  		{
  1181  			name:     "Case 3: Input url is an empty string",
  1182  			url:      "",
  1183  			filepath: "./test.yaml",
  1184  			want:     []byte{},
  1185  			wantErr:  true,
  1186  		},
  1187  	}
  1188  
  1189  	for _, tt := range tests {
  1190  		t.Run(tt.name, func(t *testing.T) {
  1191  			gotErr := false
  1192  			params := dfutil.DownloadParams{
  1193  				Request: dfutil.HTTPRequestParams{
  1194  					URL: tt.url,
  1195  				},
  1196  				Filepath: tt.filepath,
  1197  			}
  1198  			err := dfutil.DownloadFile(params)
  1199  			if err != nil {
  1200  				gotErr = true
  1201  			}
  1202  			if gotErr != tt.wantErr {
  1203  				t.Errorf("Failed to get expected error: %v", err)
  1204  			}
  1205  
  1206  			if !tt.wantErr {
  1207  				if err != nil {
  1208  					t.Errorf("Failed to download file with error %s", err)
  1209  				}
  1210  
  1211  				got, err := os.ReadFile(tt.filepath)
  1212  				if err != nil {
  1213  					t.Errorf("Failed to read file with error %s", err)
  1214  				}
  1215  
  1216  				if diff := cmp.Diff(tt.want, got); diff != "" {
  1217  					t.Errorf("dfutil.DownloadFile() mismatch (-want +got):\n%s", diff)
  1218  				}
  1219  
  1220  				// Clean up the file that downloaded in this test case
  1221  				err = os.Remove(tt.filepath)
  1222  				if err != nil {
  1223  					t.Errorf("Failed to delete file with error %s", err)
  1224  				}
  1225  			}
  1226  		})
  1227  	}
  1228  }
  1229  
  1230  func TestValidateK8sResourceName(t *testing.T) {
  1231  	tests := []struct {
  1232  		name  string
  1233  		key   string
  1234  		value string
  1235  		want  bool
  1236  	}{
  1237  		{
  1238  			name:  "Case 1: Resource name is valid",
  1239  			key:   "component name",
  1240  			value: "good-name",
  1241  			want:  true,
  1242  		},
  1243  		{
  1244  			name:  "Case 2: Resource name contains unsupported character",
  1245  			key:   "component name",
  1246  			value: "BAD@name",
  1247  			want:  false,
  1248  		},
  1249  		{
  1250  			name:  "Case 3: Resource name contains all numeric values",
  1251  			key:   "component name",
  1252  			value: "12345",
  1253  			want:  false,
  1254  		},
  1255  	}
  1256  
  1257  	for _, tt := range tests {
  1258  		t.Run(tt.name, func(t *testing.T) {
  1259  			err := dfutil.ValidateK8sResourceName(tt.key, tt.value)
  1260  			got := err == nil
  1261  			if diff := cmp.Diff(tt.want, got); diff != "" {
  1262  				t.Errorf("dfutil.ValidateK8sResourceName() mismatch (-want +got):\n%s", diff)
  1263  			}
  1264  		})
  1265  	}
  1266  }
  1267  
  1268  func TestUnzip(t *testing.T) {
  1269  	tests := []struct {
  1270  		name          string
  1271  		src           string
  1272  		pathToUnzip   string
  1273  		expectedFiles []string
  1274  		expectedError string
  1275  	}{
  1276  		{
  1277  			name:          "Case 1: Invalid source zip",
  1278  			src:           "../../tests/examples/source/devfiles/nodejs-zip/invalid.zip",
  1279  			pathToUnzip:   "",
  1280  			expectedFiles: []string{},
  1281  			expectedError: "open ../../tests/examples/source/devfiles/nodejs-zip/invalid.zip:",
  1282  		},
  1283  		{
  1284  			name:          "Case 2: Valid source zip, no pathToUnzip",
  1285  			src:           "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
  1286  			pathToUnzip:   "",
  1287  			expectedFiles: []string{"package.json", "package-lock.json", "app", "app/app.js", DotGitIgnoreFile, "LICENSE", "README.md"},
  1288  			expectedError: "",
  1289  		},
  1290  		{
  1291  			name:          "Case 3: Valid source zip with pathToUnzip",
  1292  			src:           "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
  1293  			pathToUnzip:   "app",
  1294  			expectedFiles: []string{"app.js"},
  1295  			expectedError: "",
  1296  		},
  1297  		{
  1298  			name:          "Case 4: Valid source zip with pathToUnzip - trailing /",
  1299  			src:           "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
  1300  			pathToUnzip:   "app/",
  1301  			expectedFiles: []string{"app.js"},
  1302  			expectedError: "",
  1303  		},
  1304  		{
  1305  			name:          "Case 5: Valid source zip with pathToUnzip - leading /",
  1306  			src:           "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
  1307  			pathToUnzip:   "app/",
  1308  			expectedFiles: []string{"app.js"},
  1309  			expectedError: "",
  1310  		},
  1311  		{
  1312  			name:          "Case 6: Valid source zip with pathToUnzip - leading and trailing /",
  1313  			src:           "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
  1314  			pathToUnzip:   "/app/",
  1315  			expectedFiles: []string{"app.js"},
  1316  			expectedError: "",
  1317  		},
  1318  		{
  1319  			name:          "Case 7: Valid source zip with pathToUnzip - pattern",
  1320  			src:           "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
  1321  			pathToUnzip:   "p*",
  1322  			expectedFiles: []string{"package.json", "package-lock.json"},
  1323  			expectedError: "",
  1324  		},
  1325  		{
  1326  			name:          "Case 8: Valid source zip with pathToUnzip - pattern and extension",
  1327  			src:           "../../tests/examples/source/devfiles/nodejs-zip/master.zip",
  1328  			pathToUnzip:   "*.json",
  1329  			expectedFiles: []string{"package.json", "package-lock.json"},
  1330  			expectedError: "",
  1331  		},
  1332  	}
  1333  
  1334  	for _, tt := range tests {
  1335  		t.Run(tt.name, func(t *testing.T) {
  1336  			dir := t.TempDir()
  1337  			t.Logf(dir)
  1338  
  1339  			_, err := Unzip(filepath.FromSlash(tt.src), dir, tt.pathToUnzip, filesystem.DefaultFs{})
  1340  			if err != nil {
  1341  				tt.expectedError = strings.ReplaceAll(tt.expectedError, "/", string(filepath.Separator))
  1342  				if !strings.HasPrefix(err.Error(), tt.expectedError) {
  1343  					t.Errorf("Got err: '%s'\n expected err: '%s'", err.Error(), tt.expectedError)
  1344  				}
  1345  			} else {
  1346  				for _, file := range tt.expectedFiles {
  1347  					if _, err := os.Stat(filepath.Join(dir, file)); os.IsNotExist(err) {
  1348  						t.Errorf("Expected file %s does not exist in directory after unzipping", file)
  1349  					}
  1350  				}
  1351  			}
  1352  		})
  1353  	}
  1354  }
  1355  
  1356  func TestIsValidProjectDir(t *testing.T) {
  1357  	tests := []struct {
  1358  		name          string
  1359  		devfilePath   string
  1360  		filesToCreate []string
  1361  		dirToCreate   []string
  1362  		expectedError string
  1363  	}{
  1364  		{
  1365  			name:          "Case 1: Empty Folder",
  1366  			devfilePath:   "",
  1367  			filesToCreate: []string{},
  1368  			dirToCreate:   []string{},
  1369  			expectedError: "",
  1370  		},
  1371  		{
  1372  			name:          "Case 2: Folder contains devfile.yaml",
  1373  			devfilePath:   "devfile.yaml",
  1374  			filesToCreate: []string{"devfile.yaml"},
  1375  			dirToCreate:   []string{},
  1376  			expectedError: "",
  1377  		},
  1378  		{
  1379  			name:          "Case 3: Folder contains a file which is not the devfile",
  1380  			devfilePath:   "devfile.yaml",
  1381  			filesToCreate: []string{"file1.yaml"},
  1382  			dirToCreate:   []string{},
  1383  			expectedError: "folder %s doesn't contain the devfile used",
  1384  		},
  1385  		{
  1386  			name:          "Case 4: Folder contains a hidden file which is not the devfile",
  1387  			devfilePath:   "devfile.yaml",
  1388  			filesToCreate: []string{".file1.yaml"},
  1389  			dirToCreate:   []string{},
  1390  			expectedError: "folder %s doesn't contain the devfile used",
  1391  		},
  1392  		{
  1393  			name:          "Case 5: Folder contains devfile.yaml and more files",
  1394  			devfilePath:   "devfile.yaml",
  1395  			filesToCreate: []string{"devfile.yaml", "file1.yaml", "file2.yaml"},
  1396  			dirToCreate:   []string{},
  1397  			expectedError: "folder %s is not empty. It can only contain the devfile used",
  1398  		},
  1399  	}
  1400  
  1401  	for _, tt := range tests {
  1402  		t.Run(tt.name, func(t *testing.T) {
  1403  			tmpDir := t.TempDir()
  1404  
  1405  			for _, f := range tt.filesToCreate {
  1406  				file := filepath.Join(tmpDir, f)
  1407  				if _, e := os.Create(file); e != nil {
  1408  					t.Errorf("Error creating file %s. Err: %s", file, e)
  1409  				}
  1410  			}
  1411  
  1412  			for _, d := range tt.dirToCreate {
  1413  				dir := filepath.Join(tmpDir, d)
  1414  				if e := os.Mkdir(dir, os.FileMode(0644)); e != nil {
  1415  					t.Errorf("Error creating dir %s. Err: %s", dir, e)
  1416  				}
  1417  			}
  1418  
  1419  			err := IsValidProjectDir(tmpDir, tt.devfilePath, filesystem.DefaultFs{})
  1420  			expectedError := tt.expectedError
  1421  			if expectedError != "" {
  1422  				expectedError = fmt.Sprintf(expectedError, tmpDir)
  1423  			}
  1424  
  1425  			if err != nil {
  1426  				if diff := cmp.Diff(expectedError, err.Error()); diff != "" {
  1427  					t.Errorf("IsValidProjectDir() mismatch (-want +got):\n%s", diff)
  1428  				}
  1429  			}
  1430  		})
  1431  	}
  1432  }
  1433  
  1434  func TestDownloadFileInMemory(t *testing.T) {
  1435  	// Start a local HTTP server
  1436  	server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
  1437  		// Send response to be tested
  1438  		_, err := rw.Write([]byte("OK"))
  1439  		if err != nil {
  1440  			t.Error(err)
  1441  		}
  1442  	}))
  1443  	// Close the server when test finishes
  1444  	defer server.Close()
  1445  
  1446  	tests := []struct {
  1447  		name string
  1448  		url  string
  1449  		want []byte
  1450  	}{
  1451  		{
  1452  			name: "Case 1: Input url is valid",
  1453  			url:  server.URL,
  1454  			want: []byte{79, 75},
  1455  		},
  1456  		{
  1457  			name: "Case 2: Input url is invalid",
  1458  			url:  "invalid",
  1459  			want: []byte(nil),
  1460  		},
  1461  	}
  1462  
  1463  	for _, tt := range tests {
  1464  		t.Run(tt.name, func(t *testing.T) {
  1465  			data, err := DownloadFileInMemory(dfutil.HTTPRequestParams{URL: tt.url})
  1466  			if tt.url != "invalid" && err != nil {
  1467  				t.Errorf("Failed to download file with error %s", err)
  1468  			}
  1469  
  1470  			if diff := cmp.Diff(tt.want, data); diff != "" {
  1471  				t.Errorf("DownloadFileInMemory() mismatch (-want +got):\n%s", diff)
  1472  			}
  1473  		})
  1474  	}
  1475  }
  1476  
  1477  /*
  1478  func TestGetGitHubZipURL(t *testing.T) {
  1479  	startPoint := "1.0.0"
  1480  	branch := "my-branch"
  1481  	tests := []struct {
  1482  		name          string
  1483  		location      string
  1484  		branch        string
  1485  		startPoint    string
  1486  		expectedError string
  1487  	}{
  1488  		{
  1489  			name:          "Case 1: Invalid http request",
  1490  			location:      "http://github.com/che-samples/web-nodejs-sample/archive/master",
  1491  			expectedError: "Invalid GitHub URL. Please use https://",
  1492  		},
  1493  		{
  1494  			name:          "Case 2: Invalid owner",
  1495  			location:      "https://github.com//web-nodejs-sample/archive/master",
  1496  			expectedError: "Invalid GitHub URL: owner cannot be empty. Expecting 'https://github.com/<owner>/<repo>'",
  1497  		},
  1498  		{
  1499  			name:          "Case 3: Invalid repo",
  1500  			location:      "https://github.com/che-samples//archive/master",
  1501  			expectedError: "Invalid GitHub URL: repo cannot be empty. Expecting 'https://github.com/<owner>/<repo>'",
  1502  		},
  1503  		{
  1504  			name:          "Case 4: Invalid HTTPS Github URL with tag and commit",
  1505  			location:      "https://github.com/che-samples/web-nodejs-sample.git",
  1506  			branch:        branch,
  1507  			startPoint:    startPoint,
  1508  			expectedError: fmt.Sprintf("Branch %s and StartPoint %s specified as project reference, please only specify one", branch, startPoint),
  1509  		},
  1510  	}
  1511  
  1512  	for _, tt := range tests {
  1513  		t.Run(tt.name, func(t *testing.T) {
  1514  			_, err := GetGitHubZipURL(tt.location, tt.branch, tt.startPoint)
  1515  			if err != nil {
  1516  				if !strings.Contains(err.Error(), tt.expectedError) {
  1517  					t.Errorf("Got %s,\n want %s", err.Error(), tt.expectedError)
  1518  				}
  1519  			}
  1520  		})
  1521  	}
  1522  }
  1523  */
  1524  
  1525  func TestValidateURL(t *testing.T) {
  1526  	tests := []struct {
  1527  		name    string
  1528  		url     string
  1529  		wantErr bool
  1530  	}{
  1531  		{
  1532  			name:    "Case 1: Valid URL",
  1533  			url:     "http://www.example.com/",
  1534  			wantErr: false,
  1535  		},
  1536  		{
  1537  			name:    "Valid URL, with port",
  1538  			url:     "http://192.168.1.10:30741/",
  1539  			wantErr: false,
  1540  		},
  1541  		{
  1542  			name:    "Valid URL, with port, login and password",
  1543  			url:     "http://user:pass@192.168.1.10:30741/",
  1544  			wantErr: false,
  1545  		},
  1546  		{
  1547  			name:    "Case 2: Invalid URL - No host",
  1548  			url:     "http://",
  1549  			wantErr: true,
  1550  		},
  1551  		{
  1552  			name:    "Case 3: Invalid URL - No scheme",
  1553  			url:     "://www.example.com/",
  1554  			wantErr: true,
  1555  		},
  1556  		{
  1557  			name:    "Case 4: Invalid URL - Host contains reserved character",
  1558  			url:     "http://??##",
  1559  			wantErr: true,
  1560  		},
  1561  		{
  1562  			name:    "Case 5: Invalid URL - Scheme contains reserved character",
  1563  			url:     "$$$,,://www.example.com",
  1564  			wantErr: true,
  1565  		},
  1566  	}
  1567  
  1568  	for _, tt := range tests {
  1569  		t.Run(tt.name, func(t *testing.T) {
  1570  			gotErr := false
  1571  			got := ValidateURL(tt.url)
  1572  			if got != nil {
  1573  				gotErr = true
  1574  			}
  1575  
  1576  			if gotErr != tt.wantErr {
  1577  				t.Errorf("Got %v, want %v", got, tt.wantErr)
  1578  			}
  1579  		})
  1580  	}
  1581  }
  1582  
  1583  func TestValidateFile(t *testing.T) {
  1584  	// Create temp dir and temp file
  1585  	tempDir := t.TempDir()
  1586  	tempFile, err := os.CreateTemp(tempDir, "")
  1587  	if err != nil {
  1588  		t.Errorf("Failed to create temp file: %s, error: %v", tempFile.Name(), err)
  1589  	}
  1590  	defer tempFile.Close()
  1591  
  1592  	tests := []struct {
  1593  		name     string
  1594  		filePath string
  1595  		wantErr  bool
  1596  	}{
  1597  		{
  1598  			name:     "Case 1: Valid file path",
  1599  			filePath: tempFile.Name(),
  1600  			wantErr:  false,
  1601  		},
  1602  		{
  1603  			name:     "Case 2: Invalid file path",
  1604  			filePath: "!@#",
  1605  			wantErr:  true,
  1606  		},
  1607  	}
  1608  
  1609  	for _, tt := range tests {
  1610  		t.Run(tt.name, func(t *testing.T) {
  1611  			gotErr := false
  1612  			err := dfutil.ValidateFile(tt.filePath)
  1613  			if err != nil {
  1614  				gotErr = true
  1615  			}
  1616  			if gotErr != tt.wantErr {
  1617  				t.Errorf("Got error: %v, want error: %t", err, tt.wantErr)
  1618  			}
  1619  		})
  1620  	}
  1621  }
  1622  
  1623  func TestCopyFile(t *testing.T) {
  1624  	// Create temp dir
  1625  	tempDir := t.TempDir()
  1626  
  1627  	// Create temp file under temp dir as source file
  1628  	tempFile, err := os.CreateTemp(tempDir, "")
  1629  	if err != nil {
  1630  		t.Errorf("Failed to create temp file: %s, error: %v", tempFile.Name(), err)
  1631  	}
  1632  	defer tempFile.Close()
  1633  
  1634  	srcPath := tempFile.Name()
  1635  	fakePath := "!@#/**"
  1636  	dstPath := filepath.Join(tempDir, "dstFile")
  1637  	info, _ := os.Stat(srcPath)
  1638  
  1639  	tests := []struct {
  1640  		name    string
  1641  		srcPath string
  1642  		dstPath string
  1643  		wantErr bool
  1644  	}{
  1645  		{
  1646  			name:    "Case 1: Copy successfully",
  1647  			srcPath: srcPath,
  1648  			dstPath: dstPath,
  1649  			wantErr: false,
  1650  		},
  1651  		{
  1652  			name:    "Case 2: Invalid source path",
  1653  			srcPath: fakePath,
  1654  			dstPath: dstPath,
  1655  			wantErr: true,
  1656  		},
  1657  		{
  1658  			name:    "Case 3: Invalid destination path",
  1659  			srcPath: srcPath,
  1660  			dstPath: fakePath,
  1661  			wantErr: true,
  1662  		},
  1663  	}
  1664  
  1665  	for _, tt := range tests {
  1666  		t.Run(tt.name, func(t *testing.T) {
  1667  			gotErr := false
  1668  			err = dfutil.CopyFile(tt.srcPath, tt.dstPath, info)
  1669  			if err != nil {
  1670  				gotErr = true
  1671  			}
  1672  
  1673  			if gotErr != tt.wantErr {
  1674  				t.Errorf("Got error: %v, want error: %t", err, tt.wantErr)
  1675  			}
  1676  		})
  1677  	}
  1678  }
  1679  
  1680  func TestPathEqual(t *testing.T) {
  1681  	currentDir, err := os.Getwd()
  1682  	if err != nil {
  1683  		t.Errorf("Can't get absolute path of current working directory with error: %v", err)
  1684  	}
  1685  	fileAbsPath := filepath.Join(currentDir, "file")
  1686  	fileRelPath := filepath.Join(".", "file")
  1687  
  1688  	tests := []struct {
  1689  		name       string
  1690  		firstPath  string
  1691  		secondPath string
  1692  		want       bool
  1693  	}{
  1694  		{
  1695  			name:       "Case 1: Two paths (two absolute paths) are equal",
  1696  			firstPath:  fileAbsPath,
  1697  			secondPath: fileAbsPath,
  1698  			want:       true,
  1699  		},
  1700  		{
  1701  			name:       "Case 2: Two paths (one absolute path, one relative path) are equal",
  1702  			firstPath:  fileAbsPath,
  1703  			secondPath: fileRelPath,
  1704  			want:       true,
  1705  		},
  1706  		{
  1707  			name:       "Case 3: Two paths are not equal",
  1708  			firstPath:  fileAbsPath,
  1709  			secondPath: filepath.Join(fileAbsPath, "file"),
  1710  			want:       false,
  1711  		},
  1712  	}
  1713  
  1714  	for _, tt := range tests {
  1715  		t.Run(tt.name, func(t *testing.T) {
  1716  			got := dfutil.PathEqual(tt.firstPath, tt.secondPath)
  1717  			if diff := cmp.Diff(tt.want, got); diff != "" {
  1718  				t.Errorf("dfutil.PathEqual() mismatch (-want +got):\n%s", diff)
  1719  			}
  1720  		})
  1721  	}
  1722  }
  1723  
  1724  func TestSliceContainsString(t *testing.T) {
  1725  	tests := []struct {
  1726  		name      string
  1727  		stringVal string
  1728  		slice     []string
  1729  		wantVal   bool
  1730  	}{
  1731  		{
  1732  			name:      "Case 1: string in valid slice",
  1733  			stringVal: "string",
  1734  			slice:     []string{"string", "string2"},
  1735  			wantVal:   true,
  1736  		},
  1737  		{
  1738  			name:      "Case 2: string not in valid slice",
  1739  			stringVal: "string3",
  1740  			slice:     []string{"string", "string2"},
  1741  			wantVal:   false,
  1742  		},
  1743  		{
  1744  			name:      "Case 3: string not in empty slice",
  1745  			stringVal: "string",
  1746  			slice:     []string{},
  1747  			wantVal:   false,
  1748  		},
  1749  	}
  1750  
  1751  	for _, tt := range tests {
  1752  		t.Run(tt.name, func(t *testing.T) {
  1753  			gotVal := sliceContainsString(tt.stringVal, tt.slice)
  1754  
  1755  			if diff := cmp.Diff(tt.wantVal, gotVal); diff != "" {
  1756  				t.Errorf("sliceContainsString() mismatch (-want +got):\n%s", diff)
  1757  			}
  1758  		})
  1759  	}
  1760  }
  1761  
  1762  // FileType custom type to indicate type of file
  1763  type FileType int
  1764  
  1765  const (
  1766  	// RegularFile enum to represent regular file
  1767  	RegularFile FileType = 0
  1768  	// Directory enum to represent directory
  1769  	Directory FileType = 1
  1770  )
  1771  
  1772  // FileProperties to contain meta-data of a file like, file/folder name, file/folder parent dir, file type and desired file modification type
  1773  type FileProperties struct {
  1774  	FilePath string
  1775  	FileType FileType
  1776  }
  1777  
  1778  func folderCheck(originalFolderMode os.FileMode, newFolderInfo os.FileInfo, path string) error {
  1779  	if originalFolderMode.String() != newFolderInfo.Mode().String() {
  1780  		return fmt.Errorf("folder %s created with wrong permission", path)
  1781  	}
  1782  	return nil
  1783  }
  1784  
  1785  func fileCheck(fs filesystem.Filesystem, originalFile filesystem.File, newFilePath string, newFileInfo os.FileInfo) error {
  1786  	originalFileData, err := fs.ReadFile(originalFile.Name())
  1787  	if err != nil {
  1788  		return err
  1789  	}
  1790  
  1791  	createdFileData, err := fs.ReadFile(newFilePath)
  1792  	if err != nil {
  1793  		return err
  1794  	}
  1795  
  1796  	// check the written data
  1797  	if string(createdFileData) == string(originalFileData) {
  1798  		originalInfo, err := fs.Stat(originalFile.Name())
  1799  		if err != nil {
  1800  			return err
  1801  		}
  1802  
  1803  		// check the file permission
  1804  		if newFileInfo.Mode() != originalInfo.Mode() {
  1805  			return fmt.Errorf("file %s created with wrong permission", newFilePath)
  1806  		}
  1807  	} else {
  1808  		return fmt.Errorf("file %s created with wrong data", newFilePath)
  1809  	}
  1810  	return nil
  1811  }
  1812  
  1813  func setupFileTest(fs filesystem.Filesystem, sourceName string, filePaths []FileProperties) (map[string]filesystem.File, map[string]os.FileMode, error) {
  1814  
  1815  	fileMap := make(map[string]filesystem.File)
  1816  	folderMap := make(map[string]os.FileMode)
  1817  
  1818  	for i, path := range filePaths {
  1819  
  1820  		if path.FileType == RegularFile {
  1821  			file, err := fs.Create(path.FilePath)
  1822  			if err != nil {
  1823  				return nil, nil, err
  1824  			}
  1825  			_, err = file.Write([]byte("some text" + string(rune(i))))
  1826  			if err != nil {
  1827  				return nil, nil, err
  1828  			}
  1829  
  1830  			name, err := filepath.Rel(sourceName, file.Name())
  1831  			if err != nil {
  1832  				return nil, nil, err
  1833  			}
  1834  			fileMap[name] = file
  1835  		} else if path.FileType == Directory {
  1836  			permission := os.ModeDir + 0755
  1837  			err := fs.MkdirAll(path.FilePath, permission)
  1838  			if err != nil {
  1839  				return nil, nil, err
  1840  			}
  1841  
  1842  			name, err := filepath.Rel(sourceName, path.FilePath)
  1843  			if err != nil {
  1844  				return nil, nil, err
  1845  			}
  1846  			folderMap[name] = permission
  1847  		}
  1848  	}
  1849  
  1850  	return fileMap, folderMap, nil
  1851  }
  1852  
  1853  func TestCopyFileWithFS(t *testing.T) {
  1854  	fileName := "blah.js"
  1855  
  1856  	fs := filesystem.NewFakeFs()
  1857  
  1858  	sourceName := filepath.Join(os.TempDir(), "source")
  1859  	destinationDirName := filepath.Join(os.TempDir(), "destination")
  1860  
  1861  	filePaths := []FileProperties{
  1862  		{
  1863  			FilePath: sourceName,
  1864  			FileType: Directory,
  1865  		},
  1866  		{
  1867  			FilePath: filepath.Join(sourceName, fileName),
  1868  			FileType: RegularFile,
  1869  		},
  1870  		{
  1871  			FilePath: destinationDirName,
  1872  			FileType: Directory,
  1873  		},
  1874  	}
  1875  
  1876  	printError := func(err error) {
  1877  		t.Errorf("some error occured while procession file/folder: %v", err)
  1878  	}
  1879  
  1880  	type args struct {
  1881  		src string
  1882  		dst string
  1883  		fs  filesystem.Filesystem
  1884  	}
  1885  	tests := []struct {
  1886  		name    string
  1887  		args    args
  1888  		wantErr bool
  1889  	}{
  1890  		{
  1891  			name: "case 1: normal file exists",
  1892  			args: args{
  1893  				src: filepath.Join(sourceName, fileName),
  1894  				dst: filepath.Join(destinationDirName, fileName),
  1895  				fs:  fs,
  1896  			},
  1897  		},
  1898  		{
  1899  			name: "case 2: file doesn't exist",
  1900  			args: args{
  1901  				src: filepath.Join(sourceName, fileName) + "blah",
  1902  				dst: filepath.Join(destinationDirName, fileName),
  1903  				fs:  fs,
  1904  			},
  1905  			wantErr: true,
  1906  		},
  1907  	}
  1908  	for _, tt := range tests {
  1909  		t.Run(tt.name, func(t *testing.T) {
  1910  			fileMap, _, err := setupFileTest(fs, sourceName, filePaths)
  1911  			if err != nil {
  1912  				t.Errorf("error while setting up test: %v", err)
  1913  			}
  1914  
  1915  			err = copyFileWithFs(tt.args.src, tt.args.dst, tt.args.fs)
  1916  			if (err != nil) != tt.wantErr {
  1917  				t.Errorf("MoveFile() error = %v, wantErr %v", err, tt.wantErr)
  1918  			}
  1919  
  1920  			if tt.wantErr {
  1921  				return
  1922  			}
  1923  
  1924  			files, err := fs.ReadDir(destinationDirName)
  1925  			if err != nil {
  1926  				t.Errorf("error occured while reading directory %s: %v", destinationDirName, err)
  1927  			}
  1928  
  1929  			found := false
  1930  			for _, file := range files {
  1931  
  1932  				relPath, err := filepath.Rel(destinationDirName, filepath.Join(destinationDirName, fileName))
  1933  				if err != nil {
  1934  					printError(err)
  1935  					break
  1936  				}
  1937  
  1938  				if originalFile, ok := fileMap[relPath]; ok {
  1939  					err := fileCheck(fs, originalFile, filepath.Join(destinationDirName, file.Name()), file)
  1940  					if err != nil {
  1941  						break
  1942  					}
  1943  					found = true
  1944  				} else {
  1945  					t.Errorf("extra file %s created", file.Name())
  1946  				}
  1947  			}
  1948  
  1949  			if !found && !tt.wantErr {
  1950  				t.Errorf("%s not created in directory %s", fileName, destinationDirName)
  1951  			}
  1952  
  1953  			_ = fs.RemoveAll(tt.args.src)
  1954  			_ = fs.RemoveAll(tt.args.dst)
  1955  		})
  1956  	}
  1957  }
  1958  
  1959  func TestCopyDirWithFS(t *testing.T) {
  1960  
  1961  	fs := filesystem.NewFakeFs()
  1962  
  1963  	sourceName := filepath.Join(os.TempDir(), "source")
  1964  	destinationName := filepath.Join(os.TempDir(), "destination")
  1965  
  1966  	filePaths := []FileProperties{
  1967  		{
  1968  			FilePath: sourceName,
  1969  			FileType: Directory,
  1970  		},
  1971  		{
  1972  			FilePath: filepath.Join(sourceName, "main"),
  1973  			FileType: Directory,
  1974  		},
  1975  		{
  1976  			FilePath: filepath.Join(sourceName, "blah.js"),
  1977  			FileType: RegularFile,
  1978  		},
  1979  		{
  1980  			FilePath: filepath.Join(sourceName, "main", "some-other-blah.js"),
  1981  			FileType: RegularFile,
  1982  		},
  1983  	}
  1984  
  1985  	printError := func(err error) {
  1986  		t.Errorf("some error occured while procession file/folder: %v", err)
  1987  	}
  1988  
  1989  	type args struct {
  1990  		src string
  1991  		dst string
  1992  		fs  filesystem.Filesystem
  1993  	}
  1994  	tests := []struct {
  1995  		name    string
  1996  		args    args
  1997  		wantErr bool
  1998  	}{
  1999  		{
  2000  			name: "case 1: folder with a nested file and folder",
  2001  			args: args{
  2002  				src: sourceName,
  2003  				dst: destinationName,
  2004  				fs:  fs,
  2005  			},
  2006  		},
  2007  		{
  2008  			name: "case 2: source folder doesn't exist",
  2009  			args: args{
  2010  				src: sourceName + "/extra",
  2011  				dst: destinationName,
  2012  				fs:  fs,
  2013  			},
  2014  			wantErr: true,
  2015  		},
  2016  	}
  2017  	for _, tt := range tests {
  2018  		t.Run(tt.name, func(t *testing.T) {
  2019  			fileMap, folderMap, err := setupFileTest(fs, sourceName, filePaths)
  2020  			if err != nil {
  2021  				t.Errorf("error while setting up test: %v", err)
  2022  			}
  2023  
  2024  			err = CopyDirWithFS(tt.args.src, tt.args.dst, tt.args.fs)
  2025  			if (err != nil) != tt.wantErr {
  2026  				t.Errorf("MoveDir() error = %v, wantErr %v", err, tt.wantErr)
  2027  			}
  2028  
  2029  			if tt.wantErr && err != nil {
  2030  				return
  2031  			}
  2032  
  2033  			folderCount := 0
  2034  			fileCount := 0
  2035  
  2036  			err = fs.Walk(destinationName, func(path string, info os.FileInfo, err error) error {
  2037  				if err != nil {
  2038  					return err
  2039  				}
  2040  
  2041  				relPath, err := filepath.Rel(destinationName, path)
  2042  				if err != nil {
  2043  					printError(err)
  2044  					return err
  2045  				}
  2046  
  2047  				if info.IsDir() {
  2048  
  2049  					// check the permission on the folder
  2050  					if originalFolderMode, ok := folderMap[relPath]; ok {
  2051  						err := folderCheck(originalFolderMode, info, path)
  2052  						if err != nil {
  2053  							printError(err)
  2054  							return err
  2055  						}
  2056  						folderCount++
  2057  					} else {
  2058  						t.Errorf("extra folder %s created", path)
  2059  					}
  2060  				} else {
  2061  					if file, ok := fileMap[relPath]; ok {
  2062  						err := fileCheck(fs, file, path, info)
  2063  						if err != nil {
  2064  							printError(err)
  2065  							return err
  2066  						}
  2067  						fileCount++
  2068  					} else {
  2069  						t.Errorf("extra file %s created", path)
  2070  					}
  2071  				}
  2072  				return nil
  2073  			})
  2074  
  2075  			if err != nil {
  2076  				t.Errorf("unexpected error: %v", err)
  2077  			}
  2078  
  2079  			if folderCount != 2 {
  2080  				t.Errorf("some folder were not created")
  2081  			}
  2082  
  2083  			if fileCount != 2 {
  2084  				t.Errorf("some files were not created")
  2085  			}
  2086  
  2087  			_ = fs.RemoveAll(tt.args.src)
  2088  			_ = fs.RemoveAll(tt.args.dst)
  2089  		})
  2090  	}
  2091  }
  2092  
  2093  func TestCleanDir(t *testing.T) {
  2094  	fs := filesystem.NewFakeFs()
  2095  
  2096  	sourceName := filepath.Join(os.TempDir(), "source")
  2097  
  2098  	filePaths := []FileProperties{
  2099  		{
  2100  			FilePath: sourceName,
  2101  			FileType: Directory,
  2102  		},
  2103  		{
  2104  			FilePath: filepath.Join(sourceName, "main"),
  2105  			FileType: Directory,
  2106  		},
  2107  		{
  2108  			FilePath: filepath.Join(sourceName, "main", "src"),
  2109  			FileType: Directory,
  2110  		},
  2111  		{
  2112  			FilePath: filepath.Join(sourceName, "devfile.yaml"),
  2113  			FileType: RegularFile,
  2114  		},
  2115  		{
  2116  			FilePath: filepath.Join(sourceName, "preference.yaml"),
  2117  			FileType: RegularFile,
  2118  		},
  2119  		{
  2120  			FilePath: filepath.Join(sourceName, "blah.js"),
  2121  			FileType: RegularFile,
  2122  		},
  2123  		{
  2124  			FilePath: filepath.Join(sourceName, "main", "some-other-blah.js"),
  2125  			FileType: RegularFile,
  2126  		},
  2127  		{
  2128  			FilePath: filepath.Join(sourceName, "main", "src", "another-blah.js"),
  2129  			FileType: RegularFile,
  2130  		},
  2131  	}
  2132  
  2133  	type args struct {
  2134  		originalPath     string
  2135  		leaveBehindFiles map[string]bool
  2136  		fs               filesystem.Filesystem
  2137  	}
  2138  	tests := []struct {
  2139  		name    string
  2140  		args    args
  2141  		wantErr bool
  2142  	}{
  2143  		{
  2144  			name: "case 1: leave behind two files",
  2145  			args: args{
  2146  				originalPath: sourceName,
  2147  				fs:           fs,
  2148  				leaveBehindFiles: map[string]bool{
  2149  					"devfile.yaml":    true,
  2150  					"preference.yaml": true,
  2151  				},
  2152  			},
  2153  		},
  2154  		{
  2155  			name: "case 2: source doesn't exist",
  2156  			args: args{
  2157  				originalPath: sourceName + "blah",
  2158  				fs:           fs,
  2159  				leaveBehindFiles: map[string]bool{
  2160  					"devfile.yaml":    true,
  2161  					"preference.yaml": true,
  2162  				},
  2163  			},
  2164  			wantErr: true,
  2165  		},
  2166  	}
  2167  	for _, tt := range tests {
  2168  		t.Run(tt.name, func(t *testing.T) {
  2169  			_, _, err := setupFileTest(fs, sourceName, filePaths)
  2170  			if err != nil {
  2171  				t.Errorf("error while setting up test: %v", err)
  2172  			}
  2173  
  2174  			err = cleanDir(tt.args.originalPath, tt.args.leaveBehindFiles, tt.args.fs)
  2175  			if (err != nil) != tt.wantErr {
  2176  				t.Errorf("CleanDir() error = %v, wantErr %v", err, tt.wantErr)
  2177  			}
  2178  
  2179  			if err != nil && tt.wantErr {
  2180  				return
  2181  			}
  2182  
  2183  			files, err := fs.ReadDir(sourceName)
  2184  			if err != nil {
  2185  				t.Errorf("error occured while reading directory %s: %v", sourceName, err)
  2186  			}
  2187  
  2188  			found := 0
  2189  			for _, file := range files {
  2190  				if _, ok := tt.args.leaveBehindFiles[file.Name()]; !ok {
  2191  					t.Errorf("file %s isn't cleaned up", file.Name())
  2192  				} else {
  2193  					found++
  2194  				}
  2195  			}
  2196  
  2197  			if found != 2 {
  2198  				t.Errorf("some extra file were deleted")
  2199  			}
  2200  
  2201  			_ = fs.RemoveAll(tt.args.originalPath)
  2202  		})
  2203  	}
  2204  }
  2205  
  2206  func TestGitSubDir(t *testing.T) {
  2207  
  2208  	fs := filesystem.NewFakeFs()
  2209  
  2210  	sourceName := filepath.Join(os.TempDir(), "source")
  2211  	destinationName := filepath.Join(os.TempDir(), "destination")
  2212  
  2213  	filePaths := []FileProperties{
  2214  		{
  2215  			FilePath: sourceName,
  2216  			FileType: Directory,
  2217  		},
  2218  		{
  2219  			FilePath: filepath.Join(sourceName, "main"),
  2220  			FileType: Directory,
  2221  		},
  2222  		{
  2223  			FilePath: filepath.Join(sourceName, "blah.js"),
  2224  			FileType: RegularFile,
  2225  		},
  2226  		{
  2227  			FilePath: filepath.Join(sourceName, "main", "some-other-blah.js"),
  2228  			FileType: RegularFile,
  2229  		},
  2230  		{
  2231  			FilePath: filepath.Join(sourceName, "main", "test"),
  2232  			FileType: Directory,
  2233  		},
  2234  		{
  2235  			FilePath: filepath.Join(sourceName, "main", "test", "test.java"),
  2236  			FileType: RegularFile,
  2237  		},
  2238  		{
  2239  			FilePath: filepath.Join(sourceName, "main", "src", "java"),
  2240  			FileType: Directory,
  2241  		},
  2242  		{
  2243  			FilePath: filepath.Join(sourceName, "main", "src", "java", "main.java"),
  2244  			FileType: RegularFile,
  2245  		},
  2246  		{
  2247  			FilePath: filepath.Join(sourceName, "main", "src", "resources"),
  2248  			FileType: Directory,
  2249  		},
  2250  		{
  2251  			FilePath: filepath.Join(sourceName, "main", "src", "resources", "layout"),
  2252  			FileType: Directory,
  2253  		},
  2254  		{
  2255  			FilePath: filepath.Join(sourceName, "main", "src", "resources", "index.html"),
  2256  			FileType: RegularFile,
  2257  		},
  2258  	}
  2259  
  2260  	type args struct {
  2261  		destinationPath string
  2262  		srcPath         string
  2263  		subDir          string
  2264  		fs              filesystem.Filesystem
  2265  	}
  2266  	tests := []struct {
  2267  		name    string
  2268  		args    args
  2269  		wantErr bool
  2270  	}{
  2271  		{
  2272  			name: "case 1: normal sub dir exist",
  2273  			args: args{
  2274  				srcPath:         sourceName,
  2275  				destinationPath: destinationName,
  2276  				subDir:          filepath.Join("main", "src"),
  2277  				fs:              fs,
  2278  			},
  2279  		},
  2280  		{
  2281  			name: "case 2: sub dir doesn't exist",
  2282  			args: args{
  2283  				srcPath:         sourceName,
  2284  				destinationPath: destinationName,
  2285  				subDir:          filepath.Join("main", "blah"),
  2286  				fs:              fs,
  2287  			},
  2288  			wantErr: true,
  2289  		},
  2290  		{
  2291  			name: "case 3: src doesn't exist",
  2292  			args: args{
  2293  				srcPath:         sourceName + "blah",
  2294  				destinationPath: destinationName,
  2295  				subDir:          filepath.Join("main", "src"),
  2296  				fs:              fs,
  2297  			},
  2298  			wantErr: true,
  2299  		},
  2300  	}
  2301  	for _, tt := range tests {
  2302  		t.Run(tt.name, func(t *testing.T) {
  2303  			_, _, err := setupFileTest(fs, sourceName, filePaths)
  2304  			if err != nil {
  2305  				t.Errorf("error while setting up test: %v", err)
  2306  			}
  2307  
  2308  			err = gitSubDir(tt.args.srcPath, tt.args.destinationPath, tt.args.subDir, tt.args.fs)
  2309  			if (err != nil) != tt.wantErr {
  2310  				t.Errorf("GitSubDir() error = %v, wantErr %v", err, tt.wantErr)
  2311  			}
  2312  
  2313  			if tt.wantErr && err != nil {
  2314  				return
  2315  			}
  2316  
  2317  			pathsToValidate := map[string]bool{
  2318  				filepath.Join(tt.args.destinationPath, "java"):                    true,
  2319  				filepath.Join(tt.args.destinationPath, "java", "main.java"):       true,
  2320  				filepath.Join(tt.args.destinationPath, "resources"):               true,
  2321  				filepath.Join(tt.args.destinationPath, "resources", "layout"):     true,
  2322  				filepath.Join(tt.args.destinationPath, "resources", "index.html"): true,
  2323  			}
  2324  
  2325  			pathsNotToBePresent := map[string]bool{
  2326  				filepath.Join(tt.args.destinationPath, "src"):  true,
  2327  				filepath.Join(tt.args.destinationPath, "main"): true,
  2328  			}
  2329  
  2330  			found := 0
  2331  			notToBeFound := 0
  2332  			err = fs.Walk(tt.args.destinationPath, func(path string, info os.FileInfo, err error) error {
  2333  				if err != nil {
  2334  					return err
  2335  				}
  2336  
  2337  				if ok := pathsToValidate[path]; ok {
  2338  					found++
  2339  				}
  2340  
  2341  				if ok := pathsNotToBePresent[path]; ok {
  2342  					notToBeFound++
  2343  				}
  2344  				return nil
  2345  			})
  2346  			if err != nil {
  2347  				t.Errorf("unexpected error: %v", err)
  2348  			}
  2349  
  2350  			if found != 5 {
  2351  				t.Errorf("all files were not copied")
  2352  			}
  2353  
  2354  			if notToBeFound != 0 {
  2355  				t.Errorf("extra files were created")
  2356  			}
  2357  
  2358  			_, err = os.Stat(tt.args.srcPath)
  2359  			if !os.IsNotExist(err) {
  2360  				t.Errorf("src path was not deleted")
  2361  			}
  2362  
  2363  			_ = fs.RemoveAll(tt.args.srcPath)
  2364  			_ = fs.RemoveAll(tt.args.destinationPath)
  2365  		})
  2366  	}
  2367  }
  2368  
  2369  func TestGetCommandStringFromEnvs(t *testing.T) {
  2370  	type args struct {
  2371  		envVars []v1alpha2.EnvVar
  2372  	}
  2373  	tests := []struct {
  2374  		name string
  2375  		args args
  2376  		want string
  2377  	}{
  2378  		{
  2379  			name: "case 1: three envs given",
  2380  			args: args{
  2381  				envVars: []v1alpha2.EnvVar{
  2382  					{
  2383  						Name:  "foo",
  2384  						Value: "bar",
  2385  					},
  2386  					{
  2387  						Name:  "JAVA_HOME",
  2388  						Value: "/home/user/java",
  2389  					},
  2390  					{
  2391  						Name:  "GOPATH",
  2392  						Value: "/home/user/go",
  2393  					},
  2394  				},
  2395  			},
  2396  			want: "export foo=\"bar\" JAVA_HOME=\"/home/user/java\" GOPATH=\"/home/user/go\"",
  2397  		},
  2398  		{
  2399  			name: "case 2: no envs given",
  2400  			args: args{
  2401  				envVars: []v1alpha2.EnvVar{},
  2402  			},
  2403  			want: "",
  2404  		},
  2405  	}
  2406  	for _, tt := range tests {
  2407  		t.Run(tt.name, func(t *testing.T) {
  2408  			if got := GetCommandStringFromEnvs(tt.args.envVars); got != tt.want {
  2409  				t.Errorf("GetCommandStringFromEnvs() = %v, want %v", got, tt.want)
  2410  			}
  2411  		})
  2412  	}
  2413  }
  2414  
  2415  func TestGetGitOriginPath(t *testing.T) {
  2416  	tempGitDirWithOrigin := t.TempDir()
  2417  
  2418  	repoWithOrigin, err := git.PlainInit(tempGitDirWithOrigin, true)
  2419  	if err != nil {
  2420  		t.Errorf("unexpected error %v", err)
  2421  	}
  2422  
  2423  	_, err = repoWithOrigin.CreateRemote(&config.RemoteConfig{
  2424  		Name: "origin",
  2425  		URLs: []string{"git@github.com:redhat-developer/odo.git"},
  2426  	})
  2427  	if err != nil {
  2428  		t.Errorf("unexpected error %v", err)
  2429  	}
  2430  
  2431  	tempGitDirWithoutOrigin := t.TempDir()
  2432  
  2433  	repoWithoutOrigin, err := git.PlainInit(tempGitDirWithoutOrigin, true)
  2434  	if err != nil {
  2435  		t.Errorf("unexpected error %v", err)
  2436  	}
  2437  
  2438  	_, err = repoWithoutOrigin.CreateRemote(&config.RemoteConfig{
  2439  		Name: "upstream",
  2440  		URLs: []string{"git@github.com:redhat-developer/odo.git"},
  2441  	})
  2442  	if err != nil {
  2443  		t.Errorf("unexpected error %v", err)
  2444  	}
  2445  
  2446  	type args struct {
  2447  		path string
  2448  	}
  2449  	tests := []struct {
  2450  		name string
  2451  		args args
  2452  		want string
  2453  	}{
  2454  		{
  2455  			name: "case 1: remote named origin exists",
  2456  			args: args{
  2457  				path: tempGitDirWithOrigin,
  2458  			},
  2459  			want: "git@github.com:redhat-developer/odo.git",
  2460  		},
  2461  		{
  2462  			name: "case 2: remote named origin doesn't exists",
  2463  			args: args{
  2464  				path: tempGitDirWithoutOrigin,
  2465  			},
  2466  			want: "",
  2467  		},
  2468  		{
  2469  			name: "case 3: not a git repo",
  2470  			args: args{
  2471  				path: "",
  2472  			},
  2473  			want: "",
  2474  		},
  2475  	}
  2476  	for _, tt := range tests {
  2477  		t.Run(tt.name, func(t *testing.T) {
  2478  			if got := GetGitOriginPath(tt.args.path); got != tt.want {
  2479  				t.Errorf("GetGitOriginPath() = %v, want %v", got, tt.want)
  2480  			}
  2481  		})
  2482  	}
  2483  }
  2484  
  2485  func TestConvertLabelsToSelector(t *testing.T) {
  2486  	cases := []struct {
  2487  		labels map[string]string
  2488  		want   string
  2489  	}{
  2490  		{
  2491  			labels: map[string]string{
  2492  				"app":                                  "app",
  2493  				"app.kubernetes.io/managed-by":         "odo",
  2494  				"app.kubernetes.io/managed-by-version": "v2.1",
  2495  			},
  2496  			want: "app=app,app.kubernetes.io/managed-by=odo,app.kubernetes.io/managed-by-version=v2.1",
  2497  		},
  2498  		{
  2499  			labels: map[string]string{
  2500  				"app":                                  "app",
  2501  				"app.kubernetes.io/managed-by":         "!odo",
  2502  				"app.kubernetes.io/managed-by-version": "4.8",
  2503  			},
  2504  			want: "app=app,app.kubernetes.io/managed-by!=odo,app.kubernetes.io/managed-by-version=4.8",
  2505  		},
  2506  		{
  2507  			labels: map[string]string{
  2508  				"app.kubernetes.io/managed-by": "odo",
  2509  			},
  2510  			want: "app.kubernetes.io/managed-by=odo",
  2511  		},
  2512  		{
  2513  			labels: map[string]string{
  2514  				"app.kubernetes.io/managed-by": "!odo",
  2515  			},
  2516  			want: "app.kubernetes.io/managed-by!=odo",
  2517  		},
  2518  	}
  2519  
  2520  	for _, tt := range cases {
  2521  		got := ConvertLabelsToSelector(tt.labels)
  2522  		if got != tt.want {
  2523  			t.Errorf("got: %q\nwant:%q", got, tt.want)
  2524  		}
  2525  	}
  2526  }
  2527  
  2528  func TestNamespaceKubernetesObjectWithTrim(t *testing.T) {
  2529  	type args struct {
  2530  		componentName   string
  2531  		applicationName string
  2532  	}
  2533  	tests := []struct {
  2534  		name    string
  2535  		args    args
  2536  		want    string
  2537  		wantErr bool
  2538  	}{
  2539  		{
  2540  			name: "case 1: hyphenated name is less than 63 characters",
  2541  			args: args{
  2542  				componentName:   "nodejs",
  2543  				applicationName: "app",
  2544  			},
  2545  			want:    "nodejs-app",
  2546  			wantErr: false,
  2547  		},
  2548  		{
  2549  			name: "case 2: hyphenated name is more than 63 characters",
  2550  			args: args{
  2551  				componentName:   "veryveryveryveryveryLongComponentName",
  2552  				applicationName: "veryveryveryveryveryveryLongAppName",
  2553  			},
  2554  			want:    "veryveryveryveryveryLongCompone-veryveryveryveryveryveryLongApp",
  2555  			wantErr: false,
  2556  		},
  2557  		{
  2558  			name: "case 3: hyphenated name is equal to 63 characters",
  2559  			args: args{
  2560  				componentName:   "veryveryveryveryLongComponentGo",
  2561  				applicationName: "veryveryveryveryLongAppNameInGo",
  2562  			},
  2563  			want:    "veryveryveryveryLongComponentGo-veryveryveryveryLongAppNameInGo",
  2564  			wantErr: false,
  2565  		},
  2566  		{
  2567  			name: "case 4: component name is more than 63 characters",
  2568  			args: args{
  2569  				componentName:   "123456789012345678901234567890123456789012345678901234567890ComponentName",
  2570  				applicationName: "app",
  2571  			},
  2572  			want:    "12345678901234567890123456789012345678901234567890123456789-app",
  2573  			wantErr: false,
  2574  		},
  2575  	}
  2576  	for _, tt := range tests {
  2577  		t.Run(tt.name, func(t *testing.T) {
  2578  			got, err := NamespaceKubernetesObjectWithTrim(tt.args.componentName, tt.args.applicationName, 63)
  2579  			if (err != nil) != tt.wantErr {
  2580  				t.Errorf("NamespaceKubernetesObjectWithTrim() error = %v, wantErr %v", err, tt.wantErr)
  2581  				return
  2582  			}
  2583  			if got != tt.want {
  2584  				t.Errorf("NamespaceKubernetesObjectWithTrim() got = %v, want %v", got, tt.want)
  2585  			}
  2586  
  2587  			if len(got) > 63 {
  2588  				t.Errorf("got = %s should be less than or equal to 63 characters", got)
  2589  			}
  2590  		})
  2591  	}
  2592  }
  2593  
  2594  func TestSafeGetBool(t *testing.T) {
  2595  
  2596  	tests := []struct {
  2597  		name string
  2598  		arg  *bool
  2599  		want bool
  2600  	}{
  2601  		{
  2602  			name: "case 1: nil pointer",
  2603  			arg:  nil,
  2604  			want: false,
  2605  		},
  2606  		{
  2607  			name: "case 2: true",
  2608  			arg:  GetBool(true),
  2609  			want: true,
  2610  		},
  2611  		{
  2612  			name: "case 3: false",
  2613  			arg:  GetBool(false),
  2614  			want: false,
  2615  		},
  2616  	}
  2617  	for _, tt := range tests {
  2618  		t.Run(tt.name, func(t *testing.T) {
  2619  			if got := SafeGetBool(tt.arg); got != tt.want {
  2620  				t.Errorf("SafeGetBool() = %v, want %v", got, tt.want)
  2621  			}
  2622  		})
  2623  	}
  2624  }
  2625  
  2626  func TestDisplayLog(t *testing.T) {
  2627  	const compName = "my-comp"
  2628  	type args struct {
  2629  		input    []string
  2630  		numLines int
  2631  	}
  2632  	for _, tt := range []struct {
  2633  		name    string
  2634  		wantErr bool
  2635  		want    []string
  2636  
  2637  		args
  2638  	}{
  2639  		{
  2640  			name: "numberOfLastLines==-1",
  2641  			args: args{
  2642  				input:    []string{"a", "b", "c"},
  2643  				numLines: -1,
  2644  			},
  2645  			want: []string{"a\n", "b\n", "c\n"},
  2646  		},
  2647  		{
  2648  			name: "numberOfLastLines greater than total number of lines read",
  2649  			args: args{
  2650  				input:    []string{"one-line"},
  2651  				numLines: 10,
  2652  			},
  2653  			want: []string{"one-line\n"},
  2654  		},
  2655  	} {
  2656  		t.Run(tt.name, func(t *testing.T) {
  2657  			var b bytes.Buffer
  2658  			for _, s := range tt.input {
  2659  				if _, err := b.WriteString(s + "\n"); err != nil {
  2660  					t.Errorf(" failed to write input data %q", s)
  2661  					return
  2662  				}
  2663  			}
  2664  			var w bytes.Buffer
  2665  			err := DisplayLog(false, io.NopCloser(&b), &w, compName, tt.numLines)
  2666  
  2667  			if tt.wantErr != (err != nil) {
  2668  				t.Errorf("expected %v, got %v", tt.wantErr, err)
  2669  				return
  2670  			}
  2671  
  2672  			//Read w
  2673  			reader := bufio.NewReader(&w)
  2674  			var lines []string
  2675  			var line string
  2676  			for {
  2677  				line, err = reader.ReadString('\n')
  2678  				if err != nil {
  2679  					if err == io.EOF {
  2680  						break
  2681  					}
  2682  					t.Errorf("unexpected err while reading data: %v", err)
  2683  					return
  2684  				}
  2685  				lines = append(lines, line)
  2686  			}
  2687  			if diff := cmp.Diff(tt.want, lines); diff != "" {
  2688  				t.Errorf("DisplayLog() mismatch (-want +got):\n%s", diff)
  2689  			}
  2690  		})
  2691  	}
  2692  }
  2693  
  2694  func Test_addFileToIgnoreFile(t *testing.T) {
  2695  	type args struct {
  2696  		data   string
  2697  		ignore string
  2698  	}
  2699  	tests := []struct {
  2700  		name    string
  2701  		args    args
  2702  		wantErr bool
  2703  		want    string
  2704  	}{
  2705  		{
  2706  			name: ".odo already present as .odo",
  2707  			args: args{
  2708  				data:   ".odo",
  2709  				ignore: ".odo",
  2710  			},
  2711  			want: ".odo",
  2712  		},
  2713  		{
  2714  			name: ".odo not present",
  2715  			args: args{
  2716  				data: `foo
  2717  bar`,
  2718  				ignore: ".odo",
  2719  			},
  2720  			want: `foo
  2721  bar
  2722  .odo`,
  2723  		},
  2724  	}
  2725  	for _, tt := range tests {
  2726  		t.Run(tt.name, func(t *testing.T) {
  2727  			fs := filesystem.NewFakeFs()
  2728  			var data = []byte(tt.args.data)
  2729  			path := "/.gitignore"
  2730  			err := fs.WriteFile(path, data, 0644)
  2731  			if err != nil {
  2732  				t.Error(err)
  2733  			}
  2734  
  2735  			if err = addFileToIgnoreFile(path, tt.args.ignore, fs); (err != nil) != tt.wantErr {
  2736  				t.Errorf("addFileToIgnoreFile() error = %v, wantErr %v", err, tt.wantErr)
  2737  			}
  2738  			var content []byte
  2739  			content, err = fs.ReadFile(path)
  2740  			if err != nil {
  2741  				t.Error(err)
  2742  			}
  2743  			if string(content) != tt.want {
  2744  				t.Errorf("expected \n%s\ngot \n%s", tt.want, string(content))
  2745  			}
  2746  		})
  2747  	}
  2748  }
  2749  
  2750  func TestIsPortFree(t *testing.T) {
  2751  	type serverCloser interface {
  2752  		Close()
  2753  	}
  2754  	type args struct {
  2755  		port         int
  2756  		portProvider func(address string) (int, serverCloser, error)
  2757  		address      string
  2758  	}
  2759  	type test struct {
  2760  		name string
  2761  		args args
  2762  		want bool
  2763  	}
  2764  	tests := []test{
  2765  		{
  2766  			name: "negative port should return an error, handles as false",
  2767  			args: args{port: -10},
  2768  			want: false,
  2769  		},
  2770  		{
  2771  			name: "0 should always be free",
  2772  			args: args{port: 0},
  2773  			want: true,
  2774  		},
  2775  		{
  2776  			name: "random port bound on 127.0.0.1",
  2777  			args: args{
  2778  				portProvider: func(address string) (int, serverCloser, error) {
  2779  					s := httptest.NewServer(nil)
  2780  					_, p, err := net.SplitHostPort(strings.TrimPrefix(s.URL, "http://"))
  2781  					if err != nil {
  2782  						return 0, s, err
  2783  					}
  2784  					port, err := strconv.Atoi(p)
  2785  					if err != nil {
  2786  						return 0, s, err
  2787  					}
  2788  					return port, s, nil
  2789  				},
  2790  			},
  2791  			want: false,
  2792  		},
  2793  		{
  2794  			name: "random port bound on 127.0.0.1 and checking 0 as input",
  2795  			args: args{
  2796  				portProvider: func(address string) (int, serverCloser, error) {
  2797  					s := httptest.NewServer(nil)
  2798  					return 0, s, nil
  2799  				},
  2800  			},
  2801  			want: true,
  2802  		},
  2803  		{
  2804  			name: "random port bound on 0.0.0.0 and checking 0 as input",
  2805  			args: args{
  2806  				portProvider: func(address string) (int, serverCloser, error) {
  2807  					// Intentionally not using httptest.Server, which listens to 127.0.0.1
  2808  					l, err := net.Listen("tcp", fmt.Sprintf("%s:0", address))
  2809  					if err != nil {
  2810  						return 0, nil, err
  2811  					}
  2812  					s := &httptest.Server{
  2813  						Listener: l,
  2814  						Config:   &http.Server{},
  2815  					}
  2816  					s.Start()
  2817  
  2818  					return 0, s, nil
  2819  				},
  2820  				address: "0.0.0.0",
  2821  			},
  2822  			want: true,
  2823  		},
  2824  		{
  2825  			name: "random port bound on 0.0.0.0",
  2826  			args: args{
  2827  				portProvider: func(address string) (int, serverCloser, error) {
  2828  					// Intentionally not using httptest.Server, which listens to 127.0.0.1
  2829  					l, err := net.Listen("tcp", fmt.Sprintf("%s:0", address))
  2830  					if err != nil {
  2831  						return 0, nil, err
  2832  					}
  2833  					s := &httptest.Server{
  2834  						Listener: l,
  2835  						Config:   &http.Server{},
  2836  					}
  2837  					s.Start()
  2838  
  2839  					_, p, err := net.SplitHostPort(strings.TrimPrefix(s.URL, "http://"))
  2840  					if err != nil {
  2841  						return 0, s, err
  2842  					}
  2843  					port, err := strconv.Atoi(p)
  2844  					if err != nil {
  2845  						return 0, s, err
  2846  					}
  2847  					return port, s, nil
  2848  				},
  2849  				address: "0.0.0.0",
  2850  			},
  2851  			want: false,
  2852  		},
  2853  	}
  2854  
  2855  	for _, tt := range tests {
  2856  		t.Run(tt.name, func(t *testing.T) {
  2857  			port := tt.args.port
  2858  			var s serverCloser
  2859  			var err error
  2860  			if tt.args.portProvider != nil {
  2861  				port, s, err = tt.args.portProvider(tt.args.address)
  2862  				if s != nil {
  2863  					defer s.Close()
  2864  				}
  2865  				if err != nil {
  2866  					t.Errorf("error while computing port: %v", err)
  2867  					return
  2868  				}
  2869  			}
  2870  
  2871  			if got := IsPortFree(port, tt.args.address); got != tt.want {
  2872  				t.Errorf("IsPortFree() = %v, want %v", got, tt.want)
  2873  			}
  2874  		})
  2875  	}
  2876  
  2877  }
  2878  

View as plain text