viper_test.go 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292
  1. // Copyright © 2014 Steve Francia <spf@spf13.com>.
  2. //
  3. // Use of this source code is governed by an MIT-style
  4. // license that can be found in the LICENSE file.
  5. package viper
  6. import (
  7. "bytes"
  8. "encoding/json"
  9. "io"
  10. "io/ioutil"
  11. "os"
  12. "os/exec"
  13. "path"
  14. "path/filepath"
  15. "reflect"
  16. "runtime"
  17. "sort"
  18. "strings"
  19. "sync"
  20. "testing"
  21. "time"
  22. "github.com/fsnotify/fsnotify"
  23. "github.com/mitchellh/mapstructure"
  24. "github.com/spf13/afero"
  25. "github.com/spf13/cast"
  26. "github.com/spf13/pflag"
  27. "github.com/stretchr/testify/assert"
  28. "github.com/stretchr/testify/require"
  29. )
  30. var yamlExample = []byte(`Hacker: true
  31. name: steve
  32. hobbies:
  33. - skateboarding
  34. - snowboarding
  35. - go
  36. clothing:
  37. jacket: leather
  38. trousers: denim
  39. pants:
  40. size: large
  41. age: 35
  42. eyes : brown
  43. beard: true
  44. `)
  45. var yamlExampleWithExtras = []byte(`Existing: true
  46. Bogus: true
  47. `)
  48. type testUnmarshalExtra struct {
  49. Existing bool
  50. }
  51. var tomlExample = []byte(`
  52. title = "TOML Example"
  53. [owner]
  54. organization = "MongoDB"
  55. Bio = "MongoDB Chief Developer Advocate & Hacker at Large"
  56. dob = 1979-05-27T07:32:00Z # First class dates? Why not?`)
  57. var dotenvExample = []byte(`
  58. TITLE_DOTENV="DotEnv Example"
  59. TYPE_DOTENV=donut
  60. NAME_DOTENV=Cake`)
  61. var jsonExample = []byte(`{
  62. "id": "0001",
  63. "type": "donut",
  64. "name": "Cake",
  65. "ppu": 0.55,
  66. "batters": {
  67. "batter": [
  68. { "type": "Regular" },
  69. { "type": "Chocolate" },
  70. { "type": "Blueberry" },
  71. { "type": "Devil's Food" }
  72. ]
  73. }
  74. }`)
  75. var hclExample = []byte(`
  76. id = "0001"
  77. type = "donut"
  78. name = "Cake"
  79. ppu = 0.55
  80. foos {
  81. foo {
  82. key = 1
  83. }
  84. foo {
  85. key = 2
  86. }
  87. foo {
  88. key = 3
  89. }
  90. foo {
  91. key = 4
  92. }
  93. }`)
  94. var propertiesExample = []byte(`
  95. p_id: 0001
  96. p_type: donut
  97. p_name: Cake
  98. p_ppu: 0.55
  99. p_batters.batter.type: Regular
  100. `)
  101. var remoteExample = []byte(`{
  102. "id":"0002",
  103. "type":"cronut",
  104. "newkey":"remote"
  105. }`)
  106. var iniExample = []byte(`; Package name
  107. NAME = ini
  108. ; Package version
  109. VERSION = v1
  110. ; Package import path
  111. IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
  112. # Information about package author
  113. # Bio can be written in multiple lines.
  114. [author]
  115. NAME = Unknown ; Succeeding comment
  116. E-MAIL = fake@localhost
  117. GITHUB = https://github.com/%(NAME)s
  118. BIO = """Gopher.
  119. Coding addict.
  120. Good man.
  121. """ # Succeeding comment`)
  122. func initConfigs() {
  123. Reset()
  124. var r io.Reader
  125. SetConfigType("yaml")
  126. r = bytes.NewReader(yamlExample)
  127. unmarshalReader(r, v.config)
  128. SetConfigType("json")
  129. r = bytes.NewReader(jsonExample)
  130. unmarshalReader(r, v.config)
  131. SetConfigType("hcl")
  132. r = bytes.NewReader(hclExample)
  133. unmarshalReader(r, v.config)
  134. SetConfigType("properties")
  135. r = bytes.NewReader(propertiesExample)
  136. unmarshalReader(r, v.config)
  137. SetConfigType("toml")
  138. r = bytes.NewReader(tomlExample)
  139. unmarshalReader(r, v.config)
  140. SetConfigType("env")
  141. r = bytes.NewReader(dotenvExample)
  142. unmarshalReader(r, v.config)
  143. SetConfigType("json")
  144. remote := bytes.NewReader(remoteExample)
  145. unmarshalReader(remote, v.kvstore)
  146. SetConfigType("ini")
  147. r = bytes.NewReader(iniExample)
  148. unmarshalReader(r, v.config)
  149. }
  150. func initConfig(typ, config string) {
  151. Reset()
  152. SetConfigType(typ)
  153. r := strings.NewReader(config)
  154. if err := unmarshalReader(r, v.config); err != nil {
  155. panic(err)
  156. }
  157. }
  158. func initYAML() {
  159. initConfig("yaml", string(yamlExample))
  160. }
  161. func initJSON() {
  162. Reset()
  163. SetConfigType("json")
  164. r := bytes.NewReader(jsonExample)
  165. unmarshalReader(r, v.config)
  166. }
  167. func initProperties() {
  168. Reset()
  169. SetConfigType("properties")
  170. r := bytes.NewReader(propertiesExample)
  171. unmarshalReader(r, v.config)
  172. }
  173. func initTOML() {
  174. Reset()
  175. SetConfigType("toml")
  176. r := bytes.NewReader(tomlExample)
  177. unmarshalReader(r, v.config)
  178. }
  179. func initDotEnv() {
  180. Reset()
  181. SetConfigType("env")
  182. r := bytes.NewReader(dotenvExample)
  183. unmarshalReader(r, v.config)
  184. }
  185. func initHcl() {
  186. Reset()
  187. SetConfigType("hcl")
  188. r := bytes.NewReader(hclExample)
  189. unmarshalReader(r, v.config)
  190. }
  191. func initIni() {
  192. Reset()
  193. SetConfigType("ini")
  194. r := bytes.NewReader(iniExample)
  195. unmarshalReader(r, v.config)
  196. }
  197. // make directories for testing
  198. func initDirs(t *testing.T) (string, string, func()) {
  199. var (
  200. testDirs = []string{`a a`, `b`, `C_`}
  201. config = `improbable`
  202. )
  203. if runtime.GOOS != "windows" {
  204. testDirs = append(testDirs, `d\d`)
  205. }
  206. root, err := ioutil.TempDir("", "")
  207. require.NoError(t, err, "Failed to create temporary directory")
  208. cleanup := true
  209. defer func() {
  210. if cleanup {
  211. os.Chdir("..")
  212. os.RemoveAll(root)
  213. }
  214. }()
  215. assert.Nil(t, err)
  216. err = os.Chdir(root)
  217. require.Nil(t, err)
  218. for _, dir := range testDirs {
  219. err = os.Mkdir(dir, 0750)
  220. assert.Nil(t, err)
  221. err = ioutil.WriteFile(
  222. path.Join(dir, config+".toml"),
  223. []byte("key = \"value is "+dir+"\"\n"),
  224. 0640)
  225. assert.Nil(t, err)
  226. }
  227. cleanup = false
  228. return root, config, func() {
  229. os.Chdir("..")
  230. os.RemoveAll(root)
  231. }
  232. }
  233. // stubs for PFlag Values
  234. type stringValue string
  235. func newStringValue(val string, p *string) *stringValue {
  236. *p = val
  237. return (*stringValue)(p)
  238. }
  239. func (s *stringValue) Set(val string) error {
  240. *s = stringValue(val)
  241. return nil
  242. }
  243. func (s *stringValue) Type() string {
  244. return "string"
  245. }
  246. func (s *stringValue) String() string {
  247. return string(*s)
  248. }
  249. func TestBasics(t *testing.T) {
  250. SetConfigFile("/tmp/config.yaml")
  251. filename, err := v.getConfigFile()
  252. assert.Equal(t, "/tmp/config.yaml", filename)
  253. assert.NoError(t, err)
  254. }
  255. func TestSearchInPath_WithoutConfigTypeSet(t *testing.T) {
  256. filename := ".dotfilenoext"
  257. path := "/tmp"
  258. file := filepath.Join(path, filename)
  259. SetConfigName(filename)
  260. AddConfigPath(path)
  261. _, createErr := v.fs.Create(file)
  262. defer func() {
  263. _ = v.fs.Remove(file)
  264. }()
  265. assert.NoError(t, createErr)
  266. _, err := v.getConfigFile()
  267. // unless config type is set, files without extension
  268. // are not considered
  269. assert.Error(t, err)
  270. }
  271. func TestSearchInPath(t *testing.T) {
  272. filename := ".dotfilenoext"
  273. path := "/tmp"
  274. file := filepath.Join(path, filename)
  275. SetConfigName(filename)
  276. SetConfigType("yaml")
  277. AddConfigPath(path)
  278. _, createErr := v.fs.Create(file)
  279. defer func() {
  280. _ = v.fs.Remove(file)
  281. }()
  282. assert.NoError(t, createErr)
  283. filename, err := v.getConfigFile()
  284. assert.Equal(t, file, filename)
  285. assert.NoError(t, err)
  286. }
  287. func TestSearchInPath_FilesOnly(t *testing.T) {
  288. fs := afero.NewMemMapFs()
  289. err := fs.Mkdir("/tmp/config", 0777)
  290. require.NoError(t, err)
  291. _, err = fs.Create("/tmp/config/config.yaml")
  292. require.NoError(t, err)
  293. v := New()
  294. v.SetFs(fs)
  295. v.AddConfigPath("/tmp")
  296. v.AddConfigPath("/tmp/config")
  297. filename, err := v.getConfigFile()
  298. assert.Equal(t, "/tmp/config/config.yaml", filename)
  299. assert.NoError(t, err)
  300. }
  301. func TestDefault(t *testing.T) {
  302. SetDefault("age", 45)
  303. assert.Equal(t, 45, Get("age"))
  304. SetDefault("clothing.jacket", "slacks")
  305. assert.Equal(t, "slacks", Get("clothing.jacket"))
  306. SetConfigType("yaml")
  307. err := ReadConfig(bytes.NewBuffer(yamlExample))
  308. assert.NoError(t, err)
  309. assert.Equal(t, "leather", Get("clothing.jacket"))
  310. }
  311. func TestUnmarshaling(t *testing.T) {
  312. SetConfigType("yaml")
  313. r := bytes.NewReader(yamlExample)
  314. unmarshalReader(r, v.config)
  315. assert.True(t, InConfig("name"))
  316. assert.False(t, InConfig("state"))
  317. assert.Equal(t, "steve", Get("name"))
  318. assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
  319. assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing"))
  320. assert.Equal(t, 35, Get("age"))
  321. }
  322. func TestUnmarshalExact(t *testing.T) {
  323. vip := New()
  324. target := &testUnmarshalExtra{}
  325. vip.SetConfigType("yaml")
  326. r := bytes.NewReader(yamlExampleWithExtras)
  327. vip.ReadConfig(r)
  328. err := vip.UnmarshalExact(target)
  329. if err == nil {
  330. t.Fatal("UnmarshalExact should error when populating a struct from a conf that contains unused fields")
  331. }
  332. }
  333. func TestOverrides(t *testing.T) {
  334. Set("age", 40)
  335. assert.Equal(t, 40, Get("age"))
  336. }
  337. func TestDefaultPost(t *testing.T) {
  338. assert.NotEqual(t, "NYC", Get("state"))
  339. SetDefault("state", "NYC")
  340. assert.Equal(t, "NYC", Get("state"))
  341. }
  342. func TestAliases(t *testing.T) {
  343. RegisterAlias("years", "age")
  344. assert.Equal(t, 40, Get("years"))
  345. Set("years", 45)
  346. assert.Equal(t, 45, Get("age"))
  347. }
  348. func TestAliasInConfigFile(t *testing.T) {
  349. // the config file specifies "beard". If we make this an alias for
  350. // "hasbeard", we still want the old config file to work with beard.
  351. RegisterAlias("beard", "hasbeard")
  352. assert.Equal(t, true, Get("hasbeard"))
  353. Set("hasbeard", false)
  354. assert.Equal(t, false, Get("beard"))
  355. }
  356. func TestYML(t *testing.T) {
  357. initYAML()
  358. assert.Equal(t, "steve", Get("name"))
  359. }
  360. func TestJSON(t *testing.T) {
  361. initJSON()
  362. assert.Equal(t, "0001", Get("id"))
  363. }
  364. func TestProperties(t *testing.T) {
  365. initProperties()
  366. assert.Equal(t, "0001", Get("p_id"))
  367. }
  368. func TestTOML(t *testing.T) {
  369. initTOML()
  370. assert.Equal(t, "TOML Example", Get("title"))
  371. }
  372. func TestDotEnv(t *testing.T) {
  373. initDotEnv()
  374. assert.Equal(t, "DotEnv Example", Get("title_dotenv"))
  375. }
  376. func TestHCL(t *testing.T) {
  377. initHcl()
  378. assert.Equal(t, "0001", Get("id"))
  379. assert.Equal(t, 0.55, Get("ppu"))
  380. assert.Equal(t, "donut", Get("type"))
  381. assert.Equal(t, "Cake", Get("name"))
  382. Set("id", "0002")
  383. assert.Equal(t, "0002", Get("id"))
  384. assert.NotEqual(t, "cronut", Get("type"))
  385. }
  386. func TestIni(t *testing.T) {
  387. initIni()
  388. assert.Equal(t, "ini", Get("default.name"))
  389. }
  390. func TestRemotePrecedence(t *testing.T) {
  391. initJSON()
  392. remote := bytes.NewReader(remoteExample)
  393. assert.Equal(t, "0001", Get("id"))
  394. unmarshalReader(remote, v.kvstore)
  395. assert.Equal(t, "0001", Get("id"))
  396. assert.NotEqual(t, "cronut", Get("type"))
  397. assert.Equal(t, "remote", Get("newkey"))
  398. Set("newkey", "newvalue")
  399. assert.NotEqual(t, "remote", Get("newkey"))
  400. assert.Equal(t, "newvalue", Get("newkey"))
  401. Set("newkey", "remote")
  402. }
  403. func TestEnv(t *testing.T) {
  404. initJSON()
  405. BindEnv("id")
  406. BindEnv("f", "FOOD")
  407. os.Setenv("ID", "13")
  408. os.Setenv("FOOD", "apple")
  409. os.Setenv("NAME", "crunk")
  410. assert.Equal(t, "13", Get("id"))
  411. assert.Equal(t, "apple", Get("f"))
  412. assert.Equal(t, "Cake", Get("name"))
  413. AutomaticEnv()
  414. assert.Equal(t, "crunk", Get("name"))
  415. }
  416. func TestEmptyEnv(t *testing.T) {
  417. initJSON()
  418. BindEnv("type") // Empty environment variable
  419. BindEnv("name") // Bound, but not set environment variable
  420. os.Unsetenv("type")
  421. os.Unsetenv("TYPE")
  422. os.Unsetenv("name")
  423. os.Unsetenv("NAME")
  424. os.Setenv("TYPE", "")
  425. assert.Equal(t, "donut", Get("type"))
  426. assert.Equal(t, "Cake", Get("name"))
  427. }
  428. func TestEmptyEnv_Allowed(t *testing.T) {
  429. initJSON()
  430. AllowEmptyEnv(true)
  431. BindEnv("type") // Empty environment variable
  432. BindEnv("name") // Bound, but not set environment variable
  433. os.Unsetenv("type")
  434. os.Unsetenv("TYPE")
  435. os.Unsetenv("name")
  436. os.Unsetenv("NAME")
  437. os.Setenv("TYPE", "")
  438. assert.Equal(t, "", Get("type"))
  439. assert.Equal(t, "Cake", Get("name"))
  440. }
  441. func TestEnvPrefix(t *testing.T) {
  442. initJSON()
  443. SetEnvPrefix("foo") // will be uppercased automatically
  444. BindEnv("id")
  445. BindEnv("f", "FOOD") // not using prefix
  446. os.Setenv("FOO_ID", "13")
  447. os.Setenv("FOOD", "apple")
  448. os.Setenv("FOO_NAME", "crunk")
  449. assert.Equal(t, "13", Get("id"))
  450. assert.Equal(t, "apple", Get("f"))
  451. assert.Equal(t, "Cake", Get("name"))
  452. AutomaticEnv()
  453. assert.Equal(t, "crunk", Get("name"))
  454. }
  455. func TestAutoEnv(t *testing.T) {
  456. Reset()
  457. AutomaticEnv()
  458. os.Setenv("FOO_BAR", "13")
  459. assert.Equal(t, "13", Get("foo_bar"))
  460. }
  461. func TestAutoEnvWithPrefix(t *testing.T) {
  462. Reset()
  463. AutomaticEnv()
  464. SetEnvPrefix("Baz")
  465. os.Setenv("BAZ_BAR", "13")
  466. assert.Equal(t, "13", Get("bar"))
  467. }
  468. func TestSetEnvKeyReplacer(t *testing.T) {
  469. Reset()
  470. AutomaticEnv()
  471. os.Setenv("REFRESH_INTERVAL", "30s")
  472. replacer := strings.NewReplacer("-", "_")
  473. SetEnvKeyReplacer(replacer)
  474. assert.Equal(t, "30s", Get("refresh-interval"))
  475. }
  476. func TestEnvKeyReplacer(t *testing.T) {
  477. v := NewWithOptions(EnvKeyReplacer(strings.NewReplacer("-", "_")))
  478. v.AutomaticEnv()
  479. _ = os.Setenv("REFRESH_INTERVAL", "30s")
  480. assert.Equal(t, "30s", v.Get("refresh-interval"))
  481. }
  482. func TestAllKeys(t *testing.T) {
  483. initConfigs()
  484. ks := sort.StringSlice{
  485. "title",
  486. "author.bio",
  487. "author.e-mail",
  488. "author.github",
  489. "author.name",
  490. "newkey",
  491. "owner.organization",
  492. "owner.dob",
  493. "owner.bio",
  494. "name",
  495. "beard",
  496. "ppu",
  497. "batters.batter",
  498. "hobbies",
  499. "clothing.jacket",
  500. "clothing.trousers",
  501. "default.import_path",
  502. "default.name",
  503. "default.version",
  504. "clothing.pants.size",
  505. "age",
  506. "hacker",
  507. "id",
  508. "type",
  509. "eyes",
  510. "p_id",
  511. "p_ppu",
  512. "p_batters.batter.type",
  513. "p_type",
  514. "p_name",
  515. "foos",
  516. "title_dotenv",
  517. "type_dotenv",
  518. "name_dotenv",
  519. }
  520. dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
  521. all := map[string]interface{}{
  522. "owner": map[string]interface{}{
  523. "organization": "MongoDB",
  524. "bio": "MongoDB Chief Developer Advocate & Hacker at Large",
  525. "dob": dob,
  526. },
  527. "title": "TOML Example",
  528. "author": map[string]interface{}{
  529. "e-mail": "fake@localhost",
  530. "github": "https://github.com/Unknown",
  531. "name": "Unknown",
  532. "bio": "Gopher.\nCoding addict.\nGood man.\n",
  533. },
  534. "ppu": 0.55,
  535. "eyes": "brown",
  536. "clothing": map[string]interface{}{
  537. "trousers": "denim",
  538. "jacket": "leather",
  539. "pants": map[string]interface{}{"size": "large"},
  540. },
  541. "default": map[string]interface{}{
  542. "import_path": "gopkg.in/ini.v1",
  543. "name": "ini",
  544. "version": "v1",
  545. },
  546. "id": "0001",
  547. "batters": map[string]interface{}{
  548. "batter": []interface{}{
  549. map[string]interface{}{"type": "Regular"},
  550. map[string]interface{}{"type": "Chocolate"},
  551. map[string]interface{}{"type": "Blueberry"},
  552. map[string]interface{}{"type": "Devil's Food"},
  553. },
  554. },
  555. "hacker": true,
  556. "beard": true,
  557. "hobbies": []interface{}{
  558. "skateboarding",
  559. "snowboarding",
  560. "go",
  561. },
  562. "age": 35,
  563. "type": "donut",
  564. "newkey": "remote",
  565. "name": "Cake",
  566. "p_id": "0001",
  567. "p_ppu": "0.55",
  568. "p_name": "Cake",
  569. "p_batters": map[string]interface{}{
  570. "batter": map[string]interface{}{"type": "Regular"},
  571. },
  572. "p_type": "donut",
  573. "foos": []map[string]interface{}{
  574. {
  575. "foo": []map[string]interface{}{
  576. {"key": 1},
  577. {"key": 2},
  578. {"key": 3},
  579. {"key": 4}},
  580. },
  581. },
  582. "title_dotenv": "DotEnv Example",
  583. "type_dotenv": "donut",
  584. "name_dotenv": "Cake",
  585. }
  586. allkeys := sort.StringSlice(AllKeys())
  587. allkeys.Sort()
  588. ks.Sort()
  589. assert.Equal(t, ks, allkeys)
  590. assert.Equal(t, all, AllSettings())
  591. }
  592. func TestAllKeysWithEnv(t *testing.T) {
  593. v := New()
  594. // bind and define environment variables (including a nested one)
  595. v.BindEnv("id")
  596. v.BindEnv("foo.bar")
  597. v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
  598. os.Setenv("ID", "13")
  599. os.Setenv("FOO_BAR", "baz")
  600. expectedKeys := sort.StringSlice{"id", "foo.bar"}
  601. expectedKeys.Sort()
  602. keys := sort.StringSlice(v.AllKeys())
  603. keys.Sort()
  604. assert.Equal(t, expectedKeys, keys)
  605. }
  606. func TestAliasesOfAliases(t *testing.T) {
  607. Set("Title", "Checking Case")
  608. RegisterAlias("Foo", "Bar")
  609. RegisterAlias("Bar", "Title")
  610. assert.Equal(t, "Checking Case", Get("FOO"))
  611. }
  612. func TestRecursiveAliases(t *testing.T) {
  613. RegisterAlias("Baz", "Roo")
  614. RegisterAlias("Roo", "baz")
  615. }
  616. func TestUnmarshal(t *testing.T) {
  617. SetDefault("port", 1313)
  618. Set("name", "Steve")
  619. Set("duration", "1s1ms")
  620. Set("modes", []int{1, 2, 3})
  621. type config struct {
  622. Port int
  623. Name string
  624. Duration time.Duration
  625. Modes []int
  626. }
  627. var C config
  628. err := Unmarshal(&C)
  629. if err != nil {
  630. t.Fatalf("unable to decode into struct, %v", err)
  631. }
  632. assert.Equal(
  633. t,
  634. &config{
  635. Name: "Steve",
  636. Port: 1313,
  637. Duration: time.Second + time.Millisecond,
  638. Modes: []int{1, 2, 3},
  639. },
  640. &C,
  641. )
  642. Set("port", 1234)
  643. err = Unmarshal(&C)
  644. if err != nil {
  645. t.Fatalf("unable to decode into struct, %v", err)
  646. }
  647. assert.Equal(
  648. t,
  649. &config{
  650. Name: "Steve",
  651. Port: 1234,
  652. Duration: time.Second + time.Millisecond,
  653. Modes: []int{1, 2, 3},
  654. },
  655. &C,
  656. )
  657. }
  658. func TestUnmarshalWithDecoderOptions(t *testing.T) {
  659. Set("credentials", "{\"foo\":\"bar\"}")
  660. opt := DecodeHook(mapstructure.ComposeDecodeHookFunc(
  661. mapstructure.StringToTimeDurationHookFunc(),
  662. mapstructure.StringToSliceHookFunc(","),
  663. // Custom Decode Hook Function
  664. func(rf reflect.Kind, rt reflect.Kind, data interface{}) (interface{}, error) {
  665. if rf != reflect.String || rt != reflect.Map {
  666. return data, nil
  667. }
  668. m := map[string]string{}
  669. raw := data.(string)
  670. if raw == "" {
  671. return m, nil
  672. }
  673. return m, json.Unmarshal([]byte(raw), &m)
  674. },
  675. ))
  676. type config struct {
  677. Credentials map[string]string
  678. }
  679. var C config
  680. err := Unmarshal(&C, opt)
  681. if err != nil {
  682. t.Fatalf("unable to decode into struct, %v", err)
  683. }
  684. assert.Equal(t, &config{
  685. Credentials: map[string]string{"foo": "bar"},
  686. }, &C)
  687. }
  688. func TestBindPFlags(t *testing.T) {
  689. v := New() // create independent Viper object
  690. flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
  691. var testValues = map[string]*string{
  692. "host": nil,
  693. "port": nil,
  694. "endpoint": nil,
  695. }
  696. var mutatedTestValues = map[string]string{
  697. "host": "localhost",
  698. "port": "6060",
  699. "endpoint": "/public",
  700. }
  701. for name := range testValues {
  702. testValues[name] = flagSet.String(name, "", "test")
  703. }
  704. err := v.BindPFlags(flagSet)
  705. if err != nil {
  706. t.Fatalf("error binding flag set, %v", err)
  707. }
  708. flagSet.VisitAll(func(flag *pflag.Flag) {
  709. flag.Value.Set(mutatedTestValues[flag.Name])
  710. flag.Changed = true
  711. })
  712. for name, expected := range mutatedTestValues {
  713. assert.Equal(t, expected, v.Get(name))
  714. }
  715. }
  716. func TestBindPFlagsStringSlice(t *testing.T) {
  717. tests := []struct {
  718. Expected []string
  719. Value string
  720. }{
  721. {nil, ""},
  722. {[]string{"jeden"}, "jeden"},
  723. {[]string{"dwa", "trzy"}, "dwa,trzy"},
  724. {[]string{"cztery", "piec , szesc"}, "cztery,\"piec , szesc\""},
  725. }
  726. v := New() // create independent Viper object
  727. defaultVal := []string{"default"}
  728. v.SetDefault("stringslice", defaultVal)
  729. for _, testValue := range tests {
  730. flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
  731. flagSet.StringSlice("stringslice", testValue.Expected, "test")
  732. for _, changed := range []bool{true, false} {
  733. flagSet.VisitAll(func(f *pflag.Flag) {
  734. f.Value.Set(testValue.Value)
  735. f.Changed = changed
  736. })
  737. err := v.BindPFlags(flagSet)
  738. if err != nil {
  739. t.Fatalf("error binding flag set, %v", err)
  740. }
  741. type TestStr struct {
  742. StringSlice []string
  743. }
  744. val := &TestStr{}
  745. if err := v.Unmarshal(val); err != nil {
  746. t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
  747. }
  748. if changed {
  749. assert.Equal(t, testValue.Expected, val.StringSlice)
  750. } else {
  751. assert.Equal(t, defaultVal, val.StringSlice)
  752. }
  753. }
  754. }
  755. }
  756. func TestBindPFlagsIntSlice(t *testing.T) {
  757. tests := []struct {
  758. Expected []int
  759. Value string
  760. }{
  761. {nil, ""},
  762. {[]int{1}, "1"},
  763. {[]int{2, 3}, "2,3"},
  764. }
  765. v := New() // create independent Viper object
  766. defaultVal := []int{0}
  767. v.SetDefault("intslice", defaultVal)
  768. for _, testValue := range tests {
  769. flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
  770. flagSet.IntSlice("intslice", testValue.Expected, "test")
  771. for _, changed := range []bool{true, false} {
  772. flagSet.VisitAll(func(f *pflag.Flag) {
  773. f.Value.Set(testValue.Value)
  774. f.Changed = changed
  775. })
  776. err := v.BindPFlags(flagSet)
  777. if err != nil {
  778. t.Fatalf("error binding flag set, %v", err)
  779. }
  780. type TestInt struct {
  781. IntSlice []int
  782. }
  783. val := &TestInt{}
  784. if err := v.Unmarshal(val); err != nil {
  785. t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
  786. }
  787. if changed {
  788. assert.Equal(t, testValue.Expected, val.IntSlice)
  789. } else {
  790. assert.Equal(t, defaultVal, val.IntSlice)
  791. }
  792. }
  793. }
  794. }
  795. func TestBindPFlag(t *testing.T) {
  796. var testString = "testing"
  797. var testValue = newStringValue(testString, &testString)
  798. flag := &pflag.Flag{
  799. Name: "testflag",
  800. Value: testValue,
  801. Changed: false,
  802. }
  803. BindPFlag("testvalue", flag)
  804. assert.Equal(t, testString, Get("testvalue"))
  805. flag.Value.Set("testing_mutate")
  806. flag.Changed = true // hack for pflag usage
  807. assert.Equal(t, "testing_mutate", Get("testvalue"))
  808. }
  809. func TestBindPFlagStringToString(t *testing.T) {
  810. tests := []struct {
  811. Expected map[string]string
  812. Value string
  813. }{
  814. {map[string]string{}, ""},
  815. {map[string]string{"yo": "hi"}, "yo=hi"},
  816. {map[string]string{"yo": "hi", "oh": "hi=there"}, "yo=hi,oh=hi=there"},
  817. {map[string]string{"yo": ""}, "yo="},
  818. {map[string]string{"yo": "", "oh": "hi=there"}, "yo=,oh=hi=there"},
  819. }
  820. v := New() // create independent Viper object
  821. defaultVal := map[string]string{}
  822. v.SetDefault("stringtostring", defaultVal)
  823. for _, testValue := range tests {
  824. flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
  825. flagSet.StringToString("stringtostring", testValue.Expected, "test")
  826. for _, changed := range []bool{true, false} {
  827. flagSet.VisitAll(func(f *pflag.Flag) {
  828. f.Value.Set(testValue.Value)
  829. f.Changed = changed
  830. })
  831. err := v.BindPFlags(flagSet)
  832. if err != nil {
  833. t.Fatalf("error binding flag set, %v", err)
  834. }
  835. type TestMap struct {
  836. StringToString map[string]string
  837. }
  838. val := &TestMap{}
  839. if err := v.Unmarshal(val); err != nil {
  840. t.Fatalf("%+#v cannot unmarshal: %s", testValue.Value, err)
  841. }
  842. if changed {
  843. assert.Equal(t, testValue.Expected, val.StringToString)
  844. } else {
  845. assert.Equal(t, defaultVal, val.StringToString)
  846. }
  847. }
  848. }
  849. }
  850. func TestBoundCaseSensitivity(t *testing.T) {
  851. assert.Equal(t, "brown", Get("eyes"))
  852. BindEnv("eYEs", "TURTLE_EYES")
  853. os.Setenv("TURTLE_EYES", "blue")
  854. assert.Equal(t, "blue", Get("eyes"))
  855. var testString = "green"
  856. var testValue = newStringValue(testString, &testString)
  857. flag := &pflag.Flag{
  858. Name: "eyeballs",
  859. Value: testValue,
  860. Changed: true,
  861. }
  862. BindPFlag("eYEs", flag)
  863. assert.Equal(t, "green", Get("eyes"))
  864. }
  865. func TestSizeInBytes(t *testing.T) {
  866. input := map[string]uint{
  867. "": 0,
  868. "b": 0,
  869. "12 bytes": 0,
  870. "200000000000gb": 0,
  871. "12 b": 12,
  872. "43 MB": 43 * (1 << 20),
  873. "10mb": 10 * (1 << 20),
  874. "1gb": 1 << 30,
  875. }
  876. for str, expected := range input {
  877. assert.Equal(t, expected, parseSizeInBytes(str), str)
  878. }
  879. }
  880. func TestFindsNestedKeys(t *testing.T) {
  881. initConfigs()
  882. dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
  883. Set("super", map[string]interface{}{
  884. "deep": map[string]interface{}{
  885. "nested": "value",
  886. },
  887. })
  888. expected := map[string]interface{}{
  889. "super": map[string]interface{}{
  890. "deep": map[string]interface{}{
  891. "nested": "value",
  892. },
  893. },
  894. "super.deep": map[string]interface{}{
  895. "nested": "value",
  896. },
  897. "super.deep.nested": "value",
  898. "owner.organization": "MongoDB",
  899. "batters.batter": []interface{}{
  900. map[string]interface{}{
  901. "type": "Regular",
  902. },
  903. map[string]interface{}{
  904. "type": "Chocolate",
  905. },
  906. map[string]interface{}{
  907. "type": "Blueberry",
  908. },
  909. map[string]interface{}{
  910. "type": "Devil's Food",
  911. },
  912. },
  913. "hobbies": []interface{}{
  914. "skateboarding", "snowboarding", "go",
  915. },
  916. "TITLE_DOTENV": "DotEnv Example",
  917. "TYPE_DOTENV": "donut",
  918. "NAME_DOTENV": "Cake",
  919. "title": "TOML Example",
  920. "newkey": "remote",
  921. "batters": map[string]interface{}{
  922. "batter": []interface{}{
  923. map[string]interface{}{
  924. "type": "Regular",
  925. },
  926. map[string]interface{}{
  927. "type": "Chocolate",
  928. }, map[string]interface{}{
  929. "type": "Blueberry",
  930. }, map[string]interface{}{
  931. "type": "Devil's Food",
  932. },
  933. },
  934. },
  935. "eyes": "brown",
  936. "age": 35,
  937. "owner": map[string]interface{}{
  938. "organization": "MongoDB",
  939. "bio": "MongoDB Chief Developer Advocate & Hacker at Large",
  940. "dob": dob,
  941. },
  942. "owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large",
  943. "type": "donut",
  944. "id": "0001",
  945. "name": "Cake",
  946. "hacker": true,
  947. "ppu": 0.55,
  948. "clothing": map[string]interface{}{
  949. "jacket": "leather",
  950. "trousers": "denim",
  951. "pants": map[string]interface{}{
  952. "size": "large",
  953. },
  954. },
  955. "clothing.jacket": "leather",
  956. "clothing.pants.size": "large",
  957. "clothing.trousers": "denim",
  958. "owner.dob": dob,
  959. "beard": true,
  960. "foos": []map[string]interface{}{
  961. {
  962. "foo": []map[string]interface{}{
  963. {
  964. "key": 1,
  965. },
  966. {
  967. "key": 2,
  968. },
  969. {
  970. "key": 3,
  971. },
  972. {
  973. "key": 4,
  974. },
  975. },
  976. },
  977. },
  978. }
  979. for key, expectedValue := range expected {
  980. assert.Equal(t, expectedValue, v.Get(key))
  981. }
  982. }
  983. func TestReadBufConfig(t *testing.T) {
  984. v := New()
  985. v.SetConfigType("yaml")
  986. v.ReadConfig(bytes.NewBuffer(yamlExample))
  987. t.Log(v.AllKeys())
  988. assert.True(t, v.InConfig("name"))
  989. assert.False(t, v.InConfig("state"))
  990. assert.Equal(t, "steve", v.Get("name"))
  991. assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
  992. assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
  993. assert.Equal(t, 35, v.Get("age"))
  994. }
  995. func TestIsSet(t *testing.T) {
  996. v := New()
  997. v.SetConfigType("yaml")
  998. /* config and defaults */
  999. v.ReadConfig(bytes.NewBuffer(yamlExample))
  1000. v.SetDefault("clothing.shoes", "sneakers")
  1001. assert.True(t, v.IsSet("clothing"))
  1002. assert.True(t, v.IsSet("clothing.jacket"))
  1003. assert.False(t, v.IsSet("clothing.jackets"))
  1004. assert.True(t, v.IsSet("clothing.shoes"))
  1005. /* state change */
  1006. assert.False(t, v.IsSet("helloworld"))
  1007. v.Set("helloworld", "fubar")
  1008. assert.True(t, v.IsSet("helloworld"))
  1009. /* env */
  1010. v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
  1011. v.BindEnv("eyes")
  1012. v.BindEnv("foo")
  1013. v.BindEnv("clothing.hat")
  1014. v.BindEnv("clothing.hats")
  1015. os.Setenv("FOO", "bar")
  1016. os.Setenv("CLOTHING_HAT", "bowler")
  1017. assert.True(t, v.IsSet("eyes")) // in the config file
  1018. assert.True(t, v.IsSet("foo")) // in the environment
  1019. assert.True(t, v.IsSet("clothing.hat")) // in the environment
  1020. assert.False(t, v.IsSet("clothing.hats")) // not defined
  1021. /* flags */
  1022. flagset := pflag.NewFlagSet("testisset", pflag.ContinueOnError)
  1023. flagset.Bool("foobaz", false, "foobaz")
  1024. flagset.Bool("barbaz", false, "barbaz")
  1025. foobaz, barbaz := flagset.Lookup("foobaz"), flagset.Lookup("barbaz")
  1026. v.BindPFlag("foobaz", foobaz)
  1027. v.BindPFlag("barbaz", barbaz)
  1028. barbaz.Value.Set("true")
  1029. barbaz.Changed = true // hack for pflag usage
  1030. assert.False(t, v.IsSet("foobaz"))
  1031. assert.True(t, v.IsSet("barbaz"))
  1032. }
  1033. func TestDirsSearch(t *testing.T) {
  1034. root, config, cleanup := initDirs(t)
  1035. defer cleanup()
  1036. v := New()
  1037. v.SetConfigName(config)
  1038. v.SetDefault(`key`, `default`)
  1039. entries, err := ioutil.ReadDir(root)
  1040. assert.Nil(t, err)
  1041. for _, e := range entries {
  1042. if e.IsDir() {
  1043. v.AddConfigPath(e.Name())
  1044. }
  1045. }
  1046. err = v.ReadInConfig()
  1047. assert.Nil(t, err)
  1048. assert.Equal(t, `value is `+filepath.Base(v.configPaths[0]), v.GetString(`key`))
  1049. }
  1050. func TestWrongDirsSearchNotFound(t *testing.T) {
  1051. _, config, cleanup := initDirs(t)
  1052. defer cleanup()
  1053. v := New()
  1054. v.SetConfigName(config)
  1055. v.SetDefault(`key`, `default`)
  1056. v.AddConfigPath(`whattayoutalkingbout`)
  1057. v.AddConfigPath(`thispathaintthere`)
  1058. err := v.ReadInConfig()
  1059. assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
  1060. // Even though config did not load and the error might have
  1061. // been ignored by the client, the default still loads
  1062. assert.Equal(t, `default`, v.GetString(`key`))
  1063. }
  1064. func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
  1065. _, config, cleanup := initDirs(t)
  1066. defer cleanup()
  1067. v := New()
  1068. v.SetConfigName(config)
  1069. v.SetDefault(`key`, `default`)
  1070. v.AddConfigPath(`whattayoutalkingbout`)
  1071. v.AddConfigPath(`thispathaintthere`)
  1072. err := v.MergeInConfig()
  1073. assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
  1074. // Even though config did not load and the error might have
  1075. // been ignored by the client, the default still loads
  1076. assert.Equal(t, `default`, v.GetString(`key`))
  1077. }
  1078. func TestSub(t *testing.T) {
  1079. v := New()
  1080. v.SetConfigType("yaml")
  1081. v.ReadConfig(bytes.NewBuffer(yamlExample))
  1082. subv := v.Sub("clothing")
  1083. assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("pants.size"))
  1084. subv = v.Sub("clothing.pants")
  1085. assert.Equal(t, v.Get("clothing.pants.size"), subv.Get("size"))
  1086. subv = v.Sub("clothing.pants.size")
  1087. assert.Equal(t, (*Viper)(nil), subv)
  1088. subv = v.Sub("missing.key")
  1089. assert.Equal(t, (*Viper)(nil), subv)
  1090. }
  1091. var hclWriteExpected = []byte(`"foos" = {
  1092. "foo" = {
  1093. "key" = 1
  1094. }
  1095. "foo" = {
  1096. "key" = 2
  1097. }
  1098. "foo" = {
  1099. "key" = 3
  1100. }
  1101. "foo" = {
  1102. "key" = 4
  1103. }
  1104. }
  1105. "id" = "0001"
  1106. "name" = "Cake"
  1107. "ppu" = 0.55
  1108. "type" = "donut"`)
  1109. var jsonWriteExpected = []byte(`{
  1110. "batters": {
  1111. "batter": [
  1112. {
  1113. "type": "Regular"
  1114. },
  1115. {
  1116. "type": "Chocolate"
  1117. },
  1118. {
  1119. "type": "Blueberry"
  1120. },
  1121. {
  1122. "type": "Devil's Food"
  1123. }
  1124. ]
  1125. },
  1126. "id": "0001",
  1127. "name": "Cake",
  1128. "ppu": 0.55,
  1129. "type": "donut"
  1130. }`)
  1131. var propertiesWriteExpected = []byte(`p_id = 0001
  1132. p_type = donut
  1133. p_name = Cake
  1134. p_ppu = 0.55
  1135. p_batters.batter.type = Regular
  1136. `)
  1137. var yamlWriteExpected = []byte(`age: 35
  1138. beard: true
  1139. clothing:
  1140. jacket: leather
  1141. pants:
  1142. size: large
  1143. trousers: denim
  1144. eyes: brown
  1145. hacker: true
  1146. hobbies:
  1147. - skateboarding
  1148. - snowboarding
  1149. - go
  1150. name: steve
  1151. `)
  1152. func TestWriteConfig(t *testing.T) {
  1153. fs := afero.NewMemMapFs()
  1154. testCases := map[string]struct {
  1155. configName string
  1156. inConfigType string
  1157. outConfigType string
  1158. fileName string
  1159. input []byte
  1160. expectedContent []byte
  1161. }{
  1162. "hcl with file extension": {
  1163. configName: "c",
  1164. inConfigType: "hcl",
  1165. outConfigType: "hcl",
  1166. fileName: "c.hcl",
  1167. input: hclExample,
  1168. expectedContent: hclWriteExpected,
  1169. },
  1170. "hcl without file extension": {
  1171. configName: "c",
  1172. inConfigType: "hcl",
  1173. outConfigType: "hcl",
  1174. fileName: "c",
  1175. input: hclExample,
  1176. expectedContent: hclWriteExpected,
  1177. },
  1178. "hcl with file extension and mismatch type": {
  1179. configName: "c",
  1180. inConfigType: "hcl",
  1181. outConfigType: "json",
  1182. fileName: "c.hcl",
  1183. input: hclExample,
  1184. expectedContent: hclWriteExpected,
  1185. },
  1186. "json with file extension": {
  1187. configName: "c",
  1188. inConfigType: "json",
  1189. outConfigType: "json",
  1190. fileName: "c.json",
  1191. input: jsonExample,
  1192. expectedContent: jsonWriteExpected,
  1193. },
  1194. "json without file extension": {
  1195. configName: "c",
  1196. inConfigType: "json",
  1197. outConfigType: "json",
  1198. fileName: "c",
  1199. input: jsonExample,
  1200. expectedContent: jsonWriteExpected,
  1201. },
  1202. "json with file extension and mismatch type": {
  1203. configName: "c",
  1204. inConfigType: "json",
  1205. outConfigType: "hcl",
  1206. fileName: "c.json",
  1207. input: jsonExample,
  1208. expectedContent: jsonWriteExpected,
  1209. },
  1210. "properties with file extension": {
  1211. configName: "c",
  1212. inConfigType: "properties",
  1213. outConfigType: "properties",
  1214. fileName: "c.properties",
  1215. input: propertiesExample,
  1216. expectedContent: propertiesWriteExpected,
  1217. },
  1218. "properties without file extension": {
  1219. configName: "c",
  1220. inConfigType: "properties",
  1221. outConfigType: "properties",
  1222. fileName: "c",
  1223. input: propertiesExample,
  1224. expectedContent: propertiesWriteExpected,
  1225. },
  1226. "yaml with file extension": {
  1227. configName: "c",
  1228. inConfigType: "yaml",
  1229. outConfigType: "yaml",
  1230. fileName: "c.yaml",
  1231. input: yamlExample,
  1232. expectedContent: yamlWriteExpected,
  1233. },
  1234. "yaml without file extension": {
  1235. configName: "c",
  1236. inConfigType: "yaml",
  1237. outConfigType: "yaml",
  1238. fileName: "c",
  1239. input: yamlExample,
  1240. expectedContent: yamlWriteExpected,
  1241. },
  1242. "yaml with file extension and mismatch type": {
  1243. configName: "c",
  1244. inConfigType: "yaml",
  1245. outConfigType: "json",
  1246. fileName: "c.yaml",
  1247. input: yamlExample,
  1248. expectedContent: yamlWriteExpected,
  1249. },
  1250. }
  1251. for name, tc := range testCases {
  1252. t.Run(name, func(t *testing.T) {
  1253. v := New()
  1254. v.SetFs(fs)
  1255. v.SetConfigName(tc.fileName)
  1256. v.SetConfigType(tc.inConfigType)
  1257. err := v.ReadConfig(bytes.NewBuffer(tc.input))
  1258. if err != nil {
  1259. t.Fatal(err)
  1260. }
  1261. v.SetConfigType(tc.outConfigType)
  1262. if err := v.WriteConfigAs(tc.fileName); err != nil {
  1263. t.Fatal(err)
  1264. }
  1265. read, err := afero.ReadFile(fs, tc.fileName)
  1266. if err != nil {
  1267. t.Fatal(err)
  1268. }
  1269. assert.Equal(t, tc.expectedContent, read)
  1270. })
  1271. }
  1272. }
  1273. func TestWriteConfigTOML(t *testing.T) {
  1274. fs := afero.NewMemMapFs()
  1275. testCases := map[string]struct {
  1276. configName string
  1277. configType string
  1278. fileName string
  1279. input []byte
  1280. }{
  1281. "with file extension": {
  1282. configName: "c",
  1283. configType: "toml",
  1284. fileName: "c.toml",
  1285. input: tomlExample,
  1286. },
  1287. "without file extension": {
  1288. configName: "c",
  1289. configType: "toml",
  1290. fileName: "c",
  1291. input: tomlExample,
  1292. },
  1293. }
  1294. for name, tc := range testCases {
  1295. t.Run(name, func(t *testing.T) {
  1296. v := New()
  1297. v.SetFs(fs)
  1298. v.SetConfigName(tc.configName)
  1299. v.SetConfigType(tc.configType)
  1300. err := v.ReadConfig(bytes.NewBuffer(tc.input))
  1301. if err != nil {
  1302. t.Fatal(err)
  1303. }
  1304. if err := v.WriteConfigAs(tc.fileName); err != nil {
  1305. t.Fatal(err)
  1306. }
  1307. // The TOML String method does not order the contents.
  1308. // Therefore, we must read the generated file and compare the data.
  1309. v2 := New()
  1310. v2.SetFs(fs)
  1311. v2.SetConfigName(tc.configName)
  1312. v2.SetConfigType(tc.configType)
  1313. v2.SetConfigFile(tc.fileName)
  1314. err = v2.ReadInConfig()
  1315. if err != nil {
  1316. t.Fatal(err)
  1317. }
  1318. assert.Equal(t, v.GetString("title"), v2.GetString("title"))
  1319. assert.Equal(t, v.GetString("owner.bio"), v2.GetString("owner.bio"))
  1320. assert.Equal(t, v.GetString("owner.dob"), v2.GetString("owner.dob"))
  1321. assert.Equal(t, v.GetString("owner.organization"), v2.GetString("owner.organization"))
  1322. })
  1323. }
  1324. }
  1325. func TestWriteConfigDotEnv(t *testing.T) {
  1326. fs := afero.NewMemMapFs()
  1327. testCases := map[string]struct {
  1328. configName string
  1329. configType string
  1330. fileName string
  1331. input []byte
  1332. }{
  1333. "with file extension": {
  1334. configName: "c",
  1335. configType: "env",
  1336. fileName: "c.env",
  1337. input: dotenvExample,
  1338. },
  1339. "without file extension": {
  1340. configName: "c",
  1341. configType: "env",
  1342. fileName: "c",
  1343. input: dotenvExample,
  1344. },
  1345. }
  1346. for name, tc := range testCases {
  1347. t.Run(name, func(t *testing.T) {
  1348. v := New()
  1349. v.SetFs(fs)
  1350. v.SetConfigName(tc.configName)
  1351. v.SetConfigType(tc.configType)
  1352. err := v.ReadConfig(bytes.NewBuffer(tc.input))
  1353. if err != nil {
  1354. t.Fatal(err)
  1355. }
  1356. if err := v.WriteConfigAs(tc.fileName); err != nil {
  1357. t.Fatal(err)
  1358. }
  1359. // The TOML String method does not order the contents.
  1360. // Therefore, we must read the generated file and compare the data.
  1361. v2 := New()
  1362. v2.SetFs(fs)
  1363. v2.SetConfigName(tc.configName)
  1364. v2.SetConfigType(tc.configType)
  1365. v2.SetConfigFile(tc.fileName)
  1366. err = v2.ReadInConfig()
  1367. if err != nil {
  1368. t.Fatal(err)
  1369. }
  1370. assert.Equal(t, v.GetString("title_dotenv"), v2.GetString("title_dotenv"))
  1371. assert.Equal(t, v.GetString("type_dotenv"), v2.GetString("type_dotenv"))
  1372. assert.Equal(t, v.GetString("kind_dotenv"), v2.GetString("kind_dotenv"))
  1373. })
  1374. }
  1375. }
  1376. func TestSafeWriteConfig(t *testing.T) {
  1377. v := New()
  1378. fs := afero.NewMemMapFs()
  1379. v.SetFs(fs)
  1380. v.AddConfigPath("/test")
  1381. v.SetConfigName("c")
  1382. v.SetConfigType("yaml")
  1383. require.NoError(t, v.ReadConfig(bytes.NewBuffer(yamlExample)))
  1384. require.NoError(t, v.SafeWriteConfig())
  1385. read, err := afero.ReadFile(fs, "/test/c.yaml")
  1386. require.NoError(t, err)
  1387. assert.Equal(t, yamlWriteExpected, read)
  1388. }
  1389. func TestSafeWriteConfigWithMissingConfigPath(t *testing.T) {
  1390. v := New()
  1391. fs := afero.NewMemMapFs()
  1392. v.SetFs(fs)
  1393. v.SetConfigName("c")
  1394. v.SetConfigType("yaml")
  1395. require.EqualError(t, v.SafeWriteConfig(), "missing configuration for 'configPath'")
  1396. }
  1397. func TestSafeWriteConfigWithExistingFile(t *testing.T) {
  1398. v := New()
  1399. fs := afero.NewMemMapFs()
  1400. fs.Create("/test/c.yaml")
  1401. v.SetFs(fs)
  1402. v.AddConfigPath("/test")
  1403. v.SetConfigName("c")
  1404. v.SetConfigType("yaml")
  1405. err := v.SafeWriteConfig()
  1406. require.Error(t, err)
  1407. _, ok := err.(ConfigFileAlreadyExistsError)
  1408. assert.True(t, ok, "Expected ConfigFileAlreadyExistsError")
  1409. }
  1410. func TestSafeWriteAsConfig(t *testing.T) {
  1411. v := New()
  1412. fs := afero.NewMemMapFs()
  1413. v.SetFs(fs)
  1414. err := v.ReadConfig(bytes.NewBuffer(yamlExample))
  1415. if err != nil {
  1416. t.Fatal(err)
  1417. }
  1418. require.NoError(t, v.SafeWriteConfigAs("/test/c.yaml"))
  1419. if _, err = afero.ReadFile(fs, "/test/c.yaml"); err != nil {
  1420. t.Fatal(err)
  1421. }
  1422. }
  1423. func TestSafeWriteConfigAsWithExistingFile(t *testing.T) {
  1424. v := New()
  1425. fs := afero.NewMemMapFs()
  1426. fs.Create("/test/c.yaml")
  1427. v.SetFs(fs)
  1428. err := v.SafeWriteConfigAs("/test/c.yaml")
  1429. require.Error(t, err)
  1430. _, ok := err.(ConfigFileAlreadyExistsError)
  1431. assert.True(t, ok, "Expected ConfigFileAlreadyExistsError")
  1432. }
  1433. var yamlMergeExampleTgt = []byte(`
  1434. hello:
  1435. pop: 37890
  1436. largenum: 765432101234567
  1437. num2pow63: 9223372036854775808
  1438. world:
  1439. - us
  1440. - uk
  1441. - fr
  1442. - de
  1443. `)
  1444. var yamlMergeExampleSrc = []byte(`
  1445. hello:
  1446. pop: 45000
  1447. largenum: 7654321001234567
  1448. universe:
  1449. - mw
  1450. - ad
  1451. ints:
  1452. - 1
  1453. - 2
  1454. fu: bar
  1455. `)
  1456. func TestMergeConfig(t *testing.T) {
  1457. v := New()
  1458. v.SetConfigType("yml")
  1459. if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1460. t.Fatal(err)
  1461. }
  1462. if pop := v.GetInt("hello.pop"); pop != 37890 {
  1463. t.Fatalf("pop != 37890, = %d", pop)
  1464. }
  1465. if pop := v.GetInt32("hello.pop"); pop != int32(37890) {
  1466. t.Fatalf("pop != 37890, = %d", pop)
  1467. }
  1468. if pop := v.GetInt64("hello.largenum"); pop != int64(765432101234567) {
  1469. t.Fatalf("int64 largenum != 765432101234567, = %d", pop)
  1470. }
  1471. if pop := v.GetUint("hello.pop"); pop != 37890 {
  1472. t.Fatalf("uint pop != 37890, = %d", pop)
  1473. }
  1474. if pop := v.GetUint32("hello.pop"); pop != 37890 {
  1475. t.Fatalf("uint32 pop != 37890, = %d", pop)
  1476. }
  1477. if pop := v.GetUint64("hello.num2pow63"); pop != 9223372036854775808 {
  1478. t.Fatalf("uint64 num2pow63 != 9223372036854775808, = %d", pop)
  1479. }
  1480. if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1481. t.Fatalf("len(world) != 4, = %d", len(world))
  1482. }
  1483. if fu := v.GetString("fu"); fu != "" {
  1484. t.Fatalf("fu != \"\", = %s", fu)
  1485. }
  1486. if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1487. t.Fatal(err)
  1488. }
  1489. if pop := v.GetInt("hello.pop"); pop != 45000 {
  1490. t.Fatalf("pop != 45000, = %d", pop)
  1491. }
  1492. if pop := v.GetInt32("hello.pop"); pop != int32(45000) {
  1493. t.Fatalf("pop != 45000, = %d", pop)
  1494. }
  1495. if pop := v.GetInt64("hello.largenum"); pop != int64(7654321001234567) {
  1496. t.Fatalf("int64 largenum != 7654321001234567, = %d", pop)
  1497. }
  1498. if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1499. t.Fatalf("len(world) != 4, = %d", len(world))
  1500. }
  1501. if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1502. t.Fatalf("len(universe) != 2, = %d", len(universe))
  1503. }
  1504. if ints := v.GetIntSlice("hello.ints"); len(ints) != 2 {
  1505. t.Fatalf("len(ints) != 2, = %d", len(ints))
  1506. }
  1507. if fu := v.GetString("fu"); fu != "bar" {
  1508. t.Fatalf("fu != \"bar\", = %s", fu)
  1509. }
  1510. }
  1511. func TestMergeConfigNoMerge(t *testing.T) {
  1512. v := New()
  1513. v.SetConfigType("yml")
  1514. if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1515. t.Fatal(err)
  1516. }
  1517. if pop := v.GetInt("hello.pop"); pop != 37890 {
  1518. t.Fatalf("pop != 37890, = %d", pop)
  1519. }
  1520. if world := v.GetStringSlice("hello.world"); len(world) != 4 {
  1521. t.Fatalf("len(world) != 4, = %d", len(world))
  1522. }
  1523. if fu := v.GetString("fu"); fu != "" {
  1524. t.Fatalf("fu != \"\", = %s", fu)
  1525. }
  1526. if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
  1527. t.Fatal(err)
  1528. }
  1529. if pop := v.GetInt("hello.pop"); pop != 45000 {
  1530. t.Fatalf("pop != 45000, = %d", pop)
  1531. }
  1532. if world := v.GetStringSlice("hello.world"); len(world) != 0 {
  1533. t.Fatalf("len(world) != 0, = %d", len(world))
  1534. }
  1535. if universe := v.GetStringSlice("hello.universe"); len(universe) != 2 {
  1536. t.Fatalf("len(universe) != 2, = %d", len(universe))
  1537. }
  1538. if ints := v.GetIntSlice("hello.ints"); len(ints) != 2 {
  1539. t.Fatalf("len(ints) != 2, = %d", len(ints))
  1540. }
  1541. if fu := v.GetString("fu"); fu != "bar" {
  1542. t.Fatalf("fu != \"bar\", = %s", fu)
  1543. }
  1544. }
  1545. func TestMergeConfigMap(t *testing.T) {
  1546. v := New()
  1547. v.SetConfigType("yml")
  1548. if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
  1549. t.Fatal(err)
  1550. }
  1551. assert := func(i int) {
  1552. large := v.GetInt64("hello.largenum")
  1553. pop := v.GetInt("hello.pop")
  1554. if large != 765432101234567 {
  1555. t.Fatal("Got large num:", large)
  1556. }
  1557. if pop != i {
  1558. t.Fatal("Got pop:", pop)
  1559. }
  1560. }
  1561. assert(37890)
  1562. update := map[string]interface{}{
  1563. "Hello": map[string]interface{}{
  1564. "Pop": 1234,
  1565. },
  1566. "World": map[interface{}]interface{}{
  1567. "Rock": 345,
  1568. },
  1569. }
  1570. if err := v.MergeConfigMap(update); err != nil {
  1571. t.Fatal(err)
  1572. }
  1573. if rock := v.GetInt("world.rock"); rock != 345 {
  1574. t.Fatal("Got rock:", rock)
  1575. }
  1576. assert(1234)
  1577. }
  1578. func TestUnmarshalingWithAliases(t *testing.T) {
  1579. v := New()
  1580. v.SetDefault("ID", 1)
  1581. v.Set("name", "Steve")
  1582. v.Set("lastname", "Owen")
  1583. v.RegisterAlias("UserID", "ID")
  1584. v.RegisterAlias("Firstname", "name")
  1585. v.RegisterAlias("Surname", "lastname")
  1586. type config struct {
  1587. ID int
  1588. FirstName string
  1589. Surname string
  1590. }
  1591. var C config
  1592. err := v.Unmarshal(&C)
  1593. if err != nil {
  1594. t.Fatalf("unable to decode into struct, %v", err)
  1595. }
  1596. assert.Equal(t, &config{ID: 1, FirstName: "Steve", Surname: "Owen"}, &C)
  1597. }
  1598. func TestSetConfigNameClearsFileCache(t *testing.T) {
  1599. SetConfigFile("/tmp/config.yaml")
  1600. SetConfigName("default")
  1601. f, err := v.getConfigFile()
  1602. if err == nil {
  1603. t.Fatalf("config file cache should have been cleared")
  1604. }
  1605. assert.Empty(t, f)
  1606. }
  1607. func TestShadowedNestedValue(t *testing.T) {
  1608. config := `name: steve
  1609. clothing:
  1610. jacket: leather
  1611. trousers: denim
  1612. pants:
  1613. size: large
  1614. `
  1615. initConfig("yaml", config)
  1616. assert.Equal(t, "steve", GetString("name"))
  1617. polyester := "polyester"
  1618. SetDefault("clothing.shirt", polyester)
  1619. SetDefault("clothing.jacket.price", 100)
  1620. assert.Equal(t, "leather", GetString("clothing.jacket"))
  1621. assert.Nil(t, Get("clothing.jacket.price"))
  1622. assert.Equal(t, polyester, GetString("clothing.shirt"))
  1623. clothingSettings := AllSettings()["clothing"].(map[string]interface{})
  1624. assert.Equal(t, "leather", clothingSettings["jacket"])
  1625. assert.Equal(t, polyester, clothingSettings["shirt"])
  1626. }
  1627. func TestDotParameter(t *testing.T) {
  1628. initJSON()
  1629. // shoud take precedence over batters defined in jsonExample
  1630. r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
  1631. unmarshalReader(r, v.config)
  1632. actual := Get("batters.batter")
  1633. expected := []interface{}{map[string]interface{}{"type": "Small"}}
  1634. assert.Equal(t, expected, actual)
  1635. }
  1636. func TestCaseInsensitive(t *testing.T) {
  1637. for _, config := range []struct {
  1638. typ string
  1639. content string
  1640. }{
  1641. {"yaml", `
  1642. aBcD: 1
  1643. eF:
  1644. gH: 2
  1645. iJk: 3
  1646. Lm:
  1647. nO: 4
  1648. P:
  1649. Q: 5
  1650. R: 6
  1651. `},
  1652. {"json", `{
  1653. "aBcD": 1,
  1654. "eF": {
  1655. "iJk": 3,
  1656. "Lm": {
  1657. "P": {
  1658. "Q": 5,
  1659. "R": 6
  1660. },
  1661. "nO": 4
  1662. },
  1663. "gH": 2
  1664. }
  1665. }`},
  1666. {"toml", `aBcD = 1
  1667. [eF]
  1668. gH = 2
  1669. iJk = 3
  1670. [eF.Lm]
  1671. nO = 4
  1672. [eF.Lm.P]
  1673. Q = 5
  1674. R = 6
  1675. `},
  1676. } {
  1677. doTestCaseInsensitive(t, config.typ, config.content)
  1678. }
  1679. }
  1680. func TestCaseInsensitiveSet(t *testing.T) {
  1681. Reset()
  1682. m1 := map[string]interface{}{
  1683. "Foo": 32,
  1684. "Bar": map[interface{}]interface {
  1685. }{
  1686. "ABc": "A",
  1687. "cDE": "B"},
  1688. }
  1689. m2 := map[string]interface{}{
  1690. "Foo": 52,
  1691. "Bar": map[interface{}]interface {
  1692. }{
  1693. "bCd": "A",
  1694. "eFG": "B"},
  1695. }
  1696. Set("Given1", m1)
  1697. Set("Number1", 42)
  1698. SetDefault("Given2", m2)
  1699. SetDefault("Number2", 52)
  1700. // Verify SetDefault
  1701. if v := Get("number2"); v != 52 {
  1702. t.Fatalf("Expected 52 got %q", v)
  1703. }
  1704. if v := Get("given2.foo"); v != 52 {
  1705. t.Fatalf("Expected 52 got %q", v)
  1706. }
  1707. if v := Get("given2.bar.bcd"); v != "A" {
  1708. t.Fatalf("Expected A got %q", v)
  1709. }
  1710. if _, ok := m2["Foo"]; !ok {
  1711. t.Fatal("Input map changed")
  1712. }
  1713. // Verify Set
  1714. if v := Get("number1"); v != 42 {
  1715. t.Fatalf("Expected 42 got %q", v)
  1716. }
  1717. if v := Get("given1.foo"); v != 32 {
  1718. t.Fatalf("Expected 32 got %q", v)
  1719. }
  1720. if v := Get("given1.bar.abc"); v != "A" {
  1721. t.Fatalf("Expected A got %q", v)
  1722. }
  1723. if _, ok := m1["Foo"]; !ok {
  1724. t.Fatal("Input map changed")
  1725. }
  1726. }
  1727. func TestParseNested(t *testing.T) {
  1728. type duration struct {
  1729. Delay time.Duration
  1730. }
  1731. type item struct {
  1732. Name string
  1733. Delay time.Duration
  1734. Nested duration
  1735. }
  1736. config := `[[parent]]
  1737. delay="100ms"
  1738. [parent.nested]
  1739. delay="200ms"
  1740. `
  1741. initConfig("toml", config)
  1742. var items []item
  1743. err := v.UnmarshalKey("parent", &items)
  1744. if err != nil {
  1745. t.Fatalf("unable to decode into struct, %v", err)
  1746. }
  1747. assert.Equal(t, 1, len(items))
  1748. assert.Equal(t, 100*time.Millisecond, items[0].Delay)
  1749. assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
  1750. }
  1751. func doTestCaseInsensitive(t *testing.T, typ, config string) {
  1752. initConfig(typ, config)
  1753. Set("RfD", true)
  1754. assert.Equal(t, true, Get("rfd"))
  1755. assert.Equal(t, true, Get("rFD"))
  1756. assert.Equal(t, 1, cast.ToInt(Get("abcd")))
  1757. assert.Equal(t, 1, cast.ToInt(Get("Abcd")))
  1758. assert.Equal(t, 2, cast.ToInt(Get("ef.gh")))
  1759. assert.Equal(t, 3, cast.ToInt(Get("ef.ijk")))
  1760. assert.Equal(t, 4, cast.ToInt(Get("ef.lm.no")))
  1761. assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
  1762. }
  1763. func newViperWithConfigFile(t *testing.T) (*Viper, string, func()) {
  1764. watchDir, err := ioutil.TempDir("", "")
  1765. require.Nil(t, err)
  1766. configFile := path.Join(watchDir, "config.yaml")
  1767. err = ioutil.WriteFile(configFile, []byte("foo: bar\n"), 0640)
  1768. require.Nil(t, err)
  1769. cleanup := func() {
  1770. os.RemoveAll(watchDir)
  1771. }
  1772. v := New()
  1773. v.SetConfigFile(configFile)
  1774. err = v.ReadInConfig()
  1775. require.Nil(t, err)
  1776. require.Equal(t, "bar", v.Get("foo"))
  1777. return v, configFile, cleanup
  1778. }
  1779. func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string, func()) {
  1780. watchDir, err := ioutil.TempDir("", "")
  1781. require.Nil(t, err)
  1782. dataDir1 := path.Join(watchDir, "data1")
  1783. err = os.Mkdir(dataDir1, 0777)
  1784. require.Nil(t, err)
  1785. realConfigFile := path.Join(dataDir1, "config.yaml")
  1786. t.Logf("Real config file location: %s\n", realConfigFile)
  1787. err = ioutil.WriteFile(realConfigFile, []byte("foo: bar\n"), 0640)
  1788. require.Nil(t, err)
  1789. cleanup := func() {
  1790. os.RemoveAll(watchDir)
  1791. }
  1792. // now, symlink the tm `data1` dir to `data` in the baseDir
  1793. os.Symlink(dataDir1, path.Join(watchDir, "data"))
  1794. // and link the `<watchdir>/datadir1/config.yaml` to `<watchdir>/config.yaml`
  1795. configFile := path.Join(watchDir, "config.yaml")
  1796. os.Symlink(path.Join(watchDir, "data", "config.yaml"), configFile)
  1797. t.Logf("Config file location: %s\n", path.Join(watchDir, "config.yaml"))
  1798. // init Viper
  1799. v := New()
  1800. v.SetConfigFile(configFile)
  1801. err = v.ReadInConfig()
  1802. require.Nil(t, err)
  1803. require.Equal(t, "bar", v.Get("foo"))
  1804. return v, watchDir, configFile, cleanup
  1805. }
  1806. func TestWatchFile(t *testing.T) {
  1807. if runtime.GOOS == "linux" {
  1808. // TODO(bep) FIX ME
  1809. t.Skip("Skip test on Linux ...")
  1810. }
  1811. t.Run("file content changed", func(t *testing.T) {
  1812. // given a `config.yaml` file being watched
  1813. v, configFile, cleanup := newViperWithConfigFile(t)
  1814. defer cleanup()
  1815. _, err := os.Stat(configFile)
  1816. require.NoError(t, err)
  1817. t.Logf("test config file: %s\n", configFile)
  1818. wg := sync.WaitGroup{}
  1819. wg.Add(1)
  1820. v.OnConfigChange(func(in fsnotify.Event) {
  1821. t.Logf("config file changed")
  1822. wg.Done()
  1823. })
  1824. v.WatchConfig()
  1825. // when overwriting the file and waiting for the custom change notification handler to be triggered
  1826. err = ioutil.WriteFile(configFile, []byte("foo: baz\n"), 0640)
  1827. wg.Wait()
  1828. // then the config value should have changed
  1829. require.Nil(t, err)
  1830. assert.Equal(t, "baz", v.Get("foo"))
  1831. })
  1832. t.Run("link to real file changed (à la Kubernetes)", func(t *testing.T) {
  1833. // skip if not executed on Linux
  1834. if runtime.GOOS != "linux" {
  1835. t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...")
  1836. }
  1837. v, watchDir, _, _ := newViperWithSymlinkedConfigFile(t)
  1838. // defer cleanup()
  1839. wg := sync.WaitGroup{}
  1840. v.WatchConfig()
  1841. v.OnConfigChange(func(in fsnotify.Event) {
  1842. t.Logf("config file changed")
  1843. wg.Done()
  1844. })
  1845. wg.Add(1)
  1846. // when link to another `config.yaml` file
  1847. dataDir2 := path.Join(watchDir, "data2")
  1848. err := os.Mkdir(dataDir2, 0777)
  1849. require.Nil(t, err)
  1850. configFile2 := path.Join(dataDir2, "config.yaml")
  1851. err = ioutil.WriteFile(configFile2, []byte("foo: baz\n"), 0640)
  1852. require.Nil(t, err)
  1853. // change the symlink using the `ln -sfn` command
  1854. err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run()
  1855. require.Nil(t, err)
  1856. wg.Wait()
  1857. // then
  1858. require.Nil(t, err)
  1859. assert.Equal(t, "baz", v.Get("foo"))
  1860. })
  1861. }
  1862. func TestUnmarshal_DotSeparatorBackwardCompatibility(t *testing.T) {
  1863. flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
  1864. flags.String("foo.bar", "cobra_flag", "")
  1865. v := New()
  1866. assert.NoError(t, v.BindPFlags(flags))
  1867. config := &struct {
  1868. Foo struct {
  1869. Bar string
  1870. }
  1871. }{}
  1872. assert.NoError(t, v.Unmarshal(config))
  1873. assert.Equal(t, "cobra_flag", config.Foo.Bar)
  1874. }
  1875. var yamlExampleWithDot = []byte(`Hacker: true
  1876. name: steve
  1877. hobbies:
  1878. - skateboarding
  1879. - snowboarding
  1880. - go
  1881. clothing:
  1882. jacket: leather
  1883. trousers: denim
  1884. pants:
  1885. size: large
  1886. age: 35
  1887. eyes : brown
  1888. beard: true
  1889. emails:
  1890. steve@hacker.com:
  1891. created: 01/02/03
  1892. active: true
  1893. `)
  1894. func TestKeyDelimiter(t *testing.T) {
  1895. v := NewWithOptions(KeyDelimiter("::"))
  1896. v.SetConfigType("yaml")
  1897. r := strings.NewReader(string(yamlExampleWithDot))
  1898. err := v.unmarshalReader(r, v.config)
  1899. require.NoError(t, err)
  1900. values := map[string]interface{}{
  1901. "image": map[string]interface{}{
  1902. "repository": "someImage",
  1903. "tag": "1.0.0",
  1904. },
  1905. "ingress": map[string]interface{}{
  1906. "annotations": map[string]interface{}{
  1907. "traefik.frontend.rule.type": "PathPrefix",
  1908. "traefik.ingress.kubernetes.io/ssl-redirect": "true",
  1909. },
  1910. },
  1911. }
  1912. v.SetDefault("charts::values", values)
  1913. assert.Equal(t, "leather", v.GetString("clothing::jacket"))
  1914. assert.Equal(t, "01/02/03", v.GetString("emails::steve@hacker.com::created"))
  1915. type config struct {
  1916. Charts struct {
  1917. Values map[string]interface{}
  1918. }
  1919. }
  1920. expected := config{
  1921. Charts: struct {
  1922. Values map[string]interface{}
  1923. }{
  1924. Values: values,
  1925. },
  1926. }
  1927. var actual config
  1928. assert.NoError(t, v.Unmarshal(&actual))
  1929. assert.Equal(t, expected, actual)
  1930. }
  1931. func BenchmarkGetBool(b *testing.B) {
  1932. key := "BenchmarkGetBool"
  1933. v = New()
  1934. v.Set(key, true)
  1935. for i := 0; i < b.N; i++ {
  1936. if !v.GetBool(key) {
  1937. b.Fatal("GetBool returned false")
  1938. }
  1939. }
  1940. }
  1941. func BenchmarkGet(b *testing.B) {
  1942. key := "BenchmarkGet"
  1943. v = New()
  1944. v.Set(key, true)
  1945. for i := 0; i < b.N; i++ {
  1946. if !v.Get(key).(bool) {
  1947. b.Fatal("Get returned false")
  1948. }
  1949. }
  1950. }
  1951. // BenchmarkGetBoolFromMap is the "perfect result" for the above.
  1952. func BenchmarkGetBoolFromMap(b *testing.B) {
  1953. m := make(map[string]bool)
  1954. key := "BenchmarkGetBool"
  1955. m[key] = true
  1956. for i := 0; i < b.N; i++ {
  1957. if !m[key] {
  1958. b.Fatal("Map value was false")
  1959. }
  1960. }
  1961. }