github.com/decred/politeia@v1.4.0/politeiad/backendv2/tstorebe/plugins/pi/statusescache_test.go (about)

     1  // Copyright (c) 2021 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 pi
     6  
     7  import (
     8  	"container/list"
     9  	"testing"
    10  
    11  	backend "github.com/decred/politeia/politeiad/backendv2"
    12  	"github.com/decred/politeia/politeiad/plugins/pi"
    13  	"github.com/decred/politeia/politeiad/plugins/ticketvote"
    14  )
    15  
    16  func TestGet(t *testing.T) {
    17  	// Create a new cache
    18  	statuses := proposalStatuses{
    19  		data:    make(map[string]*statusEntry, statusesCacheLimit),
    20  		entries: list.New(),
    21  	}
    22  
    23  	// Setup a cache entry
    24  	token := "key"
    25  	entry := statusEntry{
    26  		propStatus: pi.PropStatusCompleted,
    27  	}
    28  
    29  	// Ensure nil is returned when no cache entry associated with
    30  	// the token exists in cache.
    31  	ce := statuses.get(token)
    32  	if ce != nil {
    33  		t.Errorf("unexpected cache entry; want nil, got '%v'", ce)
    34  	}
    35  
    36  	// Store entry in cache.
    37  	statuses.set(token, entry)
    38  
    39  	// Get entry from cache and verify value
    40  	ce = statuses.get(token)
    41  	if entry.propStatus != ce.propStatus {
    42  		t.Errorf("want proposal status %v, got '%v'", entry.propStatus,
    43  			ce.propStatus)
    44  	}
    45  }
    46  
    47  func TestSet(t *testing.T) {
    48  	// Temporarily set global cache capacity limit to two in order to test
    49  	// adding a new entry to a full cache.
    50  	defaultCacheLimit := statusesCacheLimit
    51  	statusesCacheLimit = 2
    52  	defer func() {
    53  		statusesCacheLimit = defaultCacheLimit
    54  	}()
    55  
    56  	// Create cache
    57  	statuses := proposalStatuses{
    58  		data:    make(map[string]*statusEntry, statusesCacheLimit),
    59  		entries: list.New(),
    60  	}
    61  
    62  	// Setup test tokens and cache entries
    63  	tokens := []string{"45154fb45664714a", "45154fb45664714b"}
    64  	entries := []statusEntry{
    65  		{
    66  			propStatus:   pi.PropStatusActive,
    67  			recordState:  backend.StateUnvetted,
    68  			recordStatus: backend.StatusPublic,
    69  			voteStatus:   ticketvote.VoteStatusRejected,
    70  		},
    71  		{
    72  			propStatus:   pi.PropStatusActive,
    73  			recordState:  backend.StateUnvetted,
    74  			recordStatus: backend.StatusPublic,
    75  			voteStatus:   ticketvote.VoteStatusApproved,
    76  		},
    77  	}
    78  
    79  	// Store entries in cache
    80  	for i, token := range tokens {
    81  		statuses.set(token, entries[i])
    82  	}
    83  
    84  	// Store a third entry, it should replace the oldest entry as the cache
    85  	// is a FIFO data structure.
    86  	tokenThird := "45154fb45664714c"
    87  	entryThird := statusEntry{
    88  		propStatus:   pi.PropStatusClosed,
    89  		recordState:  backend.StateUnvetted,
    90  		recordStatus: backend.StatusPublic,
    91  		voteStatus:   ticketvote.VoteStatusApproved,
    92  	}
    93  	statuses.set(tokenThird, entryThird)
    94  
    95  	// Ensure that the oldest entry was removed, and that the other two entries
    96  	// exist is cache.
    97  	var e *statusEntry
    98  	if e = statuses.get(tokenThird); e == nil {
    99  		t.Errorf("entry not found in cache, token: %v", tokenThird)
   100  	}
   101  	if e = statuses.get(tokens[1]); e == nil {
   102  		t.Errorf("entry not found in cache, token: %v", tokens[1])
   103  	}
   104  	if e = statuses.get(tokens[0]); e != nil {
   105  		t.Errorf("unexpected entry found in cache, token: %v", tokenThird)
   106  	}
   107  
   108  	// Ensure that the cache's tokens list is a FIFO data structure where
   109  	// the oldest element is at the back of the list and the newest is the
   110  	// at the front.
   111  	listTokenLast := statuses.entries.Back().Value.(string)
   112  	if listTokenLast != tokens[1] {
   113  		t.Errorf("unexpected entry is at the back of the entries list; "+
   114  			"expected %v, got %v", tokens[1], listTokenLast)
   115  	}
   116  	listTokenFirst := statuses.entries.Front().Value.(string)
   117  	if listTokenFirst != tokenThird {
   118  		t.Errorf("unexpected entry is at the front of the entries list; "+
   119  			"expected %v, got %v", tokenThird, listTokenFirst)
   120  	}
   121  
   122  	// Overwrite existing cache entry.
   123  	entryThird.propStatus = pi.PropStatusActive
   124  	statuses.set(tokenThird, entryThird)
   125  
   126  	// Ensure that the new entry was stored in cache successfully
   127  	e = statuses.data[tokenThird]
   128  	if e.propStatus != pi.PropStatusActive {
   129  		t.Errorf("unexpected proposal status: want %v, got %v",
   130  			pi.PropStatusActive, e.propStatus)
   131  	}
   132  
   133  	// Verify that the list order has not changed on entry overwrites
   134  	listTokenLast = statuses.entries.Back().Value.(string)
   135  	if listTokenLast != tokens[1] {
   136  		t.Errorf("unexpected entry is at the back of the entries list; "+
   137  			"expected %v, got %v", tokens[1], listTokenLast)
   138  	}
   139  	listTokenFirst = statuses.entries.Front().Value.(string)
   140  	if listTokenFirst != tokenThird {
   141  		t.Errorf("unexpected entry is at the front of the entries list; "+
   142  			"expected %v, got %v", tokenThird, listTokenFirst)
   143  	}
   144  }