github.com/Synthesix/Sia@v1.3.3-0.20180413141344-f863baeed3ca/modules/renter/contractor/uptime_test.go (about)

     1  package contractor
     2  
     3  import (
     4  	"errors"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/Synthesix/Sia/build"
     9  	"github.com/Synthesix/Sia/modules"
    10  	"github.com/Synthesix/Sia/types"
    11  )
    12  
    13  // TestIntegrationReplaceOffline tests that when a host goes offline, its
    14  // contract is eventually replaced.
    15  func TestIntegrationReplaceOffline(t *testing.T) {
    16  	if testing.Short() {
    17  		t.SkipNow()
    18  	}
    19  	h, c, m, err := newTestingTrio(t.Name())
    20  	if err != nil {
    21  		t.Fatal(err)
    22  	}
    23  
    24  	// form a contract with h
    25  	c.SetAllowance(modules.Allowance{
    26  		Funds:       types.SiacoinPrecision.Mul64(250),
    27  		Hosts:       1,
    28  		Period:      50,
    29  		RenewWindow: 20,
    30  	})
    31  	// Block until the contract is registered.
    32  	err = build.Retry(50, 100*time.Millisecond, func() error {
    33  		c.mu.Lock()
    34  		lenC := c.contracts.Len()
    35  		c.mu.Unlock()
    36  		if lenC < 1 {
    37  			return errors.New("allowance forming seems to have failed")
    38  		}
    39  		return nil
    40  	})
    41  	if err != nil {
    42  		t.Log(len(c.Contracts()))
    43  		t.Error(err)
    44  	}
    45  
    46  	// Take the first host offline.
    47  	err = h.Close()
    48  	if err != nil {
    49  		t.Error(err)
    50  	}
    51  	// Block until the host is seen as offline.
    52  	hosts := c.hdb.AllHosts()
    53  	err = build.Retry(250, 250*time.Millisecond, func() error {
    54  		hosts = c.hdb.AllHosts()
    55  		if len(hosts) != 1 {
    56  			return errors.New("only expecting one host")
    57  		}
    58  		sh := hosts[0].ScanHistory
    59  		if sh[len(sh)-1].Success {
    60  			return errors.New("host is reporting as online")
    61  		}
    62  		return nil
    63  	})
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  
    68  	// create another host
    69  	dir := build.TempDir("contractor", t.Name(), "Host2")
    70  	h2, err := newTestingHost(dir, c.cs.(modules.ConsensusSet), c.tpool.(modules.TransactionPool))
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	// Announce the second host.
    75  	err = h2.Announce()
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	// Mine a block to get the announcement on-chain.
    80  	_, err = m.AddBlock()
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	// Wait for a scan of the host to complete.
    86  	err = build.Retry(250, 250*time.Millisecond, func() error {
    87  		hosts = c.hdb.AllHosts()
    88  		if len(hosts) < 2 {
    89  			return errors.New("waiting for at least two hosts to show up")
    90  		}
    91  		for _, host := range hosts {
    92  			if len(host.ScanHistory) < 2 {
    93  				return errors.New("waiting for the hosts to have been scanned")
    94  			}
    95  		}
    96  		return nil
    97  	})
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	// Mine 3 blocks to trigger an allowance refresh, which should cause the
   103  	// second, online host to be picked up. Three are mined because mining just
   104  	// one was causing NDFs.
   105  	_, err = m.AddBlock()
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	var numContracts int
   110  	err = build.Retry(250, 250*time.Millisecond, func() error {
   111  		numContracts = len(c.Contracts())
   112  		if numContracts < 2 {
   113  			return errors.New("still waiting to form the second contract")
   114  		}
   115  		return nil
   116  	})
   117  	if err != nil {
   118  		t.Fatal(err, numContracts)
   119  	}
   120  }