feat: catch interrupt signal

This commit is contained in:
lilong.129
2023-05-03 23:00:17 +08:00
parent 4ee3b43d1f
commit 1bb2079c87
6 changed files with 63 additions and 18 deletions
+10 -5
View File
@@ -45,7 +45,9 @@
{ {
"method": "tap_ocr", "method": "tap_ocr",
"params": "我知道了", "params": "我知道了",
"ignore_NotFoundError": true "options": {
"ignore_NotFoundError": true
}
} }
] ]
} }
@@ -56,7 +58,8 @@
"actions": [ "actions": [
{ {
"method": "swipe", "method": "swipe",
"params": "up" "params": "up",
"options": {}
}, },
{ {
"method": "sleep_random", "method": "sleep_random",
@@ -75,7 +78,8 @@
"actions": [ "actions": [
{ {
"method": "swipe", "method": "swipe",
"params": "up" "params": "up",
"options": {}
}, },
{ {
"method": "sleep_random", "method": "sleep_random",
@@ -94,7 +98,8 @@
"actions": [ "actions": [
{ {
"method": "swipe", "method": "swipe",
"params": "up" "params": "up",
"options": {}
}, },
{ {
"method": "sleep_random", "method": "sleep_random",
@@ -131,4 +136,4 @@
] ]
} }
] ]
} }
+2
View File
@@ -44,6 +44,7 @@ var (
InitPluginFailed = errors.New("init plugin failed") // 31 InitPluginFailed = errors.New("init plugin failed") // 31
BuildGoPluginFailed = errors.New("build go plugin failed") // 32 BuildGoPluginFailed = errors.New("build go plugin failed") // 32
BuildPyPluginFailed = errors.New("build py plugin failed") // 33 BuildPyPluginFailed = errors.New("build py plugin failed") // 33
InterruptError = errors.New("interrupt error") // 38
TimeoutError = errors.New("timeout error") // 39 TimeoutError = errors.New("timeout error") // 39
) )
@@ -112,6 +113,7 @@ var errorsMap = map[error]int{
InitPluginFailed: 31, InitPluginFailed: 31,
BuildGoPluginFailed: 32, BuildGoPluginFailed: 32,
BuildPyPluginFailed: 33, BuildPyPluginFailed: 33,
InterruptError: 38,
TimeoutError: 39, TimeoutError: 39,
// ios related // ios related
+5
View File
@@ -12,8 +12,10 @@ import (
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"os" "os"
"os/signal"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -62,6 +64,7 @@ type DriverExt struct {
frame *bytes.Buffer frame *bytes.Buffer
doneMjpegStream chan bool doneMjpegStream chan bool
OCRService IOCRService // used to get texts from image OCRService IOCRService // used to get texts from image
interruptSignal chan os.Signal
// cache step data // cache step data
cacheStepData cacheStepData cacheStepData cacheStepData
@@ -75,7 +78,9 @@ func NewDriverExt(device Device, driver WebDriver) (dExt *DriverExt, err error)
ScreenShots: make([]string, 0), ScreenShots: make([]string, 0),
OcrResults: make(map[string]string), OcrResults: make(map[string]string),
}, },
interruptSignal: make(chan os.Signal, 1),
} }
signal.Notify(dExt.interruptSignal, syscall.SIGTERM, syscall.SIGINT)
dExt.doneMjpegStream = make(chan bool, 1) dExt.doneMjpegStream = make(chan bool, 1)
// get device window size // get device window size
+11 -3
View File
@@ -148,7 +148,11 @@ func (l *LiveCrawler) Run(driver *DriverExt, enterPoint PointF) error {
for !l.currentStat.isLiveTargetAchieved() { for !l.currentStat.isLiveTargetAchieved() {
select { select {
case <-l.currentStat.timer.C: case <-l.currentStat.timer.C:
return errors.Wrap(code.TimeoutError, "timeout in live crawler") log.Warn().Msg("timeout in live crawler")
return errors.Wrap(code.TimeoutError, "live crawler timeout")
case <-l.driver.interruptSignal:
log.Warn().Msg("interrupted in live crawler")
return errors.Wrap(code.InterruptError, "live crawler interrupted")
default: default:
// check if live room // check if live room
if err := l.driver.assertActivity(l.configs.AppPackageName, "live"); err != nil { if err := l.driver.assertActivity(l.configs.AppPackageName, "live"); err != nil {
@@ -246,7 +250,11 @@ func (dExt *DriverExt) VideoCrawler(configs *VideoCrawlerConfigs) (err error) {
for { for {
select { select {
case <-currVideoStat.timer.C: case <-currVideoStat.timer.C:
return errors.Wrap(code.TimeoutError, "timeout in feed crawler") log.Warn().Msg("timeout in feed crawler")
return errors.Wrap(code.TimeoutError, "feed crawler timeout")
case <-dExt.interruptSignal:
log.Warn().Msg("interrupted in feed crawler")
return errors.Wrap(code.InterruptError, "feed crawler interrupted")
default: default:
// check if feed page // check if feed page
if err := dExt.assertActivity(configs.AppPackageName, "feed"); err != nil { if err := dExt.assertActivity(configs.AppPackageName, "feed"); err != nil {
@@ -271,7 +279,7 @@ func (dExt *DriverExt) VideoCrawler(configs *VideoCrawlerConfigs) (err error) {
log.Info().Msg("live video found") log.Info().Msg("live video found")
if !liveCrawler.currentStat.isLiveTargetAchieved() { if !liveCrawler.currentStat.isLiveTargetAchieved() {
if err := liveCrawler.Run(dExt, enterPoint); err != nil { if err := liveCrawler.Run(dExt, enterPoint); err != nil {
if errors.Is(err, code.TimeoutError) { if errors.Is(err, code.TimeoutError) || errors.Is(err, code.InterruptError) {
return err return err
} }
log.Error().Err(err).Msg("run live crawler failed, continue") log.Error().Err(err).Msg("run live crawler failed, continue")
+16
View File
@@ -8,8 +8,11 @@ import (
"net/http" "net/http"
"net/http/cookiejar" "net/http/cookiejar"
"net/url" "net/url"
"os"
"os/signal"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall"
"testing" "testing"
"time" "time"
@@ -39,6 +42,8 @@ func NewRunner(t *testing.T) *HRPRunner {
t = &testing.T{} t = &testing.T{}
} }
jar, _ := cookiejar.New(nil) jar, _ := cookiejar.New(nil)
interruptSignal := make(chan os.Signal, 1)
signal.Notify(interruptSignal, syscall.SIGTERM, syscall.SIGINT)
return &HRPRunner{ return &HRPRunner{
t: t, t: t,
failfast: true, // default to failfast failfast: true, // default to failfast
@@ -62,6 +67,7 @@ func NewRunner(t *testing.T) *HRPRunner {
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}, },
caseTimeoutTimer: time.NewTimer(time.Hour * 2), // default case timeout to 2 hour caseTimeoutTimer: time.NewTimer(time.Hour * 2), // default case timeout to 2 hour
interruptSignal: interruptSignal,
} }
} }
@@ -79,6 +85,7 @@ type HRPRunner struct {
wsDialer *websocket.Dialer wsDialer *websocket.Dialer
uiClients map[string]*uixt.DriverExt // UI automation clients for iOS and Android, key is udid/serial uiClients map[string]*uixt.DriverExt // UI automation clients for iOS and Android, key is udid/serial
caseTimeoutTimer *time.Timer // case timeout timer caseTimeoutTimer *time.Timer // case timeout timer
interruptSignal chan os.Signal // interrupt signal channel
} }
// SetClientTransport configures transport of http client for high concurrency load testing // SetClientTransport configures transport of http client for high concurrency load testing
@@ -520,7 +527,11 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
for _, step := range r.caseRunner.testCase.TestSteps { for _, step := range r.caseRunner.testCase.TestSteps {
select { select {
case <-r.caseRunner.hrpRunner.caseTimeoutTimer.C: case <-r.caseRunner.hrpRunner.caseTimeoutTimer.C:
log.Warn().Msg("timeout in session runner")
return errors.Wrap(code.TimeoutError, "session runner timeout") return errors.Wrap(code.TimeoutError, "session runner timeout")
case <-r.caseRunner.hrpRunner.interruptSignal:
log.Warn().Msg("interrupted in session runner")
return errors.Wrap(code.InterruptError, "session runner interrupted")
default: default:
// TODO: parse step struct // TODO: parse step struct
// parse step name // parse step name
@@ -579,6 +590,11 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
Bool("success", false). Bool("success", false).
Msg("run step end") Msg("run step end")
// interrupted or timeout, abort running
if errors.Is(err, code.InterruptError) || errors.Is(err, code.TimeoutError) {
return err
}
// check if failfast // check if failfast
if r.caseRunner.hrpRunner.failfast { if r.caseRunner.hrpRunner.failfast {
return errors.Wrap(err, "abort running due to failfast setting") return errors.Wrap(err, "abort running due to failfast setting")
+19 -10
View File
@@ -629,18 +629,27 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err
// run actions // run actions
for _, action := range actions { for _, action := range actions {
if action.Params, err = s.caseRunner.parser.Parse(action.Params, stepVariables); err != nil { select {
if !code.IsErrorPredefined(err) { case <-s.caseRunner.hrpRunner.caseTimeoutTimer.C:
err = errors.Wrap(code.ParseError, log.Warn().Msg("timeout in mobile UI runner")
fmt.Sprintf("parse action params failed: %v", err)) return stepResult, errors.Wrap(code.TimeoutError, "mobile UI runner timeout")
case <-s.caseRunner.hrpRunner.interruptSignal:
log.Warn().Msg("interrupted in mobile UI runner")
return stepResult, errors.Wrap(code.InterruptError, "mobile UI runner interrupted")
default:
if action.Params, err = s.caseRunner.parser.Parse(action.Params, stepVariables); err != nil {
if !code.IsErrorPredefined(err) {
err = errors.Wrap(code.ParseError,
fmt.Sprintf("parse action params failed: %v", err))
}
return stepResult, err
} }
return stepResult, err if err := uiDriver.DoAction(action); err != nil {
} if !code.IsErrorPredefined(err) {
if err := uiDriver.DoAction(action); err != nil { err = errors.Wrap(code.MobileUIDriverError, err.Error())
if !code.IsErrorPredefined(err) { }
err = errors.Wrap(code.MobileUIDriverError, err.Error()) return stepResult, err
} }
return stepResult, err
} }
} }