github.com/redhat-appstudio/e2e-tests@v0.0.0-20230619105049-9a422b2094d7/magefiles/utils_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "math/rand" 6 "strings" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/redhat-appstudio/image-controller/pkg/quay" 12 ) 13 14 type QuayClientMock struct { 15 AllRepositories []quay.Repository 16 AllRobotAccounts []quay.RobotAccount 17 AllTags []quay.Tag 18 DeleteRepositoryCalls map[string]bool 19 DeleteRobotAccountCalls map[string]bool 20 DeleteTagCalls map[string]bool 21 TagsOnPage int 22 TagPages int 23 Benchmark bool 24 } 25 26 var _ quay.QuayService = (*QuayClientMock)(nil) 27 28 func (m *QuayClientMock) GetAllRepositories(organization string) ([]quay.Repository, error) { 29 return m.AllRepositories, nil 30 } 31 32 func (m *QuayClientMock) GetAllRobotAccounts(organization string) ([]quay.RobotAccount, error) { 33 return m.AllRobotAccounts, nil 34 } 35 36 func (m *QuayClientMock) DeleteRepository(organization, repoName string) (bool, error) { 37 m.DeleteRepositoryCalls[repoName] = true 38 return true, nil 39 } 40 41 func (m *QuayClientMock) DeleteRobotAccount(organization, robotName string) (bool, error) { 42 m.DeleteRobotAccountCalls[robotName] = true 43 return true, nil 44 } 45 46 func (m *QuayClientMock) GetTagsFromPage(organization, repository string, page int) ([]quay.Tag, bool, error) { 47 if m.Benchmark { 48 time.Sleep(100 * time.Millisecond) // Mock delay for request 49 } 50 if page == m.TagPages { 51 return m.AllTags[(page-1)*m.TagsOnPage : (page * m.TagsOnPage)], false, nil 52 } 53 return m.AllTags[(page-1)*m.TagsOnPage : (page * m.TagsOnPage)], true, nil 54 } 55 56 var deleteTagCallsMutex = sync.RWMutex{} 57 58 func (m *QuayClientMock) DeleteTag(organization, repository, tag string) (bool, error) { 59 if m.Benchmark { 60 time.Sleep(100 * time.Millisecond) // Mock delay for request 61 } 62 deleteTagCallsMutex.Lock() 63 m.DeleteTagCalls[tag] = true 64 deleteTagCallsMutex.Unlock() 65 return true, nil 66 } 67 68 // Dummy functions 69 func (m *QuayClientMock) AddWritePermissionsToRobotAccount(organization, imageRepository, robotAccountName string) error { 70 return nil 71 } 72 73 func (m *QuayClientMock) CreateRepository(r quay.RepositoryRequest) (*quay.Repository, error) { 74 return nil, nil 75 } 76 77 func (m *QuayClientMock) CreateRobotAccount(organization string, robotName string) (*quay.RobotAccount, error) { 78 return nil, nil 79 } 80 81 func (m *QuayClientMock) GetRobotAccount(organization string, robotName string) (*quay.RobotAccount, error) { 82 return nil, nil 83 } 84 85 func TestCleanupQuayReposAndRobots(t *testing.T) { 86 timeFormat := "Mon, 02 Jan 2006 15:04:05 -0700" 87 88 deletedRepos := []quay.Repository{ 89 {Name: "e2e-demos/test-old"}, 90 {Name: "has-e2e/test-old"}, 91 } 92 preservedRepos := []quay.Repository{ 93 {Name: "e2e-demos/test-new"}, 94 {Name: "has-e2e/test-new"}, 95 {Name: "other/test-new"}, 96 {Name: "other/test-old"}, 97 } 98 deletedRobots := []quay.RobotAccount{ 99 {Name: "test-org+e2e-demostest-old", Created: time.Now().Add(-25 * time.Hour).Format(timeFormat)}, 100 {Name: "test-org+has-e2etest-old", Created: time.Now().Add(-25 * time.Hour).Format(timeFormat)}, 101 } 102 preservedRobots := []quay.RobotAccount{ 103 {Name: "test-org+e2e-demostest-new", Created: time.Now().Format(timeFormat)}, 104 {Name: "test-org+has-e2etest-new", Created: time.Now().Format(timeFormat)}, 105 {Name: "test-org+othertest-old", Created: time.Now().Add(-25 * time.Hour).Format(timeFormat)}, 106 {Name: "test-org+othertest-new", Created: time.Now().Format(timeFormat)}, 107 } 108 quayClientMock := QuayClientMock{ 109 AllRepositories: append(deletedRepos, preservedRepos...), 110 AllRobotAccounts: append(deletedRobots, preservedRobots...), 111 DeleteRepositoryCalls: make(map[string]bool), 112 DeleteRobotAccountCalls: make(map[string]bool), 113 } 114 err := cleanupQuayReposAndRobots(&quayClientMock, "test-org") 115 if err != nil { 116 t.Errorf("error during quay cleanup, error: %s", err) 117 } 118 119 for _, repo := range deletedRepos { 120 if !quayClientMock.DeleteRepositoryCalls[repo.Name] { 121 t.Errorf("DeleteRepository() should have been called for '%s'", repo.Name) 122 } 123 } 124 for _, repo := range preservedRepos { 125 if quayClientMock.DeleteRepositoryCalls[repo.Name] { 126 t.Errorf("DeleteRepository() should not have been called for '%s'", repo.Name) 127 } 128 } 129 for _, robot := range deletedRobots { 130 shortName := strings.Split(robot.Name, "+")[1] 131 if !quayClientMock.DeleteRobotAccountCalls[shortName] { 132 t.Errorf("DeleteRobotAccount() should have been called for '%s'", shortName) 133 } 134 } 135 for _, robot := range preservedRobots { 136 shortName := strings.Split(robot.Name, "+")[1] 137 if quayClientMock.DeleteRepositoryCalls[shortName] { 138 t.Errorf("DeleteRobotAccount() should not have been called for '%s'", shortName) 139 } 140 } 141 } 142 143 func TestCleanupQuayTags(t *testing.T) { 144 testOrg := "test-org" 145 testRepo := "test-repo" 146 147 tagsOnPage := 20 148 tagPages := 20 149 150 var deletedTags []quay.Tag 151 var preservedTags []quay.Tag 152 var allTags []quay.Tag 153 154 // Randomly generate slices of deleted and preserved tags 155 for i := 0; i < tagsOnPage*tagPages; i++ { 156 tagName := fmt.Sprintf("tag%d", i) 157 var tag quay.Tag 158 if rand.Intn(2) == 0 { 159 tag = quay.Tag{Name: tagName, StartTS: time.Now().AddDate(0, 0, -8).Unix()} 160 deletedTags = append(deletedTags, tag) 161 } else { 162 tag = quay.Tag{Name: tagName, StartTS: time.Now().Unix()} 163 preservedTags = append(preservedTags, tag) 164 } 165 allTags = append(allTags, tag) 166 } 167 168 quayClientMock := QuayClientMock{ 169 AllTags: allTags, 170 DeleteTagCalls: make(map[string]bool), 171 TagsOnPage: tagsOnPage, 172 TagPages: tagPages, 173 } 174 175 err := cleanupQuayTags(&quayClientMock, testOrg, testRepo) 176 if err != nil { 177 t.Errorf("error during quay tag cleanup, error: %s", err) 178 } 179 180 for _, tag := range deletedTags { 181 if !quayClientMock.DeleteTagCalls[tag.Name] { 182 t.Errorf("DeleteTag() should have been called for '%s'", tag.Name) 183 } 184 } 185 for _, tag := range preservedTags { 186 if quayClientMock.DeleteTagCalls[tag.Name] { 187 t.Errorf("DeleteTag() should not have been called for '%s'", tag.Name) 188 } 189 } 190 } 191 192 func BenchmarkCleanupQuayTags(b *testing.B) { 193 testOrg := "test-org" 194 testRepo := "test-repo" 195 var allTags []quay.Tag 196 197 tagsOnPage := 20 198 tagPages := 20 199 200 // Randomly generate slices of deleted and preserved tags 201 for i := 0; i < tagsOnPage*tagPages; i++ { 202 tagName := fmt.Sprintf("tag%d", i) 203 var tag quay.Tag 204 if rand.Intn(2) == 0 { 205 tag = quay.Tag{Name: tagName, StartTS: time.Now().AddDate(0, 0, -8).Unix()} 206 } else { 207 tag = quay.Tag{Name: tagName, StartTS: time.Now().Unix()} 208 } 209 allTags = append(allTags, tag) 210 } 211 212 quayClientMock := QuayClientMock{ 213 AllTags: allTags, 214 DeleteTagCalls: make(map[string]bool), 215 TagsOnPage: tagsOnPage, 216 TagPages: tagPages, 217 Benchmark: true, 218 } 219 err := cleanupQuayTags(&quayClientMock, testOrg, testRepo) 220 if err != nil { 221 b.Errorf("error during quay tag cleanup, error: %s", err) 222 } 223 }