github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/storage/storage_test.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package storage // import "github.com/stefanmcshane/helm/pkg/storage"
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/pkg/errors"
    25  
    26  	rspb "github.com/stefanmcshane/helm/pkg/release"
    27  	"github.com/stefanmcshane/helm/pkg/storage/driver"
    28  )
    29  
    30  func TestStorageCreate(t *testing.T) {
    31  	// initialize storage
    32  	storage := Init(driver.NewMemory())
    33  
    34  	// create fake release
    35  	rls := ReleaseTestData{
    36  		Name:    "angry-beaver",
    37  		Version: 1,
    38  	}.ToRelease()
    39  
    40  	assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease")
    41  
    42  	// fetch the release
    43  	res, err := storage.Get(rls.Name, rls.Version)
    44  	assertErrNil(t.Fatal, err, "QueryRelease")
    45  
    46  	// verify the fetched and created release are the same
    47  	if !reflect.DeepEqual(rls, res) {
    48  		t.Fatalf("Expected %v, got %v", rls, res)
    49  	}
    50  }
    51  
    52  func TestStorageUpdate(t *testing.T) {
    53  	// initialize storage
    54  	storage := Init(driver.NewMemory())
    55  
    56  	// create fake release
    57  	rls := ReleaseTestData{
    58  		Name:    "angry-beaver",
    59  		Version: 1,
    60  		Status:  rspb.StatusDeployed,
    61  	}.ToRelease()
    62  
    63  	assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease")
    64  
    65  	// modify the release
    66  	rls.Info.Status = rspb.StatusUninstalled
    67  	assertErrNil(t.Fatal, storage.Update(rls), "UpdateRelease")
    68  
    69  	// retrieve the updated release
    70  	res, err := storage.Get(rls.Name, rls.Version)
    71  	assertErrNil(t.Fatal, err, "QueryRelease")
    72  
    73  	// verify updated and fetched releases are the same.
    74  	if !reflect.DeepEqual(rls, res) {
    75  		t.Fatalf("Expected %v, got %v", rls, res)
    76  	}
    77  }
    78  
    79  func TestStorageDelete(t *testing.T) {
    80  	// initialize storage
    81  	storage := Init(driver.NewMemory())
    82  
    83  	// create fake release
    84  	rls := ReleaseTestData{
    85  		Name:    "angry-beaver",
    86  		Version: 1,
    87  	}.ToRelease()
    88  	rls2 := ReleaseTestData{
    89  		Name:    "angry-beaver",
    90  		Version: 2,
    91  	}.ToRelease()
    92  
    93  	assertErrNil(t.Fatal, storage.Create(rls), "StoreRelease")
    94  	assertErrNil(t.Fatal, storage.Create(rls2), "StoreRelease")
    95  
    96  	// delete the release
    97  	res, err := storage.Delete(rls.Name, rls.Version)
    98  	assertErrNil(t.Fatal, err, "DeleteRelease")
    99  
   100  	// verify updated and fetched releases are the same.
   101  	if !reflect.DeepEqual(rls, res) {
   102  		t.Fatalf("Expected %v, got %v", rls, res)
   103  	}
   104  
   105  	hist, err := storage.History(rls.Name)
   106  	if err != nil {
   107  		t.Errorf("unexpected error: %s", err)
   108  	}
   109  
   110  	// We have now deleted one of the two records.
   111  	if len(hist) != 1 {
   112  		t.Errorf("expected 1 record for deleted release version, got %d", len(hist))
   113  	}
   114  
   115  	if hist[0].Version != 2 {
   116  		t.Errorf("Expected version to be 2, got %d", hist[0].Version)
   117  	}
   118  }
   119  
   120  func TestStorageList(t *testing.T) {
   121  	// initialize storage
   122  	storage := Init(driver.NewMemory())
   123  
   124  	// setup storage with test releases
   125  	setup := func() {
   126  		// release records
   127  		rls0 := ReleaseTestData{Name: "happy-catdog", Status: rspb.StatusSuperseded}.ToRelease()
   128  		rls1 := ReleaseTestData{Name: "livid-human", Status: rspb.StatusSuperseded}.ToRelease()
   129  		rls2 := ReleaseTestData{Name: "relaxed-cat", Status: rspb.StatusSuperseded}.ToRelease()
   130  		rls3 := ReleaseTestData{Name: "hungry-hippo", Status: rspb.StatusDeployed}.ToRelease()
   131  		rls4 := ReleaseTestData{Name: "angry-beaver", Status: rspb.StatusDeployed}.ToRelease()
   132  		rls5 := ReleaseTestData{Name: "opulent-frog", Status: rspb.StatusUninstalled}.ToRelease()
   133  		rls6 := ReleaseTestData{Name: "happy-liger", Status: rspb.StatusUninstalled}.ToRelease()
   134  
   135  		// create the release records in the storage
   136  		assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'rls0'")
   137  		assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'rls1'")
   138  		assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'rls2'")
   139  		assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'rls3'")
   140  		assertErrNil(t.Fatal, storage.Create(rls4), "Storing release 'rls4'")
   141  		assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'rls5'")
   142  		assertErrNil(t.Fatal, storage.Create(rls6), "Storing release 'rls6'")
   143  	}
   144  
   145  	var listTests = []struct {
   146  		Description string
   147  		NumExpected int
   148  		ListFunc    func() ([]*rspb.Release, error)
   149  	}{
   150  		{"ListDeployed", 2, storage.ListDeployed},
   151  		{"ListReleases", 7, storage.ListReleases},
   152  		{"ListUninstalled", 2, storage.ListUninstalled},
   153  	}
   154  
   155  	setup()
   156  
   157  	for _, tt := range listTests {
   158  		list, err := tt.ListFunc()
   159  		assertErrNil(t.Fatal, err, tt.Description)
   160  		// verify the count of releases returned
   161  		if len(list) != tt.NumExpected {
   162  			t.Errorf("ListReleases(%s): expected %d, actual %d",
   163  				tt.Description,
   164  				tt.NumExpected,
   165  				len(list))
   166  		}
   167  	}
   168  }
   169  
   170  func TestStorageDeployed(t *testing.T) {
   171  	storage := Init(driver.NewMemory())
   172  
   173  	const name = "angry-bird"
   174  	const vers = 4
   175  
   176  	// setup storage with test releases
   177  	setup := func() {
   178  		// release records
   179  		rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.StatusSuperseded}.ToRelease()
   180  		rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusSuperseded}.ToRelease()
   181  		rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.StatusSuperseded}.ToRelease()
   182  		rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.StatusDeployed}.ToRelease()
   183  
   184  		// create the release records in the storage
   185  		assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)")
   186  		assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)")
   187  		assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)")
   188  		assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)")
   189  	}
   190  
   191  	setup()
   192  
   193  	rls, err := storage.Last(name)
   194  	if err != nil {
   195  		t.Fatalf("Failed to query for deployed release: %s\n", err)
   196  	}
   197  
   198  	switch {
   199  	case rls == nil:
   200  		t.Fatalf("Release is nil")
   201  	case rls.Name != name:
   202  		t.Fatalf("Expected release name %q, actual %q\n", name, rls.Name)
   203  	case rls.Version != vers:
   204  		t.Fatalf("Expected release version %d, actual %d\n", vers, rls.Version)
   205  	case rls.Info.Status != rspb.StatusDeployed:
   206  		t.Fatalf("Expected release status 'DEPLOYED', actual %s\n", rls.Info.Status.String())
   207  	}
   208  }
   209  
   210  func TestStorageDeployedWithCorruption(t *testing.T) {
   211  	storage := Init(driver.NewMemory())
   212  
   213  	const name = "angry-bird"
   214  	const vers = int(4)
   215  
   216  	// setup storage with test releases
   217  	setup := func() {
   218  		// release records (notice odd order and corruption)
   219  		rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.StatusSuperseded}.ToRelease()
   220  		rls1 := ReleaseTestData{Name: name, Version: 4, Status: rspb.StatusDeployed}.ToRelease()
   221  		rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.StatusSuperseded}.ToRelease()
   222  		rls3 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusDeployed}.ToRelease()
   223  
   224  		// create the release records in the storage
   225  		assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)")
   226  		assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)")
   227  		assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)")
   228  		assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)")
   229  	}
   230  
   231  	setup()
   232  
   233  	rls, err := storage.Deployed(name)
   234  	if err != nil {
   235  		t.Fatalf("Failed to query for deployed release: %s\n", err)
   236  	}
   237  
   238  	switch {
   239  	case rls == nil:
   240  		t.Fatalf("Release is nil")
   241  	case rls.Name != name:
   242  		t.Fatalf("Expected release name %q, actual %q\n", name, rls.Name)
   243  	case rls.Version != vers:
   244  		t.Fatalf("Expected release version %d, actual %d\n", vers, rls.Version)
   245  	case rls.Info.Status != rspb.StatusDeployed:
   246  		t.Fatalf("Expected release status 'DEPLOYED', actual %s\n", rls.Info.Status.String())
   247  	}
   248  }
   249  
   250  func TestStorageHistory(t *testing.T) {
   251  	storage := Init(driver.NewMemory())
   252  
   253  	const name = "angry-bird"
   254  
   255  	// setup storage with test releases
   256  	setup := func() {
   257  		// release records
   258  		rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.StatusSuperseded}.ToRelease()
   259  		rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusSuperseded}.ToRelease()
   260  		rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.StatusSuperseded}.ToRelease()
   261  		rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.StatusDeployed}.ToRelease()
   262  
   263  		// create the release records in the storage
   264  		assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)")
   265  		assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)")
   266  		assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)")
   267  		assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)")
   268  	}
   269  
   270  	setup()
   271  
   272  	h, err := storage.History(name)
   273  	if err != nil {
   274  		t.Fatalf("Failed to query for release history (%q): %s\n", name, err)
   275  	}
   276  	if len(h) != 4 {
   277  		t.Fatalf("Release history (%q) is empty\n", name)
   278  	}
   279  }
   280  
   281  var errMaxHistoryMockDriverSomethingHappened = errors.New("something happened")
   282  
   283  type MaxHistoryMockDriver struct {
   284  	Driver driver.Driver
   285  }
   286  
   287  func NewMaxHistoryMockDriver(d driver.Driver) *MaxHistoryMockDriver {
   288  	return &MaxHistoryMockDriver{Driver: d}
   289  }
   290  func (d *MaxHistoryMockDriver) Create(key string, rls *rspb.Release) error {
   291  	return d.Driver.Create(key, rls)
   292  }
   293  func (d *MaxHistoryMockDriver) Update(key string, rls *rspb.Release) error {
   294  	return d.Driver.Update(key, rls)
   295  }
   296  func (d *MaxHistoryMockDriver) Delete(key string) (*rspb.Release, error) {
   297  	return nil, errMaxHistoryMockDriverSomethingHappened
   298  }
   299  func (d *MaxHistoryMockDriver) Get(key string) (*rspb.Release, error) {
   300  	return d.Driver.Get(key)
   301  }
   302  func (d *MaxHistoryMockDriver) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
   303  	return d.Driver.List(filter)
   304  }
   305  func (d *MaxHistoryMockDriver) Query(labels map[string]string) ([]*rspb.Release, error) {
   306  	return d.Driver.Query(labels)
   307  }
   308  func (d *MaxHistoryMockDriver) Name() string {
   309  	return d.Driver.Name()
   310  }
   311  
   312  func TestMaxHistoryErrorHandling(t *testing.T) {
   313  	//func TestStorageRemoveLeastRecentWithError(t *testing.T) {
   314  	storage := Init(NewMaxHistoryMockDriver(driver.NewMemory()))
   315  	storage.Log = t.Logf
   316  
   317  	storage.MaxHistory = 1
   318  
   319  	const name = "angry-bird"
   320  
   321  	// setup storage with test releases
   322  	setup := func() {
   323  		// release records
   324  		rls1 := ReleaseTestData{Name: name, Version: 1, Status: rspb.StatusSuperseded}.ToRelease()
   325  
   326  		// create the release records in the storage
   327  		assertErrNil(t.Fatal, storage.Driver.Create(makeKey(rls1.Name, rls1.Version), rls1), "Storing release 'angry-bird' (v1)")
   328  	}
   329  	setup()
   330  
   331  	rls2 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusSuperseded}.ToRelease()
   332  	wantErr := errMaxHistoryMockDriverSomethingHappened
   333  	gotErr := storage.Create(rls2)
   334  	if !errors.Is(gotErr, wantErr) {
   335  		t.Fatalf("Storing release 'angry-bird' (v2) should return the error %#v, but returned %#v", wantErr, gotErr)
   336  	}
   337  }
   338  
   339  func TestStorageRemoveLeastRecent(t *testing.T) {
   340  	storage := Init(driver.NewMemory())
   341  	storage.Log = t.Logf
   342  
   343  	// Make sure that specifying this at the outset doesn't cause any bugs.
   344  	storage.MaxHistory = 10
   345  
   346  	const name = "angry-bird"
   347  
   348  	// setup storage with test releases
   349  	setup := func() {
   350  		// release records
   351  		rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.StatusSuperseded}.ToRelease()
   352  		rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusSuperseded}.ToRelease()
   353  		rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.StatusSuperseded}.ToRelease()
   354  		rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.StatusDeployed}.ToRelease()
   355  
   356  		// create the release records in the storage
   357  		assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)")
   358  		assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)")
   359  		assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)")
   360  		assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)")
   361  	}
   362  	setup()
   363  
   364  	// Because we have not set a limit, we expect 4.
   365  	expect := 4
   366  	if hist, err := storage.History(name); err != nil {
   367  		t.Fatal(err)
   368  	} else if len(hist) != expect {
   369  		t.Fatalf("expected %d items in history, got %d", expect, len(hist))
   370  	}
   371  
   372  	storage.MaxHistory = 3
   373  	rls5 := ReleaseTestData{Name: name, Version: 5, Status: rspb.StatusDeployed}.ToRelease()
   374  	assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'angry-bird' (v5)")
   375  
   376  	// On inserting the 5th record, we expect two records to be pruned from history.
   377  	hist, err := storage.History(name)
   378  	if err != nil {
   379  		t.Fatal(err)
   380  	} else if len(hist) != storage.MaxHistory {
   381  		for _, item := range hist {
   382  			t.Logf("%s %v", item.Name, item.Version)
   383  		}
   384  		t.Fatalf("expected %d items in history, got %d", storage.MaxHistory, len(hist))
   385  	}
   386  
   387  	// We expect the existing records to be 3, 4, and 5.
   388  	for i, item := range hist {
   389  		v := item.Version
   390  		if expect := i + 3; v != expect {
   391  			t.Errorf("Expected release %d, got %d", expect, v)
   392  		}
   393  	}
   394  }
   395  
   396  func TestStorageDoNotDeleteDeployed(t *testing.T) {
   397  	storage := Init(driver.NewMemory())
   398  	storage.Log = t.Logf
   399  	storage.MaxHistory = 3
   400  
   401  	const name = "angry-bird"
   402  
   403  	// setup storage with test releases
   404  	setup := func() {
   405  		// release records
   406  		rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.StatusSuperseded}.ToRelease()
   407  		rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusDeployed}.ToRelease()
   408  		rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.StatusFailed}.ToRelease()
   409  		rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.StatusFailed}.ToRelease()
   410  
   411  		// create the release records in the storage
   412  		assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)")
   413  		assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)")
   414  		assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)")
   415  		assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)")
   416  	}
   417  	setup()
   418  
   419  	rls5 := ReleaseTestData{Name: name, Version: 5, Status: rspb.StatusFailed}.ToRelease()
   420  	assertErrNil(t.Fatal, storage.Create(rls5), "Storing release 'angry-bird' (v5)")
   421  
   422  	// On inserting the 5th record, we expect a total of 3 releases, but we expect version 2
   423  	// (the only deployed release), to still exist
   424  	hist, err := storage.History(name)
   425  	if err != nil {
   426  		t.Fatal(err)
   427  	} else if len(hist) != storage.MaxHistory {
   428  		for _, item := range hist {
   429  			t.Logf("%s %v", item.Name, item.Version)
   430  		}
   431  		t.Fatalf("expected %d items in history, got %d", storage.MaxHistory, len(hist))
   432  	}
   433  
   434  	expectedVersions := map[int]bool{
   435  		2: true,
   436  		4: true,
   437  		5: true,
   438  	}
   439  
   440  	for _, item := range hist {
   441  		if !expectedVersions[item.Version] {
   442  			t.Errorf("Release version %d, found when not expected", item.Version)
   443  		}
   444  	}
   445  }
   446  
   447  func TestStorageLast(t *testing.T) {
   448  	storage := Init(driver.NewMemory())
   449  
   450  	const name = "angry-bird"
   451  
   452  	// Set up storage with test releases.
   453  	setup := func() {
   454  		// release records
   455  		rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.StatusSuperseded}.ToRelease()
   456  		rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusSuperseded}.ToRelease()
   457  		rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.StatusSuperseded}.ToRelease()
   458  		rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.StatusFailed}.ToRelease()
   459  
   460  		// create the release records in the storage
   461  		assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)")
   462  		assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)")
   463  		assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)")
   464  		assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)")
   465  	}
   466  
   467  	setup()
   468  
   469  	h, err := storage.Last(name)
   470  	if err != nil {
   471  		t.Fatalf("Failed to query for release history (%q): %s\n", name, err)
   472  	}
   473  
   474  	if h.Version != 4 {
   475  		t.Errorf("Expected revision 4, got %d", h.Version)
   476  	}
   477  }
   478  
   479  // TestUpgradeInitiallyFailedRelease tests a case when there are no deployed release yet, but history limit has been
   480  // reached: the has-no-deployed-releases error should not occur in such case.
   481  func TestUpgradeInitiallyFailedReleaseWithHistoryLimit(t *testing.T) {
   482  	storage := Init(driver.NewMemory())
   483  	storage.MaxHistory = 4
   484  
   485  	const name = "angry-bird"
   486  
   487  	// setup storage with test releases
   488  	setup := func() {
   489  		// release records
   490  		rls0 := ReleaseTestData{Name: name, Version: 1, Status: rspb.StatusFailed}.ToRelease()
   491  		rls1 := ReleaseTestData{Name: name, Version: 2, Status: rspb.StatusFailed}.ToRelease()
   492  		rls2 := ReleaseTestData{Name: name, Version: 3, Status: rspb.StatusFailed}.ToRelease()
   493  		rls3 := ReleaseTestData{Name: name, Version: 4, Status: rspb.StatusFailed}.ToRelease()
   494  
   495  		// create the release records in the storage
   496  		assertErrNil(t.Fatal, storage.Create(rls0), "Storing release 'angry-bird' (v1)")
   497  		assertErrNil(t.Fatal, storage.Create(rls1), "Storing release 'angry-bird' (v2)")
   498  		assertErrNil(t.Fatal, storage.Create(rls2), "Storing release 'angry-bird' (v3)")
   499  		assertErrNil(t.Fatal, storage.Create(rls3), "Storing release 'angry-bird' (v4)")
   500  
   501  		hist, err := storage.History(name)
   502  		if err != nil {
   503  			t.Fatalf("unexpected error: %s", err)
   504  		}
   505  
   506  		wantHistoryLen := 4
   507  		if len(hist) != wantHistoryLen {
   508  			t.Fatalf("expected history of release %q to contain %d releases, got %d", name, wantHistoryLen, len(hist))
   509  		}
   510  	}
   511  
   512  	setup()
   513  
   514  	rls5 := ReleaseTestData{Name: name, Version: 5, Status: rspb.StatusFailed}.ToRelease()
   515  	err := storage.Create(rls5)
   516  	if err != nil {
   517  		t.Fatalf("Failed to create a new release version: %s", err)
   518  	}
   519  
   520  	hist, err := storage.History(name)
   521  	if err != nil {
   522  		t.Fatalf("unexpected error: %s", err)
   523  	}
   524  
   525  	for i, rel := range hist {
   526  		wantVersion := i + 2
   527  		if rel.Version != wantVersion {
   528  			t.Fatalf("Expected history release %d version to equal %d, got %d", i+1, wantVersion, rel.Version)
   529  		}
   530  
   531  		wantStatus := rspb.StatusFailed
   532  		if rel.Info.Status != wantStatus {
   533  			t.Fatalf("Expected history release %d status to equal %q, got %q", i+1, wantStatus, rel.Info.Status)
   534  		}
   535  	}
   536  }
   537  
   538  type ReleaseTestData struct {
   539  	Name      string
   540  	Version   int
   541  	Manifest  string
   542  	Namespace string
   543  	Status    rspb.Status
   544  }
   545  
   546  func (test ReleaseTestData) ToRelease() *rspb.Release {
   547  	return &rspb.Release{
   548  		Name:      test.Name,
   549  		Version:   test.Version,
   550  		Manifest:  test.Manifest,
   551  		Namespace: test.Namespace,
   552  		Info:      &rspb.Info{Status: test.Status},
   553  	}
   554  }
   555  
   556  func assertErrNil(eh func(args ...interface{}), err error, message string) {
   557  	if err != nil {
   558  		eh(fmt.Sprintf("%s: %q", message, err))
   559  	}
   560  }