github.com/VMitov/casper@v0.4.0/cmd/casper/main_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "flag" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 "testing" 13 14 "github.com/miracl/casper/storage/consul" 15 ) 16 17 // It is defined in each package so you can run `go test ./...` 18 var full = flag.Bool("full", false, "Run all tests including integration") 19 20 var consulAddr = flag.String("consul-addr", "http://172.17.0.1:8500/?token=the_one_ring", "Consul instance to run tests agains") 21 22 func TestExample(t *testing.T) { 23 wd, err := os.Getwd() 24 if err != nil { 25 t.Fatal(err) 26 } 27 28 outputFileName := filepath.Join(wd, "../../example/output.yaml") 29 outputFileData, err := ioutil.ReadFile(outputFileName) 30 if err != nil { 31 t.Fatal(err) 32 } 33 outputFile := string(outputFileData) 34 35 noChanges := "No changes\n" 36 changes := "-key1: val1\n" + 37 "key2: val2\n" + 38 "\n" + 39 "+key1: val1a\n" + 40 "key2: val2a\n" + 41 "\n" 42 prompt := "Continue[y/N]: " 43 applyingChanges := "Applying changes...\n" 44 canceled := "Canceled" 45 46 configAbsPath := filepath.Join(wd, "../../example/config.yaml") 47 templateAbsPath := filepath.Join(wd, "../../example/template.yaml") 48 49 cases := []struct { 50 cmd string // command 51 out string // expected output 52 pwd string // change the directory relative to working dir if set 53 copy bool // copy the example folder in temporary dir if set 54 err string // string representation of expected error 55 }{ 56 {cmd: "casper fetch", out: outputFile + "\n", pwd: "../../example"}, 57 {cmd: "casper diff -key somekey", out: "No changes for key somekey\n", pwd: "../../example"}, 58 59 // without config file 60 {cmd: "casper build -t ../../example/template.yaml -s placeholder1=val1 -s placeholder2=val2", out: outputFile}, 61 62 // with bad source 63 {cmd: "casper build -t ../../example/template.yaml -s placeholder1=val1 -s source.yaml", out: outputFile, err: "creating context failed: invalid source: source.yaml"}, 64 65 // without sources 66 {cmd: "casper build -t ../../example/output.yaml", out: outputFile}, 67 {cmd: "casper diff -t ../../example/output.yaml -storage file -file-path ../../example/output.yaml", out: noChanges}, 68 69 // with overwritten placeholders so it there are differences 70 {cmd: "casper diff -s placeholder1=val1a -s placeholder2=val2a --plain", out: changes, pwd: "../../example"}, 71 {cmd: "casper push -s placeholder1=val1a -s placeholder2=val2a --plain --force", out: changes + applyingChanges, pwd: "../../example"}, 72 {cmd: "casper push -s placeholder1=val1a -s placeholder2=val2a --plain", out: changes + prompt + canceled + "\n", pwd: "../../example"}, 73 74 // 75 // Tests for correct relative path resolving. 76 // 77 78 // Build tests 79 80 // from the same directory where the config is 81 {cmd: "casper build", out: outputFile, pwd: "../../example"}, 82 {cmd: "casper -c ./config.yaml build", out: outputFile, pwd: "../../example"}, 83 {cmd: "casper -c ../example/config.yaml build -t ../example/template.yaml", out: outputFile, pwd: "../../example"}, 84 85 // from different directory where the config is 86 {cmd: "casper -c ../../example/config.yaml build", out: outputFile}, 87 {cmd: "casper -c ../../example/config.yaml build -t ../../example/template.yaml", out: outputFile}, 88 89 // with abs paths 90 {cmd: fmt.Sprintf("casper -c %v build -t %v", configAbsPath, templateAbsPath), out: outputFile}, 91 92 // Diff tests 93 94 // from the same directory where the config is 95 {cmd: "casper diff", out: noChanges, pwd: "../../example"}, 96 {cmd: "casper -c ./config.yaml diff", out: noChanges, pwd: "../../example"}, 97 {cmd: "casper -c ../example/config.yaml diff -t ../example/template.yaml", out: noChanges, pwd: "../../example"}, 98 99 // from different directory where the config is 100 {cmd: "casper -c ../../example/config.yaml diff", out: noChanges}, 101 {cmd: "casper -c ../../example/config.yaml diff -t ../../example/template.yaml", out: noChanges}, 102 103 // with abs paths 104 {cmd: fmt.Sprintf("casper -c %v build -t %v", configAbsPath, templateAbsPath), out: outputFile}, 105 } 106 107 for i, tc := range cases { 108 t.Run(fmt.Sprintf("Case%v", i), func(t *testing.T) { 109 os.Chdir(wd) 110 111 // revert any changes to the output.yaml 112 defer func() { 113 err := ioutil.WriteFile(outputFileName, outputFileData, 0664) 114 if err != nil { 115 t.Fatal(err) 116 } 117 }() 118 119 if tc.err != "" { 120 app := newApp() 121 err := app.Run(strings.Split(tc.cmd, " ")) 122 if err.Error() != tc.err { 123 t.Fatalf("\nunexpected error: %v\n\texpected: %v", err, tc.err) 124 } 125 return 126 } 127 128 if tc.pwd != "" { 129 os.Chdir(tc.pwd) 130 } 131 132 os.Args = strings.Split(tc.cmd, " ") 133 out := getStdout(t, main) 134 if out != tc.out { 135 t.Errorf("\n%vtest:/$ %v\n%v;\nExpected:\n%v;", tc.pwd, tc.cmd, out, tc.out) 136 } 137 }) 138 } 139 } 140 141 func TestConsulIntegration(t *testing.T) { 142 if !*full { 143 t.SkipNow() 144 } 145 146 // Cleanup 147 defer func() { 148 s, err := consul.New(*consulAddr) 149 if err != nil { 150 t.Fatalf("cleanup failed: %v", err) 151 } 152 153 c, err := s.GetChanges([]byte{}, "yaml", "") 154 if err != nil { 155 t.Fatalf("cleanup failed: %v", err) 156 } 157 158 err = s.Push(c) 159 if err != nil { 160 t.Fatalf("cleanup failed: %v", err) 161 } 162 }() 163 164 steps := []struct { 165 cmd string 166 exp string 167 }{ 168 { 169 cmd: fmt.Sprintf("casper fetch -format yaml -storage consul -consul-addr %v", *consulAddr), 170 exp: "{}\n\n", 171 }, 172 173 { 174 cmd: "casper diff -plain" + 175 " -storage consul -consul-addr " + *consulAddr + 176 " -template ../../example/template.yaml -s placeholder1=val1 -s placeholder2=val2", 177 exp: "+key1=val1\n+key2=val2\n\n", 178 }, 179 { 180 cmd: "casper push -plain -force" + 181 " -storage consul -consul-addr " + *consulAddr + 182 " -template ../../example/template.yaml -s placeholder1=val1 -s placeholder2=val2", 183 exp: "+key1=val1\n+key2=val2\n\nApplying changes...\n", 184 }, 185 { 186 cmd: "casper diff -plain" + 187 " -storage consul -consul-addr " + *consulAddr + 188 " -template ../../example/template.yaml -s placeholder1=val1 -s placeholder2=val2", 189 exp: "No changes\n", 190 }, 191 { 192 cmd: "casper fetch -format yaml -storage consul -consul-addr " + *consulAddr, 193 exp: "key1: val1\nkey2: val2\n\n", 194 }, 195 196 { 197 cmd: "casper diff -plain" + 198 " -storage consul -consul-addr " + *consulAddr + 199 " -template ../../example/template.yaml -s placeholder1=diffval1 -s placeholder2=diffval2", 200 exp: "-key1=val1\n+key1=diffval1\n-key2=val2\n+key2=diffval2\n\n", 201 }, 202 { 203 cmd: "casper push -plain -force" + 204 " -storage consul -consul-addr " + *consulAddr + 205 " -template ../../example/template.yaml -s placeholder1=diffval1 -s placeholder2=diffval2", 206 exp: "-key1=val1\n+key1=diffval1\n-key2=val2\n+key2=diffval2\n\nApplying changes...\n", 207 }, 208 { 209 cmd: "casper diff -plain" + 210 " -storage consul -consul-addr " + *consulAddr + 211 " -template ../../example/template.yaml -s placeholder1=diffval1 -s placeholder2=diffval2", 212 exp: "No changes\n", 213 }, 214 { 215 cmd: "casper fetch -format yaml -storage consul -consul-addr " + *consulAddr, 216 exp: "key1: diffval1\nkey2: diffval2\n\n", 217 }, 218 } 219 220 for i, step := range steps { 221 os.Args = strings.Split(step.cmd, " ") 222 out := getStdout(t, main) 223 if out != step.exp { 224 t.Errorf("\nstep%v:/$ %v\n%v;\nExpected:\n%v;", i, step.cmd, out, step.exp) 225 } 226 } 227 } 228 229 func TestAppErrors(t *testing.T) { 230 cases := []struct { 231 cmd string 232 err string 233 }{ 234 // no configurations 235 {cmd: "casper fetch", err: "reading file casper.yaml failed: open casper.yaml: no such file or directory"}, 236 {cmd: "casper build", err: "creating context failed: getting template template.yaml failed: open template.yaml: no such file or directory"}, 237 {cmd: "casper diff", err: "creating context failed: getting template template.yaml failed: open template.yaml: no such file or directory"}, 238 {cmd: "casper push", err: "creating context failed: getting template template.yaml failed: open template.yaml: no such file or directory"}, 239 240 // invalid storage 241 {cmd: "casper fetch -storage invalid", err: "invalid storage type 'invalid'"}, 242 {cmd: "casper diff -storage invalid -t ../../example/template.yaml -s key=value", err: "invalid storage type 'invalid'"}, 243 {cmd: "casper push -storage invalid -t ../../example/template.yaml -s key=value", err: "invalid storage type 'invalid'"}, 244 245 // file storage - invalid file 246 {cmd: "casper fetch -storage file -file-path invalid.txt", err: "reading file invalid.txt failed: open invalid.txt: no such file or directory"}, 247 {cmd: "casper diff -storage file -file-path invalid.txt", err: "creating context failed: getting template template.yaml failed: open template.yaml: no such file or directory"}, 248 {cmd: "casper push -storage file -file-path invalid.txt", err: "creating context failed: getting template template.yaml failed: open template.yaml: no such file or directory"}, 249 250 // invalid source 251 {cmd: "casper build -t ../../example/template.yaml -s key:val", err: "creating context failed: invalid source format key"}, 252 {cmd: "casper diff -t ../../example/template.yaml -s key:val", err: "creating context failed: invalid source format key"}, 253 {cmd: "casper push -t ../../example/template.yaml -s key:val", err: "creating context failed: invalid source format key"}, 254 } 255 256 for i, tc := range cases { 257 t.Run(fmt.Sprintf("Case%v", i), func(t *testing.T) { 258 args := strings.Split(tc.cmd, " ") 259 app := newApp() 260 err := app.Run(args) 261 262 if err != nil && tc.err == "" { 263 t.Fatalf("unexpected error '%v'", err) 264 } 265 266 if err.Error() != tc.err { 267 t.Errorf("\ntest:/$ %v\n%v\nExpected:\n%v;", tc.cmd, err, tc.err) 268 } 269 }) 270 } 271 272 } 273 274 // Runs a function and returns the stdout from it. 275 func getStdout(t *testing.T, f func()) string { 276 old := os.Stdout // keep backup of the real stdout 277 defer func() { os.Stdout = old }() 278 r, w, err := os.Pipe() 279 if err != nil { 280 t.Errorf("an error wasn't expected: %v", err) 281 } 282 os.Stdout = w 283 284 f() // executes the main function 285 286 outC := make(chan string) 287 // copy the output in a separate goroutine so printing can't block indefinitely 288 go func() { 289 var buf bytes.Buffer 290 io.Copy(&buf, r) 291 outC <- buf.String() 292 }() 293 294 // back to normal state 295 w.Close() 296 out := <-outC 297 298 return out 299 }