github.com/npaton/distribution@v2.3.1-rc.0+incompatible/registry/proxy/scheduler/scheduler_test.go (about) 1 package scheduler 2 3 import ( 4 "encoding/json" 5 "testing" 6 "time" 7 8 "github.com/docker/distribution/context" 9 "github.com/docker/distribution/reference" 10 "github.com/docker/distribution/registry/storage/driver/inmemory" 11 ) 12 13 func testRefs(t *testing.T) (reference.Reference, reference.Reference, reference.Reference) { 14 ref1, err := reference.Parse("testrepo@sha256:aaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 15 if err != nil { 16 t.Fatalf("could not parse reference: %v", err) 17 } 18 19 ref2, err := reference.Parse("testrepo@sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") 20 if err != nil { 21 t.Fatalf("could not parse reference: %v", err) 22 } 23 24 ref3, err := reference.Parse("testrepo@sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc") 25 if err != nil { 26 t.Fatalf("could not parse reference: %v", err) 27 } 28 29 return ref1, ref2, ref3 30 } 31 32 func TestSchedule(t *testing.T) { 33 ref1, ref2, ref3 := testRefs(t) 34 timeUnit := time.Millisecond 35 remainingRepos := map[string]bool{ 36 ref1.String(): true, 37 ref2.String(): true, 38 ref3.String(): true, 39 } 40 41 s := New(context.Background(), inmemory.New(), "/ttl") 42 deleteFunc := func(repoName reference.Reference) error { 43 if len(remainingRepos) == 0 { 44 t.Fatalf("Incorrect expiry count") 45 } 46 _, ok := remainingRepos[repoName.String()] 47 if !ok { 48 t.Fatalf("Trying to remove nonexistant repo: %s", repoName) 49 } 50 t.Log("removing", repoName) 51 delete(remainingRepos, repoName.String()) 52 53 return nil 54 } 55 s.onBlobExpire = deleteFunc 56 err := s.Start() 57 if err != nil { 58 t.Fatalf("Error starting ttlExpirationScheduler: %s", err) 59 } 60 61 s.add(ref1, 3*timeUnit, entryTypeBlob) 62 s.add(ref2, 1*timeUnit, entryTypeBlob) 63 64 func() { 65 s.add(ref3, 1*timeUnit, entryTypeBlob) 66 67 }() 68 69 // Ensure all repos are deleted 70 <-time.After(50 * timeUnit) 71 if len(remainingRepos) != 0 { 72 t.Fatalf("Repositories remaining: %#v", remainingRepos) 73 } 74 } 75 76 func TestRestoreOld(t *testing.T) { 77 ref1, ref2, _ := testRefs(t) 78 remainingRepos := map[string]bool{ 79 ref1.String(): true, 80 ref2.String(): true, 81 } 82 83 deleteFunc := func(r reference.Reference) error { 84 if r.String() == ref1.String() && len(remainingRepos) == 2 { 85 t.Errorf("ref1 should be removed first") 86 } 87 _, ok := remainingRepos[r.String()] 88 if !ok { 89 t.Fatalf("Trying to remove nonexistant repo: %s", r) 90 } 91 delete(remainingRepos, r.String()) 92 return nil 93 } 94 95 timeUnit := time.Millisecond 96 serialized, err := json.Marshal(&map[string]schedulerEntry{ 97 ref1.String(): { 98 Expiry: time.Now().Add(1 * timeUnit), 99 Key: ref1.String(), 100 EntryType: 0, 101 }, 102 ref2.String(): { 103 Expiry: time.Now().Add(-3 * timeUnit), // TTL passed, should be removed first 104 Key: ref2.String(), 105 EntryType: 0, 106 }, 107 }) 108 if err != nil { 109 t.Fatalf("Error serializing test data: %s", err.Error()) 110 } 111 112 ctx := context.Background() 113 pathToStatFile := "/ttl" 114 fs := inmemory.New() 115 err = fs.PutContent(ctx, pathToStatFile, serialized) 116 if err != nil { 117 t.Fatal("Unable to write serialized data to fs") 118 } 119 s := New(context.Background(), fs, "/ttl") 120 s.onBlobExpire = deleteFunc 121 err = s.Start() 122 if err != nil { 123 t.Fatalf("Error starting ttlExpirationScheduler: %s", err) 124 } 125 126 <-time.After(50 * timeUnit) 127 if len(remainingRepos) != 0 { 128 t.Fatalf("Repositories remaining: %#v", remainingRepos) 129 } 130 } 131 132 func TestStopRestore(t *testing.T) { 133 ref1, ref2, _ := testRefs(t) 134 135 timeUnit := time.Millisecond 136 remainingRepos := map[string]bool{ 137 ref1.String(): true, 138 ref2.String(): true, 139 } 140 141 deleteFunc := func(r reference.Reference) error { 142 delete(remainingRepos, r.String()) 143 return nil 144 } 145 146 fs := inmemory.New() 147 pathToStateFile := "/ttl" 148 s := New(context.Background(), fs, pathToStateFile) 149 s.onBlobExpire = deleteFunc 150 151 err := s.Start() 152 if err != nil { 153 t.Fatalf(err.Error()) 154 } 155 s.add(ref1, 300*timeUnit, entryTypeBlob) 156 s.add(ref2, 100*timeUnit, entryTypeBlob) 157 158 // Start and stop before all operations complete 159 // state will be written to fs 160 s.Stop() 161 time.Sleep(10 * time.Millisecond) 162 163 // v2 will restore state from fs 164 s2 := New(context.Background(), fs, pathToStateFile) 165 s2.onBlobExpire = deleteFunc 166 err = s2.Start() 167 if err != nil { 168 t.Fatalf("Error starting v2: %s", err.Error()) 169 } 170 171 <-time.After(500 * timeUnit) 172 if len(remainingRepos) != 0 { 173 t.Fatalf("Repositories remaining: %#v", remainingRepos) 174 } 175 176 } 177 178 func TestDoubleStart(t *testing.T) { 179 s := New(context.Background(), inmemory.New(), "/ttl") 180 err := s.Start() 181 if err != nil { 182 t.Fatalf("Unable to start scheduler") 183 } 184 err = s.Start() 185 if err == nil { 186 t.Fatalf("Scheduler started twice without error") 187 } 188 }