From 5458dc27c8c74cfcfe9219fd52491ccb9bddde01 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Tue, 11 Apr 2023 22:03:14 +0800 Subject: [PATCH] feat: SleepRandom add weight argument to specify the probability of the time range --- examples/uitest/demo_feed_random_slide.json | 37 ++++++++-- .../uitest/demo_feed_random_slide_test.go | 17 +++-- hrp/pkg/uixt/ext.go | 71 +++++++++++++++---- hrp/step_mobile_ui.go | 8 ++- 4 files changed, 104 insertions(+), 29 deletions(-) diff --git a/examples/uitest/demo_feed_random_slide.json b/examples/uitest/demo_feed_random_slide.json index 86c62947..5a89c1cc 100644 --- a/examples/uitest/demo_feed_random_slide.json +++ b/examples/uitest/demo_feed_random_slide.json @@ -43,7 +43,7 @@ } }, { - "name": "滑动 Feed 35 次,随机间隔 0-20s", + "name": "滑动 Feed 3 次,随机间隔 0-5s", "android": { "actions": [ { @@ -54,15 +54,15 @@ "method": "sleep_random", "params": [ 0, - 20 + 5 ] } ] }, - "loops": 35 + "loops": 3 }, { - "name": "滑动 Feed 15 次,随机间隔 15-50s", + "name": "滑动 Feed 1 次,随机间隔 5-10s", "android": { "actions": [ { @@ -72,13 +72,36 @@ { "method": "sleep_random", "params": [ - 15, - 50 + 5, + 10 ] } ] }, - "loops": 15 + "loops": 1 + }, + { + "name": "滑动 Feed 10 次,70% 随机间隔 0-5s,30% 随机间隔 5-10s", + "android": { + "actions": [ + { + "method": "swipe", + "params": "up" + }, + { + "method": "sleep_random", + "params": [ + 0, + 5, + 0.7, + 5, + 10, + 0.3 + ] + } + ] + }, + "loops": 10 } ] } diff --git a/examples/uitest/demo_feed_random_slide_test.go b/examples/uitest/demo_feed_random_slide_test.go index cc7c5d95..ad892b87 100644 --- a/examples/uitest/demo_feed_random_slide_test.go +++ b/examples/uitest/demo_feed_random_slide_test.go @@ -25,16 +25,21 @@ func TestAndroidDouyinFeedTest(t *testing.T) { hrp.NewStep("处理青少年弹窗"). Android(). TapByOCR("我知道了", uixt.WithIgnoreNotFoundError(true)), - hrp.NewStep("滑动 Feed 35 次,随机间隔 0-20s"). - Loop(35). + hrp.NewStep("滑动 Feed 3 次,随机间隔 0-5s"). + Loop(3). Android(). SwipeUp(). - SleepRandom(0, 20), - hrp.NewStep("滑动 Feed 15 次,随机间隔 15-50s"). - Loop(15). + SleepRandom(0, 5), + hrp.NewStep("滑动 Feed 1 次,随机间隔 5-10s"). + Loop(1). Android(). SwipeUp(). - SleepRandom(15, 50), + SleepRandom(5, 10), + hrp.NewStep("滑动 Feed 10 次,70% 随机间隔 0-5s,30% 随机间隔 5-10s"). + Loop(10). + Android(). + SwipeUp(). + SleepRandom(0, 5, 0.7, 5, 10, 0.3), }, } diff --git a/hrp/pkg/uixt/ext.go b/hrp/pkg/uixt/ext.go index ddc67bbe..5bfe9e09 100644 --- a/hrp/pkg/uixt/ext.go +++ b/hrp/pkg/uixt/ext.go @@ -348,6 +348,19 @@ func (dExt *DriverExt) IsImageExist(text string) bool { 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 { 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) case CtlSleepRandom: - if params, ok := action.Params.([]interface{}); ok && len(params) == 2 { - var a, b float64 - if v, ok := params[0].(float64); ok { - a = v - } else if v, ok := params[0].(int64); ok { - a = float64(v) + params, ok := action.Params.([]interface{}) + if !ok { + return fmt.Errorf("invalid sleep random params: %v(%T)", action.Params, action.Params) + } + // append default weight 1 + 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 { - b = v - } else if v, ok := params[1].(int64); ok { - b = float64(v) + max, err := convertToFloat64(params[i+1]) + if err != nil { + return errors.Wrapf(err, "invalid maximum time: %v", params[i+1]) } - n := a + rand.Float64()*(b-a) - log.Info().Float64("duration", n).Msg("sleep random seconds") - time.Sleep(time.Duration(n*1000) * time.Millisecond) + weight, err := convertToFloat64(params[i+2]) + if err != nil { + 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 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: // take snapshot log.Info().Msg("take snapshot for current screen") diff --git a/hrp/step_mobile_ui.go b/hrp/step_mobile_ui.go index 16dc290b..a193f0b8 100644 --- a/hrp/step_mobile_ui.go +++ b/hrp/step_mobile_ui.go @@ -281,10 +281,14 @@ func (s *StepMobile) Sleep(n float64) *StepMobile { 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{ Method: uixt.CtlSleepRandom, - Params: []float64{a, b}, + Params: params, }) return &StepMobile{step: s.step} }