github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/querylogger/worker_test.go (about) 1 // Copyright 2023 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package querylogger 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 time "time" 11 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/worker/v3/workertest" 15 "go.uber.org/mock/gomock" 16 gc "gopkg.in/check.v1" 17 ) 18 19 type loggerSuite struct { 20 testing.IsolationSuite 21 22 clock *MockClock 23 timer *MockTimer 24 logger *MockLogger 25 } 26 27 var _ = gc.Suite(&loggerSuite{}) 28 29 func (s *loggerSuite) TestLogger(c *gc.C) { 30 defer s.setupMocks(c).Finish() 31 32 dir := c.MkDir() 33 34 ch := make(chan time.Time) 35 s.timer.EXPECT().Chan().Return(ch).AnyTimes() 36 37 w := s.newWorker(c, dir) 38 defer workertest.DirtyKill(c, w) 39 40 args := []any{0.1, "SELECT * FROM foo"} 41 s.logger.EXPECT().Warningf("slow query: hello", args) 42 43 w.RecordSlowQuery("hello", "SELECT * FROM foo", args, 0.1) 44 45 select { 46 case ch <- time.Now(): 47 case <-time.After(testing.ShortWait): 48 c.Fatal("timed out waiting for log to be written") 49 } 50 51 s.expectLogResult(c, dir, ` 52 slow query took 0.100s for statement: SELECT * FROM foo 53 stack trace: 54 dummy stack 55 56 `[1:]) 57 58 workertest.CleanKill(c, w) 59 } 60 61 func (s *loggerSuite) TestLoggerMultipleTimes(c *gc.C) { 62 defer s.setupMocks(c).Finish() 63 64 dir := c.MkDir() 65 66 ch := make(chan time.Time) 67 s.timer.EXPECT().Chan().Return(ch).AnyTimes() 68 69 w := s.newWorker(c, dir) 70 defer workertest.DirtyKill(c, w) 71 72 for i := 0; i < 100; i++ { 73 stmt := fmt.Sprintf("SELECT %d FROM foo", i) 74 args := []any{i, stmt} 75 76 s.logger.EXPECT().Warningf("slow query: hello", args) 77 78 w.RecordSlowQuery("hello", stmt, args, float64(i)) 79 } 80 81 select { 82 case ch <- time.Now(): 83 case <-time.After(testing.ShortWait): 84 c.Fatal("timed out waiting for log to be written") 85 } 86 87 template := ` 88 slow query took %0.3fs for statement: SELECT %d FROM foo 89 stack trace: 90 dummy stack 91 92 `[1:] 93 94 var expected string 95 for i := 0; i < 100; i++ { 96 expected += fmt.Sprintf(template, float64(i), i) 97 } 98 99 s.expectLogResult(c, dir, expected) 100 101 workertest.CleanKill(c, w) 102 } 103 104 func (s *loggerSuite) expectLogResult(c *gc.C, dir string, match string) { 105 data, err := os.ReadFile(filepath.Join(dir, filename)) 106 c.Assert(err, jc.ErrorIsNil) 107 c.Assert(string(data), gc.Equals, match) 108 } 109 110 func (s *loggerSuite) setupMocks(c *gc.C) *gomock.Controller { 111 ctrl := gomock.NewController(c) 112 113 s.timer = NewMockTimer(ctrl) 114 s.timer.EXPECT().Reset(PollInterval) 115 s.timer.EXPECT().Stop() 116 117 s.clock = NewMockClock(ctrl) 118 s.clock.EXPECT().NewTimer(PollInterval).Return(s.timer) 119 120 s.logger = NewMockLogger(ctrl) 121 122 return ctrl 123 } 124 125 func (s *loggerSuite) newWorker(c *gc.C, dir string) *loggerWorker { 126 w, err := newWorker(&WorkerConfig{ 127 LogDir: dir, 128 Clock: s.clock, 129 Logger: s.logger, 130 StackGatherer: func() []byte { 131 return []byte("dummy stack") 132 }, 133 }) 134 c.Assert(err, jc.ErrorIsNil) 135 136 return w 137 }