github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/stream/logger_test.go (about) 1 /* 2 Copyright 2017 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package stream 18 19 import ( 20 "bufio" 21 "encoding/json" 22 "io/ioutil" 23 "os" 24 "path/filepath" 25 "sync" 26 "testing" 27 "time" 28 ) 29 30 func setupTmpLogFile() string { 31 baseDir, _ := ioutil.TempDir("", "virtlet-log") 32 outputFile := filepath.Join(baseDir, "output.log") 33 os.Mkdir(baseDir, 0777) 34 return outputFile 35 } 36 37 func verifyJSONLines(t *testing.T, filePath string, lines []map[string]interface{}) { 38 if _, err := os.Stat(filePath); os.IsNotExist(err) { 39 t.Errorf("output file should exist, but does not") 40 } 41 42 f, err := os.Open(filePath) 43 if err != nil { 44 t.Errorf("failed to open file: %s", filePath) 45 } 46 defer f.Close() 47 48 scanner := bufio.NewScanner(f) 49 for n := 0; scanner.Scan(); n++ { 50 l := scanner.Text() 51 if n >= len(lines) { 52 t.Errorf("excess line in the log: %q", l) 53 continue 54 } 55 var m map[string]interface{} 56 if err := json.Unmarshal([]byte(l), &m); err != nil { 57 t.Errorf("failed to unmarshal log line %q: %v", l, err) 58 continue 59 } 60 timeStr, ok := m["time"].(string) 61 if !ok { 62 t.Errorf("bad/absent time in the log line %q", l) 63 continue 64 } 65 logTime, err := time.Parse(time.RFC3339, timeStr) 66 if err != nil { 67 t.Errorf("failed to parse log time %q: %v", m["time"], err) 68 continue 69 } 70 timeDiff := time.Now().Sub(logTime) 71 if timeDiff < 0 || timeDiff > 10*time.Minute { 72 t.Errorf("log time too far from now: %v", m["time"]) 73 continue 74 } 75 for k, v := range lines[n] { 76 if m[k] != v { 77 t.Errorf("bad %q value in log line %q: got %v, expected %v", k, l, m[k], v) 78 } 79 } 80 } 81 if err := scanner.Err(); err != nil { 82 t.Errorf("error reading the output file: %v", err) 83 } 84 } 85 86 func TestLoggingInNewLogWritter(t *testing.T) { 87 var wg sync.WaitGroup 88 89 cases := []struct { 90 name string 91 outputFile string 92 c chan []byte 93 lines [][]byte 94 jsonLines []map[string]interface{} 95 }{ 96 { 97 name: "One line", 98 outputFile: setupTmpLogFile(), 99 c: make(chan []byte), 100 lines: [][]byte{[]byte("test")}, 101 jsonLines: []map[string]interface{}{ 102 { 103 "stream": "stdout", 104 "log": "test\n", 105 }, 106 }, 107 }, 108 { 109 name: "Many lines in one message", 110 outputFile: setupTmpLogFile(), 111 c: make(chan []byte), 112 lines: [][]byte{[]byte("test\ntest2\n")}, 113 jsonLines: []map[string]interface{}{ 114 { 115 "stream": "stdout", 116 "log": "test\n", 117 }, 118 { 119 "stream": "stdout", 120 "log": "test2\n", 121 }, 122 }, 123 }, 124 { 125 name: "Many messages", 126 outputFile: setupTmpLogFile(), 127 c: make(chan []byte), 128 lines: [][]byte{[]byte("test\n"), []byte("test2\n")}, 129 jsonLines: []map[string]interface{}{ 130 { 131 "stream": "stdout", 132 "log": "test\n", 133 }, 134 { 135 "stream": "stdout", 136 "log": "test2\n", 137 }, 138 }, 139 }, 140 { 141 name: "No messages", 142 outputFile: setupTmpLogFile(), 143 c: make(chan []byte), 144 lines: [][]byte{}, 145 jsonLines: []map[string]interface{}{}, 146 }, 147 } 148 149 for _, test := range cases { 150 t.Logf("Running `%s` test", test.name) 151 defer os.RemoveAll(test.outputFile) 152 wg.Add(1) 153 go NewLogWriter(test.c, test.outputFile, &wg) 154 for _, line := range test.lines { 155 test.c <- line 156 } 157 close(test.c) 158 wg.Wait() 159 160 verifyJSONLines(t, test.outputFile, test.jsonLines) 161 } 162 }