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  }