github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/cmd/ethtest/main.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // ethtest executes Ethereum JSON tests.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"io"
    23  	"io/ioutil"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  
    28  	"github.com/codegangsta/cli"
    29  	"github.com/ethereum/go-ethereum/core/vm"
    30  	"github.com/ethereum/go-ethereum/logger/glog"
    31  	"github.com/ethereum/go-ethereum/tests"
    32  )
    33  
    34  var (
    35  	continueOnError = false
    36  	testExtension   = ".json"
    37  	defaultTest     = "all"
    38  	defaultDir      = "."
    39  	allTests        = []string{"BlockTests", "StateTests", "TransactionTests", "VMTests", "RLPTests"}
    40  	testDirMapping  = map[string]string{"BlockTests": "BlockchainTests"}
    41  	skipTests       = []string{}
    42  
    43  	TestFlag = cli.StringFlag{
    44  		Name:  "test",
    45  		Usage: "Test type (string): VMTests, TransactionTests, StateTests, BlockTests",
    46  		Value: defaultTest,
    47  	}
    48  	FileFlag = cli.StringFlag{
    49  		Name:   "file",
    50  		Usage:  "Test file or directory. Directories are searched for .json files 1 level deep",
    51  		Value:  defaultDir,
    52  		EnvVar: "ETHEREUM_TEST_PATH",
    53  	}
    54  	ContinueOnErrorFlag = cli.BoolFlag{
    55  		Name:  "continue",
    56  		Usage: "Continue running tests on error (true) or [default] exit immediately (false)",
    57  	}
    58  	ReadStdInFlag = cli.BoolFlag{
    59  		Name:  "stdin",
    60  		Usage: "Accept input from stdin instead of reading from file",
    61  	}
    62  	SkipTestsFlag = cli.StringFlag{
    63  		Name:  "skip",
    64  		Usage: "Tests names to skip",
    65  	}
    66  	TraceFlag = cli.BoolFlag{
    67  		Name:  "trace",
    68  		Usage: "Enable VM tracing",
    69  	}
    70  )
    71  
    72  func runTestWithReader(test string, r io.Reader) error {
    73  	glog.Infoln("runTest", test)
    74  	var err error
    75  	switch strings.ToLower(test) {
    76  	case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
    77  		err = tests.RunBlockTestWithReader(r, skipTests)
    78  	case "st", "state", "statetest", "statetests":
    79  		err = tests.RunStateTestWithReader(r, skipTests)
    80  	case "tx", "transactiontest", "transactiontests":
    81  		err = tests.RunTransactionTestsWithReader(r, skipTests)
    82  	case "vm", "vmtest", "vmtests":
    83  		err = tests.RunVmTestWithReader(r, skipTests)
    84  	case "rlp", "rlptest", "rlptests":
    85  		err = tests.RunRLPTestWithReader(r, skipTests)
    86  	default:
    87  		err = fmt.Errorf("Invalid test type specified: %v", test)
    88  	}
    89  
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func getFiles(path string) ([]string, error) {
    98  	glog.Infoln("getFiles", path)
    99  	var files []string
   100  	f, err := os.Open(path)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	defer f.Close()
   105  
   106  	fi, err := f.Stat()
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	switch mode := fi.Mode(); {
   112  	case mode.IsDir():
   113  		fi, _ := ioutil.ReadDir(path)
   114  		files = make([]string, len(fi))
   115  		for i, v := range fi {
   116  			// only go 1 depth and leave directory entires blank
   117  			if !v.IsDir() && v.Name()[len(v.Name())-len(testExtension):len(v.Name())] == testExtension {
   118  				files[i] = filepath.Join(path, v.Name())
   119  				glog.Infoln("Found file", files[i])
   120  			}
   121  		}
   122  	case mode.IsRegular():
   123  		files = make([]string, 1)
   124  		files[0] = path
   125  	}
   126  
   127  	return files, nil
   128  }
   129  
   130  func runSuite(test, file string) {
   131  	var tests []string
   132  
   133  	if test == defaultTest {
   134  		tests = allTests
   135  	} else {
   136  		tests = []string{test}
   137  	}
   138  
   139  	for _, curTest := range tests {
   140  		glog.Infoln("runSuite", curTest, file)
   141  		var err error
   142  		var files []string
   143  		if test == defaultTest {
   144  			// check if we have an explicit directory mapping for the test
   145  			if _, ok := testDirMapping[curTest]; ok {
   146  				files, err = getFiles(filepath.Join(file, testDirMapping[curTest]))
   147  			} else {
   148  				// otherwise assume test name
   149  				files, err = getFiles(filepath.Join(file, curTest))
   150  			}
   151  		} else {
   152  			files, err = getFiles(file)
   153  		}
   154  		if err != nil {
   155  			glog.Fatalln(err)
   156  		}
   157  
   158  		if len(files) == 0 {
   159  			glog.Warningln("No files matched path")
   160  		}
   161  		for _, curFile := range files {
   162  			// Skip blank entries
   163  			if len(curFile) == 0 {
   164  				continue
   165  			}
   166  
   167  			r, err := os.Open(curFile)
   168  			if err != nil {
   169  				glog.Fatalln(err)
   170  			}
   171  			defer r.Close()
   172  
   173  			err = runTestWithReader(curTest, r)
   174  			if err != nil {
   175  				if continueOnError {
   176  					glog.Errorln(err)
   177  				} else {
   178  					glog.Fatalln(err)
   179  				}
   180  			}
   181  		}
   182  	}
   183  }
   184  
   185  func setupApp(c *cli.Context) {
   186  	flagTest := c.GlobalString(TestFlag.Name)
   187  	flagFile := c.GlobalString(FileFlag.Name)
   188  	continueOnError = c.GlobalBool(ContinueOnErrorFlag.Name)
   189  	useStdIn := c.GlobalBool(ReadStdInFlag.Name)
   190  	skipTests = strings.Split(c.GlobalString(SkipTestsFlag.Name), " ")
   191  	vm.Debug = c.GlobalBool(TraceFlag.Name)
   192  
   193  	if !useStdIn {
   194  		runSuite(flagTest, flagFile)
   195  	} else {
   196  		if err := runTestWithReader(flagTest, os.Stdin); err != nil {
   197  			glog.Fatalln(err)
   198  		}
   199  
   200  	}
   201  }
   202  
   203  func main() {
   204  	glog.SetToStderr(true)
   205  
   206  	app := cli.NewApp()
   207  	app.Name = "ethtest"
   208  	app.Usage = "go-ethereum test interface"
   209  	app.Action = setupApp
   210  	app.Version = "0.2.0"
   211  	app.Author = "go-ethereum team"
   212  
   213  	app.Flags = []cli.Flag{
   214  		TestFlag,
   215  		FileFlag,
   216  		ContinueOnErrorFlag,
   217  		ReadStdInFlag,
   218  		SkipTestsFlag,
   219  		TraceFlag,
   220  	}
   221  
   222  	if err := app.Run(os.Args); err != nil {
   223  		glog.Fatalln(err)
   224  	}
   225  
   226  }