Merge pull request #1582 from httprunner/random_swipe

feat: random swipe with weight for multiple time ranges
This commit is contained in:
debugtalk
2023-04-12 10:25:07 +08:00
committed by GitHub
6 changed files with 115 additions and 30 deletions

View File

@@ -1,5 +1,15 @@
# Release History # Release History
## v4.3.3 (2023-04-11)
**go version**
- feat: add `sleep_random` to sleep random seconds, with weight for multiple time ranges
- feat: input text with adb
- fix: adb driver for TapFloat
- fix: stop logcat only when enabled
- fix: do not fail case when kill logcat error
## v4.3.2 (2022-12-26) ## v4.3.2 (2022-12-26)
**go version** **go version**

View File

@@ -43,7 +43,7 @@
} }
}, },
{ {
"name": "滑动 Feed 35 次,随机间隔 0-20s", "name": "滑动 Feed 3 次,随机间隔 0-5s",
"android": { "android": {
"actions": [ "actions": [
{ {
@@ -54,15 +54,15 @@
"method": "sleep_random", "method": "sleep_random",
"params": [ "params": [
0, 0,
20 5
] ]
} }
] ]
}, },
"loops": 35 "loops": 3
}, },
{ {
"name": "滑动 Feed 15 次,随机间隔 15-50s", "name": "滑动 Feed 1 次,随机间隔 5-10s",
"android": { "android": {
"actions": [ "actions": [
{ {
@@ -72,13 +72,36 @@
{ {
"method": "sleep_random", "method": "sleep_random",
"params": [ "params": [
15, 5,
50 10
] ]
} }
] ]
}, },
"loops": 15 "loops": 1
},
{
"name": "滑动 Feed 10 次70% 随机间隔 0-5s30% 随机间隔 5-10s",
"android": {
"actions": [
{
"method": "swipe",
"params": "up"
},
{
"method": "sleep_random",
"params": [
0,
5,
0.7,
5,
10,
0.3
]
}
]
},
"loops": 10
} }
] ]
} }

View File

@@ -25,16 +25,21 @@ func TestAndroidDouyinFeedTest(t *testing.T) {
hrp.NewStep("处理青少年弹窗"). hrp.NewStep("处理青少年弹窗").
Android(). Android().
TapByOCR("我知道了", uixt.WithIgnoreNotFoundError(true)), TapByOCR("我知道了", uixt.WithIgnoreNotFoundError(true)),
hrp.NewStep("滑动 Feed 35 次,随机间隔 0-20s"). hrp.NewStep("滑动 Feed 3 次,随机间隔 0-5s").
Loop(35). Loop(3).
Android(). Android().
SwipeUp(). SwipeUp().
SleepRandom(0, 20), SleepRandom(0, 5),
hrp.NewStep("滑动 Feed 15 次,随机间隔 15-50s"). hrp.NewStep("滑动 Feed 1 次,随机间隔 5-10s").
Loop(15). Loop(1).
Android(). Android().
SwipeUp(). SwipeUp().
SleepRandom(15, 50), SleepRandom(5, 10),
hrp.NewStep("滑动 Feed 10 次70% 随机间隔 0-5s30% 随机间隔 5-10s").
Loop(10).
Android().
SwipeUp().
SleepRandom(0, 5, 0.7, 5, 10, 0.3),
}, },
} }

View File

@@ -1 +1 @@
v4.3.2 v4.3.3

View File

@@ -348,6 +348,19 @@ func (dExt *DriverExt) IsImageExist(text string) bool {
var errActionNotImplemented = errors.New("UI action not implemented") var errActionNotImplemented = errors.New("UI action not implemented")
func convertToFloat64(val interface{}) (float64, error) {
switch v := val.(type) {
case float64:
return v, nil
case int:
return float64(v), nil
case int64:
return float64(v), nil
default:
return 0, fmt.Errorf("invalid type for conversion to float64: %T, value: %+v", val, val)
}
}
func (dExt *DriverExt) DoAction(action MobileAction) error { func (dExt *DriverExt) DoAction(action MobileAction) error {
log.Info().Str("method", string(action.Method)).Interface("params", action.Params).Msg("start UI action") log.Info().Str("method", string(action.Method)).Interface("params", action.Params).Msg("start UI action")
@@ -609,24 +622,54 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
} }
return fmt.Errorf("invalid sleep params: %v(%T)", action.Params, action.Params) return fmt.Errorf("invalid sleep params: %v(%T)", action.Params, action.Params)
case CtlSleepRandom: case CtlSleepRandom:
if params, ok := action.Params.([]interface{}); ok && len(params) == 2 { params, ok := action.Params.([]interface{})
var a, b float64 if !ok {
if v, ok := params[0].(float64); ok { return fmt.Errorf("invalid sleep random params: %v(%T)", action.Params, action.Params)
a = v }
} else if v, ok := params[0].(int64); ok { // append default weight 1
a = float64(v) if len(params) == 2 {
params = append(params, 1.0)
}
var sections []struct {
min, max, weight float64
}
totalProb := 0.0
for i := 0; i+3 <= len(params); i += 3 {
min, err := convertToFloat64(params[i])
if err != nil {
return errors.Wrapf(err, "invalid minimum time: %v", params[i])
} }
if v, ok := params[1].(float64); ok { max, err := convertToFloat64(params[i+1])
b = v if err != nil {
} else if v, ok := params[1].(int64); ok { return errors.Wrapf(err, "invalid maximum time: %v", params[i+1])
b = float64(v)
} }
n := a + rand.Float64()*(b-a) weight, err := convertToFloat64(params[i+2])
log.Info().Float64("duration", n).Msg("sleep random seconds") if err != nil {
time.Sleep(time.Duration(n*1000) * time.Millisecond) return errors.Wrapf(err, "invalid weight value: %v", params[i+2])
}
totalProb += weight
sections = append(sections,
struct{ min, max, weight float64 }{min, max, weight},
)
}
if totalProb == 0 {
log.Warn().Msg("total weight is 0, skip sleep")
return nil return nil
} }
return fmt.Errorf("invalid sleep random params: %v(%T)", action.Params, action.Params)
r := rand.Float64()
accProb := 0.0
for _, s := range sections {
accProb += s.weight / totalProb
if r < accProb {
n := s.min + rand.Float64()*(s.max-s.min)
log.Info().Float64("duration", n).Msg("sleep random seconds")
time.Sleep(time.Duration(n*1000) * time.Millisecond)
return nil
}
}
case CtlScreenShot: case CtlScreenShot:
// take snapshot // take snapshot
log.Info().Msg("take snapshot for current screen") log.Info().Msg("take snapshot for current screen")

View File

@@ -281,10 +281,14 @@ func (s *StepMobile) Sleep(n float64) *StepMobile {
return &StepMobile{step: s.step} return &StepMobile{step: s.step}
} }
func (s *StepMobile) SleepRandom(a, b float64) *StepMobile { // SleepRandom specify random sleeping seconds after last action
// params have two different kinds:
// 1. [min, max] : min and max are float64 time range boudaries
// 2. [min1, max1, weight1, min2, max2, weight2, ...] : weight is the probability of the time range
func (s *StepMobile) SleepRandom(params ...float64) *StepMobile {
s.mobileStep().Actions = append(s.mobileStep().Actions, uixt.MobileAction{ s.mobileStep().Actions = append(s.mobileStep().Actions, uixt.MobileAction{
Method: uixt.CtlSleepRandom, Method: uixt.CtlSleepRandom,
Params: []float64{a, b}, Params: params,
}) })
return &StepMobile{step: s.step} return &StepMobile{step: s.step}
} }