gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/host/contractmanager/contractmanager_test.go (about)

     1  package contractmanager
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"gitlab.com/SiaPrime/SiaPrime/build"
    10  	"gitlab.com/SiaPrime/SiaPrime/modules"
    11  )
    12  
    13  // contractManagerTester holds a contract manager along with some other fields
    14  // useful for testing, and has methods implemented on it that can assist
    15  // testing.
    16  type contractManagerTester struct {
    17  	cm *ContractManager
    18  
    19  	persistDir string
    20  }
    21  
    22  // panicClose will attempt to call Close on the contract manager tester. If
    23  // there is an error, the function will panic. A convenient function for making
    24  // sure that the cleanup code is always running correctly, without needing to
    25  // write a lot of boiler code.
    26  func (cmt *contractManagerTester) panicClose() {
    27  	err := cmt.Close()
    28  	if err != nil {
    29  		panic(err)
    30  	}
    31  }
    32  
    33  // Close will perform clean shutdown on the contract manager tester.
    34  func (cmt *contractManagerTester) Close() error {
    35  	if cmt.cm == nil {
    36  		return errors.New("nil contract manager")
    37  	}
    38  	return cmt.cm.Close()
    39  }
    40  
    41  // newContractManagerTester returns a ready-to-rock contract manager tester.
    42  func newContractManagerTester(name string) (*contractManagerTester, error) {
    43  	if testing.Short() {
    44  		panic("use of newContractManagerTester during short testing")
    45  	}
    46  
    47  	testdir := build.TempDir(modules.ContractManagerDir, name)
    48  	cm, err := New(filepath.Join(testdir, modules.ContractManagerDir))
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	cmt := &contractManagerTester{
    53  		cm:         cm,
    54  		persistDir: testdir,
    55  	}
    56  	return cmt, nil
    57  }
    58  
    59  // newMockedContractManagerTester returns a contract manager tester that uses
    60  // the input dependencies instead of the production ones.
    61  func newMockedContractManagerTester(d modules.Dependencies, name string) (*contractManagerTester, error) {
    62  	if testing.Short() {
    63  		panic("use of newContractManagerTester during short testing")
    64  	}
    65  
    66  	testdir := build.TempDir(modules.ContractManagerDir, name)
    67  	cm, err := newContractManager(d, filepath.Join(testdir, modules.ContractManagerDir))
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	cmt := &contractManagerTester{
    72  		cm:         cm,
    73  		persistDir: testdir,
    74  	}
    75  	return cmt, nil
    76  }
    77  
    78  // TestNewContractManager does basic startup and shutdown of a contract
    79  // manager, checking for egregious errors.
    80  func TestNewContractManager(t *testing.T) {
    81  	if testing.Short() {
    82  		t.SkipNow()
    83  	}
    84  	t.Parallel()
    85  
    86  	// Create a contract manager.
    87  	parentDir := build.TempDir(modules.ContractManagerDir, "TestNewContractManager")
    88  	cmDir := filepath.Join(parentDir, modules.ContractManagerDir)
    89  	cm, err := New(cmDir)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  	// Close the contract manager.
    94  	err = cm.Close()
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  
    99  	// Create a new contract manager using the same directory.
   100  	cm, err = New(cmDir)
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  	// Close it again.
   105  	err = cm.Close()
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  }
   110  
   111  // dependencyErroredStartupis a mocked dependency that will cause the contract
   112  // manager to be returned with an error upon startup.
   113  type dependencyErroredStartup struct {
   114  	modules.ProductionDependencies
   115  }
   116  
   117  // disrupt will disrupt the threadedSyncLoop, causing the loop to terminate as
   118  // soon as it is created.
   119  func (d *dependencyErroredStartup) Disrupt(s string) bool {
   120  	// Cause an error to be returned during startup.
   121  	if s == "erroredStartup" {
   122  		return true
   123  	}
   124  	return false
   125  }
   126  
   127  // TestNewContractManagerErroredStartup uses disruption to simulate an error
   128  // during startup, allowing the test to verify that the cleanup code ran
   129  // correctly.
   130  func TestNewContractManagerErroredStartup(t *testing.T) {
   131  	if testing.Short() {
   132  		t.SkipNow()
   133  	}
   134  	t.Parallel()
   135  
   136  	// Create a new contract manager where the startup gets disrupted.
   137  	d := new(dependencyErroredStartup)
   138  	testdir := build.TempDir(modules.ContractManagerDir, "TestNewContractManagerErroredStartup")
   139  	cmd := filepath.Join(testdir, modules.ContractManagerDir)
   140  	_, err := newContractManager(d, cmd)
   141  	if err == nil || err.Error() != "startup disrupted" {
   142  		t.Fatal("expecting contract manager startup to be disrupted:", err)
   143  	}
   144  
   145  	// Verify that shutdown was triggered correctly - tmp files should be gone,
   146  	// WAL file should also be gone.
   147  	walFileName := filepath.Join(cmd, walFile)
   148  	walFileTmpName := filepath.Join(cmd, walFileTmp)
   149  	settingsFileTmpName := filepath.Join(cmd, settingsFileTmp)
   150  	_, err = os.Stat(walFileName)
   151  	if !os.IsNotExist(err) {
   152  		t.Error("file should have been removed:", err)
   153  	}
   154  	_, err = os.Stat(walFileTmpName)
   155  	if !os.IsNotExist(err) {
   156  		t.Error("file should have been removed:", err)
   157  	}
   158  	_, err = os.Stat(settingsFileTmpName)
   159  	if !os.IsNotExist(err) {
   160  		t.Error("file should have been removed:", err)
   161  	}
   162  }