boulder/json-logger_test.go

277 lines
5.9 KiB
Go

// Copyright 2014 ISRG. All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package boulder
import (
"bufio"
"strings"
"fmt"
"net"
"testing"
"time"
)
const TimeoutIndicator = "<TIMEOUT>"
func AssertNotError(t *testing.T, err error, message string) {
if err != nil {
t.Error(message, err)
}
}
func AssertEquals(t *testing.T, one string, two string) {
if one != two {
t.Errorf("String [%s] != [%s]", one, two)
}
}
func AssertContains(t *testing.T, haystack string, needle string) {
if ! strings.Contains(haystack, needle) {
t.Errorf("String [%s] does not contain [%s]", haystack, needle)
}
}
func AssertSeverity(t *testing.T, data string, severity int) {
expected := fmt.Sprintf("\"severity\":%d", severity)
AssertContains(t, data, expected)
}
func readChanWithTimeout(outChan <-chan string) string {
timeout := time.After(time.Second)
select {
case line := <-outChan:
return line
case <-timeout:
return TimeoutIndicator
}
}
func awaitMessage(t *testing.T, scheme string, address string) (net.Listener, <-chan string) {
outChan := make(chan string)
socket, err := net.Listen(scheme, address)
AssertNotError(t, err, "Could not listen")
recvLog := func() {
conn, err := socket.Accept()
if conn == nil {
t.Error("Conn nil; programmer error in test.")
return
}
defer func(){
conn.Close()
fmt.Println("Exiting")
}()
AssertNotError(t, err, "Could not accept")
reader := bufio.NewReader(conn)
for {
conn.SetDeadline(time.Now().Add(time.Second))
line, _ := reader.ReadString('\n')
// Emit the line if it's not-empty.
if line != "" {
outChan <- line
}
}
}
go recvLog()
// Let the caller close the socket
return socket, outChan
}
func TestWriteTcp(t *testing.T) {
const Scheme = "tcp"
const Address = "127.0.0.1:9999"
socket, outChan := awaitMessage(t, Scheme, Address)
defer socket.Close()
log := NewJsonLogger("just a test")
log.SetEndpoint(Scheme, Address)
msg := "Test " + Scheme + " " + Address
log.Critical(msg, nil)
rsp := <-outChan
AssertContains(t, rsp, msg)
AssertSeverity(t, rsp, CRITICAL)
}
func TestWriteNoNetwork(t *testing.T) {
log := NewJsonLogger("just a test")
log.Debug("Check", nil)
// Nothing to assert
log.EnableStdOut(true)
log.Debug("Check", nil)
// Nothing to assert
}
func TestWriteUnMarshallable(t *testing.T) {
const Scheme = "tcp"
const Address = "127.0.0.1:9998"
socket, outChan := awaitMessage(t, Scheme, Address)
defer socket.Close()
log := NewJsonLogger("please don't work")
log.SetEndpoint(Scheme, Address)
log.Connect()
log.Debug("Check", func(){})
rsp := readChanWithTimeout(outChan)
AssertEquals(t, rsp, TimeoutIndicator)
}
func TestWriteTcpAllLevels(t *testing.T) {
const Scheme = "tcp"
const Address = "127.0.0.1:9997"
socket, outChan := awaitMessage(t, Scheme, Address)
defer socket.Close()
log := NewJsonLogger("just a test")
log.SetEndpoint(Scheme, Address)
msg := "Test " + Scheme + " " + Address
{
log.Critical(msg, msg)
rsp := <-outChan
AssertSeverity(t, rsp, CRITICAL)
AssertContains(t, rsp, msg)
}
{
log.Alert(msg, msg)
rsp := <-outChan
AssertSeverity(t, rsp, ALERT)
AssertContains(t, rsp, msg)
}
{
log.Emergency(msg, msg)
rsp := <-outChan
AssertSeverity(t, rsp, EMERGENCY)
AssertContains(t, rsp, msg)
}
{
log.Error(msg, msg)
rsp := <-outChan
AssertSeverity(t, rsp, ERROR)
AssertContains(t, rsp, msg)
}
{
log.Warning(msg, msg)
rsp := <-outChan
AssertSeverity(t, rsp, WARNING)
AssertContains(t, rsp, msg)
}
{
log.Notice(msg, msg)
rsp := <-outChan
AssertSeverity(t, rsp, NOTICE)
AssertContains(t, rsp, msg)
}
{
log.Info(msg, msg)
rsp := <-outChan
AssertSeverity(t, rsp, INFO)
AssertContains(t, rsp, msg)
}
{
log.Debug(msg, msg)
rsp := <-outChan
AssertSeverity(t, rsp, DEBUG)
AssertContains(t, rsp, msg)
}
}
func TestLevelMasking(t *testing.T) {
const Scheme = "tcp"
const Address = "127.0.0.1:9996"
socket, outChan := awaitMessage(t, Scheme, Address)
defer socket.Close()
log := NewJsonLogger("just a test")
log.SetEndpoint(Scheme, Address)
msg := "Test " + Scheme + " " + Address
{
log.Info(msg, msg)
rsp := readChanWithTimeout(outChan)
AssertSeverity(t, rsp, INFO)
AssertContains(t, rsp, msg)
}
// Notice and lower numbers should emit; Info should not.
log.SetLevel(NOTICE)
{
log.Info(msg, msg)
rsp := readChanWithTimeout(outChan)
AssertEquals(t, rsp, TimeoutIndicator)
}
// Warning, being lower than Notice, should emit.
{
log.Warning(msg, msg)
rsp := readChanWithTimeout(outChan)
AssertSeverity(t, rsp, WARNING)
AssertContains(t, rsp, msg)
}
}
func TestEmbeddedNewline(t *testing.T) {
const Scheme = "tcp"
const Address = "127.0.0.1:9995"
socket, outChan := awaitMessage(t, Scheme, Address)
defer socket.Close()
log := NewJsonLogger("embedded newline")
log.SetEndpoint(Scheme, Address)
payload := struct {
One string
Two string
}{
One: "A\nTOYOTA'S\nA\nTOYOTA",
Two: "\n\n\n\n\n",
}
msg := "There's a newline in the payload:"
log.Critical(msg, payload)
rsp := <-outChan
AssertContains(t, rsp, msg)
AssertSeverity(t, rsp, CRITICAL)
// I can't do an AssertContains directly because rsp is escaped, while the
// payload values are not. Since escaping routines are not so easy to find,
// payload I can't just JSON-marshal (because that is a loopback test),
// I do it manually.
AssertContains(t, rsp, strings.Replace(payload.One, "\n", "\\n", -1))
AssertContains(t, rsp, strings.Replace(payload.Two, "\n", "\\n", -1))
}