github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/cmd/geth/flag_test.go (about) 1 package main 2 3 import ( 4 "flag" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "testing" 9 10 "reflect" 11 12 "os/exec" 13 14 "github.com/ethereumproject/go-ethereum/accounts" 15 "github.com/ethereumproject/go-ethereum/common" 16 "github.com/ethereumproject/go-ethereum/core" 17 "github.com/ethereumproject/go-ethereum/logger/glog" 18 "gopkg.in/urfave/cli.v1" 19 ) 20 21 var ogHome string // placeholder 22 var tmpHOME string // fake $HOME (for defaults) 23 var tmpDir string // temp DATA_DIR (inside tmpHOME) 24 25 var app *cli.App 26 var context *cli.Context 27 28 var set *flag.FlagSet 29 30 // globally available flags that go will parse, making them available for the mock app 31 type flags []struct { 32 name string 33 aliases []string 34 value interface{} 35 } 36 37 var gFlags flags 38 39 func init() { 40 glog.SetD(0) 41 glog.SetV(0) 42 } 43 44 func makeTmpDataDir(t *testing.T) { 45 ogHome = common.HomeDir() 46 var e error 47 48 tmpHOME, e = ioutil.TempDir(ogHome, "HOME") 49 if e != nil { 50 t.Fatalf("Failed to create temp directory in: %v", ogHome) 51 } 52 53 if e = os.Setenv("HOME", tmpHOME); e != nil { 54 t.Fatalf("Failed to temporarily set system home: %v", e) 55 } 56 57 td, err := ioutil.TempDir(tmpHOME, "DATADIR") 58 if err != nil { 59 t.Fatalf("Failed to create temp directory in: %v", tmpHOME) 60 } 61 tmpDir = td 62 } 63 64 func rmTmpDataDir(t *testing.T) { 65 if e := os.RemoveAll(tmpHOME); e != nil { 66 t.Fatalf("Failed to remove temp dir: %v", e) 67 } 68 69 if e := os.Setenv("HOME", ogHome); e != nil { 70 t.Fatalf("Failed to reset system home env var: %v", e) 71 } 72 } 73 74 func setupFlags(t *testing.T) { 75 76 gFlags = flags{ 77 {"testnet", []string{}, false}, 78 {"data-dir", []string{"datadir"}, common.DefaultDataDir()}, 79 {"bootnodes", []string{}, ""}, 80 {"chain", []string{}, ""}, 81 } 82 83 app = makeCLIApp() 84 app.Writer = ioutil.Discard 85 86 set = flag.NewFlagSet("test", 0) 87 88 for _, f := range gFlags { 89 switch f.value.(type) { 90 case string: 91 set.String(f.name, f.value.(string), "") 92 case bool: 93 set.Bool(f.name, f.value.(bool), "") 94 case int: 95 set.Int(f.name, f.value.(int), "") 96 } 97 98 if len(f.aliases) > 0 { 99 for _, a := range f.aliases { 100 switch f.value.(type) { 101 case string: 102 set.String(a, f.value.(string), "") 103 case bool: 104 set.Bool(a, f.value.(bool), "") 105 case int: 106 set.Int(a, f.value.(int), "") 107 } 108 } 109 } 110 } 111 } 112 113 func TestMustMakeChainDataDir(t *testing.T) { 114 115 makeTmpDataDir(t) 116 defer rmTmpDataDir(t) 117 118 dd := common.DefaultDataDir() 119 funkyName := "my.private-chain_2chainz!" 120 121 cases := []struct { 122 flags []string 123 want string 124 err error 125 }{ 126 {[]string{}, filepath.Join(dd, "mainnet"), nil}, 127 128 {[]string{"--datadir", tmpDir}, filepath.Join(tmpDir, "mainnet"), nil}, 129 {[]string{"--data-dir", tmpDir}, filepath.Join(tmpDir, "mainnet"), nil}, 130 131 {[]string{"--testnet", "--data-dir", tmpDir}, filepath.Join(tmpDir, "morden"), nil}, 132 {[]string{"--testnet"}, filepath.Join(dd, "morden"), nil}, 133 134 {[]string{"--chain"}, "", ErrInvalidFlag}, 135 {[]string{"--chain", "main"}, filepath.Join(dd, "mainnet"), nil}, 136 {[]string{"--chain", "morden"}, filepath.Join(dd, "morden"), nil}, 137 {[]string{"--chain", "testnet"}, filepath.Join(dd, "morden"), nil}, 138 {[]string{"--chain", "kitty"}, filepath.Join(dd, "kitty"), nil}, 139 140 {[]string{"--chain", "kitty/cat"}, filepath.Join(dd, "kitty", "cat"), nil}, 141 {[]string{"--chain", funkyName}, filepath.Join(dd, funkyName), nil}, 142 } 143 144 for _, c := range cases { 145 // Unset cache. 146 core.SetCacheChainIdentity("") 147 148 setupFlags(t) 149 150 if e := set.Parse(c.flags); e != nil { 151 if c.err == nil { 152 t.Fatal(e) 153 } else { 154 // don't compare the errors for now, this is enough 155 t.Log("got expected error/+usage info: ok\n(checks cli context flag parsing requires an argument)") 156 continue 157 } 158 } 159 context = cli.NewContext(app, set, nil) 160 161 got := MustMakeChainDataDir(context) 162 163 if c.err == nil && got != c.want { 164 t.Errorf("flag: %v, chaindir want: %v, got: %v", c.flags, c.want, got) 165 } 166 if c.err == nil && !filepath.IsAbs(got) { 167 t.Errorf("flag: %v, unexpected relative path: %v", c.flags, got) 168 } 169 if c.err != nil && got != "" { 170 t.Errorf("flag: %v, want: %v, got: %v", c.flags, c.err, got) 171 } 172 } 173 } 174 175 func TestGetChainIdentityValue(t *testing.T) { 176 177 cases := []struct { 178 flags []string 179 want string 180 }{ 181 // Known (defaulty) chain values. 182 {[]string{"--chain", "morden"}, "morden"}, 183 {[]string{"--chain", "testnet"}, "morden"}, 184 {[]string{"--chain", "main"}, "mainnet"}, 185 {[]string{"--chain", "mainnet"}, "mainnet"}, 186 187 // Custom. 188 {[]string{"--chain", "kitty"}, "kitty"}, 189 {[]string{"--chain", "kitty/cat"}, filepath.Join("kitty", "cat")}, 190 191 // Blacklisted. 192 {[]string{"--chain", "chaindata"}, ""}, 193 } 194 195 for _, c := range cases { 196 // Unset cache. 197 core.SetCacheChainIdentity("") 198 199 setupFlags(t) 200 201 if e := set.Parse(c.flags); e != nil { 202 t.Fatal(e) 203 } 204 context = cli.NewContext(app, set, nil) 205 206 if c.want != "" { 207 got := mustMakeChainIdentity(context) 208 if c.want != got { 209 t.Fatalf("[%v] want: %v, got: %v", c.flags, c.want, got) 210 } 211 } else { 212 // https://stackoverflow.com/questions/26225513/how-to-test-os-exit-scenarios-in-go 213 if os.Getenv("DOES_GLOG_FATAL") == "1" { 214 mustMakeChainIdentity(context) 215 return 216 } 217 cmd := exec.Command(os.Args[0], "-test.run=TestGetChainIdentityValue") 218 cmd.Env = append(os.Environ(), "DOES_GLOG_FATAL=1") 219 err := cmd.Run() 220 if e, ok := err.(*exec.ExitError); ok && !e.Success() { 221 t.Log("expected osexit=1: ok", c.flags) 222 return 223 } 224 t.Fatalf("process ran with err %v, want exit status 1", err) 225 } 226 227 } 228 } 229 230 // Bootnodes flag parse 1 231 func TestMakeBootstrapNodesFromContext1(t *testing.T) { 232 233 makeTmpDataDir(t) 234 defer rmTmpDataDir(t) 235 setupFlags(t) 236 237 arg := []string{ 238 "--bootnodes", 239 "enode://6e538e7c1280f0a31ff08b382db5302480f775480b8e68f8febca0ceff81e4b19153c6f8bf60313b93bef2cc34d34e1df41317de0ce613a201d1660a788a03e2@52.206.67.235:30303", 240 } 241 if e := set.Parse(arg); e != nil { 242 t.Fatal(e) 243 } 244 context = cli.NewContext(app, set, nil) 245 got := MakeBootstrapNodesFromContext(context) 246 if len(got) != 1 { 247 t.Errorf("wanted: 1, got %v", len(got)) 248 } 249 if got[0].IP.String() != "52.206.67.235" { 250 t.Errorf("unexpected: %v", got[0].IP.String()) 251 } 252 } 253 254 // Bootnodes flag parse 2 255 func TestMakeBootstrapNodesFromContext2(t *testing.T) { 256 257 makeTmpDataDir(t) 258 defer rmTmpDataDir(t) 259 setupFlags(t) 260 261 arg := []string{ 262 "--bootnodes", 263 `enode://6e538e7c1280f0a31ff08b382db5302480f775480b8e68f8febca0ceff81e4b19153c6f8bf60313b93bef2cc34d34e1df41317de0ce613a201d1660a788a03e2@52.206.67.235:30303,enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306`, 264 } 265 if e := set.Parse(arg); e != nil { 266 t.Fatal(e) 267 } 268 context = cli.NewContext(app, set, nil) 269 got := MakeBootstrapNodesFromContext(context) 270 if len(got) != 2 { 271 t.Errorf("wanted: 2, got %v", len(got)) 272 } 273 if got[0].IP.String() != "52.206.67.235" { 274 t.Errorf("unexpected: %v", got[0].IP.String()) 275 } 276 if got[1].IP.String() != "144.76.238.49" { 277 t.Errorf("unexpected: %v", got[1].IP.String()) 278 } 279 } 280 281 // Bootnodes default 282 func TestMakeBootstrapNodesFromContext3(t *testing.T) { 283 284 makeTmpDataDir(t) 285 defer rmTmpDataDir(t) 286 setupFlags(t) 287 288 arg := []string{} 289 if e := set.Parse(arg); e != nil { 290 t.Fatal(e) 291 } 292 context = cli.NewContext(app, set, nil) 293 got := MakeBootstrapNodesFromContext(context) 294 if len(got) != len(core.DefaultConfigMainnet.ParsedBootstrap) { 295 t.Errorf("wanted: %v, got %v", len(core.DefaultConfigMainnet.ParsedBootstrap), len(got)) 296 } 297 } 298 299 // Bootnodes testnet default 300 func TestMakeBootstrapNodesFromContext4(t *testing.T) { 301 302 makeTmpDataDir(t) 303 defer rmTmpDataDir(t) 304 setupFlags(t) 305 306 arg := []string{"--testnet"} 307 if e := set.Parse(arg); e != nil { 308 t.Fatal(e) 309 } 310 context = cli.NewContext(app, set, nil) 311 got := MakeBootstrapNodesFromContext(context) 312 if len(got) != len(core.DefaultConfigMorden.ParsedBootstrap) { 313 t.Errorf("wanted: %v, got %v", len(core.DefaultConfigMorden.ParsedBootstrap), len(got)) 314 } 315 } 316 317 func TestMakeAddress(t *testing.T) { 318 accAddr := "f466859ead1932d743d622cb74fc058882e8648a" // account[0] address 319 cachetestdir := filepath.Join("accounts", "testdata", "keystore") 320 am, err := accounts.NewManager(cachetestdir, accounts.LightScryptN, accounts.LightScryptP, false) 321 if err != nil { 322 t.Fatal(err) 323 } 324 gotAccount, e := MakeAddress(am, accAddr) 325 if e != nil { 326 t.Fatalf("makeaddress: %v", e) 327 } 328 wantAccount := accounts.Account{ 329 Address: common.HexToAddress(accAddr), 330 } 331 // compare all 332 if !reflect.DeepEqual(wantAccount, gotAccount) { 333 t.Fatalf("want: %v, got: %v", wantAccount, gotAccount) 334 } 335 }