This is an automated email from the ASF dual-hosted git repository.

huajianlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 5d0216d6706 [chore](test) add log to find bug of unstable test (#37982)
5d0216d6706 is described below

commit 5d0216d67061e50ba41a4225951b54a46f77ba19
Author: 924060929 <[email protected]>
AuthorDate: Thu Jul 18 17:20:59 2024 +0800

    [chore](test) add log to find bug of unstable test (#37982)
    
    add log to find bug of unstable test
    support profile action to fetch profile
---
 .../doris/regression/action/HttpCliAction.groovy   |  38 ++++++-
 .../doris/regression/action/ProfileAction.groovy   | 122 +++++++++++++++++++++
 .../org/apache/doris/regression/suite/Suite.groovy |   5 +
 .../framework/src/main/groovy/suite.gdsl           |   4 +-
 .../suites/query_p0/cache/sql_cache.groovy         |  86 ++++++++++-----
 5 files changed, 223 insertions(+), 32 deletions(-)

diff --git 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/HttpCliAction.groovy
 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/HttpCliAction.groovy
index 8aaf7ef4883..366905b31f5 100644
--- 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/HttpCliAction.groovy
+++ 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/HttpCliAction.groovy
@@ -17,6 +17,7 @@
 
 package org.apache.doris.regression.action
 
+import com.google.common.collect.Maps
 import groovy.transform.stc.ClosureParams
 import groovy.transform.stc.FromString
 import groovy.util.logging.Slf4j
@@ -37,7 +38,9 @@ class HttpCliAction implements SuiteAction {
     private String body
     private String result
     private String op
+    private Map<String, String> headers = Maps.newLinkedHashMap()
     private Closure check
+    private boolean printResponse = true
     SuiteContext context
 
     HttpCliAction(SuiteContext context) {
@@ -60,6 +63,17 @@ class HttpCliAction implements SuiteAction {
         this.uri = uri
     }
 
+    void header(String key, String value) {
+        this.headers.put(key, value)
+    }
+
+    void basicAuthorization(String user, String password) {
+        String credentials = user + ":" + (password.is(null) ? "" : password)
+        String encodedCredentials = 
Base64.getEncoder().encodeToString(credentials.getBytes())
+        String headerValue = "Basic " + encodedCredentials;
+        headers.put("Authorization", headerValue)
+    }
+
     void body(Closure<String> bodySupplier) {
         this.body = bodySupplier.call()
     }
@@ -80,6 +94,10 @@ class HttpCliAction implements SuiteAction {
         this.result = result
     }
 
+    void printResponse(boolean printResponse) {
+        this.printResponse = printResponse
+    }
+
     @Override
     void run() {
         try {
@@ -91,17 +109,25 @@ class HttpCliAction implements SuiteAction {
 
                 if (op == "get") {
                     HttpGet httpGet = new HttpGet(uri)
+                    for (final def header in headers.entrySet()) {
+                        httpGet.setHeader(header.getKey(), header.getValue())
+                    }
 
                     client.execute(httpGet).withCloseable { resp ->
                         resp.withCloseable {
                             String respJson = 
EntityUtils.toString(resp.getEntity())
                             def respCode = resp.getStatusLine().getStatusCode()
-                            log.info("respCode: ${respCode}, respJson: 
${respJson}")
+                            if (printResponse) {
+                                log.info("respCode: ${respCode}, respJson: 
${respJson}")
+                            }
                             return new ActionResult(respCode, respJson)
                         }
                     }
                 } else {
                     HttpPost httpPost = new HttpPost(uri)
+                    for (final def header in headers.entrySet()) {
+                        httpPost.setHeader(header.getKey(), header.getValue())
+                    }
                     StringEntity requestEntity = new StringEntity(
                             body,
                             ContentType.APPLICATION_JSON);
@@ -111,14 +137,18 @@ class HttpCliAction implements SuiteAction {
                         resp.withCloseable {
                             String respJson = 
EntityUtils.toString(resp.getEntity())
                             def respCode = resp.getStatusLine().getStatusCode()
-                            log.info("respCode: ${respCode}, respJson: 
${respJson}")
+                            if (printResponse) {
+                                log.info("respCode: ${respCode}, respJson: 
${respJson}")
+                            }
                             return new ActionResult(respCode, respJson)
                         }
                     }
                 }
             }
-            log.info("result:${result}".toString())
-            log.info("this.result:${this.result}".toString())
+            if (printResponse) {
+                log.info("result:${result}".toString())
+                log.info("this.result:${this.result}".toString())
+            }
             if (check != null) {
                 check.call(result.respCode, result.body)
             } else {
diff --git 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/ProfileAction.groovy
 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/ProfileAction.groovy
new file mode 100644
index 00000000000..b019e6c24aa
--- /dev/null
+++ 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/ProfileAction.groovy
@@ -0,0 +1,122 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.regression.action
+
+import groovy.json.JsonSlurper
+import groovy.transform.stc.ClosureParams
+import groovy.transform.stc.FromString
+import groovy.util.logging.Slf4j
+import org.apache.doris.regression.suite.SuiteContext
+import org.apache.doris.regression.util.JdbcUtils
+
+@Slf4j
+class ProfileAction implements SuiteAction {
+    private String tag
+    private Runnable runCallback
+    private Closure<String> check
+    private SuiteContext context
+
+    ProfileAction(SuiteContext context, String tag) {
+        this.context = context
+        this.tag = Objects.requireNonNull(tag, "tag can not be null")
+    }
+
+    void run(@ClosureParams(value = FromString, options = []) Runnable run) {
+        runCallback = run
+    }
+
+    void check(
+        @ClosureParams(value = FromString, options = ["String, Throwable"]) 
Closure check) {
+        this.check = check
+    }
+
+    @Override
+    void run() {
+        if (runCallback.is(null)) {
+            throw new IllegalStateException("Missing tag")
+        }
+        if (check.is(null)) {
+            throw new IllegalStateException("Missing check")
+        }
+        def conn = context.getConnection()
+        try {
+            JdbcUtils.executeToList(conn, "set enable_profile=true")
+
+            Throwable exception = null
+            try {
+                this.runCallback.run()
+            } catch (Throwable t) {
+                exception = t
+            }
+
+            def httpCli = new HttpCliAction(context)
+            httpCli.endpoint(context.config.feHttpAddress)
+            httpCli.uri("/rest/v1/query_profile")
+            httpCli.op("get")
+            httpCli.printResponse(false)
+
+            if (context.config.fetchRunMode()) {
+                httpCli.basicAuthorization(context.config.feCloudHttpUser, 
context.config.feCloudHttpPassword)
+            } else {
+                httpCli.basicAuthorization(context.config.feHttpUser, 
context.config.feHttpPassword)
+            }
+            httpCli.check { code, body ->
+                if (code != 200) {
+                    throw new IllegalStateException("Get profile list failed, 
code: ${code}, body:\n${body}")
+                }
+
+                def jsonSlurper = new JsonSlurper()
+                List profileData = jsonSlurper.parseText(body).data.rows
+                for (final def profileItem in profileData) {
+                    if (profileItem["Sql Statement"].toString().contains(tag)) 
{
+                        def profileId = profileItem["Profile ID"].toString()
+
+                        def profileCli = new HttpCliAction(context)
+                        profileCli.endpoint(context.config.feHttpAddress)
+                        profileCli.uri("/rest/v1/query_profile/${profileId}")
+                        profileCli.op("get")
+                        profileCli.printResponse(false)
+
+                        if (context.config.fetchRunMode()) {
+                            
profileCli.basicAuthorization(context.config.feCloudHttpUser, 
context.config.feCloudHttpPassword)
+                        } else {
+                            
profileCli.basicAuthorization(context.config.feHttpUser, 
context.config.feHttpPassword)
+                        }
+                        profileCli.check { profileCode, profileResp ->
+                            if (profileCode != 200) {
+                                throw new IllegalStateException("Get profile 
failed, url: ${"/rest/v1/query_profile/${profileId}"}, code: ${profileCode}, 
body:\n${profileResp}")
+                            }
+
+                            def jsonSlurper2 = new JsonSlurper()
+                            def profileText = 
jsonSlurper2.parseText(profileResp).data
+                            profileText = profileText.replace("&nbsp;", " ")
+                            profileText = profileText.replace("</br>", "\n")
+                            this.check(profileText, exception)
+                        }
+                        profileCli.run()
+
+                        break
+                    }
+                }
+            }
+            httpCli.run()
+        } finally {
+            JdbcUtils.executeToList(conn, "set enable_profile=false")
+        }
+    }
+}
diff --git 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy
 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy
index 50d430b6c6d..1685b1e4d46 100644
--- 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy
+++ 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy
@@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableList
 import org.apache.commons.lang3.ObjectUtils
 import org.apache.doris.regression.Config
 import org.apache.doris.regression.action.BenchmarkAction
+import org.apache.doris.regression.action.ProfileAction
 import org.apache.doris.regression.action.WaitForAction
 import org.apache.doris.regression.util.DataUtils
 import org.apache.doris.regression.util.OutputUtils
@@ -620,6 +621,10 @@ class Suite implements GroovyInterceptable {
         }
     }
 
+    void profile(String tag, Closure<String> actionSupplier) {
+        runAction(new ProfileAction(context, tag), actionSupplier)
+    }
+
     void createMV(String sql) {
         (new CreateMVAction(context, sql)).run()
     }
diff --git a/regression-test/framework/src/main/groovy/suite.gdsl 
b/regression-test/framework/src/main/groovy/suite.gdsl
index aec43ab51a1..bf8da34c2c6 100644
--- a/regression-test/framework/src/main/groovy/suite.gdsl
+++ b/regression-test/framework/src/main/groovy/suite.gdsl
@@ -50,6 +50,7 @@ bindAction("streamLoad", 
"org.apache.doris.regression.action.StreamLoadAction")
 bindAction("httpTest", "org.apache.doris.regression.action.HttpCliAction")
 bindAction("benchmark", "org.apache.doris.regression.action.BenchmarkAction")
 bindAction("waitForSchemaChangeDone", 
"org.apache.doris.regression.action.WaitForAction")
+bindAction("profile", "org.apache.doris.regression.action.ProfileAction")
 
 // bind qt_xxx and order_qt_xxx methods
 contributor([suiteContext]) {
@@ -81,7 +82,8 @@ contributor([suiteContext]) {
                         !enclosingCall("explain") &&
                         !enclosingCall("streamLoad") &&
                         !enclosingCall("httpTest") &&
-                        !enclosingCall("waitForSchemaChangeDone"))) {
+                        !enclosingCall("waitForSchemaChangeDone") &&
+                        !enclosingCall("profile"))) {
             // bind other suite method and field
             def suiteClass = findClass(suiteClassName)
             delegatesTo(suiteClass)
diff --git a/regression-test/suites/query_p0/cache/sql_cache.groovy 
b/regression-test/suites/query_p0/cache/sql_cache.groovy
index c38c0800740..48f585f3bd9 100644
--- a/regression-test/suites/query_p0/cache/sql_cache.groovy
+++ b/regression-test/suites/query_p0/cache/sql_cache.groovy
@@ -19,12 +19,20 @@
 // 
/testing/trino-product-tests/src/main/resources/sql-tests/testcases/aggregate
 // and modified by Doris.
 
+import java.util.stream.Collectors
+
 suite("sql_cache") {
     // TODO: regression-test does not support check query profile,
     // so this suite does not check whether cache is used, :)
     def tableName = "test_sql_cache"
     sql  "ADMIN SET FRONTEND CONFIG ('cache_last_version_interval_second' = 
'0')"
 
+    def variables = sql "show variables"
+    def variableString = variables.stream()
+            .map { it.toString() }
+            .collect(Collectors.joining("\n"))
+    logger.info("Variables:\n${variableString}")
+
     sql """ DROP TABLE IF EXISTS ${tableName} """
     sql """
             CREATE TABLE IF NOT EXISTS ${tableName} (
@@ -183,33 +191,57 @@ suite("sql_cache") {
     sql 'set default_order_by_limit = 2'
     sql 'set sql_select_limit = 1'
 
-    qt_sql_cache8 """
-                    select
-                        k1,
-                        sum(k2) as total_pv 
-                    from
-                        ${tableName} 
-                    where
-                        k1 between '2022-05-28' and '2022-06-30' 
-                    group by
-                        k1 
-                    order by
-                        k1;
-                """
-    
-    qt_sql_cache9 """
-                    select
-                        k1,
-                        sum(k2) as total_pv 
-                    from
-                        ${tableName} 
-                    where
-                        k1 between '2022-05-28' and '2022-06-30' 
-                    group by
-                        k1 
-                    order by
-                        k1;
-                """
+    profile("sql_cache8") {
+        run {
+            qt_sql_cache8 """
+                -- sql_cache8
+                select
+                    k1,
+                    sum(k2) as total_pv 
+                from
+                    ${tableName} 
+                where
+                    k1 between '2022-05-28' and '2022-06-30' 
+                group by
+                    k1 
+                order by
+                    k1;
+            """
+        }
+
+        check { profileString, exception ->
+            if (!exception.is(null)) {
+                logger.error("Profile failed, profile 
result:\n${profileString}", exception)
+                throw exception
+            }
+        }
+    }
+
+    profile("sql_cache9") {
+        run {
+            qt_sql_cache9 """
+                -- sql_cache9
+                select
+                    k1,
+                    sum(k2) as total_pv 
+                from
+                    ${tableName} 
+                where
+                    k1 between '2022-05-28' and '2022-06-30' 
+                group by
+                    k1 
+                order by
+                    k1;
+            """
+        }
+
+        check { profileString, exception ->
+            if (!exception.is(null)) {
+                logger.error("Profile failed, profile 
result:\n${profileString}", exception)
+                throw exception
+            }
+        }
+    }
 
     sql  "ADMIN SET FRONTEND CONFIG ('cache_last_version_interval_second' = 
'10')"
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to