github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/cmd/syft/cli/commands/update_test.go (about)

     1  package commands
     2  
     3  import (
     4  	"net/http"
     5  	"net/http/httptest"
     6  	"testing"
     7  
     8  	"github.com/anchore/clio"
     9  	hashiVersion "github.com/anchore/go-version"
    10  	"github.com/anchore/syft/cmd/syft/internal"
    11  )
    12  
    13  func TestIsUpdateAvailable(t *testing.T) {
    14  	tests := []struct {
    15  		name          string
    16  		buildVersion  string
    17  		latestVersion string
    18  		code          int
    19  		isAvailable   bool
    20  		newVersion    string
    21  		err           bool
    22  	}{
    23  		{
    24  			name:          "equal",
    25  			buildVersion:  "1.0.0",
    26  			latestVersion: "1.0.0",
    27  			code:          200,
    28  			isAvailable:   false,
    29  			newVersion:    "",
    30  			err:           false,
    31  		},
    32  		{
    33  			name:          "hasUpdate",
    34  			buildVersion:  "1.0.0",
    35  			latestVersion: "1.2.0",
    36  			code:          200,
    37  			isAvailable:   true,
    38  			newVersion:    "1.2.0",
    39  			err:           false,
    40  		},
    41  		{
    42  			name:          "aheadOfLatest",
    43  			buildVersion:  "1.2.0",
    44  			latestVersion: "1.0.0",
    45  			code:          200,
    46  			isAvailable:   false,
    47  			newVersion:    "",
    48  			err:           false,
    49  		},
    50  		{
    51  			name:          "EmptyUpdate",
    52  			buildVersion:  "1.0.0",
    53  			latestVersion: "",
    54  			code:          200,
    55  			isAvailable:   false,
    56  			newVersion:    "",
    57  			err:           true,
    58  		},
    59  		{
    60  			name:          "GarbageUpdate",
    61  			buildVersion:  "1.0.0",
    62  			latestVersion: "hdfjksdhfhkj",
    63  			code:          200,
    64  			isAvailable:   false,
    65  			newVersion:    "",
    66  			err:           true,
    67  		},
    68  		{
    69  			name:          "BadUpdate",
    70  			buildVersion:  "1.0.0",
    71  			latestVersion: "1.0.",
    72  			code:          500,
    73  			isAvailable:   false,
    74  			newVersion:    "",
    75  			err:           true,
    76  		},
    77  		{
    78  			name:          "NoBuildVersion",
    79  			buildVersion:  internal.NotProvided,
    80  			latestVersion: "1.0.0",
    81  			code:          200,
    82  			isAvailable:   false,
    83  			newVersion:    "",
    84  			err:           false,
    85  		},
    86  		{
    87  			name:          "SnapshotBuildVersion",
    88  			buildVersion:  "2.0.0-SHAPSHOT-a78bf9c",
    89  			latestVersion: "1.0.0",
    90  			code:          200,
    91  			isAvailable:   false,
    92  			newVersion:    "",
    93  			err:           false,
    94  		},
    95  		{
    96  			name:          "BadUpdateValidVersion",
    97  			buildVersion:  "1.0.0",
    98  			latestVersion: "2.0.0",
    99  			code:          404,
   100  			isAvailable:   false,
   101  			newVersion:    "",
   102  			err:           true,
   103  		},
   104  	}
   105  
   106  	for _, test := range tests {
   107  		t.Run(test.name, func(t *testing.T) {
   108  			// setup mocks
   109  			// local...
   110  			id := clio.Identification{Name: "Syft", Version: test.buildVersion}
   111  			// remote...
   112  			handler := http.NewServeMux()
   113  			handler.HandleFunc(latestAppVersionURL.path, func(w http.ResponseWriter, r *http.Request) {
   114  				w.WriteHeader(test.code)
   115  				_, _ = w.Write([]byte(test.latestVersion))
   116  			})
   117  			mockSrv := httptest.NewServer(handler)
   118  			latestAppVersionURL.host = mockSrv.URL
   119  			defer mockSrv.Close()
   120  
   121  			isAvailable, newVersion, err := isUpdateAvailable(id)
   122  			if err != nil && !test.err {
   123  				t.Fatalf("got error but expected none: %+v", err)
   124  			} else if err == nil && test.err {
   125  				t.Fatalf("expected error but got none")
   126  			}
   127  
   128  			if newVersion != test.newVersion {
   129  				t.Errorf("unexpected NEW version: %+v", newVersion)
   130  			}
   131  
   132  			if isAvailable != test.isAvailable {
   133  				t.Errorf("unexpected result: %+v", isAvailable)
   134  			}
   135  		})
   136  	}
   137  
   138  }
   139  
   140  func TestFetchLatestApplicationVersion(t *testing.T) {
   141  	tests := []struct {
   142  		name            string
   143  		response        string
   144  		code            int
   145  		err             bool
   146  		id              clio.Identification
   147  		expected        *hashiVersion.Version
   148  		expectedHeaders map[string]string
   149  	}{
   150  		{
   151  			name:            "gocase",
   152  			response:        "1.0.0",
   153  			code:            200,
   154  			id:              clio.Identification{Name: "Syft", Version: "0.0.0"},
   155  			expected:        hashiVersion.Must(hashiVersion.NewVersion("1.0.0")),
   156  			expectedHeaders: map[string]string{"User-Agent": "Syft 0.0.0"},
   157  			err:             false,
   158  		},
   159  		{
   160  			name:            "garbage",
   161  			response:        "garbage",
   162  			code:            200,
   163  			id:              clio.Identification{Name: "Syft", Version: "0.0.0"},
   164  			expected:        nil,
   165  			expectedHeaders: nil,
   166  			err:             true,
   167  		},
   168  		{
   169  			name:            "http 500",
   170  			response:        "1.0.0",
   171  			code:            500,
   172  			id:              clio.Identification{Name: "Syft", Version: "0.0.0"},
   173  			expected:        nil,
   174  			expectedHeaders: nil,
   175  			err:             true,
   176  		},
   177  		{
   178  			name:            "http 404",
   179  			response:        "1.0.0",
   180  			code:            404,
   181  			id:              clio.Identification{Name: "Syft", Version: "0.0.0"},
   182  			expected:        nil,
   183  			expectedHeaders: nil,
   184  			err:             true,
   185  		},
   186  		{
   187  			name:            "empty",
   188  			response:        "",
   189  			code:            200,
   190  			id:              clio.Identification{Name: "Syft", Version: "0.0.0"},
   191  			expected:        nil,
   192  			expectedHeaders: nil,
   193  			err:             true,
   194  		},
   195  		{
   196  			name:            "too long",
   197  			response:        "this is really long this is really long this is really long this is really long this is really long this is really long this is really long this is really long ",
   198  			code:            200,
   199  			id:              clio.Identification{Name: "Syft", Version: "0.0.0"},
   200  			expected:        nil,
   201  			expectedHeaders: nil,
   202  			err:             true,
   203  		},
   204  	}
   205  
   206  	for _, test := range tests {
   207  		t.Run(test.name, func(t *testing.T) {
   208  			// setup mock
   209  			handler := http.NewServeMux()
   210  			handler.HandleFunc(latestAppVersionURL.path, func(w http.ResponseWriter, r *http.Request) {
   211  				if test.expectedHeaders != nil {
   212  					for headerName, headerValue := range test.expectedHeaders {
   213  						actualHeader := r.Header.Get(headerName)
   214  						if actualHeader != headerValue {
   215  							t.Fatalf("expected header %v=%v but got %v", headerName, headerValue, actualHeader)
   216  						}
   217  					}
   218  				}
   219  
   220  				w.WriteHeader(test.code)
   221  				_, _ = w.Write([]byte(test.response))
   222  			})
   223  			mockSrv := httptest.NewServer(handler)
   224  			latestAppVersionURL.host = mockSrv.URL
   225  			defer mockSrv.Close()
   226  
   227  			actual, err := fetchLatestApplicationVersion(test.id)
   228  			if err != nil && !test.err {
   229  				t.Fatalf("got error but expected none: %+v", err)
   230  			} else if err == nil && test.err {
   231  				t.Fatalf("expected error but got none")
   232  			}
   233  
   234  			if err != nil {
   235  				return
   236  			}
   237  
   238  			if actual.String() != test.expected.String() {
   239  				t.Errorf("unexpected version: %+v", actual.String())
   240  			}
   241  		})
   242  	}
   243  
   244  }