code.gitea.io/gitea@v1.22.3/modules/test/logchecker.go (about)

     1  // Copyright 2023 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package test
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"strings"
    10  	"sync"
    11  	"sync/atomic"
    12  	"time"
    13  
    14  	"code.gitea.io/gitea/modules/log"
    15  )
    16  
    17  type LogChecker struct {
    18  	*log.EventWriterBaseImpl
    19  
    20  	filterMessages []string
    21  	filtered       []bool
    22  
    23  	stopMark string
    24  	stopped  bool
    25  
    26  	mu sync.Mutex
    27  }
    28  
    29  func (lc *LogChecker) Run(ctx context.Context) {
    30  	for {
    31  		select {
    32  		case <-ctx.Done():
    33  			return
    34  		case event, ok := <-lc.Queue:
    35  			if !ok {
    36  				return
    37  			}
    38  			lc.checkLogEvent(event)
    39  		}
    40  	}
    41  }
    42  
    43  func (lc *LogChecker) checkLogEvent(event *log.EventFormatted) {
    44  	lc.mu.Lock()
    45  	defer lc.mu.Unlock()
    46  	for i, msg := range lc.filterMessages {
    47  		if strings.Contains(event.Origin.MsgSimpleText, msg) {
    48  			lc.filtered[i] = true
    49  		}
    50  	}
    51  	if strings.Contains(event.Origin.MsgSimpleText, lc.stopMark) {
    52  		lc.stopped = true
    53  	}
    54  }
    55  
    56  var checkerIndex int64
    57  
    58  func NewLogChecker(namePrefix string) (logChecker *LogChecker, cancel func()) {
    59  	logger := log.GetManager().GetLogger(namePrefix)
    60  	newCheckerIndex := atomic.AddInt64(&checkerIndex, 1)
    61  	writerName := namePrefix + "-" + fmt.Sprint(newCheckerIndex)
    62  
    63  	lc := &LogChecker{}
    64  	lc.EventWriterBaseImpl = log.NewEventWriterBase(writerName, "test-log-checker", log.WriterMode{})
    65  	logger.AddWriters(lc)
    66  	return lc, func() { _ = logger.RemoveWriter(writerName) }
    67  }
    68  
    69  // Filter will make the `Check` function to check if these logs are outputted.
    70  func (lc *LogChecker) Filter(msgs ...string) *LogChecker {
    71  	lc.mu.Lock()
    72  	defer lc.mu.Unlock()
    73  	lc.filterMessages = make([]string, len(msgs))
    74  	copy(lc.filterMessages, msgs)
    75  	lc.filtered = make([]bool, len(lc.filterMessages))
    76  	return lc
    77  }
    78  
    79  func (lc *LogChecker) StopMark(msg string) *LogChecker {
    80  	lc.mu.Lock()
    81  	defer lc.mu.Unlock()
    82  	lc.stopMark = msg
    83  	lc.stopped = false
    84  	return lc
    85  }
    86  
    87  // Check returns the filtered slice and whether the stop mark is reached.
    88  func (lc *LogChecker) Check(d time.Duration) (filtered []bool, stopped bool) {
    89  	stop := time.Now().Add(d)
    90  
    91  	for {
    92  		lc.mu.Lock()
    93  		stopped = lc.stopped
    94  		lc.mu.Unlock()
    95  
    96  		if time.Now().After(stop) || stopped {
    97  			lc.mu.Lock()
    98  			f := make([]bool, len(lc.filtered))
    99  			copy(f, lc.filtered)
   100  			lc.mu.Unlock()
   101  			return f, stopped
   102  		}
   103  		time.Sleep(10 * time.Millisecond)
   104  	}
   105  }