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  }