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 }