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 }