diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 99ce8cbe..3d8a7e8b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## v4.3.4 (2023-05-31) +## v4.3.4 (2023-06-01) **go version** @@ -8,10 +8,12 @@ - feat: cache screenshot ocr texts - feat: set testcase and request timeout in seconds - feat: catch interrupt signal -- feat: add new exit code MobileUILaunchAppError/InterruptError/TimeoutError/MobileUIActivityNotMatchError/MobileUIPopupError +- feat: add new exit code MobileUILaunchAppError/InterruptError/TimeoutError/MobileUIActivityNotMatchError/MobileUIPopupError/LoopActionNotFoundError - feat: find text with regex - feat: add UI ocr tags to summary - feat: check android device offline when running shell failed +- feat: print hrp runner exit code when running finished +- feat: add screen resolution and step start time in summary - refactor: replace OCR APIs with image APIs - refactor: FindText(s) returns OCRText(s) - refactor: merge ActionOption with DataOption diff --git a/hrp/internal/code/code.go b/hrp/internal/code/code.go index 7c633649..3e9d74c1 100644 --- a/hrp/internal/code/code.go +++ b/hrp/internal/code/code.go @@ -80,11 +80,12 @@ var ( // OCR related: [80, 90) var ( - OCREnvMissedError = errors.New("OCR env missed error") // 80 - OCRRequestError = errors.New("OCR prepare request error") // 81 - OCRServiceConnectionError = errors.New("OCR service connect error") // 82 - OCRResponseError = errors.New("OCR parse response error") // 83 - OCRTextNotFoundError = errors.New("OCR text not found") // 84 + OCREnvMissedError = errors.New("OCR env missed error") // 80 + OCRRequestError = errors.New("OCR prepare request error") // 81 + OCRServiceConnectionError = errors.New("OCR service connect error") // 82 + OCRResponseError = errors.New("OCR parse response error") // 83 + OCRTextNotFoundError = errors.New("OCR text not found") // 84 + LoopActionNotFoundError = errors.New("loop action not found error") // 85 ) // CV related: [90, 100) @@ -146,6 +147,7 @@ var errorsMap = map[error]int{ OCRServiceConnectionError: 82, OCRResponseError: 83, OCRTextNotFoundError: 84, + LoopActionNotFoundError: 85, } func IsErrorPredefined(err error) bool { diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index bd4c8f53..d3a0da3a 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.3.4 \ No newline at end of file +v4.3.4-beta-2306012121 \ No newline at end of file diff --git a/hrp/pkg/uixt/android_adb_driver.go b/hrp/pkg/uixt/android_adb_driver.go index 650aa9b8..0ac9b3b2 100644 --- a/hrp/pkg/uixt/android_adb_driver.go +++ b/hrp/pkg/uixt/android_adb_driver.go @@ -57,17 +57,29 @@ func (ad *adbDriver) BatteryInfo() (batteryInfo BatteryInfo, err error) { func (ad *adbDriver) WindowSize() (size Size, err error) { // adb shell wm size - resp, err := ad.adbClient.RunShellCommand("wm", "size") + output, err := ad.adbClient.RunShellCommand("wm", "size") if err != nil { - return size, errors.Wrap(err, "get window size failed") + return size, errors.Wrap(err, "get window size failed with adb") } + // output may contain both Physical and Override size // Physical size: 1080x2340 - s := strings.Trim(strings.Split(resp, ": ")[1], "\n") - ss := strings.Split(s, "x") - width, _ := strconv.Atoi(ss[0]) - height, _ := strconv.Atoi(ss[1]) - size = Size{Width: width, Height: height} + // Override size: 1080x2220 + var resolution string + sizeList := strings.Split(output, "\n") + log.Info().Msgf("window size: %v", sizeList) + for _, size := range sizeList { + if strings.Contains(size, "Physical") { + resolution = strings.Split(size, ": ")[1] + // 1080x2340 + ss := strings.Split(resolution, "x") + width, _ := strconv.Atoi(ss[0]) + height, _ := strconv.Atoi(ss[1]) + return Size{Width: width, Height: height}, nil + } + } + + err = errors.New("physical window size not found by adb") return } diff --git a/hrp/pkg/uixt/ext.go b/hrp/pkg/uixt/ext.go index 4b38d701..782e4ec4 100644 --- a/hrp/pkg/uixt/ext.go +++ b/hrp/pkg/uixt/ext.go @@ -210,6 +210,11 @@ func (dExt *DriverExt) GetStepCacheData() map[string]interface{} { cacheData["screenshots"] = dExt.cacheStepData.screenShots cacheData["screenshots_urls"] = dExt.cacheStepData.screenShotsUrls + screenSize, err := dExt.Driver.WindowSize() + if err != nil { + log.Warn().Err(err).Msg("get screen resolution failed") + screenSize = Size{} + } screenResults := make(map[string]interface{}) for imagePath, screenResult := range dExt.cacheStepData.screenResults { o, _ := json.Marshal(screenResult.Texts) @@ -217,6 +222,10 @@ func (dExt *DriverExt) GetStepCacheData() map[string]interface{} { "tags": screenResult.Tags, "texts": string(o), "popularity": screenResult.Popularity, + "resolution": map[string]int{ + "width": screenSize.Width, + "height": screenSize.Height, + }, } screenResults[imagePath] = data diff --git a/hrp/pkg/uixt/swipe.go b/hrp/pkg/uixt/swipe.go index cf880ecf..abcdc89b 100644 --- a/hrp/pkg/uixt/swipe.go +++ b/hrp/pkg/uixt/swipe.go @@ -84,7 +84,7 @@ func (dExt *DriverExt) LoopUntil(findAction, findCondition, foundAction Action, time.Sleep(time.Duration(1000*interval) * time.Millisecond) } - return errors.Wrap(code.OCRTextNotFoundError, + return errors.Wrap(code.LoopActionNotFoundError, fmt.Sprintf("loop %d times, match find condition failed", maxRetryTimes)) } diff --git a/hrp/pkg/uixt/video_crawler.go b/hrp/pkg/uixt/video_crawler.go index 1da4803f..b22b8aa0 100644 --- a/hrp/pkg/uixt/video_crawler.go +++ b/hrp/pkg/uixt/video_crawler.go @@ -468,9 +468,12 @@ var popups = [][]string{ {".*青少年.*", "我知道了"}, // 青少年弹窗 {".*个人信息保护.*", "同意"}, {".*更新.*", "以后再说"}, - {".*定位.*", ".*允许.*"}, + {".*定位.*", "仅.*允许"}, {".*拍照.*", "仅.*允许"}, {".*录音.*", "仅.*允许"}, + {".*位置.*", "仅.*允许"}, + {".*权限.*", "仅.*允许"}, + {".*允许.*", "仅.*允许"}, {"管理使用时间", ".*忽略.*"}, } diff --git a/hrp/runner.go b/hrp/runner.go index b30ca69e..0cd212bb 100644 --- a/hrp/runner.go +++ b/hrp/runner.go @@ -191,7 +191,7 @@ func (r *HRPRunner) GenHTMLReport() *HRPRunner { } // Run starts to execute one or multiple testcases. -func (r *HRPRunner) Run(testcases ...ITestCase) error { +func (r *HRPRunner) Run(testcases ...ITestCase) (err error) { log.Info().Str("hrp_version", version.VERSION).Msg("start running") event := sdk.EventTracking{ Category: "RunAPITests", @@ -204,6 +204,11 @@ func (r *HRPRunner) Run(testcases ...ITestCase) error { // record execution data to summary s := newOutSummary() + defer func() { + exitCode := code.GetErrorCode(err) + log.Info().Int("code", exitCode).Msg("hrp runner exit code") + }() + // load all testcases testCases, err := LoadTestCases(testcases...) if err != nil { @@ -221,7 +226,6 @@ func (r *HRPRunner) Run(testcases ...ITestCase) error { }) }() - var runErr error // run testcase one by one for _, testcase := range testCases { // each testcase has its own case runner @@ -245,20 +249,20 @@ func (r *HRPRunner) Run(testcases ...ITestCase) error { err1 := sessionRunner.Start(it.Next()) if err1 != nil { log.Error().Err(err1).Msg("[Run] run testcase failed") - runErr = err1 + err = err1 } caseSummary, err2 := sessionRunner.GetSummary() s.appendCaseSummary(caseSummary) if err2 != nil { log.Error().Err(err2).Msg("[Run] get summary failed") if err1 != nil { - runErr = errors.Wrap(err1, err2.Error()) + err = errors.Wrap(err1, err2.Error()) } else { - runErr = err2 + err = err2 } } - if runErr != nil && r.failfast { + if err != nil && r.failfast { break } } @@ -267,21 +271,19 @@ func (r *HRPRunner) Run(testcases ...ITestCase) error { // save summary if r.saveTests { - err := s.genSummary() - if err != nil { + if err := s.genSummary(); err != nil { return err } } // generate HTML report if r.genHTMLReport { - err := s.genHTMLReport() - if err != nil { + if err := s.genHTMLReport(); err != nil { return err } } - return runErr + return err } // NewCaseRunner creates a new case runner for testcase. @@ -564,8 +566,10 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error { } // run step + stepStartTime := time.Now().Unix() stepResult, err = step.Run(r) stepResult.Name = stepName + loopIndex + stepResult.StartTime = stepStartTime r.updateSummary(stepResult) } diff --git a/hrp/step.go b/hrp/step.go index 4776e311..88641370 100644 --- a/hrp/step.go +++ b/hrp/step.go @@ -16,6 +16,7 @@ const ( type StepResult struct { Name string `json:"name" yaml:"name"` // step name + StartTime int64 `json:"start_time" yaml:"time"` // step start time StepType StepType `json:"step_type" yaml:"step_type"` // step type, testcase/request/transaction/rendezvous Success bool `json:"success" yaml:"success"` // step execution result Elapsed int64 `json:"elapsed_ms" yaml:"elapsed_ms"` // step execution time in millisecond(ms)