github.com/sdboyer/gps@v0.16.3/version_queue_test.go (about) 1 package gps 2 3 import ( 4 "fmt" 5 "testing" 6 ) 7 8 // just need a ListVersions method 9 type fakeBridge struct { 10 *bridge 11 vl []Version 12 } 13 14 var fakevl = []Version{ 15 NewVersion("v2.0.0").Is("200rev"), 16 NewVersion("v1.1.1").Is("111rev"), 17 NewVersion("v1.1.0").Is("110rev"), 18 NewVersion("v1.0.0").Is("100rev"), 19 NewBranch("master").Is("masterrev"), 20 } 21 22 func init() { 23 SortForUpgrade(fakevl) 24 } 25 26 func (fb *fakeBridge) ListVersions(id ProjectIdentifier) ([]PairedVersion, error) { 27 return nil, nil 28 } 29 30 func (fb *fakeBridge) listVersions(id ProjectIdentifier) ([]Version, error) { 31 // it's a fixture, we only ever do the one, regardless of id 32 return fb.vl, nil 33 } 34 35 type fakeFailBridge struct { 36 *bridge 37 } 38 39 var errVQ = fmt.Errorf("vqerr") 40 41 func (fb *fakeFailBridge) ListVersions(id ProjectIdentifier) ([]PairedVersion, error) { 42 return nil, nil 43 } 44 45 func (fb *fakeFailBridge) listVersions(id ProjectIdentifier) ([]Version, error) { 46 return nil, errVQ 47 } 48 49 func TestVersionQueueSetup(t *testing.T) { 50 id := ProjectIdentifier{ProjectRoot: ProjectRoot("foo")}.normalize() 51 52 // shouldn't even need to embed a real bridge 53 fb := &fakeBridge{vl: fakevl} 54 ffb := &fakeFailBridge{} 55 56 _, err := newVersionQueue(id, nil, nil, ffb) 57 if err == nil { 58 t.Error("Expected err when providing no prefv or lockv, and injected bridge returns err from ListVersions()") 59 } 60 61 vq, err := newVersionQueue(id, nil, nil, fb) 62 if err != nil { 63 t.Errorf("Unexpected err on vq create: %s", err) 64 } else { 65 if len(vq.pi) != 5 { 66 t.Errorf("Should have five versions from listVersions() when providing no prefv or lockv; got %v:\n\t%s", len(vq.pi), vq.String()) 67 } 68 if !vq.allLoaded { 69 t.Errorf("allLoaded flag should be set, but wasn't") 70 } 71 72 if vq.prefv != nil || vq.lockv != nil { 73 t.Error("lockv and prefv should be nil") 74 } 75 if vq.current() != fakevl[0] { 76 t.Errorf("current should be head of fakevl (%s), got %s", fakevl[0], vq.current()) 77 } 78 } 79 80 lockv := fakevl[0] 81 prefv := fakevl[1] 82 vq, err = newVersionQueue(id, lockv, nil, fb) 83 if err != nil { 84 t.Errorf("Unexpected err on vq create: %s", err) 85 } else { 86 if len(vq.pi) != 1 { 87 t.Errorf("Should have one version when providing only a lockv; got %v:\n\t%s", len(vq.pi), vq.String()) 88 } 89 if vq.allLoaded { 90 t.Errorf("allLoaded flag should not be set") 91 } 92 if vq.lockv != lockv { 93 t.Errorf("lockv should be %s, was %s", lockv, vq.lockv) 94 } 95 if vq.current() != lockv { 96 t.Errorf("current should be lockv (%s), got %s", lockv, vq.current()) 97 } 98 } 99 100 vq, err = newVersionQueue(id, nil, prefv, fb) 101 if err != nil { 102 t.Errorf("Unexpected err on vq create: %s", err) 103 } else { 104 if len(vq.pi) != 1 { 105 t.Errorf("Should have one version when providing only a prefv; got %v:\n\t%s", len(vq.pi), vq.String()) 106 } 107 if vq.allLoaded { 108 t.Errorf("allLoaded flag should not be set") 109 } 110 if vq.prefv != prefv { 111 t.Errorf("prefv should be %s, was %s", prefv, vq.prefv) 112 } 113 if vq.current() != prefv { 114 t.Errorf("current should be prefv (%s), got %s", prefv, vq.current()) 115 } 116 } 117 118 vq, err = newVersionQueue(id, lockv, prefv, fb) 119 if err != nil { 120 t.Errorf("Unexpected err on vq create: %s", err) 121 } else { 122 if len(vq.pi) != 2 { 123 t.Errorf("Should have two versions when providing both a prefv and lockv; got %v:\n\t%s", len(vq.pi), vq.String()) 124 } 125 if vq.allLoaded { 126 t.Errorf("allLoaded flag should not be set") 127 } 128 if vq.prefv != prefv { 129 t.Errorf("prefv should be %s, was %s", prefv, vq.prefv) 130 } 131 if vq.lockv != lockv { 132 t.Errorf("lockv should be %s, was %s", lockv, vq.lockv) 133 } 134 if vq.current() != lockv { 135 t.Errorf("current should be lockv (%s), got %s", lockv, vq.current()) 136 } 137 } 138 } 139 140 func TestVersionQueueAdvance(t *testing.T) { 141 fb := &fakeBridge{vl: fakevl} 142 id := ProjectIdentifier{ProjectRoot: ProjectRoot("foo")}.normalize() 143 144 // First with no prefv or lockv 145 vq, err := newVersionQueue(id, nil, nil, fb) 146 if err != nil { 147 t.Fatalf("Unexpected err on vq create: %s", err) 148 } 149 150 for k, v := range fakevl[1:] { 151 err = vq.advance(fmt.Errorf("advancment fail for %s", fakevl[k])) 152 if err != nil { 153 t.Errorf("error on advancing vq from %s to %s", fakevl[k], v) 154 break 155 } 156 157 if vq.current() != v { 158 t.Errorf("on advance() %v, current should be %s, got %s", k, v, vq.current()) 159 } 160 } 161 162 if vq.isExhausted() { 163 t.Error("should not be exhausted until advancing 'past' the end") 164 } 165 if err = vq.advance(fmt.Errorf("final advance failure")); err != nil { 166 t.Errorf("should not error on advance, even past end, but got %s", err) 167 } 168 169 if !vq.isExhausted() { 170 t.Error("advanced past end, should now report exhaustion") 171 } 172 if vq.current() != nil { 173 t.Error("advanced past end, current should return nil") 174 } 175 176 // now, do one with both a prefv and lockv 177 lockv := fakevl[2] 178 prefv := fakevl[0] 179 vq, err = newVersionQueue(id, lockv, prefv, fb) 180 if vq.String() != "[v1.1.0, v2.0.0]" { 181 t.Error("stringifying vq did not have expected outcome, got", vq.String()) 182 } 183 if vq.isExhausted() { 184 t.Error("can't be exhausted, we aren't even 'allLoaded' yet") 185 } 186 187 err = vq.advance(fmt.Errorf("dequeue lockv")) 188 if err != nil { 189 t.Error("unexpected error when advancing past lockv", err) 190 } else { 191 if vq.current() != prefv { 192 t.Errorf("current should be prefv (%s) after first advance, got %s", prefv, vq.current()) 193 } 194 if len(vq.pi) != 1 { 195 t.Errorf("should have just prefv elem left in vq, but there are %v:\n\t%s", len(vq.pi), vq.String()) 196 } 197 } 198 199 err = vq.advance(fmt.Errorf("dequeue prefv")) 200 if err != nil { 201 t.Error("unexpected error when advancing past prefv", err) 202 } else { 203 if !vq.allLoaded { 204 t.Error("allLoaded should now be true") 205 } 206 if len(vq.pi) != 3 { 207 t.Errorf("should have three remaining versions after removing prefv and lockv, but there are %v:\n\t%s", len(vq.pi), vq.String()) 208 } 209 if vq.current() != fakevl[1] { 210 t.Errorf("current should be first elem of fakevl (%s) after advancing into all, got %s", fakevl[1], vq.current()) 211 } 212 } 213 214 // make sure the queue ordering is still right even with a double-delete 215 vq.advance(nil) 216 if vq.current() != fakevl[3] { 217 t.Errorf("second elem after ListVersions() should be idx 3 of fakevl (%s), got %s", fakevl[3], vq.current()) 218 } 219 vq.advance(nil) 220 if vq.current() != fakevl[4] { 221 t.Errorf("third elem after ListVersions() should be idx 4 of fakevl (%s), got %s", fakevl[4], vq.current()) 222 } 223 vq.advance(nil) 224 if vq.current() != nil || !vq.isExhausted() { 225 t.Error("should be out of versions in the queue") 226 } 227 228 // Make sure we handle things correctly when listVersions adds nothing new 229 fb = &fakeBridge{vl: []Version{lockv, prefv}} 230 vq, err = newVersionQueue(id, lockv, prefv, fb) 231 vq.advance(nil) 232 vq.advance(nil) 233 if vq.current() != nil || !vq.isExhausted() { 234 t.Errorf("should have no versions left, as ListVersions() added nothing new, but still have %s", vq.String()) 235 } 236 err = vq.advance(nil) 237 if err != nil { 238 t.Errorf("should be fine to advance on empty queue, per docs, but got err %s", err) 239 } 240 241 // Also handle it well when advancing calls ListVersions() and it gets an 242 // error 243 vq, err = newVersionQueue(id, lockv, nil, &fakeFailBridge{}) 244 if err != nil { 245 t.Errorf("should not err on creation when preseeded with lockv, but got err %s", err) 246 } 247 err = vq.advance(nil) 248 if err == nil { 249 t.Error("advancing should trigger call to erroring bridge, but no err") 250 } 251 err = vq.advance(nil) 252 if err == nil { 253 t.Error("err should be stored for reuse on any subsequent calls") 254 } 255 256 }