github.com/lbryio/lbcd@v0.22.119/config_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"reflect"
     9  	"regexp"
    10  	"runtime"
    11  	"testing"
    12  )
    13  
    14  var (
    15  	rpcuserRegexp = regexp.MustCompile("(?m)^rpcuser=.+$")
    16  	rpcpassRegexp = regexp.MustCompile("(?m)^rpcpass=.+$")
    17  )
    18  
    19  // Define a struct "configCmdLineOnly" containing a subset of configuration
    20  // parameters which are command-line only. These fields are copied line-by-line
    21  // from "config" struct in "config.go", and the field names, types, and tags must
    22  // match for the test to work.
    23  type configCmdLineOnly struct {
    24  	ConfigFile          string   `short:"C" long:"configfile" description:"Path to configuration file"`
    25  	DbType              string   `long:"dbtype" description:"Database backend to use for the Block Chain"`
    26  	DropCfIndex         bool     `long:"dropcfindex" description:"Deletes the index used for committed filtering (CF) support from the database on start up and then exits."`
    27  	DropTxIndex         bool     `long:"droptxindex" description:"Deletes the hash-based transaction index from the database on start up and then exits."`
    28  	DisableCheckpoints  bool     `long:"nocheckpoints" description:"Disable built-in checkpoints.  Don't do this unless you know what you're doing."`
    29  	NoWinService        bool     `long:"nowinservice" description:"Do not start as a background service on Windows -- NOTE: This flag only works on the command line, not in the config file"`
    30  	DisableStallHandler bool     `long:"nostalldetect" description:"Disables the stall handler system for each peer, useful in simnet/regtest integration tests frameworks"`
    31  	RegressionTest      bool     `long:"regtest" description:"Use the regression test network"`
    32  	SimNet              bool     `long:"simnet" description:"Use the simulation test network"`
    33  	SigNet              bool     `long:"signet" description:"Use the signet test network"`
    34  	SigNetChallenge     string   `long:"signetchallenge" description:"Connect to a custom signet network defined by this challenge instead of using the global default signet test network -- Can be specified multiple times"`
    35  	SigNetSeedNode      []string `long:"signetseednode" description:"Specify a seed node for the signet network instead of using the global default signet network seed nodes"`
    36  	ShowVersion         bool     `short:"V" long:"version" description:"Display version information and exit"`
    37  }
    38  
    39  func fieldEq(f1, f2 reflect.StructField) bool {
    40  	return (f1.Name == f2.Name) && (f1.Type == f2.Type) && (f1.Tag == f2.Tag)
    41  }
    42  
    43  func TestSampleConfigFileComplete(t *testing.T) {
    44  	// find out where the sample config lives
    45  	_, path, _, ok := runtime.Caller(0)
    46  	if !ok {
    47  		t.Fatalf("Failed finding config file path")
    48  	}
    49  	sampleConfigFile := filepath.Join(filepath.Dir(path), sampleConfigFilename)
    50  
    51  	// Read the sample config file
    52  	content, err := ioutil.ReadFile(sampleConfigFile)
    53  	if err != nil {
    54  		t.Fatalf("Failed reading sample config file: %v", err)
    55  	}
    56  
    57  	allFields := reflect.VisibleFields(reflect.TypeOf(config{}))
    58  	cmdlineFields := reflect.VisibleFields(reflect.TypeOf(configCmdLineOnly{}))
    59  
    60  	// Verify cmdlineFields is a subset of allFields.
    61  	for _, cf := range cmdlineFields {
    62  		// Check for presence of field "cf" in config struct.
    63  		var field *reflect.StructField
    64  		for _, f := range allFields {
    65  			f := f // new instance of loop var for return
    66  			if fieldEq(cf, f) {
    67  				field = &f
    68  				break
    69  			}
    70  		}
    71  		if field == nil {
    72  			t.Errorf("cmdline field: %s type: %s is not present in type %s",
    73  				cf.Name, cf.Type, reflect.TypeOf(config{}))
    74  		}
    75  	}
    76  
    77  	// Verify sample config covers all parameters.
    78  	for _, f := range allFields {
    79  		longname, ok := f.Tag.Lookup("long")
    80  		if !ok {
    81  			// Field has no long-form name, so not eligible for
    82  			// inclusion in sample config.
    83  			continue
    84  		}
    85  
    86  		// Check for presence of field "f" in our configCmdLineOnly struct.
    87  		var cmdline *reflect.StructField
    88  		for _, cf := range cmdlineFields {
    89  			cf := cf // new instance of loop var for return
    90  			if fieldEq(cf, f) {
    91  				cmdline = &cf
    92  				break
    93  			}
    94  		}
    95  
    96  		// Look for assignment (<longname>="), or commented assignment ("; <longname>=").
    97  		pattern := fmt.Sprintf("(?m)^(;\\s*)?%s=.*$", longname)
    98  		assignment, err := regexp.Compile(pattern)
    99  		if err != nil {
   100  			t.Errorf("config field: %s longname: %s failed compiling regexp (%s): %v",
   101  				f.Name, longname, pattern, err)
   102  			continue
   103  		}
   104  
   105  		assigned := assignment.Match(content)
   106  
   107  		// Field "f" must be present in either the sample config (<longname>=X),
   108  		// or it must be one of the command line only fields, but not both.
   109  		if !assigned && (cmdline == nil) {
   110  			t.Errorf("config field: %s longname: %s assignment (%s) should be present in %s",
   111  				f.Name, longname, assignment, sampleConfigFilename)
   112  		}
   113  		if assigned && (cmdline != nil) {
   114  			t.Errorf("config field: %s longname: %s should not be present in both %s and type %s",
   115  				f.Name, longname, sampleConfigFilename, reflect.TypeOf(configCmdLineOnly{}).Name())
   116  		}
   117  	}
   118  }
   119  
   120  func TestCreateDefaultConfigFile(t *testing.T) {
   121  	// find out where the sample config lives
   122  	_, path, _, ok := runtime.Caller(0)
   123  	if !ok {
   124  		t.Fatalf("Failed finding config file path")
   125  	}
   126  	sampleConfigFile := filepath.Join(filepath.Dir(path), "sample-lbcd.conf")
   127  
   128  	// Setup a temporary directory
   129  	tmpDir, err := ioutil.TempDir("", "lbcd")
   130  	if err != nil {
   131  		t.Fatalf("Failed creating a temporary directory: %v", err)
   132  	}
   133  	testpath := filepath.Join(tmpDir, "test.conf")
   134  
   135  	// copy config file to location of lbcd binary
   136  	data, err := ioutil.ReadFile(sampleConfigFile)
   137  	if err != nil {
   138  		t.Fatalf("Failed reading sample config file: %v", err)
   139  	}
   140  	appPath, err := filepath.Abs(filepath.Dir(os.Args[0]))
   141  	if err != nil {
   142  		t.Fatalf("Failed obtaining app path: %v", err)
   143  	}
   144  	tmpConfigFile := filepath.Join(appPath, "sample-lbcd.conf")
   145  	err = ioutil.WriteFile(tmpConfigFile, data, 0644)
   146  	if err != nil {
   147  		t.Fatalf("Failed copying sample config file: %v", err)
   148  	}
   149  
   150  	// Clean-up
   151  	defer func() {
   152  		os.Remove(testpath)
   153  		os.Remove(tmpConfigFile)
   154  		os.Remove(tmpDir)
   155  	}()
   156  
   157  	err = createDefaultConfigFile(testpath)
   158  
   159  	if err != nil {
   160  		t.Fatalf("Failed to create a default config file: %v", err)
   161  	}
   162  
   163  	content, err := ioutil.ReadFile(testpath)
   164  	if err != nil {
   165  		t.Fatalf("Failed to read generated default config file: %v", err)
   166  	}
   167  
   168  	if !rpcuserRegexp.Match(content) {
   169  		t.Error("Could not find rpcuser in generated default config file.")
   170  	}
   171  
   172  	if !rpcpassRegexp.Match(content) {
   173  		t.Error("Could not find rpcpass in generated default config file.")
   174  	}
   175  }