code.cestus.io/tools/fabricator@v0.4.3/pkg/cmd/plugin/plugin_test.go (about) 1 package plugin 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "strings" 8 "testing" 9 10 "code.cestus.io/tools/fabricator/pkg/fabricator" 11 ) 12 13 func TestPluginPathsAreUnaltered(t *testing.T) { 14 tempDir, err := ioutil.TempDir(os.TempDir(), "test-cmd-plugins") 15 if err != nil { 16 t.Fatalf("unexpected error: %v", err) 17 } 18 tempDir2, err := ioutil.TempDir(os.TempDir(), "test-cmd-plugins2") 19 if err != nil { 20 t.Fatalf("unexpected error: %v", err) 21 } 22 // cleanup 23 defer func() { 24 if err := os.RemoveAll(tempDir); err != nil { 25 panic(fmt.Errorf("unexpected cleanup error: %v", err)) 26 } 27 if err := os.RemoveAll(tempDir2); err != nil { 28 panic(fmt.Errorf("unexpected cleanup error: %v", err)) 29 } 30 }() 31 32 ioStreams, _, _, errOut := fabricator.NewTestIOStreams() 33 verifier := newFakePluginPathVerifier() 34 pluginPaths := []string{tempDir, tempDir2} 35 o := &Options{ 36 Verifier: verifier, 37 IOStreams: ioStreams, 38 39 PluginPaths: pluginPaths, 40 } 41 42 // write at least one valid plugin file 43 if _, err := ioutil.TempFile(tempDir, "fabricator-"); err != nil { 44 t.Fatalf("unexpected error %v", err) 45 } 46 if _, err := ioutil.TempFile(tempDir2, "fabricator-"); err != nil { 47 t.Fatalf("unexpected error %v", err) 48 } 49 50 if err := o.Run(); err != nil { 51 t.Fatalf("unexpected error %v - %v", err, errOut.String()) 52 } 53 54 // ensure original paths remain unaltered 55 if len(verifier.seenUnsorted) != len(pluginPaths) { 56 t.Fatalf("saw unexpected plugin paths. Expecting %v, got %v", pluginPaths, verifier.seenUnsorted) 57 } 58 for actual := range verifier.seenUnsorted { 59 if !strings.HasPrefix(verifier.seenUnsorted[actual], pluginPaths[actual]) { 60 t.Fatalf("expected PATH slice to be unaltered. Expecting %v, but got %v", pluginPaths[actual], verifier.seenUnsorted[actual]) 61 } 62 } 63 } 64 65 func TestPluginPathsAreValid(t *testing.T) { 66 tempDir, err := ioutil.TempDir(os.TempDir(), "test-cmd-plugins") 67 if err != nil { 68 t.Fatalf("unexpected error: %v", err) 69 } 70 // cleanup 71 defer func() { 72 if err := os.RemoveAll(tempDir); err != nil { 73 panic(fmt.Errorf("unexpected cleanup error: %v", err)) 74 } 75 }() 76 77 tc := []struct { 78 name string 79 pluginPaths []string 80 pluginFile func() (*os.File, error) 81 verifier *fakePluginPathVerifier 82 expectVerifyErrors []error 83 expectErr string 84 expectErrOut string 85 expectOut string 86 }{ 87 { 88 name: "ensure no plugins found if no files begin with fabricator- prefix", 89 pluginPaths: []string{tempDir}, 90 verifier: newFakePluginPathVerifier(), 91 pluginFile: func() (*os.File, error) { 92 return ioutil.TempFile(tempDir, "notfabricator-") 93 }, 94 expectErr: "error: unable to find any fabricator plugins in your PATH\n", 95 }, 96 { 97 name: "ensure de-duplicated plugin-paths slice", 98 pluginPaths: []string{tempDir, tempDir}, 99 verifier: newFakePluginPathVerifier(), 100 pluginFile: func() (*os.File, error) { 101 return ioutil.TempFile(tempDir, "fabricator-") 102 }, 103 expectOut: "The following compatible plugins are available:", 104 }, 105 { 106 name: "ensure no errors when empty string or blank path are specified", 107 pluginPaths: []string{tempDir, "", " "}, 108 verifier: newFakePluginPathVerifier(), 109 pluginFile: func() (*os.File, error) { 110 return ioutil.TempFile(tempDir, "fabricator-") 111 }, 112 expectOut: "The following compatible plugins are available:", 113 }, 114 } 115 116 for _, test := range tc { 117 t.Run(test.name, func(t *testing.T) { 118 ioStreams, _, out, errOut := fabricator.NewTestIOStreams() 119 o := &Options{ 120 Verifier: test.verifier, 121 IOStreams: ioStreams, 122 123 PluginPaths: test.pluginPaths, 124 } 125 126 // create files 127 if test.pluginFile != nil { 128 if _, err := test.pluginFile(); err != nil { 129 t.Fatalf("unexpected error creating plugin file: %v", err) 130 } 131 } 132 133 for _, expected := range test.expectVerifyErrors { 134 for _, actual := range test.verifier.errors { 135 if expected != actual { 136 t.Fatalf("unexpected error: expected %v, but got %v", expected, actual) 137 } 138 } 139 } 140 141 err := o.Run() 142 if err == nil && len(test.expectErr) > 0 { 143 t.Fatalf("unexpected non-error: expected %v, but got nothing", test.expectErr) 144 } else if err != nil && len(test.expectErr) == 0 { 145 t.Fatalf("unexpected error: expected nothing, but got %v", err.Error()) 146 } else if err != nil && err.Error() != test.expectErr { 147 t.Fatalf("unexpected error: expected %v, but got %v", test.expectErr, err.Error()) 148 } 149 150 if len(test.expectErrOut) == 0 && errOut.Len() > 0 { 151 t.Fatalf("unexpected error output: expected nothing, but got %v", errOut.String()) 152 } else if len(test.expectErrOut) > 0 && !strings.Contains(errOut.String(), test.expectErrOut) { 153 t.Fatalf("unexpected error output: expected to contain %v, but got %v", test.expectErrOut, errOut.String()) 154 } 155 156 if len(test.expectOut) == 0 && out.Len() > 0 { 157 t.Fatalf("unexpected output: expected nothing, but got %v", out.String()) 158 } else if len(test.expectOut) > 0 && !strings.Contains(out.String(), test.expectOut) { 159 t.Fatalf("unexpected output: expected to contain %v, but got %v", test.expectOut, out.String()) 160 } 161 }) 162 } 163 } 164 165 type duplicatePathError struct { 166 path string 167 } 168 169 func (d *duplicatePathError) Error() string { 170 return fmt.Sprintf("path %q already visited", d.path) 171 } 172 173 type fakePluginPathVerifier struct { 174 errors []error 175 seen map[string]bool 176 seenUnsorted []string 177 } 178 179 func (f *fakePluginPathVerifier) Verify(path string) []error { 180 if f.seen[path] { 181 err := &duplicatePathError{path} 182 f.errors = append(f.errors, err) 183 return []error{err} 184 } 185 f.seen[path] = true 186 f.seenUnsorted = append(f.seenUnsorted, path) 187 return nil 188 } 189 190 func newFakePluginPathVerifier() *fakePluginPathVerifier { 191 return &fakePluginPathVerifier{seen: make(map[string]bool)} 192 }