1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package logger 16 17import ( 18 "bytes" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "reflect" 26 "sort" 27 "syscall" 28 "testing" 29) 30 31func TestCreateFileWithRotation(t *testing.T) { 32 dir, err := ioutil.TempDir("", "test-rotation") 33 if err != nil { 34 t.Fatalf("Failed to get TempDir: %v", err) 35 } 36 defer os.RemoveAll(dir) 37 38 file := filepath.Join(dir, "build.log") 39 40 writeFile := func(name string, data string) { 41 f, err := CreateFileWithRotation(name, 3) 42 if err != nil { 43 t.Fatalf("Failed to create file: %v", err) 44 } 45 if n, err := io.WriteString(f, data); err == nil && n < len(data) { 46 t.Fatalf("Short write") 47 } else if err != nil { 48 t.Fatalf("Failed to write: %v", err) 49 } 50 if err := f.Close(); err != nil { 51 t.Fatalf("Failed to close: %v", err) 52 } 53 } 54 55 writeFile(file, "a") 56 writeFile(file, "b") 57 writeFile(file, "c") 58 writeFile(file, "d") 59 writeFile(file, "e") 60 61 d, err := os.Open(dir) 62 if err != nil { 63 t.Fatalf("Failed to open dir: %v", err) 64 } 65 names, err := d.Readdirnames(0) 66 if err != nil { 67 t.Fatalf("Failed to read dir: %v", err) 68 } 69 sort.Strings(names) 70 expected := []string{".lock_build.log", "build.1.log", "build.2.log", "build.3.log", "build.log"} 71 if !reflect.DeepEqual(names, expected) { 72 t.Errorf("File list does not match.") 73 t.Errorf(" got: %v", names) 74 t.Errorf("expected: %v", expected) 75 t.FailNow() 76 } 77 78 expectFileContents := func(name, expected string) { 79 data, err := ioutil.ReadFile(filepath.Join(dir, name)) 80 if err != nil { 81 t.Errorf("Error reading file: %v", err) 82 return 83 } 84 str := string(data) 85 if str != expected { 86 t.Errorf("Contents of %v does not match.", name) 87 t.Errorf(" got: %v", data) 88 t.Errorf("expected: %v", expected) 89 } 90 } 91 92 expectFileContents("build.log", "e") 93 expectFileContents("build.1.log", "d") 94 expectFileContents("build.2.log", "c") 95 expectFileContents("build.3.log", "b") 96} 97 98func TestPanic(t *testing.T) { 99 if os.Getenv("ACTUALLY_PANIC") == "1" { 100 panicValue := "foo" 101 log := New(&bytes.Buffer{}) 102 103 defer func() { 104 p := recover() 105 106 if p == panicValue { 107 os.Exit(42) 108 } else { 109 fmt.Fprintf(os.Stderr, "Expected %q, got %v\n", panicValue, p) 110 os.Exit(3) 111 } 112 }() 113 defer log.Cleanup() 114 115 log.Panic(panicValue) 116 os.Exit(2) 117 return 118 } 119 120 // Run this in an external process so that we don't pollute stderr 121 cmd := exec.Command(os.Args[0], "-test.run=TestPanic") 122 cmd.Env = append(os.Environ(), "ACTUALLY_PANIC=1") 123 err := cmd.Run() 124 if e, ok := err.(*exec.ExitError); ok && e.Sys().(syscall.WaitStatus).ExitStatus() == 42 { 125 return 126 } 127 t.Errorf("Expected process to exit with status 42, got %v", err) 128} 129 130func TestFatal(t *testing.T) { 131 if os.Getenv("ACTUALLY_FATAL") == "1" { 132 log := New(&bytes.Buffer{}) 133 defer func() { 134 // Shouldn't get here 135 os.Exit(3) 136 }() 137 defer log.Cleanup() 138 log.Fatal("Test") 139 os.Exit(0) 140 return 141 } 142 143 cmd := exec.Command(os.Args[0], "-test.run=TestFatal") 144 cmd.Env = append(os.Environ(), "ACTUALLY_FATAL=1") 145 err := cmd.Run() 146 if e, ok := err.(*exec.ExitError); ok && e.Sys().(syscall.WaitStatus).ExitStatus() == 1 { 147 return 148 } 149 t.Errorf("Expected process to exit with status 1, got %v", err) 150} 151 152func TestNonFatal(t *testing.T) { 153 if os.Getenv("ACTUAL_TEST") == "1" { 154 log := New(&bytes.Buffer{}) 155 defer log.Cleanup() 156 log.Println("Test") 157 return 158 } 159 160 cmd := exec.Command(os.Args[0], "-test.run=TestNonFatal") 161 cmd.Env = append(os.Environ(), "ACTUAL_TEST=1") 162 err := cmd.Run() 163 if e, ok := err.(*exec.ExitError); ok || (ok && !e.Success()) { 164 t.Errorf("Expected process to exit cleanly, got %v", err) 165 } 166} 167 168func TestRecoverFatal(t *testing.T) { 169 log := New(&bytes.Buffer{}) 170 defer func() { 171 if p := recover(); p != nil { 172 t.Errorf("Unexpected panic: %#v", p) 173 } 174 }() 175 defer Recover(func(err error) { 176 if err.Error() != "Test" { 177 t.Errorf("Expected %q, but got %q", "Test", err.Error()) 178 } 179 }) 180 log.Fatal("Test") 181 t.Errorf("Should not get here") 182} 183 184func TestRecoverNonFatal(t *testing.T) { 185 log := New(&bytes.Buffer{}) 186 defer func() { 187 if p := recover(); p == nil { 188 t.Errorf("Panic not thrown") 189 } else if p != "Test" { 190 t.Errorf("Expected %q, but got %#v", "Test", p) 191 } 192 }() 193 defer Recover(func(err error) { 194 t.Errorf("Recover function should not be called") 195 }) 196 log.Panic("Test") 197 t.Errorf("Should not get here") 198} 199 200func TestRuntimePanic(t *testing.T) { 201 defer func() { 202 if p := recover(); p == nil { 203 t.Errorf("Panic not thrown") 204 } 205 }() 206 defer Recover(func(err error) { 207 t.Errorf("Recover function should not be called") 208 }) 209 var i *int 210 *i = 0 211 t.Errorf("Should not get here") 212} 213