github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/host/dependencies.go (about)

     1  package host
     2  
     3  import (
     4  	"crypto/rand"
     5  	"errors"
     6  	"io/ioutil"
     7  	"net"
     8  	"os"
     9  	"strings"
    10  
    11  	"github.com/NebulousLabs/Sia/persist"
    12  )
    13  
    14  // Fake errors that get returned when a simulated failure of a dependency is
    15  // desired for testing.
    16  var (
    17  	mockErrListen       = errors.New("simulated Listen failure")
    18  	mockErrLoadFile     = errors.New("simulated LoadFile failure")
    19  	mockErrMkdirAll     = errors.New("simulated MkdirAll failure")
    20  	mockErrNewLogger    = errors.New("simulated NewLogger failure")
    21  	mockErrOpenDatabase = errors.New("simulated OpenDatabase failure")
    22  	mockErrReadFile     = errors.New("simulated ReadFile failure")
    23  	mockErrRemoveFile   = errors.New("simulated RemoveFile faulure")
    24  	mockErrSymlink      = errors.New("simulated Symlink failure")
    25  	mockErrWriteFile    = errors.New("simulated WriteFile failure")
    26  )
    27  
    28  // These interfaces define the Host's dependencies. Mocking implementation
    29  // complexity can be reduced by defining each dependency as the minimum
    30  // possible subset of the real dependency.
    31  type (
    32  	// dependencies defines all of the dependencies of the Host.
    33  	dependencies interface {
    34  		// listen gives the host the ability to receive incoming connections.
    35  		listen(string, string) (net.Listener, error)
    36  
    37  		// loadFile allows the host to load a persistence structure form disk.
    38  		loadFile(persist.Metadata, interface{}, string) error
    39  
    40  		// mkdirAll gives the host the ability to create chains of folders
    41  		// within the filesystem.
    42  		mkdirAll(string, os.FileMode) error
    43  
    44  		// newLogger creates a logger that the host can use to log messages and
    45  		// write critical statements.
    46  		newLogger(string) (*persist.Logger, error)
    47  
    48  		// openDatabase creates a database that the host can use to interact
    49  		// with large volumes of persistent data.
    50  		openDatabase(persist.Metadata, string) (*persist.BoltDatabase, error)
    51  
    52  		// randRead fills the input bytes with random data.
    53  		randRead([]byte) (int, error)
    54  
    55  		// readFile reads a file in full from the filesystem.
    56  		readFile(string) ([]byte, error)
    57  
    58  		// removeFile removes a file from file filesystem.
    59  		removeFile(string) error
    60  
    61  		// symlink creates a sym link between a source and a destination.
    62  		symlink(s1, s2 string) error
    63  
    64  		// writeFile writes data to the filesystem using the provided filename.
    65  		writeFile(string, []byte, os.FileMode) error
    66  	}
    67  )
    68  
    69  type (
    70  	// productionDependencies is an empty struct that implements all of the
    71  	// dependencies using full featured libraries.
    72  	productionDependencies struct{}
    73  )
    74  
    75  // composeErrors will take two errors and compose them into a single errors
    76  // with a longer message. Any nil errors used as inputs will be stripped out,
    77  // and if there are zero non-nil inputs then 'nil' will be returned.
    78  func composeErrors(errs ...error) error {
    79  	// Strip out any nil errors.
    80  	var errStrings []string
    81  	for _, err := range errs {
    82  		if err != nil {
    83  			errStrings = append(errStrings, err.Error())
    84  		}
    85  	}
    86  
    87  	// Return nil if there are no non-nil errors in the input.
    88  	if len(errStrings) <= 0 {
    89  		return nil
    90  	}
    91  
    92  	// Combine all of the non-nil errors into one larger return value.
    93  	return errors.New(strings.Join(errStrings, "; "))
    94  }
    95  
    96  // listen gives the host the ability to receive incoming connections.
    97  func (productionDependencies) listen(s1, s2 string) (net.Listener, error) {
    98  	return net.Listen(s1, s2)
    99  }
   100  
   101  // loadFile allows the host to load a persistence structure form disk.
   102  func (productionDependencies) loadFile(m persist.Metadata, i interface{}, s string) error {
   103  	return persist.LoadFile(m, i, s)
   104  }
   105  
   106  // mkdirAll gives the host the ability to create chains of folders within the
   107  // filesystem.
   108  func (productionDependencies) mkdirAll(s string, fm os.FileMode) error {
   109  	return os.MkdirAll(s, fm)
   110  }
   111  
   112  // newLogger creates a logger that the host can use to log messages and write
   113  // critical statements.
   114  func (productionDependencies) newLogger(s string) (*persist.Logger, error) {
   115  	return persist.NewFileLogger(s)
   116  }
   117  
   118  // openDatabase creates a database that the host can use to interact with large
   119  // volumes of persistent data.
   120  func (productionDependencies) openDatabase(m persist.Metadata, s string) (*persist.BoltDatabase, error) {
   121  	return persist.OpenDatabase(m, s)
   122  }
   123  
   124  // randRead fills the input bytes with random data.
   125  func (productionDependencies) randRead(b []byte) (int, error) {
   126  	return rand.Read(b)
   127  }
   128  
   129  // readFile reads a file from the filesystem.
   130  func (productionDependencies) readFile(s string) ([]byte, error) {
   131  	return ioutil.ReadFile(s)
   132  }
   133  
   134  // removeFile removes a file from the filesystem.
   135  func (productionDependencies) removeFile(s string) error {
   136  	return os.Remove(s)
   137  }
   138  
   139  // symlink creates a symlink between a source and a destination file.
   140  func (productionDependencies) symlink(s1, s2 string) error {
   141  	return os.Symlink(s1, s2)
   142  }
   143  
   144  // writeFile writes a file to the filesystem.
   145  func (productionDependencies) writeFile(s string, b []byte, fm os.FileMode) error {
   146  	return ioutil.WriteFile(s, b, fm)
   147  }