github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/xlog/buffer_syncer_test.go (about) 1 package xlog 2 3 import ( 4 "archive/zip" 5 "context" 6 "os" 7 "path/filepath" 8 "strconv" 9 "sync" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/require" 14 "go.uber.org/zap/zapcore" 15 16 "github.com/benz9527/xboot/lib/id" 17 ) 18 19 type syncerOutWriter struct { 20 data [][]byte 21 } 22 23 func (w *syncerOutWriter) Write(data []byte) (n int, err error) { 24 l := len(data) 25 tmp := make([]byte, l) 26 copy(tmp, data) 27 w.data = append(w.data, tmp) 28 return l, nil 29 } 30 31 func (w *syncerOutWriter) Close() error { 32 return nil 33 } 34 35 func genLog(strLen, count int) (keys []string) { 36 nanoID, err := id.ClassicNanoID(strLen) 37 if err != nil { 38 panic(err) 39 } 40 keys = make([]string, count) 41 for i := range keys { 42 keys[i] = nanoID() 43 } 44 return 45 } 46 47 func TestXLogBufferSyncer_Console(t *testing.T) { 48 ctx, cancel := context.WithCancel(context.TODO()) 49 w := &syncerOutWriter{} 50 syncer := &xLogBufferSyncer{ 51 ctx: ctx, 52 outWriter: w, 53 arena: &xLogArena{ 54 size: 1 << 10, 55 }, 56 flushInterval: 500 * time.Millisecond, 57 } 58 syncer.initialize() 59 60 logs := genLog(100, 200) 61 for _, log := range logs { 62 _, err := syncer.Write([]byte(log)) 63 require.NoError(t, err) 64 } 65 time.Sleep(1 * time.Second) 66 err := syncer.Sync() 67 require.NoError(t, err) 68 require.NotZero(t, len(w.data)) 69 for i, log := range logs { 70 require.Equal(t, w.data[i], []byte(log)) 71 } 72 cancel() 73 } 74 75 func TestXLogBufferSyncer_Console_DataRace(t *testing.T) { 76 ctx, cancel := context.WithCancel(context.TODO()) 77 w := &syncerOutWriter{} 78 syncer := &xLogBufferSyncer{ 79 ctx: ctx, 80 outWriter: w, 81 arena: &xLogArena{ 82 size: 1 << 10, 83 }, 84 flushInterval: 500 * time.Millisecond, 85 } 86 syncer.initialize() 87 88 wg := sync.WaitGroup{} 89 wg.Add(2) 90 logs := genLog(100, 200) 91 go func() { 92 for i := 0; i < len(logs)>>1; i++ { 93 _, err := syncer.Write([]byte(logs[i])) 94 require.NoError(t, err) 95 } 96 wg.Done() 97 }() 98 go func() { 99 for i := len(logs) >> 1; i < len(logs); i++ { 100 _, err := syncer.Write([]byte(logs[i])) 101 require.NoError(t, err) 102 } 103 wg.Done() 104 }() 105 wg.Wait() 106 time.Sleep(1 * time.Second) 107 err := syncer.Sync() 108 require.NoError(t, err) 109 require.NotZero(t, len(w.data)) 110 set := make(map[string]struct{}, len(logs)) 111 for _, log := range logs { 112 set[log] = struct{}{} 113 } 114 for _, log := range w.data { 115 _, ok := set[string(log)] 116 require.True(t, ok) 117 } 118 cancel() 119 } 120 121 func testBufferSyncerRotateLogWriteRunCore(t *testing.T, syncer zapcore.WriteSyncer) { 122 var err error 123 for i := 0; i < 100; i++ { 124 data := []byte(strconv.Itoa(i) + " " + time.Now().UTC().Format(backupDateTimeFormat) + " xlog rolling log write test!\n") 125 _, err = syncer.Write(data) 126 require.NoError(t, err) 127 } 128 time.Sleep(1 * time.Second) 129 } 130 131 func testBufferSyncerRotateLogWriteDataRaceRunCore(t *testing.T, syncer zapcore.WriteSyncer) { 132 wg := sync.WaitGroup{} 133 wg.Add(2) 134 go func() { 135 for i := 0; i < 50; i++ { 136 data := []byte(strconv.Itoa(i) + " " + time.Now().UTC().Format(backupDateTimeFormat) + " xlog rolling log write test!\n") 137 _, err := syncer.Write(data) 138 require.NoError(t, err) 139 } 140 wg.Done() 141 }() 142 go func() { 143 for i := 50; i < 100; i++ { 144 data := []byte(strconv.Itoa(i) + " " + time.Now().UTC().Format(backupDateTimeFormat) + " xlog rolling log write test!\n") 145 _, err := syncer.Write(data) 146 require.NoError(t, err) 147 } 148 wg.Done() 149 }() 150 wg.Wait() 151 time.Sleep(1 * time.Second) 152 } 153 154 func TestXLogBufferSyncer_RotateLog(t *testing.T) { 155 nano, err := id.ClassicNanoID(6) 156 require.NoError(t, err) 157 rngLogSuffix := "_" + nano() + "_xlog" 158 rngLogZipSuffix := rngLogSuffix + "s" 159 ctx, cancel := context.WithCancel(context.TODO()) 160 cfg := &FileCoreConfig{ 161 FileMaxSize: "1KB", 162 Filename: filepath.Base(os.Args[0]) + rngLogSuffix + ".log", 163 FileCompressible: true, 164 FileMaxBackups: 4, 165 FileMaxAge: "3day", 166 FileCompressBatch: 2, 167 FileZipName: filepath.Base(os.Args[0]) + rngLogZipSuffix + ".zip", 168 FilePath: os.TempDir(), 169 } 170 log := RotateLog(ctx, cfg) 171 172 size, err := parseFileSize(log.(*rotateLog).fileMaxSize) 173 require.NoError(t, err) 174 require.Equal(t, uint64(1024), size) 175 176 syncer := XLogBufferSyncer(ctx, log, 1<<10, 500) 177 178 loop := 2 179 for i := 0; i < loop; i++ { 180 testBufferSyncerRotateLogWriteRunCore(t, syncer) 181 require.NoError(t, log.Close()) 182 } 183 cancel() 184 185 reader, err := zip.OpenReader(filepath.Join(cfg.FilePath, cfg.FileZipName)) 186 require.NoError(t, err) 187 require.LessOrEqual(t, int((loop-1)*cfg.FileMaxBackups), len(reader.File)) 188 require.NoError(t, reader.Close()) 189 testCleanLogFiles(t, os.TempDir(), filepath.Base(os.Args[0])+rngLogSuffix, ".log") 190 testCleanLogFiles(t, os.TempDir(), filepath.Base(os.Args[0])+rngLogZipSuffix, ".zip") 191 } 192 193 func TestXLogBufferSyncer_RotateLog_DataRace(t *testing.T) { 194 nano, err := id.ClassicNanoID(6) 195 require.NoError(t, err) 196 rngLogSuffix := "_" + nano() + "_xlog" 197 rngLogZipSuffix := rngLogSuffix + "s" 198 ctx, cancel := context.WithCancel(context.TODO()) 199 cfg := &FileCoreConfig{ 200 FileMaxSize: "1KB", 201 Filename: filepath.Base(os.Args[0]) + rngLogSuffix + ".log", 202 FileCompressible: true, 203 FileMaxBackups: 4, 204 FileMaxAge: "3day", 205 FileCompressBatch: 2, 206 FileZipName: filepath.Base(os.Args[0]) + rngLogZipSuffix + ".zip", 207 FilePath: os.TempDir(), 208 } 209 log := RotateLog(ctx, cfg) 210 211 size, err := parseFileSize(log.(*rotateLog).fileMaxSize) 212 require.NoError(t, err) 213 require.Equal(t, uint64(1024), size) 214 215 syncer := XLogBufferSyncer(ctx, log, 1<<10, 500) 216 217 loop := 2 218 for i := 0; i < loop; i++ { 219 testBufferSyncerRotateLogWriteDataRaceRunCore(t, syncer) 220 } 221 cancel() 222 223 reader, err := zip.OpenReader(filepath.Join(cfg.FilePath, cfg.FileZipName)) 224 require.NoError(t, err) 225 require.LessOrEqual(t, int((loop-1)*cfg.FileMaxBackups), len(reader.File)) 226 require.NoError(t, reader.Close()) 227 testCleanLogFiles(t, os.TempDir(), filepath.Base(os.Args[0])+rngLogSuffix, ".log") 228 testCleanLogFiles(t, os.TempDir(), filepath.Base(os.Args[0])+rngLogZipSuffix, ".zip") 229 }