github.com/quay/claircore@v1.5.28/indexer/controller/controller_test.go (about)

     1  package controller
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"testing"
     8  
     9  	"github.com/golang/mock/gomock"
    10  	"github.com/google/go-cmp/cmp"
    11  	"github.com/quay/zlog"
    12  
    13  	"github.com/quay/claircore"
    14  	indexer "github.com/quay/claircore/test/mock/indexer"
    15  )
    16  
    17  // TestControllerIndexError confirms the state machine does the correct thing
    18  // when a stateFunc returns an error.
    19  //
    20  // The controller starts in checkManifest state. We will have the mock fail the
    21  // call to s.Store.ManifestScanned forcing checkManifest to return an error and
    22  // evaluate our scanner's state afterwards.
    23  func TestControllerIndexerError(t *testing.T) {
    24  	ctx := context.Background()
    25  	tt := []struct {
    26  		mock func(t *testing.T) (indexer.Store, indexer.FetchArena)
    27  		name string
    28  	}{
    29  		{
    30  			name: "CheckManifest",
    31  			mock: func(t *testing.T) (indexer.Store, indexer.FetchArena) {
    32  				ctrl := gomock.NewController(t)
    33  				store := indexer.NewMockStore(ctrl)
    34  				fa := indexer.NewMockFetchArena(ctrl)
    35  				realizer := indexer.NewMockRealizer(ctrl)
    36  				realizer.EXPECT().Close()
    37  				fa.EXPECT().Realizer(gomock.Any()).Return(realizer)
    38  
    39  				// let call to SetIndexReport in checkManifest pass
    40  				store.EXPECT().SetIndexReport(gomock.Any(), gomock.Any()).Return(nil)
    41  
    42  				// lets fail call to s.Store.ManifestScanned in check manifest - checkManifest will now return an error and
    43  				// if all is well scanner should hijack FSM flow into entering scanError state
    44  				store.EXPECT().ManifestScanned(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, fmt.Errorf("expected failure for test"))
    45  
    46  				return store, fa
    47  			},
    48  		},
    49  		{
    50  			name: "SetIndexReport",
    51  			mock: func(t *testing.T) (indexer.Store, indexer.FetchArena) {
    52  				ctrl := gomock.NewController(t)
    53  				store := indexer.NewMockStore(ctrl)
    54  				fa := indexer.NewMockFetchArena(ctrl)
    55  				realizer := indexer.NewMockRealizer(ctrl)
    56  				realizer.EXPECT().Close()
    57  				fa.EXPECT().Realizer(gomock.Any()).Return(realizer)
    58  
    59  				store.EXPECT().PersistManifest(gomock.Any(), gomock.Any()).Return(nil)
    60  				store.EXPECT().ManifestScanned(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil)
    61  
    62  				// fail the call to s.Store.SetIndexReport after processing for state CheckManifest
    63  				store.EXPECT().SetIndexReport(gomock.Any(), gomock.Any()).Return(fmt.Errorf("expected failure in SetIndexReport"))
    64  
    65  				return store, fa
    66  			},
    67  		},
    68  	}
    69  
    70  	for _, table := range tt {
    71  		t.Run(table.name, func(t *testing.T) {
    72  			ctx := zlog.Test(ctx, t)
    73  			store, fa := table.mock(t)
    74  			c := New(&indexer.Options{
    75  				Store:      store,
    76  				FetchArena: fa,
    77  			})
    78  
    79  			_, err := c.Index(ctx, &claircore.Manifest{})
    80  			if errors.Is(err, nil) {
    81  				t.Error("expected non-nil error")
    82  			}
    83  			if !cmp.Equal(false, c.report.Success) {
    84  				t.Fatal(cmp.Diff(false, c.report.Success))
    85  			}
    86  			if c.report.Err == "" {
    87  				t.Fatalf("expected Err string on index report")
    88  			}
    89  			if !cmp.Equal(IndexError.String(), c.report.State) {
    90  				t.Fatal(cmp.Diff(IndexError.String(), c.report.State))
    91  			}
    92  		})
    93  	}
    94  }
    95  
    96  // TestControllerIndexFinished tests that our state machine does the correct
    97  // thing when it reaches ScanFinished terminal state.
    98  func TestControllerIndexFinished(t *testing.T) {
    99  	ctx := context.Background()
   100  	tt := []struct {
   101  		mock                  func(t *testing.T) (indexer.Store, indexer.FetchArena)
   102  		name                  string
   103  		expectedState         State
   104  		expectedResultSuccess bool
   105  	}{
   106  		{
   107  			name:                  "Success",
   108  			expectedState:         IndexFinished,
   109  			expectedResultSuccess: true,
   110  			mock: func(t *testing.T) (indexer.Store, indexer.FetchArena) {
   111  				ctrl := gomock.NewController(t)
   112  				store := indexer.NewMockStore(ctrl)
   113  				fa := indexer.NewMockFetchArena(ctrl)
   114  				realizer := indexer.NewMockRealizer(ctrl)
   115  
   116  				realizer.EXPECT().Close()
   117  				fa.EXPECT().Realizer(gomock.Any()).Return(realizer)
   118  
   119  				store.EXPECT().SetIndexFinished(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
   120  				store.EXPECT().SetIndexReport(gomock.Any(), gomock.Any()).Return(nil)
   121  
   122  				return store, fa
   123  			},
   124  		},
   125  	}
   126  
   127  	for _, table := range tt {
   128  		t.Run(table.name, func(t *testing.T) {
   129  			ctx := zlog.Test(ctx, t)
   130  			store, fa := table.mock(t)
   131  			c := New(&indexer.Options{
   132  				Store:      store,
   133  				FetchArena: fa,
   134  			})
   135  			c.setState(IndexFinished)
   136  
   137  			c.Index(ctx, &claircore.Manifest{})
   138  			if got, want := c.report.Success, table.expectedResultSuccess; !cmp.Equal(got, want) {
   139  				t.Fatal(cmp.Diff(got, want))
   140  			}
   141  			if got, want := c.currentState, table.expectedState; !cmp.Equal(got, want) {
   142  				t.Fatal(cmp.Diff(got, want))
   143  			}
   144  		})
   145  	}
   146  }