github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/config/toml_test.go (about) 1 package config 2 3 import ( 4 "io" 5 "os" 6 "path/filepath" 7 "reflect" 8 "strings" 9 "testing" 10 11 "github.com/gnolang/gno/tm2/pkg/testutils" 12 "github.com/pelletier/go-toml" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func ensureFiles(t *testing.T, rootDir string, files ...string) { 18 t.Helper() 19 20 for _, f := range files { 21 p := filepath.Join(rootDir, f) 22 _, err := os.Stat(p) 23 assert.Nil(t, err, p) 24 } 25 } 26 27 func TestEnsureRoot(t *testing.T) { 28 t.Parallel() 29 30 // setup temp dir for test 31 tmpDir := t.TempDir() 32 33 // create root dir 34 throwaway := DefaultConfig() 35 throwaway.SetRootDir(tmpDir) 36 require.NoError(t, throwaway.EnsureDirs()) 37 38 configPath := filepath.Join(tmpDir, defaultConfigPath) 39 require.NoError(t, WriteConfigFile(configPath, throwaway)) 40 41 // make sure config is set properly 42 data, err := os.ReadFile(filepath.Join(tmpDir, defaultConfigPath)) 43 require.Nil(t, err) 44 45 require.True(t, checkConfig(string(data))) 46 47 ensureFiles(t, tmpDir, DefaultDBDir) 48 } 49 50 func TestEnsureTestRoot(t *testing.T) { 51 t.Parallel() 52 53 testName := "ensureTestRoot" 54 55 // create root dir 56 cfg, _ := ResetTestRoot(testName) 57 defer os.RemoveAll(cfg.RootDir) 58 rootDir := cfg.RootDir 59 60 // make sure config is set properly 61 data, err := os.ReadFile(filepath.Join(rootDir, defaultConfigPath)) 62 require.Nil(t, err) 63 64 require.True(t, checkConfig(string(data))) 65 66 // TODO: make sure the cfg returned and testconfig are the same! 67 baseConfig := DefaultBaseConfig() 68 ensureFiles( 69 t, 70 rootDir, 71 "genesis.json", 72 DefaultDBDir, 73 baseConfig.PrivValidatorKey, 74 baseConfig.PrivValidatorState, 75 ) 76 } 77 78 func checkConfig(configFile string) bool { 79 var valid bool 80 81 // list of words we expect in the config 82 elems := []string{ 83 "moniker", 84 "seeds", 85 "proxy_app", 86 "fast_sync", 87 "create_empty_blocks", 88 "peer", 89 "timeout", 90 "broadcast", 91 "send", 92 "addr", 93 "wal", 94 "propose", 95 "max", 96 } 97 for _, e := range elems { 98 if !strings.Contains(configFile, e) { 99 valid = false 100 } else { 101 valid = true 102 } 103 } 104 return valid 105 } 106 107 func TestTOML_LoadConfig(t *testing.T) { 108 t.Parallel() 109 110 t.Run("config does not exist", func(t *testing.T) { 111 t.Parallel() 112 113 cfg, loadErr := LoadConfigFile("dummy-path") 114 115 assert.Error(t, loadErr) 116 assert.Nil(t, cfg) 117 }) 118 119 t.Run("config is not valid toml", func(t *testing.T) { 120 t.Parallel() 121 122 // Create config file 123 configFile, cleanup := testutils.NewTestFile(t) 124 t.Cleanup(cleanup) 125 126 // Write invalid TOML 127 _, writeErr := configFile.WriteString("invalid TOML") 128 require.NoError(t, writeErr) 129 130 cfg, loadErr := LoadConfigFile(configFile.Name()) 131 132 assert.Error(t, loadErr) 133 assert.Nil(t, cfg) 134 }) 135 136 t.Run("valid config", func(t *testing.T) { 137 t.Parallel() 138 139 // Create config file 140 configFile, cleanup := testutils.NewTestFile(t) 141 t.Cleanup(cleanup) 142 143 // Create the default config 144 defaultConfig := DefaultConfig() 145 146 // Marshal the default config 147 defaultConfigRaw, marshalErr := toml.Marshal(defaultConfig) 148 require.NoError(t, marshalErr) 149 150 // Write valid TOML 151 _, writeErr := configFile.Write(defaultConfigRaw) 152 require.NoError(t, writeErr) 153 154 cfg, loadErr := LoadConfigFile(configFile.Name()) 155 require.NoError(t, loadErr) 156 157 assert.EqualValues(t, defaultConfig.BaseConfig, cfg.BaseConfig) 158 assert.EqualValues(t, defaultConfig.RPC, cfg.RPC) 159 assert.EqualValues(t, defaultConfig.P2P, cfg.P2P) 160 assert.EqualValues(t, defaultConfig.Mempool, cfg.Mempool) 161 assert.EqualValues(t, defaultConfig.Consensus, cfg.Consensus) 162 assert.Equal(t, defaultConfig.TxEventStore.EventStoreType, cfg.TxEventStore.EventStoreType) 163 assert.Empty(t, defaultConfig.TxEventStore.Params, cfg.TxEventStore.Params) 164 }) 165 } 166 167 func TestTOML_ConfigComments(t *testing.T) { 168 t.Parallel() 169 170 collectCommentTags := func(v reflect.Value) []string { 171 var ( 172 comments = make([]string, 0) 173 structStack = []reflect.Value{v} 174 ) 175 176 // Descend on and parse all child fields 177 for len(structStack) > 0 { 178 structVal := structStack[len(structStack)-1] 179 structStack = structStack[:len(structStack)-1] 180 181 // Process all fields of the struct 182 for i := 0; i < structVal.NumField(); i++ { 183 fieldVal := structVal.Field(i) 184 fieldType := structVal.Type().Field(i) 185 186 // If the field is a struct, push it onto the stack for further processing 187 if fieldVal.Kind() == reflect.Struct { 188 structStack = append(structStack, fieldVal) 189 190 continue 191 } 192 193 // Collect the comment tag value from the field 194 if commentTag := fieldType.Tag.Get("comment"); commentTag != "" { 195 comments = append(comments, commentTag) 196 } 197 } 198 } 199 200 return comments 201 } 202 203 cleanComments := func(original string) string { 204 return strings.ReplaceAll(original, "#", "") 205 } 206 207 // Create test config file 208 configFile, cleanup := testutils.NewTestFile(t) 209 t.Cleanup(cleanup) 210 211 // Create the default config 212 defaultConfig := DefaultConfig() 213 214 // Write valid TOML 215 require.NoError(t, WriteConfigFile(configFile.Name(), defaultConfig)) 216 217 // Collect config comments 218 comments := collectCommentTags(reflect.ValueOf(*defaultConfig)) 219 require.NotEmpty(t, comments) 220 221 // Read the entire config file 222 rawConfig, err := io.ReadAll(configFile) 223 require.NoError(t, err) 224 225 // Verify TOML comments are present 226 content := cleanComments(string(rawConfig)) 227 for _, comment := range comments { 228 assert.Contains(t, content, cleanComments(comment)) 229 } 230 }