github.com/release-engineering/exodus-rsync@v1.11.2/internal/args/parse_test.go (about)

     1  package args
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/alecthomas/kong"
     9  )
    10  
    11  func TestParseOk(t *testing.T) {
    12  	tests := map[string]struct {
    13  		input []string
    14  		want  Config
    15  	}{
    16  		"trivial": {input: []string{"exodus-rsync", "some-src", "some-dest"},
    17  			want: Config{Src: "some-src", Dest: "some-dest"}},
    18  
    19  		"ignored args": {
    20  			// At least all compound names should be in long-form to ensure rsync compatibility.
    21  			input: []string{
    22  				"exodus-rsync",
    23  				"-arpEogDtz",
    24  				"--copy-links",
    25  				"--keep-dirlinks",
    26  				"--hard-links",
    27  				"--acls",
    28  				"--xattrs",
    29  				"--atimes",
    30  				"--crtimes",
    31  				"--omit-dir-times",
    32  				"--rsh", "abc",
    33  				"--delete",
    34  				"--prune-empty-dirs",
    35  				"--timeout", "123",
    36  				"--stats",
    37  				"--itemize-changes",
    38  				"x",
    39  				"y"},
    40  			want: Config{Src: "x", Dest: "y",
    41  				IgnoredConfig: IgnoredConfig{
    42  					Archive:         true,
    43  					Recursive:       true,
    44  					CopyLinks:       true,
    45  					KeepDirlinks:    true,
    46  					HardLinks:       true,
    47  					Perms:           true,
    48  					Executability:   true,
    49  					Acls:            true,
    50  					Xattrs:          true,
    51  					Owner:           true,
    52  					Group:           true,
    53  					Devices:         true,
    54  					Specials:        true,
    55  					DevicesSpecials: true,
    56  					Times:           true,
    57  					Atimes:          true,
    58  					Crtimes:         true,
    59  					OmitDirTimes:    true,
    60  					Rsh:             "abc",
    61  					Delete:          true,
    62  					PruneEmptyDirs:  true,
    63  					Timeout:         123,
    64  					Compress:        true,
    65  					Stats:           true,
    66  					ItemizeChanges:  true,
    67  				}}},
    68  
    69  		"verbose": {
    70  			input: []string{
    71  				"exodus-rsync",
    72  				"-vv", "--verbose",
    73  				"x",
    74  				"y"},
    75  			want: Config{Verbose: 3, Src: "x", Dest: "y"}},
    76  
    77  		"relative": {
    78  			input: []string{
    79  				"exodus-rsync",
    80  				"--relative",
    81  				"x",
    82  				"y"},
    83  			want: Config{Relative: true, Src: "x", Dest: "y"}},
    84  
    85  		"links": {
    86  			input: []string{
    87  				"exodus-rsync",
    88  				"-l",
    89  				"x",
    90  				"y"},
    91  			want: Config{Links: true, Src: "x", Dest: "y"}},
    92  
    93  		"exclude": {
    94  			input: []string{
    95  				"exodus-rsync",
    96  				"--exclude",
    97  				".*",
    98  				"--exclude",
    99  				"*.conf",
   100  				"x",
   101  				"y"},
   102  			want: Config{Exclude: []string{".*", "*.conf"}, Src: "x", Dest: "y"}},
   103  
   104  		"files-from": {
   105  			input: []string{
   106  				"exodus-rsync",
   107  				"--files-from",
   108  				"sources.txt",
   109  				"x",
   110  				"y"},
   111  			want: Config{FilesFrom: "sources.txt", Src: "x", Dest: "y"}},
   112  
   113  		"tolerable filter": {
   114  			input: []string{
   115  				"exodus-rsync",
   116  				"--filter", "+ **/hi/**",
   117  				"--filter=-/_*",
   118  				"x",
   119  				"y"},
   120  			want: Config{Src: "x", Dest: "y", Filter: []string{"+ **/hi/**", "-/_*"}}},
   121  		"with publish": {
   122  			input: []string{
   123  				"exodus-rsync",
   124  				"--exodus-publish",
   125  				"3e0a4539-be4a-437e-a45f-6d72f7192f17",
   126  				"x",
   127  				"y",
   128  			},
   129  			want: Config{Src: "x", Dest: "y", ExodusConfig: ExodusConfig{Publish: "3e0a4539-be4a-437e-a45f-6d72f7192f17"}},
   130  		},
   131  	}
   132  	for name, tc := range tests {
   133  		t.Run(name, func(t *testing.T) {
   134  			got := Parse(tc.input, "", nil)
   135  			if !reflect.DeepEqual(tc.want, got) {
   136  				t.Fatalf("expected: %v, got: %v", tc.want, got)
   137  			}
   138  		})
   139  	}
   140  }
   141  
   142  func TestParseErrors(t *testing.T) {
   143  	tests := map[string]struct {
   144  		input []string
   145  	}{
   146  		"missing src dest": {[]string{"exodus-rsync"}},
   147  
   148  		"bad filter": {[]string{"exodus-rsync", "--filter", "quux", "x", "y"}},
   149  	}
   150  
   151  	for name, tc := range tests {
   152  		exitcode := 0
   153  
   154  		t.Run(name, func(t *testing.T) {
   155  			Parse(tc.input, "", func(code int) {
   156  				exitcode = code
   157  			})
   158  
   159  			if exitcode == 0 {
   160  				t.Fatal("should have exited with error, did not")
   161  			}
   162  		})
   163  	}
   164  }
   165  
   166  func TestDestPath(t *testing.T) {
   167  	tests := []struct {
   168  		name string
   169  		src  string
   170  		dest string
   171  		rel  bool
   172  		want string
   173  	}{
   174  		{"no : in dest", ".", "some-dest", true, ""},
   175  		{": in dest", ".", "user@somehost:/some/rsync/path", false, "/some/rsync/path"},
   176  		{"relative dest", "/some/path", "user@somehost:/rsync/", true, "/rsync/some/path"},
   177  	}
   178  	for _, tc := range tests {
   179  		t.Run(tc.name, func(t *testing.T) {
   180  			c := Config{Src: tc.src, Dest: tc.dest, Relative: tc.rel}
   181  			if got := c.DestPath(); got != tc.want {
   182  				t.Errorf("Config.DestPath() = %v, want %v", got, tc.want)
   183  			}
   184  		})
   185  	}
   186  }
   187  
   188  func TestStringMapDecodeError(t *testing.T) {
   189  	err := argStringMapper{}.Decode(
   190  		&kong.DecodeContext{Value: &kong.Value{}, Scan: &kong.Scanner{}},
   191  		reflect.Value{},
   192  	)
   193  
   194  	// Scan holds no tokens; no flag or flag value to decode.
   195  	if err.Error() != "flag : missing value" {
   196  		t.Fatalf("didn't get expected error, got %s", err.Error())
   197  	}
   198  }
   199  
   200  func TestConfigValidationErrors(t *testing.T) {
   201  	var exitcode int
   202  
   203  	config := Parse([]string{"exodus-rsync", "some-src", strings.Repeat("some-dest", 250), "--exodus-publish", "zombies"}, "", func(code int) {
   204  		exitcode = code
   205  	})
   206  	if exitcode != 0 {
   207  		t.Fatalf("unexpected parsing error: %d\nconfig: %v", exitcode, config)
   208  	}
   209  
   210  	expected := []string{
   211  		"validation error(s):",
   212  		"Key: 'Config.Dest' Error:Field validation for 'Dest' failed on the 'max' tag",
   213  		"Key: 'Config.ExodusConfig.Publish' Error:Field validation for 'Publish' failed on the 'uuid' tag",
   214  	}
   215  	err := config.ValidateConfig()
   216  	if err == nil {
   217  		t.Fatalf("didn't raise a validation error")
   218  	}
   219  	for _, str := range expected {
   220  		if !strings.Contains(err.Error(), str) {
   221  			t.Fatalf("didn't get expected error, got %s", err.Error())
   222  		}
   223  	}
   224  }