Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
a5f29019
Commit
a5f29019
authored
Feb 12, 2026
by
yangjianbo
Browse files
test(ops): 提升日志链路覆盖率并修复lint阻塞
parent
208c5380
Changes
4
Show whitespace changes
Inline
Side-by-side
backend/internal/handler/admin/ops_system_log_handler_test.go
0 → 100644
View file @
a5f29019
package
admin
import
(
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
)
type
responseEnvelope
struct
{
Code
int
`json:"code"`
Message
string
`json:"message"`
Data
json
.
RawMessage
`json:"data"`
}
func
newOpsSystemLogTestRouter
(
handler
*
OpsHandler
,
withUser
bool
)
*
gin
.
Engine
{
gin
.
SetMode
(
gin
.
TestMode
)
r
:=
gin
.
New
()
if
withUser
{
r
.
Use
(
func
(
c
*
gin
.
Context
)
{
c
.
Set
(
string
(
middleware
.
ContextKeyUser
),
middleware
.
AuthSubject
{
UserID
:
99
})
c
.
Next
()
})
}
r
.
GET
(
"/logs"
,
handler
.
ListSystemLogs
)
r
.
POST
(
"/logs/cleanup"
,
handler
.
CleanupSystemLogs
)
r
.
GET
(
"/logs/health"
,
handler
.
GetSystemLogIngestionHealth
)
return
r
}
func
TestOpsSystemLogHandler_ListUnavailable
(
t
*
testing
.
T
)
{
h
:=
NewOpsHandler
(
nil
)
r
:=
newOpsSystemLogTestRouter
(
h
,
false
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/logs"
,
nil
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusServiceUnavailable
{
t
.
Fatalf
(
"status=%d, want 503"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_ListInvalidUserID
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
false
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/logs?user_id=abc"
,
nil
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusBadRequest
{
t
.
Fatalf
(
"status=%d, want 400"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_ListInvalidAccountID
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
false
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/logs?account_id=-1"
,
nil
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusBadRequest
{
t
.
Fatalf
(
"status=%d, want 400"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_ListMonitoringDisabled
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
&
config
.
Config
{
Ops
:
config
.
OpsConfig
{
Enabled
:
false
},
},
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
false
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/logs"
,
nil
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusNotFound
{
t
.
Fatalf
(
"status=%d, want 404"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_ListSuccess
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
false
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/logs?time_range=30m&page=1&page_size=20"
,
nil
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusOK
{
t
.
Fatalf
(
"status=%d, want 200"
,
w
.
Code
)
}
var
resp
responseEnvelope
if
err
:=
json
.
Unmarshal
(
w
.
Body
.
Bytes
(),
&
resp
);
err
!=
nil
{
t
.
Fatalf
(
"unmarshal response: %v"
,
err
)
}
if
resp
.
Code
!=
0
{
t
.
Fatalf
(
"unexpected response code: %+v"
,
resp
)
}
}
func
TestOpsSystemLogHandler_CleanupUnauthorized
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
false
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/logs/cleanup"
,
bytes
.
NewBufferString
(
`{"request_id":"r1"}`
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusUnauthorized
{
t
.
Fatalf
(
"status=%d, want 401"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_CleanupInvalidPayload
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
true
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/logs/cleanup"
,
bytes
.
NewBufferString
(
`{bad-json`
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusBadRequest
{
t
.
Fatalf
(
"status=%d, want 400"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_CleanupInvalidTime
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
true
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/logs/cleanup"
,
bytes
.
NewBufferString
(
`{"start_time":"bad","request_id":"r1"}`
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusBadRequest
{
t
.
Fatalf
(
"status=%d, want 400"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_CleanupInvalidEndTime
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
true
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/logs/cleanup"
,
bytes
.
NewBufferString
(
`{"end_time":"bad","request_id":"r1"}`
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusBadRequest
{
t
.
Fatalf
(
"status=%d, want 400"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_CleanupServiceUnavailable
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
true
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/logs/cleanup"
,
bytes
.
NewBufferString
(
`{"request_id":"r1"}`
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusServiceUnavailable
{
t
.
Fatalf
(
"status=%d, want 503"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_CleanupMonitoringDisabled
(
t
*
testing
.
T
)
{
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
&
config
.
Config
{
Ops
:
config
.
OpsConfig
{
Enabled
:
false
},
},
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
true
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/logs/cleanup"
,
bytes
.
NewBufferString
(
`{"request_id":"r1"}`
))
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusNotFound
{
t
.
Fatalf
(
"status=%d, want 404"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_Health
(
t
*
testing
.
T
)
{
sink
:=
service
.
NewOpsSystemLogSink
(
nil
)
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
sink
)
h
:=
NewOpsHandler
(
svc
)
r
:=
newOpsSystemLogTestRouter
(
h
,
false
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/logs/health"
,
nil
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusOK
{
t
.
Fatalf
(
"status=%d, want 200"
,
w
.
Code
)
}
}
func
TestOpsSystemLogHandler_HealthUnavailableAndMonitoringDisabled
(
t
*
testing
.
T
)
{
h
:=
NewOpsHandler
(
nil
)
r
:=
newOpsSystemLogTestRouter
(
h
,
false
)
w
:=
httptest
.
NewRecorder
()
req
:=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/logs/health"
,
nil
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusServiceUnavailable
{
t
.
Fatalf
(
"status=%d, want 503"
,
w
.
Code
)
}
svc
:=
service
.
NewOpsService
(
nil
,
nil
,
&
config
.
Config
{
Ops
:
config
.
OpsConfig
{
Enabled
:
false
},
},
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
h
=
NewOpsHandler
(
svc
)
r
=
newOpsSystemLogTestRouter
(
h
,
false
)
w
=
httptest
.
NewRecorder
()
req
=
httptest
.
NewRequest
(
http
.
MethodGet
,
"/logs/health"
,
nil
)
r
.
ServeHTTP
(
w
,
req
)
if
w
.
Code
!=
http
.
StatusNotFound
{
t
.
Fatalf
(
"status=%d, want 404"
,
w
.
Code
)
}
}
backend/internal/service/ops_log_runtime_test.go
0 → 100644
View file @
a5f29019
package
service
import
(
"context"
"encoding/json"
"errors"
"testing"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/pkg/logger"
)
type
runtimeSettingRepoStub
struct
{
values
map
[
string
]
string
deleted
map
[
string
]
bool
setCalls
int
getValueFn
func
(
key
string
)
(
string
,
error
)
setFn
func
(
key
,
value
string
)
error
deleteFn
func
(
key
string
)
error
}
func
newRuntimeSettingRepoStub
()
*
runtimeSettingRepoStub
{
return
&
runtimeSettingRepoStub
{
values
:
map
[
string
]
string
{},
deleted
:
map
[
string
]
bool
{},
}
}
func
(
s
*
runtimeSettingRepoStub
)
Get
(
ctx
context
.
Context
,
key
string
)
(
*
Setting
,
error
)
{
value
,
err
:=
s
.
GetValue
(
ctx
,
key
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
Setting
{
Key
:
key
,
Value
:
value
},
nil
}
func
(
s
*
runtimeSettingRepoStub
)
GetValue
(
_
context
.
Context
,
key
string
)
(
string
,
error
)
{
if
s
.
getValueFn
!=
nil
{
return
s
.
getValueFn
(
key
)
}
value
,
ok
:=
s
.
values
[
key
]
if
!
ok
{
return
""
,
ErrSettingNotFound
}
return
value
,
nil
}
func
(
s
*
runtimeSettingRepoStub
)
Set
(
_
context
.
Context
,
key
,
value
string
)
error
{
if
s
.
setFn
!=
nil
{
if
err
:=
s
.
setFn
(
key
,
value
);
err
!=
nil
{
return
err
}
}
s
.
values
[
key
]
=
value
s
.
setCalls
++
return
nil
}
func
(
s
*
runtimeSettingRepoStub
)
GetMultiple
(
_
context
.
Context
,
keys
[]
string
)
(
map
[
string
]
string
,
error
)
{
out
:=
make
(
map
[
string
]
string
,
len
(
keys
))
for
_
,
key
:=
range
keys
{
if
value
,
ok
:=
s
.
values
[
key
];
ok
{
out
[
key
]
=
value
}
}
return
out
,
nil
}
func
(
s
*
runtimeSettingRepoStub
)
SetMultiple
(
_
context
.
Context
,
settings
map
[
string
]
string
)
error
{
for
key
,
value
:=
range
settings
{
s
.
values
[
key
]
=
value
}
return
nil
}
func
(
s
*
runtimeSettingRepoStub
)
GetAll
(
_
context
.
Context
)
(
map
[
string
]
string
,
error
)
{
out
:=
make
(
map
[
string
]
string
,
len
(
s
.
values
))
for
key
,
value
:=
range
s
.
values
{
out
[
key
]
=
value
}
return
out
,
nil
}
func
(
s
*
runtimeSettingRepoStub
)
Delete
(
_
context
.
Context
,
key
string
)
error
{
if
s
.
deleteFn
!=
nil
{
if
err
:=
s
.
deleteFn
(
key
);
err
!=
nil
{
return
err
}
}
if
_
,
ok
:=
s
.
values
[
key
];
!
ok
{
return
ErrSettingNotFound
}
delete
(
s
.
values
,
key
)
s
.
deleted
[
key
]
=
true
return
nil
}
func
TestUpdateRuntimeLogConfig_InvalidConfigShouldNotApply
(
t
*
testing
.
T
)
{
repo
:=
newRuntimeSettingRepoStub
()
svc
:=
&
OpsService
{
settingRepo
:
repo
,
cfg
:
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"info"
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
false
,
Initial
:
100
,
Thereafter
:
100
,
},
},
},
}
if
err
:=
logger
.
Init
(
logger
.
InitOptions
{
Level
:
"info"
,
Format
:
"json"
,
ServiceName
:
"sub2api"
,
Environment
:
"test"
,
Output
:
logger
.
OutputOptions
{
ToStdout
:
true
,
ToFile
:
false
,
},
});
err
!=
nil
{
t
.
Fatalf
(
"init logger: %v"
,
err
)
}
_
,
err
:=
svc
.
UpdateRuntimeLogConfig
(
context
.
Background
(),
&
OpsRuntimeLogConfig
{
Level
:
"trace"
,
EnableSampling
:
true
,
SamplingInitial
:
100
,
SamplingNext
:
100
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
RetentionDays
:
30
,
},
1
)
if
err
==
nil
{
t
.
Fatalf
(
"expected validation error"
)
}
if
logger
.
CurrentLevel
()
!=
"info"
{
t
.
Fatalf
(
"logger level changed unexpectedly: %s"
,
logger
.
CurrentLevel
())
}
if
repo
.
setCalls
!=
1
{
// GetRuntimeLogConfig() 会在 key 缺失时写入默认值,此处应只有这一次持久化。
t
.
Fatalf
(
"unexpected set calls: %d"
,
repo
.
setCalls
)
}
}
func
TestResetRuntimeLogConfig_ShouldFallbackToBaseline
(
t
*
testing
.
T
)
{
repo
:=
newRuntimeSettingRepoStub
()
existing
:=
&
OpsRuntimeLogConfig
{
Level
:
"debug"
,
EnableSampling
:
true
,
SamplingInitial
:
50
,
SamplingNext
:
50
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
RetentionDays
:
60
,
Source
:
"runtime_setting"
,
}
raw
,
_
:=
json
.
Marshal
(
existing
)
repo
.
values
[
SettingKeyOpsRuntimeLogConfig
]
=
string
(
raw
)
svc
:=
&
OpsService
{
settingRepo
:
repo
,
cfg
:
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"warn"
,
Caller
:
false
,
StacktraceLevel
:
"fatal"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
false
,
Initial
:
100
,
Thereafter
:
100
,
},
},
Ops
:
config
.
OpsConfig
{
Cleanup
:
config
.
OpsCleanupConfig
{
ErrorLogRetentionDays
:
45
,
},
},
},
}
if
err
:=
logger
.
Init
(
logger
.
InitOptions
{
Level
:
"debug"
,
Format
:
"json"
,
ServiceName
:
"sub2api"
,
Environment
:
"test"
,
Output
:
logger
.
OutputOptions
{
ToStdout
:
true
,
ToFile
:
false
,
},
});
err
!=
nil
{
t
.
Fatalf
(
"init logger: %v"
,
err
)
}
resetCfg
,
err
:=
svc
.
ResetRuntimeLogConfig
(
context
.
Background
(),
9
)
if
err
!=
nil
{
t
.
Fatalf
(
"ResetRuntimeLogConfig() error: %v"
,
err
)
}
if
resetCfg
.
Source
!=
"baseline"
{
t
.
Fatalf
(
"source = %q, want baseline"
,
resetCfg
.
Source
)
}
if
resetCfg
.
Level
!=
"warn"
{
t
.
Fatalf
(
"level = %q, want warn"
,
resetCfg
.
Level
)
}
if
resetCfg
.
RetentionDays
!=
45
{
t
.
Fatalf
(
"retention_days = %d, want 45"
,
resetCfg
.
RetentionDays
)
}
if
logger
.
CurrentLevel
()
!=
"warn"
{
t
.
Fatalf
(
"logger level = %q, want warn"
,
logger
.
CurrentLevel
())
}
if
!
repo
.
deleted
[
SettingKeyOpsRuntimeLogConfig
]
{
t
.
Fatalf
(
"runtime setting key should be deleted"
)
}
}
func
TestResetRuntimeLogConfig_InvalidOperator
(
t
*
testing
.
T
)
{
svc
:=
&
OpsService
{
settingRepo
:
newRuntimeSettingRepoStub
()}
_
,
err
:=
svc
.
ResetRuntimeLogConfig
(
context
.
Background
(),
0
)
if
err
==
nil
{
t
.
Fatalf
(
"expected invalid operator error"
)
}
if
err
.
Error
()
!=
"invalid operator id"
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
}
func
TestGetRuntimeLogConfig_InvalidJSONFallback
(
t
*
testing
.
T
)
{
repo
:=
newRuntimeSettingRepoStub
()
repo
.
values
[
SettingKeyOpsRuntimeLogConfig
]
=
`{invalid-json}`
svc
:=
&
OpsService
{
settingRepo
:
repo
,
cfg
:
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"warn"
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
false
,
Initial
:
100
,
Thereafter
:
100
,
},
},
},
}
got
,
err
:=
svc
.
GetRuntimeLogConfig
(
context
.
Background
())
if
err
!=
nil
{
t
.
Fatalf
(
"GetRuntimeLogConfig() error: %v"
,
err
)
}
if
got
.
Level
!=
"warn"
{
t
.
Fatalf
(
"level = %q, want warn"
,
got
.
Level
)
}
}
func
TestUpdateRuntimeLogConfig_PersistFailureRollback
(
t
*
testing
.
T
)
{
repo
:=
newRuntimeSettingRepoStub
()
oldCfg
:=
&
OpsRuntimeLogConfig
{
Level
:
"info"
,
EnableSampling
:
false
,
SamplingInitial
:
100
,
SamplingNext
:
100
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
RetentionDays
:
30
,
}
raw
,
_
:=
json
.
Marshal
(
oldCfg
)
repo
.
values
[
SettingKeyOpsRuntimeLogConfig
]
=
string
(
raw
)
repo
.
setFn
=
func
(
key
,
value
string
)
error
{
if
key
==
SettingKeyOpsRuntimeLogConfig
{
return
errors
.
New
(
"db down"
)
}
return
nil
}
svc
:=
&
OpsService
{
settingRepo
:
repo
,
cfg
:
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"info"
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
false
,
Initial
:
100
,
Thereafter
:
100
,
},
},
},
}
if
err
:=
logger
.
Init
(
logger
.
InitOptions
{
Level
:
"info"
,
Format
:
"json"
,
ServiceName
:
"sub2api"
,
Environment
:
"test"
,
Output
:
logger
.
OutputOptions
{
ToStdout
:
true
,
ToFile
:
false
,
},
});
err
!=
nil
{
t
.
Fatalf
(
"init logger: %v"
,
err
)
}
_
,
err
:=
svc
.
UpdateRuntimeLogConfig
(
context
.
Background
(),
&
OpsRuntimeLogConfig
{
Level
:
"debug"
,
EnableSampling
:
false
,
SamplingInitial
:
100
,
SamplingNext
:
100
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
RetentionDays
:
30
,
},
5
)
if
err
==
nil
{
t
.
Fatalf
(
"expected persist error"
)
}
// Persist failure should rollback runtime level back to old effective level.
if
logger
.
CurrentLevel
()
!=
"info"
{
t
.
Fatalf
(
"logger level should rollback to info, got %s"
,
logger
.
CurrentLevel
())
}
}
func
TestApplyRuntimeLogConfigOnStartup
(
t
*
testing
.
T
)
{
repo
:=
newRuntimeSettingRepoStub
()
cfgRaw
:=
`{"level":"debug","enable_sampling":false,"sampling_initial":100,"sampling_thereafter":100,"caller":true,"stacktrace_level":"error","retention_days":30}`
repo
.
values
[
SettingKeyOpsRuntimeLogConfig
]
=
cfgRaw
svc
:=
&
OpsService
{
settingRepo
:
repo
,
cfg
:
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"info"
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
false
,
Initial
:
100
,
Thereafter
:
100
,
},
},
},
}
if
err
:=
logger
.
Init
(
logger
.
InitOptions
{
Level
:
"info"
,
Format
:
"json"
,
ServiceName
:
"sub2api"
,
Environment
:
"test"
,
Output
:
logger
.
OutputOptions
{
ToStdout
:
true
,
ToFile
:
false
,
},
});
err
!=
nil
{
t
.
Fatalf
(
"init logger: %v"
,
err
)
}
svc
.
applyRuntimeLogConfigOnStartup
(
context
.
Background
())
if
logger
.
CurrentLevel
()
!=
"debug"
{
t
.
Fatalf
(
"expected startup apply debug, got %s"
,
logger
.
CurrentLevel
())
}
}
func
TestDefaultNormalizeAndValidateRuntimeLogConfig
(
t
*
testing
.
T
)
{
defaults
:=
defaultOpsRuntimeLogConfig
(
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"DEBUG"
,
Caller
:
false
,
StacktraceLevel
:
"FATAL"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
true
,
Initial
:
50
,
Thereafter
:
20
,
},
},
Ops
:
config
.
OpsConfig
{
Cleanup
:
config
.
OpsCleanupConfig
{
ErrorLogRetentionDays
:
7
,
},
},
})
if
defaults
.
Level
!=
"debug"
||
defaults
.
StacktraceLevel
!=
"fatal"
||
defaults
.
RetentionDays
!=
7
{
t
.
Fatalf
(
"unexpected defaults: %+v"
,
defaults
)
}
cfg
:=
&
OpsRuntimeLogConfig
{
Level
:
" "
,
EnableSampling
:
true
,
SamplingInitial
:
0
,
SamplingNext
:
-
1
,
Caller
:
true
,
StacktraceLevel
:
""
,
RetentionDays
:
0
,
}
normalizeOpsRuntimeLogConfig
(
cfg
,
defaults
)
if
cfg
.
Level
!=
"debug"
||
cfg
.
StacktraceLevel
!=
"fatal"
{
t
.
Fatalf
(
"normalize level/stacktrace failed: %+v"
,
cfg
)
}
if
cfg
.
SamplingInitial
!=
50
||
cfg
.
SamplingNext
!=
20
||
cfg
.
RetentionDays
!=
7
{
t
.
Fatalf
(
"normalize numeric defaults failed: %+v"
,
cfg
)
}
if
err
:=
validateOpsRuntimeLogConfig
(
cfg
);
err
!=
nil
{
t
.
Fatalf
(
"validate normalized config should pass: %v"
,
err
)
}
}
func
TestValidateRuntimeLogConfigErrors
(
t
*
testing
.
T
)
{
cases
:=
[]
struct
{
name
string
cfg
*
OpsRuntimeLogConfig
}{
{
name
:
"nil"
,
cfg
:
nil
},
{
name
:
"bad level"
,
cfg
:
&
OpsRuntimeLogConfig
{
Level
:
"trace"
,
StacktraceLevel
:
"error"
,
SamplingInitial
:
1
,
SamplingNext
:
1
,
RetentionDays
:
1
}},
{
name
:
"bad stack"
,
cfg
:
&
OpsRuntimeLogConfig
{
Level
:
"info"
,
StacktraceLevel
:
"warn"
,
SamplingInitial
:
1
,
SamplingNext
:
1
,
RetentionDays
:
1
}},
{
name
:
"bad initial"
,
cfg
:
&
OpsRuntimeLogConfig
{
Level
:
"info"
,
StacktraceLevel
:
"error"
,
SamplingInitial
:
0
,
SamplingNext
:
1
,
RetentionDays
:
1
}},
{
name
:
"bad next"
,
cfg
:
&
OpsRuntimeLogConfig
{
Level
:
"info"
,
StacktraceLevel
:
"error"
,
SamplingInitial
:
1
,
SamplingNext
:
0
,
RetentionDays
:
1
}},
{
name
:
"bad retention"
,
cfg
:
&
OpsRuntimeLogConfig
{
Level
:
"info"
,
StacktraceLevel
:
"error"
,
SamplingInitial
:
1
,
SamplingNext
:
1
,
RetentionDays
:
0
}},
}
for
_
,
tc
:=
range
cases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
if
err
:=
validateOpsRuntimeLogConfig
(
tc
.
cfg
);
err
==
nil
{
t
.
Fatalf
(
"expected validation error"
)
}
})
}
}
func
TestGetRuntimeLogConfigFallbackAndErrors
(
t
*
testing
.
T
)
{
var
nilSvc
*
OpsService
cfg
,
err
:=
nilSvc
.
GetRuntimeLogConfig
(
context
.
Background
())
if
err
!=
nil
{
t
.
Fatalf
(
"nil svc should fallback default: %v"
,
err
)
}
if
cfg
.
Level
!=
"info"
{
t
.
Fatalf
(
"unexpected nil svc default level: %s"
,
cfg
.
Level
)
}
repo
:=
newRuntimeSettingRepoStub
()
repo
.
getValueFn
=
func
(
key
string
)
(
string
,
error
)
{
return
""
,
errors
.
New
(
"boom"
)
}
svc
:=
&
OpsService
{
settingRepo
:
repo
,
cfg
:
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"warn"
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
false
,
Initial
:
100
,
Thereafter
:
100
,
},
},
},
}
if
_
,
err
:=
svc
.
GetRuntimeLogConfig
(
context
.
Background
());
err
==
nil
{
t
.
Fatalf
(
"expected get value error"
)
}
}
func
TestUpdateRuntimeLogConfig_PreconditionErrors
(
t
*
testing
.
T
)
{
svc
:=
&
OpsService
{}
if
_
,
err
:=
svc
.
UpdateRuntimeLogConfig
(
context
.
Background
(),
&
OpsRuntimeLogConfig
{},
1
);
err
==
nil
{
t
.
Fatalf
(
"expected setting repo not initialized"
)
}
svc
=
&
OpsService
{
settingRepo
:
newRuntimeSettingRepoStub
()}
if
_
,
err
:=
svc
.
UpdateRuntimeLogConfig
(
context
.
Background
(),
nil
,
1
);
err
==
nil
{
t
.
Fatalf
(
"expected invalid config"
)
}
if
_
,
err
:=
svc
.
UpdateRuntimeLogConfig
(
context
.
Background
(),
&
OpsRuntimeLogConfig
{
Level
:
"info"
,
StacktraceLevel
:
"error"
,
SamplingInitial
:
1
,
SamplingNext
:
1
,
RetentionDays
:
1
,
},
0
);
err
==
nil
{
t
.
Fatalf
(
"expected invalid operator"
)
}
}
func
TestUpdateRuntimeLogConfig_Success
(
t
*
testing
.
T
)
{
repo
:=
newRuntimeSettingRepoStub
()
svc
:=
&
OpsService
{
settingRepo
:
repo
,
cfg
:
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"info"
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
false
,
Initial
:
100
,
Thereafter
:
100
,
},
},
},
}
if
err
:=
logger
.
Init
(
logger
.
InitOptions
{
Level
:
"info"
,
Format
:
"json"
,
ServiceName
:
"sub2api"
,
Environment
:
"test"
,
Output
:
logger
.
OutputOptions
{
ToStdout
:
true
,
ToFile
:
false
,
},
});
err
!=
nil
{
t
.
Fatalf
(
"init logger: %v"
,
err
)
}
next
,
err
:=
svc
.
UpdateRuntimeLogConfig
(
context
.
Background
(),
&
OpsRuntimeLogConfig
{
Level
:
"debug"
,
EnableSampling
:
false
,
SamplingInitial
:
100
,
SamplingNext
:
100
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
RetentionDays
:
30
,
},
2
)
if
err
!=
nil
{
t
.
Fatalf
(
"UpdateRuntimeLogConfig() error: %v"
,
err
)
}
if
next
.
Source
!=
"runtime_setting"
||
next
.
UpdatedByUserID
!=
2
||
next
.
UpdatedAt
==
""
{
t
.
Fatalf
(
"unexpected metadata: %+v"
,
next
)
}
if
logger
.
CurrentLevel
()
!=
"debug"
{
t
.
Fatalf
(
"expected applied level debug, got %s"
,
logger
.
CurrentLevel
())
}
}
func
TestResetRuntimeLogConfig_IgnoreNotFoundDelete
(
t
*
testing
.
T
)
{
repo
:=
newRuntimeSettingRepoStub
()
repo
.
deleteFn
=
func
(
key
string
)
error
{
return
ErrSettingNotFound
}
svc
:=
&
OpsService
{
settingRepo
:
repo
,
cfg
:
&
config
.
Config
{
Log
:
config
.
LogConfig
{
Level
:
"info"
,
Caller
:
true
,
StacktraceLevel
:
"error"
,
Sampling
:
config
.
LogSamplingConfig
{
Enabled
:
false
,
Initial
:
100
,
Thereafter
:
100
,
},
},
},
}
if
_
,
err
:=
svc
.
ResetRuntimeLogConfig
(
context
.
Background
(),
1
);
err
!=
nil
{
t
.
Fatalf
(
"reset should ignore ErrSettingNotFound: %v"
,
err
)
}
}
func
TestApplyRuntimeLogConfigHelpers
(
t
*
testing
.
T
)
{
if
err
:=
applyOpsRuntimeLogConfig
(
nil
);
err
==
nil
{
t
.
Fatalf
(
"expected nil config error"
)
}
normalizeOpsRuntimeLogConfig
(
nil
,
&
OpsRuntimeLogConfig
{
Level
:
"info"
})
normalizeOpsRuntimeLogConfig
(
&
OpsRuntimeLogConfig
{
Level
:
"debug"
},
nil
)
var
nilSvc
*
OpsService
nilSvc
.
applyRuntimeLogConfigOnStartup
(
context
.
Background
())
}
backend/internal/service/ops_settings_models.go
View file @
a5f29019
...
...
@@ -68,6 +68,20 @@ type OpsMetricThresholds struct {
UpstreamErrorRatePercentMax
*
float64
`json:"upstream_error_rate_percent_max,omitempty"`
// 上游错误率高于此值变红
}
type
OpsRuntimeLogConfig
struct
{
Level
string
`json:"level"`
EnableSampling
bool
`json:"enable_sampling"`
SamplingInitial
int
`json:"sampling_initial"`
SamplingNext
int
`json:"sampling_thereafter"`
Caller
bool
`json:"caller"`
StacktraceLevel
string
`json:"stacktrace_level"`
RetentionDays
int
`json:"retention_days"`
Source
string
`json:"source,omitempty"`
UpdatedAt
string
`json:"updated_at,omitempty"`
UpdatedByUserID
int64
`json:"updated_by_user_id,omitempty"`
Extra
map
[
string
]
any
`json:"extra,omitempty"`
}
type
OpsAlertRuntimeSettings
struct
{
EvaluationIntervalSeconds
int
`json:"evaluation_interval_seconds"`
...
...
backend/internal/service/ops_system_log_service_test.go
0 → 100644
View file @
a5f29019
package
service
import
(
"context"
"database/sql"
"errors"
"strings"
"testing"
"time"
"github.com/Wei-Shaw/sub2api/internal/config"
)
func
TestOpsServiceListSystemLogs_DefaultClampAndSuccess
(
t
*
testing
.
T
)
{
var
gotFilter
*
OpsSystemLogFilter
repo
:=
&
opsRepoMock
{
ListSystemLogsFn
:
func
(
ctx
context
.
Context
,
filter
*
OpsSystemLogFilter
)
(
*
OpsSystemLogList
,
error
)
{
gotFilter
=
filter
return
&
OpsSystemLogList
{
Logs
:
[]
*
OpsSystemLog
{{
ID
:
1
,
Level
:
"warn"
,
Message
:
"x"
}},
Total
:
1
,
Page
:
filter
.
Page
,
PageSize
:
filter
.
PageSize
,
},
nil
},
}
svc
:=
NewOpsService
(
repo
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
out
,
err
:=
svc
.
ListSystemLogs
(
context
.
Background
(),
&
OpsSystemLogFilter
{
Page
:
0
,
PageSize
:
999
,
})
if
err
!=
nil
{
t
.
Fatalf
(
"ListSystemLogs() error: %v"
,
err
)
}
if
gotFilter
==
nil
{
t
.
Fatalf
(
"expected repository to receive filter"
)
}
if
gotFilter
.
Page
!=
1
||
gotFilter
.
PageSize
!=
200
{
t
.
Fatalf
(
"filter normalized unexpectedly: page=%d pageSize=%d"
,
gotFilter
.
Page
,
gotFilter
.
PageSize
)
}
if
out
.
Total
!=
1
||
len
(
out
.
Logs
)
!=
1
{
t
.
Fatalf
(
"unexpected result: %+v"
,
out
)
}
}
func
TestOpsServiceListSystemLogs_MonitoringDisabled
(
t
*
testing
.
T
)
{
svc
:=
NewOpsService
(
&
opsRepoMock
{},
nil
,
&
config
.
Config
{
Ops
:
config
.
OpsConfig
{
Enabled
:
false
}},
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
)
_
,
err
:=
svc
.
ListSystemLogs
(
context
.
Background
(),
&
OpsSystemLogFilter
{})
if
err
==
nil
{
t
.
Fatalf
(
"expected disabled error"
)
}
}
func
TestOpsServiceListSystemLogs_NilRepoReturnsEmpty
(
t
*
testing
.
T
)
{
svc
:=
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
out
,
err
:=
svc
.
ListSystemLogs
(
context
.
Background
(),
nil
)
if
err
!=
nil
{
t
.
Fatalf
(
"ListSystemLogs() error: %v"
,
err
)
}
if
out
==
nil
||
out
.
Page
!=
1
||
out
.
PageSize
!=
50
||
out
.
Total
!=
0
||
len
(
out
.
Logs
)
!=
0
{
t
.
Fatalf
(
"unexpected nil-repo result: %+v"
,
out
)
}
}
func
TestOpsServiceListSystemLogs_RepoErrorMapped
(
t
*
testing
.
T
)
{
repo
:=
&
opsRepoMock
{
ListSystemLogsFn
:
func
(
ctx
context
.
Context
,
filter
*
OpsSystemLogFilter
)
(
*
OpsSystemLogList
,
error
)
{
return
nil
,
errors
.
New
(
"db down"
)
},
}
svc
:=
NewOpsService
(
repo
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
_
,
err
:=
svc
.
ListSystemLogs
(
context
.
Background
(),
&
OpsSystemLogFilter
{})
if
err
==
nil
{
t
.
Fatalf
(
"expected mapped internal error"
)
}
if
!
strings
.
Contains
(
err
.
Error
(),
"OPS_SYSTEM_LOG_LIST_FAILED"
)
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
}
func
TestOpsServiceCleanupSystemLogs_SuccessAndAudit
(
t
*
testing
.
T
)
{
var
audit
*
OpsSystemLogCleanupAudit
repo
:=
&
opsRepoMock
{
DeleteSystemLogsFn
:
func
(
ctx
context
.
Context
,
filter
*
OpsSystemLogCleanupFilter
)
(
int64
,
error
)
{
return
3
,
nil
},
InsertSystemLogCleanupAuditFn
:
func
(
ctx
context
.
Context
,
input
*
OpsSystemLogCleanupAudit
)
error
{
audit
=
input
return
nil
},
}
svc
:=
NewOpsService
(
repo
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
userID
:=
int64
(
7
)
now
:=
time
.
Now
()
.
UTC
()
filter
:=
&
OpsSystemLogCleanupFilter
{
StartTime
:
&
now
,
Level
:
"warn"
,
RequestID
:
"req-1"
,
ClientRequestID
:
"creq-1"
,
UserID
:
&
userID
,
Query
:
"timeout"
,
}
deleted
,
err
:=
svc
.
CleanupSystemLogs
(
context
.
Background
(),
filter
,
99
)
if
err
!=
nil
{
t
.
Fatalf
(
"CleanupSystemLogs() error: %v"
,
err
)
}
if
deleted
!=
3
{
t
.
Fatalf
(
"deleted=%d, want 3"
,
deleted
)
}
if
audit
==
nil
{
t
.
Fatalf
(
"expected cleanup audit"
)
}
if
!
strings
.
Contains
(
audit
.
Conditions
,
`"client_request_id":"creq-1"`
)
{
t
.
Fatalf
(
"audit conditions should include client_request_id: %s"
,
audit
.
Conditions
)
}
if
!
strings
.
Contains
(
audit
.
Conditions
,
`"user_id":7`
)
{
t
.
Fatalf
(
"audit conditions should include user_id: %s"
,
audit
.
Conditions
)
}
}
func
TestOpsServiceCleanupSystemLogs_RepoUnavailableAndInvalidOperator
(
t
*
testing
.
T
)
{
svc
:=
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
if
_
,
err
:=
svc
.
CleanupSystemLogs
(
context
.
Background
(),
&
OpsSystemLogCleanupFilter
{
RequestID
:
"r"
},
1
);
err
==
nil
{
t
.
Fatalf
(
"expected repo unavailable error"
)
}
svc
=
NewOpsService
(
&
opsRepoMock
{},
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
if
_
,
err
:=
svc
.
CleanupSystemLogs
(
context
.
Background
(),
&
OpsSystemLogCleanupFilter
{
RequestID
:
"r"
},
0
);
err
==
nil
{
t
.
Fatalf
(
"expected invalid operator error"
)
}
}
func
TestOpsServiceCleanupSystemLogs_FilterRequired
(
t
*
testing
.
T
)
{
repo
:=
&
opsRepoMock
{
DeleteSystemLogsFn
:
func
(
ctx
context
.
Context
,
filter
*
OpsSystemLogCleanupFilter
)
(
int64
,
error
)
{
return
0
,
errors
.
New
(
"cleanup requires at least one filter condition"
)
},
}
svc
:=
NewOpsService
(
repo
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
_
,
err
:=
svc
.
CleanupSystemLogs
(
context
.
Background
(),
&
OpsSystemLogCleanupFilter
{},
1
)
if
err
==
nil
{
t
.
Fatalf
(
"expected filter required error"
)
}
if
!
strings
.
Contains
(
strings
.
ToLower
(
err
.
Error
()),
"filter"
)
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
}
func
TestOpsServiceCleanupSystemLogs_InvalidRange
(
t
*
testing
.
T
)
{
repo
:=
&
opsRepoMock
{}
svc
:=
NewOpsService
(
repo
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
start
:=
time
.
Now
()
.
UTC
()
end
:=
start
.
Add
(
-
time
.
Hour
)
_
,
err
:=
svc
.
CleanupSystemLogs
(
context
.
Background
(),
&
OpsSystemLogCleanupFilter
{
StartTime
:
&
start
,
EndTime
:
&
end
,
},
1
)
if
err
==
nil
{
t
.
Fatalf
(
"expected invalid range error"
)
}
}
func
TestOpsServiceCleanupSystemLogs_NoRowsAndInternalError
(
t
*
testing
.
T
)
{
repo
:=
&
opsRepoMock
{
DeleteSystemLogsFn
:
func
(
ctx
context
.
Context
,
filter
*
OpsSystemLogCleanupFilter
)
(
int64
,
error
)
{
return
0
,
sql
.
ErrNoRows
},
}
svc
:=
NewOpsService
(
repo
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
deleted
,
err
:=
svc
.
CleanupSystemLogs
(
context
.
Background
(),
&
OpsSystemLogCleanupFilter
{
RequestID
:
"req-1"
,
},
1
)
if
err
!=
nil
||
deleted
!=
0
{
t
.
Fatalf
(
"expected no rows shortcut, deleted=%d err=%v"
,
deleted
,
err
)
}
repo
.
DeleteSystemLogsFn
=
func
(
ctx
context
.
Context
,
filter
*
OpsSystemLogCleanupFilter
)
(
int64
,
error
)
{
return
0
,
errors
.
New
(
"boom"
)
}
if
_
,
err
:=
svc
.
CleanupSystemLogs
(
context
.
Background
(),
&
OpsSystemLogCleanupFilter
{
RequestID
:
"req-1"
,
},
1
);
err
==
nil
{
t
.
Fatalf
(
"expected internal cleanup error"
)
}
}
func
TestOpsServiceCleanupSystemLogs_AuditFailureIgnored
(
t
*
testing
.
T
)
{
repo
:=
&
opsRepoMock
{
DeleteSystemLogsFn
:
func
(
ctx
context
.
Context
,
filter
*
OpsSystemLogCleanupFilter
)
(
int64
,
error
)
{
return
5
,
nil
},
InsertSystemLogCleanupAuditFn
:
func
(
ctx
context
.
Context
,
input
*
OpsSystemLogCleanupAudit
)
error
{
return
errors
.
New
(
"audit down"
)
},
}
svc
:=
NewOpsService
(
repo
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
deleted
,
err
:=
svc
.
CleanupSystemLogs
(
context
.
Background
(),
&
OpsSystemLogCleanupFilter
{
RequestID
:
"r1"
,
},
1
)
if
err
!=
nil
||
deleted
!=
5
{
t
.
Fatalf
(
"audit failure should not break cleanup, deleted=%d err=%v"
,
deleted
,
err
)
}
}
func
TestMarshalSystemLogCleanupConditions_NilAndMarshalError
(
t
*
testing
.
T
)
{
if
got
:=
marshalSystemLogCleanupConditions
(
nil
);
got
!=
"{}"
{
t
.
Fatalf
(
"nil filter should return {}, got %s"
,
got
)
}
now
:=
time
.
Now
()
.
UTC
()
userID
:=
int64
(
1
)
filter
:=
&
OpsSystemLogCleanupFilter
{
StartTime
:
&
now
,
EndTime
:
&
now
,
UserID
:
&
userID
,
}
got
:=
marshalSystemLogCleanupConditions
(
filter
)
if
!
strings
.
Contains
(
got
,
`"start_time"`
)
||
!
strings
.
Contains
(
got
,
`"user_id":1`
)
{
t
.
Fatalf
(
"unexpected marshal payload: %s"
,
got
)
}
}
func
TestOpsServiceGetSystemLogSinkHealth
(
t
*
testing
.
T
)
{
svc
:=
NewOpsService
(
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
health
:=
svc
.
GetSystemLogSinkHealth
()
if
health
.
QueueCapacity
!=
0
||
health
.
QueueDepth
!=
0
{
t
.
Fatalf
(
"unexpected health for nil sink: %+v"
,
health
)
}
sink
:=
NewOpsSystemLogSink
(
&
opsRepoMock
{})
svc
=
NewOpsService
(
&
opsRepoMock
{},
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
,
sink
)
health
=
svc
.
GetSystemLogSinkHealth
()
if
health
.
QueueCapacity
<=
0
{
t
.
Fatalf
(
"expected non-zero queue capacity: %+v"
,
health
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment