github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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  	"math/big"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  
    29  	"github.com/ethereumproject/go-ethereum/logger/glog"
    30  	"github.com/ethereumproject/go-ethereum/tests"
    31  	"gopkg.in/urfave/cli.v1"
    32  )
    33  
    34  // Version is the application revision identifier. It can be set with the linker
    35  // as in: go build -ldflags "-X main.Version="`git describe --tags`
    36  var Version = "unknown"
    37  
    38  var (
    39  	continueOnError = false
    40  	testExtension   = ".json"
    41  	defaultTest     = "all"
    42  	defaultDir      = "."
    43  	allTests        = []string{"BlockTests", "StateTests", "TransactionTests", "VMTests", "RLPTests"}
    44  	testDirMapping  = map[string]string{"BlockTests": "BlockchainTests"}
    45  	skipTests       = []string{}
    46  
    47  	TestFlag = cli.StringFlag{
    48  		Name:  "test",
    49  		Usage: "Test type (string): VMTests, TransactionTests, StateTests, BlockTests",
    50  		Value: defaultTest,
    51  	}
    52  	FileFlag = cli.StringFlag{
    53  		Name:   "file",
    54  		Usage:  "Test file or directory. Directories are searched for .json files 1 level deep",
    55  		Value:  defaultDir,
    56  		EnvVar: "ETHEREUM_TEST_PATH",
    57  	}
    58  	ContinueOnErrorFlag = cli.BoolFlag{
    59  		Name:  "continue",
    60  		Usage: "Continue running tests on error (true) or [default] exit immediately (false)",
    61  	}
    62  	ReadStdInFlag = cli.BoolFlag{
    63  		Name:  "stdin",
    64  		Usage: "Accept input from stdin instead of reading from file",
    65  	}
    66  	SkipTestsFlag = cli.StringFlag{
    67  		Name:  "skip",
    68  		Usage: "Tests names to skip",
    69  	}
    70  	TraceFlag = cli.BoolFlag{
    71  		Name:  "trace",
    72  		Usage: "Enable VM tracing",
    73  	}
    74  )
    75  
    76  func runTestWithReader(test string, r io.Reader) error {
    77  	glog.Infoln("runTest", test)
    78  	var err error
    79  	switch strings.ToLower(test) {
    80  	case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
    81  		err = tests.RunBlockTestWithReader(big.NewInt(1150000), nil, r, skipTests)
    82  	case "st", "state", "statetest", "statetests":
    83  		rs := tests.RuleSet{HomesteadBlock: big.NewInt(1150000)}
    84  		err = tests.RunStateTestWithReader(rs, r, skipTests)
    85  	case "tx", "transactiontest", "transactiontests":
    86  		err = tests.RunTransactionTestsWithReader(r, skipTests)
    87  	case "vm", "vmtest", "vmtests":
    88  		err = tests.RunVmTestWithReader(r, skipTests)
    89  	case "rlp", "rlptest", "rlptests":
    90  		err = tests.RunRLPTestWithReader(r, skipTests)
    91  	default:
    92  		err = fmt.Errorf("Invalid test type specified: %v", test)
    93  	}
    94  
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	return nil
   100  }
   101  
   102  func getFiles(path string) ([]string, error) {
   103  	glog.Infoln("getFiles", path)
   104  	var files []string
   105  	f, err := os.Open(path)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	defer f.Close()
   110  
   111  	fi, err := f.Stat()
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	switch mode := fi.Mode(); {
   117  	case mode.IsDir():
   118  		fi, _ := ioutil.ReadDir(path)
   119  		files = make([]string, len(fi))
   120  		for i, v := range fi {
   121  			// only go 1 depth and leave directory entires blank
   122  			if !v.IsDir() && v.Name()[len(v.Name())-len(testExtension):len(v.Name())] == testExtension {
   123  				files[i] = filepath.Join(path, v.Name())
   124  				glog.Infoln("Found file", files[i])
   125  			}
   126  		}
   127  	case mode.IsRegular():
   128  		files = make([]string, 1)
   129  		files[0] = path
   130  	}
   131  
   132  	return files, nil
   133  }
   134  
   135  func runSuite(test, file string) {
   136  	var tests []string
   137  
   138  	if test == defaultTest {
   139  		tests = allTests
   140  	} else {
   141  		tests = []string{test}
   142  	}
   143  
   144  	for _, curTest := range tests {
   145  		glog.Infoln("runSuite", curTest, file)
   146  		var err error
   147  		var files []string
   148  		if test == defaultTest {
   149  			// check if we have an explicit directory mapping for the test
   150  			if _, ok := testDirMapping[curTest]; ok {
   151  				files, err = getFiles(filepath.Join(file, testDirMapping[curTest]))
   152  			} else {
   153  				// otherwise assume test name
   154  				files, err = getFiles(filepath.Join(file, curTest))
   155  			}
   156  		} else {
   157  			files, err = getFiles(file)
   158  		}
   159  		if err != nil {
   160  			glog.Fatalln(err)
   161  		}
   162  
   163  		if len(files) == 0 {
   164  			glog.Warningln("No files matched path")
   165  		}
   166  		for _, curFile := range files {
   167  			// Skip blank entries
   168  			if len(curFile) == 0 {
   169  				continue
   170  			}
   171  
   172  			r, err := os.Open(curFile)
   173  			if err != nil {
   174  				glog.Fatalln(err)
   175  			}
   176  			defer r.Close()
   177  
   178  			err = runTestWithReader(curTest, r)
   179  			if err != nil {
   180  				if continueOnError {
   181  					glog.Errorln(err)
   182  				} else {
   183  					glog.Fatalln(err)
   184  				}
   185  			}
   186  		}
   187  	}
   188  }
   189  
   190  func setupApp(c *cli.Context) error {
   191  	flagTest := c.GlobalString(TestFlag.Name)
   192  	flagFile := c.GlobalString(FileFlag.Name)
   193  	continueOnError = c.GlobalBool(ContinueOnErrorFlag.Name)
   194  	useStdIn := c.GlobalBool(ReadStdInFlag.Name)
   195  	skipTests = strings.Split(c.GlobalString(SkipTestsFlag.Name), " ")
   196  
   197  	if !useStdIn {
   198  		runSuite(flagTest, flagFile)
   199  	} else {
   200  		if err := runTestWithReader(flagTest, os.Stdin); err != nil {
   201  			glog.Fatalln(err)
   202  		}
   203  	}
   204  	return nil
   205  }
   206  
   207  func main() {
   208  	glog.SetToStderr(true)
   209  
   210  	app := cli.NewApp()
   211  	app.Name = filepath.Base(os.Args[0])
   212  	app.Version = Version
   213  	app.Usage = "go-ethereum test interface"
   214  	app.Action = setupApp
   215  
   216  	app.Flags = []cli.Flag{
   217  		TestFlag,
   218  		FileFlag,
   219  		ContinueOnErrorFlag,
   220  		ReadStdInFlag,
   221  		SkipTestsFlag,
   222  		TraceFlag,
   223  	}
   224  
   225  	if err := app.Run(os.Args); err != nil {
   226  		glog.Fatalln(err)
   227  	}
   228  
   229  }