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 }