github.com/decred/politeia@v1.4.0/politeiad/backend/gitbe/gitbe_test.go (about)

     1  // Copyright (c) 2017-2020 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package gitbe
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/sha1"
    10  	"crypto/sha256"
    11  	"encoding/base64"
    12  	"encoding/hex"
    13  	"errors"
    14  	"fmt"
    15  	"os"
    16  	"path/filepath"
    17  	"reflect"
    18  	"strconv"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/davecgh/go-spew/spew"
    23  	"github.com/decred/dcrd/chaincfg/v3"
    24  	pd "github.com/decred/politeia/politeiad/api/v1"
    25  	"github.com/decred/politeia/politeiad/api/v1/mime"
    26  	"github.com/decred/politeia/politeiad/backend"
    27  	"github.com/decred/politeia/util"
    28  	"github.com/decred/slog"
    29  )
    30  
    31  func validateMD(got, want *backend.RecordMetadata) error {
    32  	if got.Iteration != want.Iteration+1 ||
    33  		got.Status != backend.MDStatusVetted ||
    34  		want.Status != backend.MDStatusUnvetted ||
    35  		got.Merkle != want.Merkle ||
    36  		got.Token != want.Token {
    37  		return fmt.Errorf("unexpected rm got %v, wanted %v",
    38  			spew.Sdump(*got), spew.Sdump(*want))
    39  	}
    40  
    41  	return nil
    42  }
    43  
    44  func TestExtendUnextend(t *testing.T) {
    45  	sha1Digest := make([]byte, sha1.Size)
    46  	for i := 0; i < sha1.Size; i++ {
    47  		sha1Digest[i] = byte(i)
    48  	}
    49  
    50  	sha256ExtendDigest := extendSHA1(sha1Digest)
    51  	sha256UnextendDigest := unextendSHA256(sha256ExtendDigest)
    52  
    53  	if !bytes.Equal(sha1Digest, sha256UnextendDigest) {
    54  		t.Fatalf("unextend")
    55  	}
    56  }
    57  
    58  func createTextFile(fileName string) (backend.File, error) {
    59  	r, err := util.Random(64)
    60  	if err != nil {
    61  		return backend.File{}, err
    62  	}
    63  
    64  	payload := hex.EncodeToString(r)
    65  	digest := hex.EncodeToString(util.Digest([]byte(payload)))
    66  	// We expect base64 encoded content
    67  	b64 := base64.StdEncoding.EncodeToString([]byte(payload))
    68  
    69  	return backend.File{
    70  		Name:    fileName,
    71  		MIME:    mime.DetectMimeType([]byte(payload)),
    72  		Digest:  digest,
    73  		Payload: b64,
    74  	}, nil
    75  }
    76  
    77  func TestAnchorWithCommits(t *testing.T) {
    78  	log := slog.NewBackend(&testWriter{t}).Logger("TEST")
    79  	UseLogger(log)
    80  
    81  	dir, err := os.MkdirTemp("", "politeia.test")
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	defer os.RemoveAll(dir)
    86  
    87  	// Initialize stuff we need
    88  	g, err := New(chaincfg.TestNet3Params(), dir, "", "", nil,
    89  		testing.Verbose(), "")
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  	g.test = true
    94  
    95  	// Create 5 unvetted records
    96  	propCount := 5
    97  	fileCount := 3
    98  	t.Logf("===== CREATE %v RECORDS WITH %v FILES =====", propCount,
    99  		fileCount)
   100  	rm := make([]*backend.RecordMetadata, propCount)
   101  	allFiles := make([][]backend.File, propCount)
   102  	for i := 0; i < propCount; i++ {
   103  		name := fmt.Sprintf("record%v", i)
   104  		files := make([]backend.File, 0, fileCount)
   105  		for j := 0; j < fileCount; j++ {
   106  			file, err := createTextFile(name + "_" + strconv.Itoa(j))
   107  			if err != nil {
   108  				t.Fatal(err)
   109  			}
   110  			files = append(files, file)
   111  		}
   112  		allFiles[i] = files
   113  
   114  		rm[i], err = g.New([]backend.MetadataStream{{
   115  			ID:      0, // XXX
   116  			Payload: "this is metadata",
   117  		}}, files)
   118  		if err != nil {
   119  			t.Fatal(err)
   120  		}
   121  	}
   122  
   123  	// Expect propCount + master branches in unvetted
   124  	branches, err := g.git(g.unvetted, "branch")
   125  	if err != nil {
   126  		t.Fatalf("%v", err)
   127  	}
   128  	found := 0
   129  	master := 0
   130  	for _, branch := range branches {
   131  		for _, v := range rm {
   132  			s := strings.Trim(branch, " \n")
   133  			if s == v.Token {
   134  				found++
   135  				break
   136  			}
   137  			if strings.HasSuffix(s, "master") {
   138  				master++
   139  				break
   140  			}
   141  		}
   142  	}
   143  	if found != propCount || master != 1 {
   144  		t.Fatalf("unexpected props got %v wanted %v master %v",
   145  			found, propCount, master)
   146  	}
   147  
   148  	// Read all MDs from the branches and call getunvetted to verify
   149  	// integrity
   150  	for k, v := range rm {
   151  		token, err := hex.DecodeString(v.Token)
   152  		if err != nil {
   153  			t.Fatal(err)
   154  		}
   155  		pru, err := g.GetUnvetted(token)
   156  		if err != nil {
   157  			t.Fatalf("%v", err)
   158  		}
   159  		if !reflect.DeepEqual(&pru.RecordMetadata, rm[k]) {
   160  			t.Fatalf("unexpected rm got %v, wanted %v",
   161  				spew.Sdump(pru.RecordMetadata),
   162  				spew.Sdump(rm[k]))
   163  		}
   164  		if !reflect.DeepEqual(pru.Files, allFiles[k]) {
   165  			t.Fatalf("unexpected payload got %v, wanted %v",
   166  				spew.Sdump(pru.Files), spew.Sdump(allFiles[k]))
   167  		}
   168  	}
   169  
   170  	// Expect 1 branch in vetted
   171  	branches, err = g.git(g.vetted, "branch")
   172  	if err != nil {
   173  		t.Fatalf("%v", err)
   174  	}
   175  	if len(branches) != 1 {
   176  		t.Fatalf("too many branches on master got %v want 1",
   177  			len(branches))
   178  	}
   179  
   180  	// Vet 1 of the records
   181  	t.Logf("===== VET RECORD 1 =====")
   182  	emptyMD := []backend.MetadataStream{}
   183  	token, err := hex.DecodeString(rm[1].Token)
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	record, err := g.SetUnvettedStatus(token,
   188  		backend.MDStatusVetted, emptyMD, emptyMD)
   189  	if err != nil {
   190  		t.Fatal(err)
   191  	}
   192  	if record.RecordMetadata.Status != backend.MDStatusVetted {
   193  		t.Fatalf("unexpected status: got %v wanted %v",
   194  			record.RecordMetadata.Status, backend.MDStatusVetted)
   195  	}
   196  	//Get it as well to validate the GetVetted call
   197  	pru, err := g.GetVetted(token, "")
   198  	if err != nil {
   199  		t.Fatal(err)
   200  	}
   201  	psrG := &pru.RecordMetadata
   202  	if psrG.Status != backend.MDStatusVetted {
   203  		t.Fatalf("unexpected status: got %v wanted %v", psrG.Status,
   204  			backend.MDStatusVetted)
   205  	}
   206  
   207  	err = validateMD(psrG, rm[1])
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  	if !reflect.DeepEqual(pru.Files, allFiles[1]) {
   212  		t.Fatalf("unexpected payload got %v, wanted %v",
   213  			spew.Sdump(pru.Files), spew.Sdump(allFiles[1]))
   214  	}
   215  
   216  	// Anchor all repos
   217  	t.Logf("===== ANCHOR =====")
   218  	err = g.anchorAllRepos()
   219  	if err != nil {
   220  		t.Fatal(err)
   221  	}
   222  	// Read unconfirmed and verify content
   223  	unconfirmed, err := g.readUnconfirmedAnchorRecord()
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	if len(unconfirmed.Merkles) != 1 {
   228  		t.Fatalf("invalid merkles len %v", len(unconfirmed.Merkles))
   229  	}
   230  	// Read anchor pointed at by merkle from git log
   231  	var mr [sha256.Size]byte
   232  	copy(mr[:], unconfirmed.Merkles[0])
   233  	anchor, err := g.readAnchorRecord(mr)
   234  	if err != nil {
   235  		t.Fatal(err)
   236  	}
   237  	// Verify last commit
   238  	lastGitDigest, err := g.gitLastDigest(g.vetted)
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  	lastGitDigest = extendSHA1(lastGitDigest)
   243  	la, err := g.readLastAnchorRecord()
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  	if !bytes.Equal(lastGitDigest, la.Last) {
   248  		t.Fatalf("invalid unconfirmed digest got %x wanted %x",
   249  			lastGitDigest, la.Last)
   250  	}
   251  	if anchor.Type != AnchorUnverified {
   252  		t.Fatalf("invalid anchor type %v expected %v", anchor.Type,
   253  			AnchorVerified)
   254  	}
   255  
   256  	// Anchor again and make sure nothing changed
   257  	t.Logf("===== REANCHOR NOTHING TO DO =====")
   258  	err = g.anchorAllRepos()
   259  	if err != nil {
   260  		t.Fatal(err)
   261  	}
   262  	// Read unconfirmed again and verify content
   263  	unconfirmed2, err := g.readUnconfirmedAnchorRecord()
   264  	if err != nil {
   265  		t.Fatal(err)
   266  	}
   267  	if len(unconfirmed2.Merkles) != 1 {
   268  		t.Fatalf("invalid merkles len %v", len(unconfirmed2.Merkles))
   269  	}
   270  	if !reflect.DeepEqual(unconfirmed, unconfirmed2) {
   271  		t.Fatalf("unconfirmed got %v wanted %v",
   272  			spew.Sdump(unconfirmed2),
   273  			spew.Sdump(unconfirmed))
   274  	}
   275  	// Read anchor again pointed at by merkle from git log
   276  	var mr2 [sha256.Size]byte
   277  	copy(mr2[:], unconfirmed.Merkles[0])
   278  	anchor2, err := g.readAnchorRecord(mr2)
   279  	if err != nil {
   280  		t.Fatal(err)
   281  	}
   282  	if !bytes.Equal(mr[:], mr2[:]) {
   283  		t.Fatalf("mr got %x wanted %x", mr2, mr)
   284  	}
   285  	// Verify last commit again
   286  	lastGitDigest2, err := g.gitLastDigest(g.vetted)
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	lastGitDigest2 = extendSHA1(lastGitDigest2)
   291  	la2, err := g.readLastAnchorRecord()
   292  	if err != nil {
   293  		t.Fatal(err)
   294  	}
   295  	if !bytes.Equal(lastGitDigest2, la2.Last) {
   296  		t.Fatalf("invalid unconfirmed digest got %x wanted %x",
   297  			lastGitDigest2, la2.Last)
   298  	}
   299  	if !bytes.Equal(lastGitDigest2, lastGitDigest) {
   300  		t.Fatalf("invalid lastGitDigest got %x wanted %x",
   301  			lastGitDigest2, lastGitDigest)
   302  	}
   303  	if !reflect.DeepEqual(anchor2, anchor) {
   304  		t.Fatalf("invalid anchor got %x wanted %x",
   305  			spew.Sdump(anchor2), spew.Sdump(anchor))
   306  	}
   307  
   308  	// Complete anchor
   309  	t.Logf("===== COMPLETE ANCHOR PROCESS =====")
   310  	err = g.anchorChecker()
   311  	if err != nil {
   312  		t.Fatal(err)
   313  	}
   314  	// Verify that we updated unconfirmed
   315  	unconfirmed, err = g.readUnconfirmedAnchorRecord()
   316  	if err != nil {
   317  		t.Fatal(err)
   318  	}
   319  	if len(unconfirmed.Merkles) != 0 {
   320  		t.Fatalf("invalid merkles len %v", len(unconfirmed.Merkles))
   321  	}
   322  	// Verify that anchor record was updated
   323  	anchor3, err := g.readAnchorRecord(mr)
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  	if anchor3.Type != AnchorVerified {
   328  		t.Fatalf("invalid anchor type %v expected %v", anchor3.Type,
   329  			AnchorVerified)
   330  	}
   331  	// Verify that Merkle was cleared in last anchor record
   332  	la, err = g.readLastAnchorRecord()
   333  	if err != nil {
   334  		t.Fatal(err)
   335  	}
   336  
   337  	// Drop an anchor to verify that we don't pick up the anchor commit
   338  	t.Logf("===== DROP ANCHOR ON TOP OF ANCHOR =====")
   339  	lastGitDigest, err = g.gitLastDigest(g.vetted)
   340  	if err != nil {
   341  		t.Fatal(err)
   342  	}
   343  	err = g.anchorAllRepos()
   344  	if err != nil {
   345  		t.Fatal(err)
   346  	}
   347  	lastGitDigestAfter, err := g.gitLastDigest(g.vetted)
   348  	if err != nil {
   349  		t.Fatal(err)
   350  	}
   351  	if !bytes.Equal(lastGitDigest, lastGitDigestAfter) {
   352  		t.Fatalf("git digest got %x wanted %x",
   353  			lastGitDigest, lastGitDigestAfter)
   354  	}
   355  
   356  	// Interleave incomplete anchors:
   357  	//	vet -> anchor1 -> vet -> anchor2 -> confirm
   358  
   359  	// Vet + anchor
   360  	t.Logf("===== INTERLEAVE ANCHORS =====")
   361  	token2, err := hex.DecodeString(rm[2].Token)
   362  	if err != nil {
   363  		t.Fatal(err)
   364  	}
   365  	_, err = g.SetUnvettedStatus(token2, backend.MDStatusVetted,
   366  		emptyMD, emptyMD)
   367  	if err != nil {
   368  		t.Fatal(err)
   369  	}
   370  	err = g.anchorAllRepos()
   371  	if err != nil {
   372  		t.Fatal(err)
   373  	}
   374  
   375  	// Vet + anchor
   376  	token0, err := hex.DecodeString(rm[0].Token)
   377  	if err != nil {
   378  		t.Fatal(err)
   379  	}
   380  	_, err = g.SetUnvettedStatus(token0, backend.MDStatusVetted,
   381  		emptyMD, emptyMD)
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  	err = g.anchorAllRepos()
   386  	if err != nil {
   387  		t.Fatal(err)
   388  	}
   389  
   390  	// Complete anchor
   391  	t.Logf("===== COMPLETE INTERLEAVED ANCHOR PROCESS =====")
   392  	err = g.anchorChecker()
   393  	if err != nil {
   394  		t.Fatal(err)
   395  	}
   396  
   397  	// Drop an anchor to verify that we don't pick up the anchor commit
   398  	t.Logf("===== DROP ANCHOR ON TOP OF ANCHOR 2 =====")
   399  	err = g.anchorAllRepos()
   400  	if err != nil {
   401  		t.Fatal(err)
   402  	}
   403  }
   404  
   405  func TestFilePathVersion(t *testing.T) {
   406  	dir, err := os.MkdirTemp("", "pathversion")
   407  	if err != nil {
   408  		t.Fatal(err)
   409  	}
   410  	defer os.RemoveAll(dir)
   411  
   412  	t.Logf("dir: %v", dir)
   413  	d, err := _joinLatest(dir)
   414  	if !errors.Is(err, backend.ErrRecordNotFound) {
   415  		t.Fatal(err)
   416  	}
   417  	if d != "" {
   418  		t.Fatalf("expected \"\", got %v", d)
   419  	}
   420  
   421  	// Create version 0 and check again
   422  	newDir := pijoin(dir, "0")
   423  	err = os.MkdirAll(newDir, 0766)
   424  	if err != nil {
   425  		t.Fatal(err)
   426  	}
   427  	testDir := joinLatest(dir)
   428  	// Abuse filepath.Split by pretending 0 is a file
   429  	splitDir, splitFile := filepath.Split(testDir)
   430  	if splitDir != dir+"/" {
   431  		t.Fatalf("invalid dir, expected %v, got %v", dir+"/", splitDir)
   432  	}
   433  	if splitFile != "0" {
   434  		t.Fatalf("invalid dir, expected 0, got %v", splitFile)
   435  	}
   436  
   437  	// Create version 1 and check again
   438  	newDir = pijoin(dir, "1")
   439  	err = os.MkdirAll(newDir, 0766)
   440  	if err != nil {
   441  		t.Fatal(err)
   442  	}
   443  	testDir = joinLatest(dir)
   444  	// Abuse filepath.Split by pretending 1 is a file
   445  	splitDir, splitFile = filepath.Split(testDir)
   446  	if splitDir != dir+"/" {
   447  		t.Fatalf("invalid dir, expected %v, got %v", dir+"/", splitDir)
   448  	}
   449  	if splitFile != "1" {
   450  		t.Fatalf("invalid dir, expected 1, got %v", splitFile)
   451  	}
   452  
   453  	// Create version 33 and check again
   454  	newDir = pijoin(dir, "33")
   455  	err = os.MkdirAll(newDir, 0766)
   456  	if err != nil {
   457  		t.Fatal(err)
   458  	}
   459  	testDir = joinLatest(dir)
   460  	// Abuse filepath.Split by pretending 33 is a file
   461  	splitDir, splitFile = filepath.Split(testDir)
   462  	if splitDir != dir+"/" {
   463  		t.Fatalf("invalid dir, expected %v, got %v", dir+"/", splitDir)
   464  	}
   465  	if splitFile != "33" {
   466  		t.Fatalf("invalid dir, expected 33, got %v", splitFile)
   467  	}
   468  }
   469  
   470  func TestUpdateReadme(t *testing.T) {
   471  	dir, err := os.MkdirTemp("", "politeia.test")
   472  	if err != nil {
   473  		t.Fatal(err)
   474  	}
   475  	defer os.RemoveAll(dir)
   476  
   477  	g, err := New(chaincfg.TestNet3Params(), dir, "", "", nil,
   478  		testing.Verbose(), "")
   479  	if err != nil {
   480  		t.Fatal(err)
   481  	}
   482  	g.test = true
   483  
   484  	updatedReadmeContent := "Updated Readme Content!! \n"
   485  	err = g.UpdateReadme(updatedReadmeContent)
   486  	if err != nil {
   487  		t.Fatal(err)
   488  	}
   489  
   490  	unvettedReadmePath := filepath.Join(g.unvetted, "README.md")
   491  	unvettedReadmeContent, err := os.ReadFile(unvettedReadmePath)
   492  	if err != nil {
   493  		t.Fatal(err)
   494  	}
   495  	unvettedReadmeString := string(unvettedReadmeContent)
   496  	if unvettedReadmeString != updatedReadmeContent {
   497  		t.Fatalf("Expected README.md content to be: %s \n but got: %s ",
   498  			updatedReadmeContent,
   499  			unvettedReadmeString)
   500  	}
   501  
   502  	vettedReadmePath := filepath.Join(g.vetted, "README.md")
   503  	vettedReadmeContent, err := os.ReadFile(vettedReadmePath)
   504  	if err != nil {
   505  		t.Fatal(err)
   506  	}
   507  	vettedReadmeString := string(vettedReadmeContent)
   508  	if vettedReadmeString != updatedReadmeContent {
   509  		t.Fatalf("Expected README.md content to be: %s \n but got: %s ",
   510  			updatedReadmeContent,
   511  			vettedReadmeString)
   512  	}
   513  
   514  	branches, err := g.git(g.unvetted, "branch")
   515  	if err != nil {
   516  		t.Fatalf("%v", err)
   517  	}
   518  	if len(branches) != 1 {
   519  		t.Fatalf("Expected 1 branch in unvetted repo, but it got %v",
   520  			len(branches))
   521  	}
   522  	if !strings.HasSuffix(branches[0], "master") {
   523  		t.Fatalf("The only branch in the vetted repo should be master")
   524  	}
   525  
   526  	branches, err = g.git(g.vetted, "branch")
   527  	if err != nil {
   528  		t.Fatalf("%v", err)
   529  	}
   530  	if len(branches) != 1 {
   531  		t.Fatalf("Expected 1 branch in vetted repo, but it got %v",
   532  			len(branches))
   533  	}
   534  	if !strings.HasSuffix(branches[0], "master") {
   535  		t.Fatalf("The only branch in the vetted repo should be master")
   536  	}
   537  
   538  	// Trying to update readme to the same content returns an error, but does
   539  	// not add any new branches.
   540  	err = g.UpdateReadme(updatedReadmeContent)
   541  	if err == nil {
   542  		t.Fatal("Updating readme the current content should return an error")
   543  	}
   544  
   545  	branches, err = g.git(g.unvetted, "branch")
   546  	if err != nil {
   547  		t.Fatalf("%v", err)
   548  	}
   549  	if len(branches) != 1 {
   550  		t.Fatalf("Expected 1 branch in unvetted repo, but it got %v",
   551  			len(branches))
   552  	}
   553  	if !strings.HasSuffix(branches[0], "master") {
   554  		t.Fatalf("The only branch in the vetted repo should be master")
   555  	}
   556  
   557  	branches, err = g.git(g.vetted, "branch")
   558  	if err != nil {
   559  		t.Fatalf("%v", err)
   560  	}
   561  	if len(branches) != 1 {
   562  		t.Fatalf("Expected 1 branch in vetted repo, but it got %v",
   563  			len(branches))
   564  	}
   565  	if !strings.HasSuffix(branches[0], "master") {
   566  		t.Fatalf("The only branch in the vetted repo should be master")
   567  	}
   568  }
   569  
   570  func updateTokenPrefixLength(length int) {
   571  	pd.TokenPrefixLength = length
   572  }
   573  
   574  func TestTokenPrefixGeneration(t *testing.T) {
   575  	originalPrefixLength := pd.TokenPrefixLength
   576  	updateTokenPrefixLength(1)
   577  	defer updateTokenPrefixLength(originalPrefixLength)
   578  
   579  	dir, err := os.MkdirTemp("", "politeia.test")
   580  	if err != nil {
   581  		t.Fatal(err)
   582  	}
   583  	defer os.RemoveAll(dir)
   584  
   585  	g, err := New(chaincfg.TestNet3Params(), dir, "", "", nil,
   586  		testing.Verbose(), "")
   587  	if err != nil {
   588  		t.Fatal(err)
   589  	}
   590  	g.test = true
   591  
   592  	files := make([]backend.File, 0, 1)
   593  	file, err := createTextFile("randomFileName")
   594  	if err != nil {
   595  		t.Fatal(err)
   596  	}
   597  	files = append(files, file)
   598  
   599  	// Since we use a prefix length of 1 in test mode, only 16 unique tokens
   600  	// should be able to be generated.
   601  	for i := 0; i < 16; i++ {
   602  		_, err = g.New([]backend.MetadataStream{{
   603  			ID:      0,
   604  			Payload: "this is metadata",
   605  		}}, files)
   606  
   607  		if err != nil {
   608  			t.Fatalf("Error creating less than 16 new records: %v", err)
   609  		}
   610  	}
   611  
   612  	_, err = g.New([]backend.MetadataStream{{
   613  		ID:      0,
   614  		Payload: "this is metadata",
   615  	}}, files)
   616  
   617  	if err == nil {
   618  		t.Fatalf("Should only be able to create 16 tokens with unique " +
   619  			"prefix of length 1, but was able to create 17")
   620  	}
   621  
   622  	// Here we test that the getUnvettedTokens and getVettedTokens methods
   623  	// work as expected.
   624  	g.Lock()
   625  	unvettedTokens, err := g.getUnvettedTokens()
   626  	g.Unlock()
   627  	if err != nil {
   628  		t.Fatal(err)
   629  	}
   630  	if len(unvettedTokens) != 16 {
   631  		t.Fatalf("There should be 16 unvetted tokens, but there are %v",
   632  			len(unvettedTokens))
   633  	}
   634  
   635  	// We update the status of the first two records to vetted.
   636  	emptyMD := []backend.MetadataStream{}
   637  	token, err := hex.DecodeString(unvettedTokens[0])
   638  	if err != nil {
   639  		t.Fatal(err)
   640  	}
   641  	_, err = g.SetUnvettedStatus(token,
   642  		backend.MDStatusVetted, emptyMD, emptyMD)
   643  	if err != nil {
   644  		t.Fatal(err)
   645  	}
   646  	token, err = hex.DecodeString(unvettedTokens[1])
   647  	if err != nil {
   648  		t.Fatal(err)
   649  	}
   650  	_, err = g.SetUnvettedStatus(token,
   651  		backend.MDStatusVetted, emptyMD, emptyMD)
   652  	if err != nil {
   653  		t.Fatal(err)
   654  	}
   655  
   656  	// Since we updated the status of 2 records, there should be 14 unvetted
   657  	// and 2 vetted proposals.
   658  	g.Lock()
   659  	unvettedTokens, err = g.getUnvettedTokens()
   660  	g.Unlock()
   661  	if err != nil {
   662  		t.Fatal(err)
   663  	}
   664  	if len(unvettedTokens) != 14 {
   665  		t.Fatalf("There should be 14 tokens, but there are %v", len(unvettedTokens))
   666  	}
   667  
   668  	g.Lock()
   669  	vettedTokens, err := g.getVettedTokens()
   670  	g.Unlock()
   671  	if err != nil {
   672  		t.Fatal(err)
   673  	}
   674  	if len(vettedTokens) != 2 {
   675  		t.Fatalf("There should be 2 tokens, but there are %v", len(vettedTokens))
   676  	}
   677  
   678  	// Now we test that when creating a new gitbe object on an existing folder,
   679  	// the prefix cache is populated correctly.
   680  	oldPrefixCache := g.prefixCache
   681  	g, err = New(chaincfg.TestNet3Params(), dir, "", "", nil,
   682  		testing.Verbose(), "")
   683  	if err != nil {
   684  		t.Fatal(err)
   685  	}
   686  	g.test = true
   687  
   688  	if len(oldPrefixCache) != len(g.prefixCache) {
   689  		t.Fatalf("The prefix cache does not contain the correct amount of" +
   690  			" prefixes")
   691  	}
   692  	for prefix := range oldPrefixCache {
   693  		if _, ok := g.prefixCache[prefix]; !ok {
   694  			t.Fatalf("The prefix map does not contain an expected prefix: %v",
   695  				prefix)
   696  		}
   697  	}
   698  }