github.com/Finschia/finschia-sdk@v0.48.1/server/util_test.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"path"
     9  	"path/filepath"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/spf13/cobra"
    14  
    15  	"github.com/Finschia/finschia-sdk/client/flags"
    16  )
    17  
    18  var cancelledInPreRun = errors.New("Cancelled in prerun")
    19  
    20  // Used in each test to run the function under test via Cobra
    21  // but to always halt the command
    22  func preRunETestImpl(cmd *cobra.Command, args []string) error {
    23  	err := InterceptConfigsPreRunHandler(cmd, "", nil)
    24  	if err != nil {
    25  		return err
    26  	}
    27  
    28  	return cancelledInPreRun
    29  }
    30  
    31  func TestInterceptConfigsPreRunHandlerCreatesConfigFilesWhenMissing(t *testing.T) {
    32  	tempDir := t.TempDir()
    33  	cmd := StartCmd(nil, "/foobar")
    34  	if err := cmd.Flags().Set(flags.FlagHome, tempDir); err != nil {
    35  		t.Fatalf("Could not set home flag [%T] %v", err, err)
    36  	}
    37  
    38  	cmd.PreRunE = preRunETestImpl
    39  
    40  	serverCtx := &Context{}
    41  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
    42  	if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun {
    43  		t.Fatalf("function failed with [%T] %v", err, err)
    44  	}
    45  
    46  	// Test that config.toml is created
    47  	configTomlPath := path.Join(tempDir, "config", "config.toml")
    48  	s, err := os.Stat(configTomlPath)
    49  	if err != nil {
    50  		t.Fatalf("Could not stat config.toml after run %v", err)
    51  	}
    52  
    53  	if !s.Mode().IsRegular() {
    54  		t.Fatal("config.toml not created as regular file")
    55  	}
    56  
    57  	if s.Size() == 0 {
    58  		t.Fatal("config.toml created as empty file")
    59  	}
    60  
    61  	// Test that ostracon config is initialized
    62  	if serverCtx.Config == nil {
    63  		t.Fatal("ostracon config not created")
    64  	}
    65  
    66  	// Test that app.toml is created
    67  	appTomlPath := path.Join(tempDir, "config", "app.toml")
    68  	s, err = os.Stat(appTomlPath)
    69  	if err != nil {
    70  		t.Fatalf("Could not stat app.toml after run %v", err)
    71  	}
    72  
    73  	if !s.Mode().IsRegular() {
    74  		t.Fatal("appp.toml not created as regular file")
    75  	}
    76  
    77  	if s.Size() == 0 {
    78  		t.Fatal("config.toml created as empty file")
    79  	}
    80  
    81  	// Test that the config for use in server/start.go is created
    82  	if serverCtx.Viper == nil {
    83  		t.Error("app config Viper instance not created")
    84  	}
    85  }
    86  
    87  func TestInterceptConfigsPreRunHandlerReadsConfigToml(t *testing.T) {
    88  	const testDbBackend = "awesome_test_db"
    89  	tempDir := t.TempDir()
    90  	err := os.Mkdir(path.Join(tempDir, "config"), os.ModePerm)
    91  	if err != nil {
    92  		t.Fatalf("creating config dir failed: %v", err)
    93  	}
    94  	configTomlPath := path.Join(tempDir, "config", "config.toml")
    95  	writer, err := os.Create(configTomlPath)
    96  	if err != nil {
    97  		t.Fatalf("creating config.toml file failed: %v", err)
    98  	}
    99  
   100  	_, err = writer.WriteString(fmt.Sprintf("db_backend = '%s'\n", testDbBackend))
   101  	if err != nil {
   102  		t.Fatalf("Failed writing string to config.toml: %v", err)
   103  	}
   104  
   105  	if err := writer.Close(); err != nil {
   106  		t.Fatalf("Failed closing config.toml: %v", err)
   107  	}
   108  
   109  	cmd := StartCmd(nil, "/foobar")
   110  	if err := cmd.Flags().Set(flags.FlagHome, tempDir); err != nil {
   111  		t.Fatalf("Could not set home flag [%T] %v", err, err)
   112  	}
   113  
   114  	cmd.PreRunE = preRunETestImpl
   115  
   116  	serverCtx := &Context{}
   117  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   118  
   119  	if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun {
   120  		t.Fatalf("function failed with [%T] %v", err, err)
   121  	}
   122  
   123  	if testDbBackend != serverCtx.Config.DBBackend {
   124  		t.Error("DBPath was not set from config.toml")
   125  	}
   126  }
   127  
   128  func TestInterceptConfigsPreRunHandlerReadsAppToml(t *testing.T) {
   129  	const testHaltTime = 1337
   130  	tempDir := t.TempDir()
   131  	err := os.Mkdir(path.Join(tempDir, "config"), os.ModePerm)
   132  	if err != nil {
   133  		t.Fatalf("creating config dir failed: %v", err)
   134  	}
   135  	appTomlPath := path.Join(tempDir, "config", "app.toml")
   136  	writer, err := os.Create(appTomlPath)
   137  	if err != nil {
   138  		t.Fatalf("creating app.toml file failed: %v", err)
   139  	}
   140  
   141  	_, err = writer.WriteString(fmt.Sprintf("halt-time = %d\n", testHaltTime))
   142  	if err != nil {
   143  		t.Fatalf("Failed writing string to app.toml: %v", err)
   144  	}
   145  
   146  	if err := writer.Close(); err != nil {
   147  		t.Fatalf("Failed closing app.toml: %v", err)
   148  	}
   149  	cmd := StartCmd(nil, tempDir)
   150  
   151  	cmd.PreRunE = preRunETestImpl
   152  
   153  	serverCtx := &Context{}
   154  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   155  
   156  	if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun {
   157  		t.Fatalf("function failed with [%T] %v", err, err)
   158  	}
   159  
   160  	if testHaltTime != serverCtx.Viper.GetInt("halt-time") {
   161  		t.Error("Halt time was not set from app.toml")
   162  	}
   163  }
   164  
   165  func TestInterceptConfigsPreRunHandlerReadsFlags(t *testing.T) {
   166  	const testAddr = "tcp://127.1.2.3:12345"
   167  	tempDir := t.TempDir()
   168  	cmd := StartCmd(nil, "/foobar")
   169  
   170  	if err := cmd.Flags().Set(flags.FlagHome, tempDir); err != nil {
   171  		t.Fatalf("Could not set home flag [%T] %v", err, err)
   172  	}
   173  
   174  	// This flag is added by ostracon
   175  	if err := cmd.Flags().Set("rpc.laddr", testAddr); err != nil {
   176  		t.Fatalf("Could not set address flag [%T] %v", err, err)
   177  	}
   178  
   179  	cmd.PreRunE = preRunETestImpl
   180  
   181  	serverCtx := &Context{}
   182  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   183  
   184  	if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun {
   185  		t.Fatalf("function failed with [%T] %v", err, err)
   186  	}
   187  
   188  	if testAddr != serverCtx.Config.RPC.ListenAddress {
   189  		t.Error("RPCListenAddress was not set from command flags")
   190  	}
   191  }
   192  
   193  func TestInterceptConfigsPreRunHandlerReadsEnvVars(t *testing.T) {
   194  	const testAddr = "tcp://127.1.2.3:12345"
   195  	tempDir := t.TempDir()
   196  	cmd := StartCmd(nil, "/foobar")
   197  	if err := cmd.Flags().Set(flags.FlagHome, tempDir); err != nil {
   198  		t.Fatalf("Could not set home flag [%T] %v", err, err)
   199  	}
   200  
   201  	executableName, err := os.Executable()
   202  	if err != nil {
   203  		t.Fatalf("Could not get executable name: %v", err)
   204  	}
   205  	basename := path.Base(executableName)
   206  	basename = strings.ReplaceAll(basename, ".", "_")
   207  	// This is added by ostracon
   208  	envVarName := fmt.Sprintf("%s_RPC_LADDR", strings.ToUpper(basename))
   209  	os.Setenv(envVarName, testAddr)
   210  	t.Cleanup(func() {
   211  		os.Unsetenv(envVarName)
   212  	})
   213  
   214  	cmd.PreRunE = preRunETestImpl
   215  
   216  	serverCtx := &Context{}
   217  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   218  
   219  	if err := cmd.ExecuteContext(ctx); err != cancelledInPreRun {
   220  		t.Fatalf("function failed with [%T] %v", err, err)
   221  	}
   222  
   223  	if testAddr != serverCtx.Config.RPC.ListenAddress {
   224  		t.Errorf("RPCListenAddress was not set from env. var. %q", envVarName)
   225  	}
   226  }
   227  
   228  /*
   229   The following tests are here to check the precedence of each
   230   of the configuration sources. A common setup functionality is used
   231   to avoid duplication of code between tests.
   232  */
   233  
   234  var (
   235  	TestAddrExpected    = "tcp://127.126.125.124:12345" // expected to be used in test
   236  	TestAddrNotExpected = "tcp://127.127.127.127:11111" // not expected to be used in test
   237  )
   238  
   239  type precedenceCommon struct {
   240  	envVarName     string
   241  	flagName       string
   242  	configTomlPath string
   243  
   244  	cmd *cobra.Command
   245  }
   246  
   247  func newPrecedenceCommon(t *testing.T) precedenceCommon {
   248  	retval := precedenceCommon{}
   249  
   250  	// Determine the env. var. name based off the executable name
   251  	executableName, err := os.Executable()
   252  	if err != nil {
   253  		t.Fatalf("Could not get executable name: %v", err)
   254  	}
   255  	basename := path.Base(executableName)
   256  	basename = strings.ReplaceAll(basename, ".", "_")
   257  	basename = strings.ReplaceAll(basename, "-", "_")
   258  	// Store the name of the env. var.
   259  	retval.envVarName = fmt.Sprintf("%s_RPC_LADDR", strings.ToUpper(basename))
   260  
   261  	// Store the flag name. This flag is added by ostracon
   262  	retval.flagName = "rpc.laddr"
   263  
   264  	// Create a tempdir and create './config' under that
   265  	tempDir := t.TempDir()
   266  	err = os.Mkdir(path.Join(tempDir, "config"), os.ModePerm)
   267  	if err != nil {
   268  		t.Fatalf("creating config dir failed: %v", err)
   269  	}
   270  	// Store the path for config.toml
   271  	retval.configTomlPath = path.Join(tempDir, "config", "config.toml")
   272  
   273  	// always remove the env. var. after each test execution
   274  	t.Cleanup(func() {
   275  		// This should not fail but if it does just panic
   276  		if err := os.Unsetenv(retval.envVarName); err != nil {
   277  			panic("Could not clear configuration env. var. used in test")
   278  		}
   279  	})
   280  
   281  	// Set up the command object that is used in this test
   282  	retval.cmd = StartCmd(nil, tempDir)
   283  	retval.cmd.PreRunE = preRunETestImpl
   284  
   285  	return retval
   286  }
   287  
   288  func (v precedenceCommon) setAll(t *testing.T, setFlag *string, setEnvVar *string, setConfigFile *string) {
   289  	if setFlag != nil {
   290  		if err := v.cmd.Flags().Set(v.flagName, *setFlag); err != nil {
   291  			t.Fatalf("Failed setting flag %q", v.flagName)
   292  		}
   293  	}
   294  
   295  	if setEnvVar != nil {
   296  		os.Setenv(v.envVarName, *setEnvVar)
   297  	}
   298  
   299  	if setConfigFile != nil {
   300  		writer, err := os.Create(v.configTomlPath)
   301  		if err != nil {
   302  			t.Fatalf("creating config.toml file failed: %v", err)
   303  		}
   304  
   305  		_, err = writer.WriteString(fmt.Sprintf("[rpc]\nladdr = \"%s\"\n", *setConfigFile))
   306  		if err != nil {
   307  			t.Fatalf("Failed writing string to config.toml: %v", err)
   308  		}
   309  
   310  		if err := writer.Close(); err != nil {
   311  			t.Fatalf("Failed closing config.toml: %v", err)
   312  		}
   313  	}
   314  }
   315  
   316  func TestInterceptConfigsPreRunHandlerPrecedenceFlag(t *testing.T) {
   317  	testCommon := newPrecedenceCommon(t)
   318  	testCommon.setAll(t, &TestAddrExpected, &TestAddrNotExpected, &TestAddrNotExpected)
   319  
   320  	serverCtx := &Context{}
   321  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   322  
   323  	if err := testCommon.cmd.ExecuteContext(ctx); err != cancelledInPreRun {
   324  		t.Fatalf("function failed with [%T] %v", err, err)
   325  	}
   326  
   327  	if TestAddrExpected != serverCtx.Config.RPC.ListenAddress {
   328  		t.Fatalf("RPCListenAddress was not set from flag %q", testCommon.flagName)
   329  	}
   330  }
   331  
   332  func TestInterceptConfigsPreRunHandlerPrecedenceEnvVar(t *testing.T) {
   333  	testCommon := newPrecedenceCommon(t)
   334  	testCommon.setAll(t, nil, &TestAddrExpected, &TestAddrNotExpected)
   335  
   336  	serverCtx := &Context{}
   337  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   338  
   339  	if err := testCommon.cmd.ExecuteContext(ctx); err != cancelledInPreRun {
   340  		t.Fatalf("function failed with [%T] %v", err, err)
   341  	}
   342  
   343  	if TestAddrExpected != serverCtx.Config.RPC.ListenAddress {
   344  		t.Errorf("RPCListenAddress was not set from env. var. %q", testCommon.envVarName)
   345  	}
   346  }
   347  
   348  func TestInterceptConfigsPreRunHandlerPrecedenceConfigFile(t *testing.T) {
   349  	testCommon := newPrecedenceCommon(t)
   350  	testCommon.setAll(t, nil, nil, &TestAddrExpected)
   351  
   352  	serverCtx := &Context{}
   353  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   354  
   355  	if err := testCommon.cmd.ExecuteContext(ctx); err != cancelledInPreRun {
   356  		t.Fatalf("function failed with [%T] %v", err, err)
   357  	}
   358  
   359  	if TestAddrExpected != serverCtx.Config.RPC.ListenAddress {
   360  		t.Errorf("RPCListenAddress was not read from file %q", testCommon.configTomlPath)
   361  	}
   362  }
   363  
   364  func TestInterceptConfigsPreRunHandlerPrecedenceConfigDefault(t *testing.T) {
   365  	testCommon := newPrecedenceCommon(t)
   366  	// Do not set anything
   367  
   368  	serverCtx := &Context{}
   369  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   370  
   371  	if err := testCommon.cmd.ExecuteContext(ctx); err != cancelledInPreRun {
   372  		t.Fatalf("function failed with [%T] %v", err, err)
   373  	}
   374  
   375  	if "tcp://127.0.0.1:26657" != serverCtx.Config.RPC.ListenAddress {
   376  		t.Error("RPCListenAddress is not using default")
   377  	}
   378  }
   379  
   380  // Ensure that if interceptConfigs encounters any error other than non-existen errors
   381  // that we correctly return the offending error, for example a permission error.
   382  // See https://github.com/cosmos/cosmos-sdk/issues/7578
   383  func TestInterceptConfigsWithBadPermissions(t *testing.T) {
   384  	tempDir := t.TempDir()
   385  	subDir := filepath.Join(tempDir, "nonPerms")
   386  	if err := os.Mkdir(subDir, 0o600); err != nil {
   387  		t.Fatalf("Failed to create sub directory: %v", err)
   388  	}
   389  	cmd := StartCmd(nil, "/foobar")
   390  	if err := cmd.Flags().Set(flags.FlagHome, subDir); err != nil {
   391  		t.Fatalf("Could not set home flag [%T] %v", err, err)
   392  	}
   393  
   394  	cmd.PreRunE = preRunETestImpl
   395  
   396  	serverCtx := &Context{}
   397  	ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
   398  	if err := cmd.ExecuteContext(ctx); !os.IsPermission(err) {
   399  		t.Fatalf("Failed to catch permissions error, got: [%T] %v", err, err)
   400  	}
   401  }