// Copyright (c) 2012-2018 The Revel Framework Authors, All rights reserved. // Revel Framework source code and usage is governed by a MIT style // license that can be found in the LICENSE file. package logger_test import ( "os" "strings" "testing" "github.com/revel/cmd/logger" "github.com/revel/config" "github.com/stretchr/testify/assert" ) type ( // A counter for the tester. testCounter struct { debug, info, warn, error, critical int } // The data to tes. testData struct { config []string result testResult tc *testCounter } // The test result. testResult struct { debug, info, warn, error, critical int } ) // Single test cases. var singleCases = []testData{ { config: []string{"log.crit.output"}, result: testResult{0, 0, 0, 0, 1}, }, { config: []string{"log.error.output"}, result: testResult{0, 0, 0, 1, 1}, }, { config: []string{"log.warn.output"}, result: testResult{0, 0, 1, 0, 0}, }, { config: []string{"log.info.output"}, result: testResult{0, 1, 0, 0, 0}, }, { config: []string{"log.debug.output"}, result: testResult{1, 0, 0, 0, 0}, }, } // Test singles. func TestSingleCases(t *testing.T) { rootLog := logger.New() for _, testCase := range singleCases { testCase.logTest(t, rootLog) testCase.validate(t) } } // Filter test cases. var filterCases = []testData{ { config: []string{"log.crit.filter.module.app"}, result: testResult{0, 0, 0, 0, 1}, }, { config: []string{"log.crit.filter.module.appa"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.error.filter.module.app"}, result: testResult{0, 0, 0, 1, 1}, }, { config: []string{"log.error.filter.module.appa"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.warn.filter.module.app"}, result: testResult{0, 0, 1, 0, 0}, }, { config: []string{"log.warn.filter.module.appa"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.info.filter.module.app"}, result: testResult{0, 1, 0, 0, 0}, }, { config: []string{"log.info.filter.module.appa"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.debug.filter.module.app"}, result: testResult{1, 0, 0, 0, 0}, }, { config: []string{"log.debug.filter.module.appa"}, result: testResult{0, 0, 0, 0, 0}, }, } // Filter test. func TestFilterCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range filterCases { testCase.logTest(t, rootLog) testCase.validate(t) } } // Inverse test cases. var nfilterCases = []testData{ { config: []string{"log.crit.nfilter.module.appa"}, result: testResult{0, 0, 0, 0, 1}, }, { config: []string{"log.crit.nfilter.modules.appa"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.crit.nfilter.module.app"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.error.nfilter.module.appa"}, // Special case, when error is not nill critical inherits from error result: testResult{0, 0, 0, 1, 1}, }, { config: []string{"log.error.nfilter.module.app"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.warn.nfilter.module.appa"}, result: testResult{0, 0, 1, 0, 0}, }, { config: []string{"log.warn.nfilter.module.app"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.info.nfilter.module.appa"}, result: testResult{0, 1, 0, 0, 0}, }, { config: []string{"log.info.nfilter.module.app"}, result: testResult{0, 0, 0, 0, 0}, }, { config: []string{"log.debug.nfilter.module.appa"}, result: testResult{1, 0, 0, 0, 0}, }, { config: []string{"log.debug.nfilter.module.app"}, result: testResult{0, 0, 0, 0, 0}, }, } // Inverse test. func TestNotFilterCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range nfilterCases { testCase.logTest(t, rootLog) testCase.validate(t) } } // off test cases. var offCases = []testData{ { config: []string{"log.all.output", "log.error.output=off"}, result: testResult{1, 1, 1, 0, 1}, }, } // Off test. func TestOffCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range offCases { testCase.logTest(t, rootLog) testCase.validate(t) } } // Duplicate test cases. var duplicateCases = []testData{ { config: []string{"log.all.output", "log.error.output", "log.error.filter.module.app"}, result: testResult{1, 1, 1, 2, 1}, }, } // test duplicate cases. func TestDuplicateCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range duplicateCases { testCase.logTest(t, rootLog) testCase.validate(t) } } // Contradicting cases. var contradictCases = []testData{ { config: []string{"log.all.output", "log.error.output=off", "log.all.output"}, result: testResult{1, 1, 1, 0, 1}, }, { config: []string{"log.all.output", "log.error.output=off", "log.debug.filter.module.app"}, result: testResult{2, 1, 1, 0, 1}, }, { config: []string{"log.all.filter.module.app", "log.info.output=off", "log.info.filter.module.app"}, result: testResult{1, 2, 1, 1, 1}, }, { config: []string{"log.all.output", "log.info.output=off", "log.info.filter.module.app"}, result: testResult{1, 1, 1, 1, 1}, }, } // Contradiction test. func TestContradictCases(t *testing.T) { rootLog := logger.New("module", "app") for _, testCase := range contradictCases { testCase.logTest(t, rootLog) testCase.validate(t) } } // All test cases. var allCases = []testData{ { config: []string{"log.all.filter.module.app"}, result: testResult{1, 1, 1, 1, 1}, }, { config: []string{"log.all.output"}, result: testResult{2, 2, 2, 2, 2}, }, } // All tests. func TestAllCases(t *testing.T) { rootLog := logger.New("module", "app") for i, testCase := range allCases { testCase.logTest(t, rootLog) allCases[i] = testCase } rootLog = logger.New() for i, testCase := range allCases { testCase.logTest(t, rootLog) allCases[i] = testCase } for _, testCase := range allCases { testCase.validate(t) } } func (c *testCounter) Log(r *logger.Record) error { switch r.Level { case logger.LvlDebug: c.debug++ case logger.LvlInfo: c.info++ case logger.LvlWarn: c.warn++ case logger.LvlError: c.error++ case logger.LvlCrit: c.critical++ default: panic("Unknown log level") } return nil } func (td *testData) logTest(t *testing.T, rootLog logger.MultiLogger) { t.Helper() if td.tc == nil { td.tc = &testCounter{} counterInit(td.tc) } newContext := config.NewContext() for _, i := range td.config { iout := strings.Split(i, "=") if len(iout) > 1 { newContext.SetOption(iout[0], iout[1]) } else { newContext.SetOption(i, "test") } } newContext.SetOption("specialUseFlag", "true") handler := logger.InitializeFromConfig("test", newContext) rootLog.SetHandler(handler) td.runLogTest(rootLog) } func (td *testData) runLogTest(log logger.MultiLogger) { log.Debug("test") log.Info("test") log.Warn("test") log.Error("test") log.Crit("test") } func (td *testData) validate(t *testing.T) { t.Helper() t.Logf("Test %#v expected %#v", td.tc, td.result) assert.Equal(t, td.result.debug, td.tc.debug, "Debug failed "+strings.Join(td.config, " ")) assert.Equal(t, td.result.info, td.tc.info, "Info failed "+strings.Join(td.config, " ")) assert.Equal(t, td.result.warn, td.tc.warn, "Warn failed "+strings.Join(td.config, " ")) assert.Equal(t, td.result.error, td.tc.error, "Error failed "+strings.Join(td.config, " ")) assert.Equal(t, td.result.critical, td.tc.critical, "Critical failed "+strings.Join(td.config, " ")) } // Add test to the function map. func counterInit(tc *testCounter) { logger.LogFunctionMap["test"] = func(c *logger.CompositeMultiHandler, logOptions *logger.LogOptions) { // Output to the test log and the stdout outHandler := logger.LogHandler( logger.NewListLogHandler(tc, logger.StreamHandler(os.Stdout, logger.TerminalFormatHandler(false, true))), ) if logOptions.HandlerWrap != nil { outHandler = logOptions.HandlerWrap.SetChild(outHandler) } c.SetHandlers(outHandler, logOptions) } }