Merge branch 'master' into v1.4
This commit is contained in:
commit
7c2d0dd8af
|
@ -13,12 +13,10 @@ import io.metersphere.notice.service.MailService;
|
||||||
import io.metersphere.notice.service.NoticeService;
|
import io.metersphere.notice.service.NoticeService;
|
||||||
import io.metersphere.track.service.TestPlanTestCaseService;
|
import io.metersphere.track.service.TestPlanTestCaseService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.http.protocol.HTTP;
|
|
||||||
import org.apache.jmeter.assertions.AssertionResult;
|
import org.apache.jmeter.assertions.AssertionResult;
|
||||||
import org.apache.jmeter.samplers.SampleResult;
|
import org.apache.jmeter.samplers.SampleResult;
|
||||||
import org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient;
|
import org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient;
|
||||||
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
|
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
|
||||||
import org.pac4j.core.context.HttpConstants;
|
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -41,6 +39,12 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
|
|
||||||
private APIReportService apiReportService;
|
private APIReportService apiReportService;
|
||||||
|
|
||||||
|
private TestPlanTestCaseService testPlanTestCaseService;
|
||||||
|
|
||||||
|
private NoticeService noticeService;
|
||||||
|
|
||||||
|
private MailService mailService;
|
||||||
|
|
||||||
public String runMode = ApiRunMode.RUN.name();
|
public String runMode = ApiRunMode.RUN.name();
|
||||||
|
|
||||||
// 测试ID
|
// 测试ID
|
||||||
|
@ -60,6 +64,18 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
if (apiReportService == null) {
|
if (apiReportService == null) {
|
||||||
LogUtil.error("apiReportService is required");
|
LogUtil.error("apiReportService is required");
|
||||||
}
|
}
|
||||||
|
testPlanTestCaseService = CommonBeanFactory.getBean(TestPlanTestCaseService.class);
|
||||||
|
if (testPlanTestCaseService == null) {
|
||||||
|
LogUtil.error("testPlanTestCaseService is required");
|
||||||
|
}
|
||||||
|
noticeService = CommonBeanFactory.getBean(NoticeService.class);
|
||||||
|
if (noticeService == null) {
|
||||||
|
LogUtil.error("noticeService is required");
|
||||||
|
}
|
||||||
|
mailService = CommonBeanFactory.getBean(MailService.class);
|
||||||
|
if (mailService == null) {
|
||||||
|
LogUtil.error("mailService is required");
|
||||||
|
}
|
||||||
super.setupTest(context);
|
super.setupTest(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +128,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
|
|
||||||
testResult.getScenarios().addAll(scenarios.values());
|
testResult.getScenarios().addAll(scenarios.values());
|
||||||
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
|
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
|
||||||
ApiTestReport report = null;
|
ApiTestReport report;
|
||||||
if (StringUtils.equals(this.runMode, ApiRunMode.DEBUG.name())) {
|
if (StringUtils.equals(this.runMode, ApiRunMode.DEBUG.name())) {
|
||||||
report = apiReportService.get(debugReportId);
|
report = apiReportService.get(debugReportId);
|
||||||
} else {
|
} else {
|
||||||
|
@ -123,7 +139,6 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
queue.clear();
|
queue.clear();
|
||||||
super.teardownTest(context);
|
super.teardownTest(context);
|
||||||
|
|
||||||
TestPlanTestCaseService testPlanTestCaseService = CommonBeanFactory.getBean(TestPlanTestCaseService.class);
|
|
||||||
List<String> ids = testPlanTestCaseService.getTestPlanTestCaseIds(testResult.getTestId());
|
List<String> ids = testPlanTestCaseService.getTestPlanTestCaseIds(testResult.getTestId());
|
||||||
if (ids.size() > 0) {
|
if (ids.size() > 0) {
|
||||||
try {
|
try {
|
||||||
|
@ -137,10 +152,8 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
NoticeService noticeService = CommonBeanFactory.getBean(NoticeService.class);
|
|
||||||
try {
|
try {
|
||||||
List<NoticeDetail> noticeList = noticeService.queryNotice(testResult.getTestId());
|
List<NoticeDetail> noticeList = noticeService.queryNotice(testResult.getTestId());
|
||||||
MailService mailService = CommonBeanFactory.getBean(MailService.class);
|
|
||||||
mailService.sendApiNotification(report, noticeList);
|
mailService.sendApiNotification(report, noticeList);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error(e);
|
LogUtil.error(e);
|
||||||
|
|
|
@ -30,6 +30,8 @@ public class JMeterService {
|
||||||
public void run(String testId, String debugReportId, InputStream is) {
|
public void run(String testId, String debugReportId, InputStream is) {
|
||||||
String JMETER_HOME = getJmeterHome();
|
String JMETER_HOME = getJmeterHome();
|
||||||
|
|
||||||
|
// 将当前类加载器设置为 loader ,解决由系统类加载器加载的 JMeter 无法动态加载 jar 包问题
|
||||||
|
// 同时隔离在 beanshell 中访问由系统类加载器加载的其他类
|
||||||
NewDriver.setContextClassLoader();
|
NewDriver.setContextClassLoader();
|
||||||
|
|
||||||
String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties";
|
String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties";
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
|
|
||||||
<select id="getTestCaseByNotInReview" resultType="io.metersphere.base.domain.TestCase">
|
<select id="getTestCaseByNotInReview" resultType="io.metersphere.base.domain.TestCase">
|
||||||
select test_case.id, test_case.name, test_case.priority, test_case.type, test_case.review_status from test_case as test_case
|
select test_case.id, test_case.name, test_case.priority, test_case.type, test_case.review_status from test_case as test_case
|
||||||
left join test_case_review_test_case as T2 on test_case.id=T2.case_id
|
left join test_case_review_test_case as T2 on test_case.id=T2.case_id and T2.review_id =#{request.reviewId}
|
||||||
<where>
|
<where>
|
||||||
<if test="request.combine != null">
|
<if test="request.combine != null">
|
||||||
<include refid="combine">
|
<include refid="combine">
|
||||||
|
@ -153,7 +153,7 @@
|
||||||
|
|
||||||
<select id="getTestCaseByNotInPlan" resultType="io.metersphere.base.domain.TestCase">
|
<select id="getTestCaseByNotInPlan" resultType="io.metersphere.base.domain.TestCase">
|
||||||
select test_case.id, test_case.name, test_case.priority, test_case.type, test_case.review_status from test_case as test_case
|
select test_case.id, test_case.name, test_case.priority, test_case.type, test_case.review_status from test_case as test_case
|
||||||
left join test_plan_test_case as T2 on test_case.id=T2.case_id
|
left join test_plan_test_case as T2 on test_case.id=T2.case_id and T2.plan_id =#{request.planId}
|
||||||
<where>
|
<where>
|
||||||
<if test="request.combine != null">
|
<if test="request.combine != null">
|
||||||
<include refid="combine">
|
<include refid="combine">
|
||||||
|
|
|
@ -542,7 +542,7 @@ public class TestCaseNodeService {
|
||||||
|
|
||||||
rootPath = rootPath + rootNode.getName();
|
rootPath = rootPath + rootNode.getName();
|
||||||
|
|
||||||
if (level > 5) {
|
if (level > 8) {
|
||||||
MSException.throwException(Translator.get("node_deep_limit"));
|
MSException.throwException(Translator.get("node_deep_limit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit ee74568be0beba46da19616f5832e83f9164c688
|
Subproject commit cf6b06526324326a563d933e07118fac014a63b4
|
|
@ -71,25 +71,32 @@ public final class NewDriver {
|
||||||
|
|
||||||
// Find JMeter home dir from the initial classpath
|
// Find JMeter home dir from the initial classpath
|
||||||
String tmpDir;
|
String tmpDir;
|
||||||
StringTokenizer tok = new StringTokenizer(initiaClasspath, File.pathSeparator);
|
|
||||||
if (tok.countTokens() == 1
|
// StringTokenizer tok = new StringTokenizer(initiaClasspath, File.pathSeparator);
|
||||||
|| (tok.countTokens() == 2 // Java on Mac OS can add a second entry to the initial classpath
|
// if (tok.countTokens() == 1
|
||||||
&& OS_NAME_LC.startsWith("mac os x")// $NON-NLS-1$
|
// || (tok.countTokens() == 2 // Java on Mac OS can add a second entry to the initial classpath
|
||||||
)
|
// && OS_NAME_LC.startsWith("mac os x")// $NON-NLS-1$
|
||||||
) {
|
// )
|
||||||
File jar = new File(tok.nextToken());
|
// ) {
|
||||||
try {
|
// File jar = new File(tok.nextToken());
|
||||||
tmpDir = jar.getCanonicalFile().getParentFile().getParent();
|
// try {
|
||||||
} catch (IOException e) {
|
// tmpDir = jar.getCanonicalFile().getParentFile().getParent();
|
||||||
tmpDir = null;
|
// System.out.println(tmpDir + "111");
|
||||||
}
|
// } catch (IOException e) {
|
||||||
} else {// e.g. started from IDE with full classpath
|
// tmpDir = null;
|
||||||
|
// }
|
||||||
|
// } else {// e.g. started from IDE with full classpath
|
||||||
|
|
||||||
|
//只从 jmeter.home 加载
|
||||||
tmpDir = System.getProperty("jmeter.home","");// Allow override $NON-NLS-1$ $NON-NLS-2$
|
tmpDir = System.getProperty("jmeter.home","");// Allow override $NON-NLS-1$ $NON-NLS-2$
|
||||||
|
System.out.println(System.getProperty("jmeter.home",""));
|
||||||
|
System.out.println(tmpDir + "222");
|
||||||
if (tmpDir.length() == 0) {
|
if (tmpDir.length() == 0) {
|
||||||
File userDir = new File(System.getProperty("user.dir"));// $NON-NLS-1$
|
File userDir = new File(System.getProperty("user.dir"));// $NON-NLS-1$
|
||||||
tmpDir = userDir.getAbsoluteFile().getParent();
|
tmpDir = userDir.getAbsoluteFile().getParent();
|
||||||
|
System.out.println(tmpDir + "333");
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
JMETER_INSTALLATION_DIRECTORY=tmpDir;
|
JMETER_INSTALLATION_DIRECTORY=tmpDir;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -0,0 +1,334 @@
|
||||||
|
//
|
||||||
|
// Source code recreated from a .class file by IntelliJ IDEA
|
||||||
|
// (powered by Fernflower decompiler)
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.apache.jmeter.visualizers.backend;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
import org.apache.jmeter.config.Arguments;
|
||||||
|
import org.apache.jmeter.engine.util.NoThreadClone;
|
||||||
|
import org.apache.jmeter.samplers.Remoteable;
|
||||||
|
import org.apache.jmeter.samplers.SampleEvent;
|
||||||
|
import org.apache.jmeter.samplers.SampleListener;
|
||||||
|
import org.apache.jmeter.samplers.SampleResult;
|
||||||
|
import org.apache.jmeter.testelement.AbstractTestElement;
|
||||||
|
import org.apache.jmeter.testelement.TestStateListener;
|
||||||
|
import org.apache.jmeter.testelement.property.TestElementProperty;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
// 当前上下文类加载为 NewDriver 的类加载器,这里使用系统类加载器加载 APIBackendListenerClient
|
||||||
|
|
||||||
|
public class BackendListener extends AbstractTestElement implements Backend, Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BackendListener.class);
|
||||||
|
public static final String CLASSNAME = "classname";
|
||||||
|
public static final String QUEUE_SIZE = "QUEUE_SIZE";
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
public static final String ARGUMENTS = "arguments";
|
||||||
|
private Class<?> clientClass;
|
||||||
|
public static final String DEFAULT_QUEUE_SIZE = "5000";
|
||||||
|
private static final transient SampleResult FINAL_SAMPLE_RESULT = new SampleResult();
|
||||||
|
private static final Map<String, BackendListener.ListenerClientData> queuesByTestElementName = new ConcurrentHashMap();
|
||||||
|
private transient String myName;
|
||||||
|
private transient BackendListener.ListenerClientData listenerClientData;
|
||||||
|
|
||||||
|
public BackendListener() {
|
||||||
|
this.setArguments(new Arguments());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone() {
|
||||||
|
BackendListener clone = (BackendListener)super.clone();
|
||||||
|
clone.clientClass = this.clientClass;
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> initClass() {
|
||||||
|
String name = this.getClassname().trim();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 当前上下文类加载为 NewDriver 的类加载器,这里使用系统类加载器加载 APIBackendListenerClient
|
||||||
|
return Class.forName(name, false, this.getClass().getClassLoader());
|
||||||
|
} catch (Exception var3) {
|
||||||
|
log.error("{}\tException initialising: {}", new Object[]{this.whoAmI(), name, var3});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String whoAmI() {
|
||||||
|
return Thread.currentThread().getName() + "@" + Integer.toHexString(this.hashCode()) + "-" + this.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sampleOccurred(SampleEvent event) {
|
||||||
|
Arguments args = this.getArguments();
|
||||||
|
BackendListenerContext context = new BackendListenerContext(args);
|
||||||
|
SampleResult sr = this.listenerClientData.client.createSampleResult(context, event.getResult());
|
||||||
|
if (sr == null) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("{} => Dropping SampleResult: {}", this.getName(), event.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
if (!this.listenerClientData.queue.offer(sr)) {
|
||||||
|
this.listenerClientData.queueWaits.add(1L);
|
||||||
|
long t1 = System.nanoTime();
|
||||||
|
this.listenerClientData.queue.put(sr);
|
||||||
|
long t2 = System.nanoTime();
|
||||||
|
this.listenerClientData.queueWaitTime.add(t2 - t1);
|
||||||
|
}
|
||||||
|
} catch (Exception var9) {
|
||||||
|
log.error("sampleOccurred, failed to queue the sample", var9);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendToListener(BackendListenerClient backendListenerClient, BackendListenerContext context, List<SampleResult> sampleResults) {
|
||||||
|
if (!sampleResults.isEmpty()) {
|
||||||
|
backendListenerClient.handleSampleResults(sampleResults, context);
|
||||||
|
sampleResults.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BackendListenerClient createBackendListenerClientImpl(Class<?> clientClass) {
|
||||||
|
if (clientClass == null) {
|
||||||
|
return new BackendListener.ErrorBackendListenerClient();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return (BackendListenerClient)clientClass.getDeclaredConstructor().newInstance();
|
||||||
|
} catch (Exception var2) {
|
||||||
|
log.error("Exception creating: {}", clientClass, var2);
|
||||||
|
return new BackendListener.ErrorBackendListenerClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStarted() {
|
||||||
|
this.testStarted("local");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStarted(String host) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("{}\ttestStarted({})", this.whoAmI(), host);
|
||||||
|
}
|
||||||
|
|
||||||
|
String size = this.getQueueSize();
|
||||||
|
|
||||||
|
int queueSize;
|
||||||
|
try {
|
||||||
|
queueSize = Integer.parseInt(size);
|
||||||
|
} catch (NumberFormatException var12) {
|
||||||
|
log.warn("Invalid queue size '{}' defaulting to {}", size, "5000");
|
||||||
|
queueSize = Integer.parseInt("5000");
|
||||||
|
}
|
||||||
|
|
||||||
|
Object var4 = LOCK;
|
||||||
|
synchronized(LOCK) {
|
||||||
|
this.myName = this.getName();
|
||||||
|
this.listenerClientData = (BackendListener.ListenerClientData)queuesByTestElementName.get(this.myName);
|
||||||
|
if (this.listenerClientData == null) {
|
||||||
|
this.clientClass = this.initClass();
|
||||||
|
BackendListenerClient backendListenerClient = createBackendListenerClientImpl(this.clientClass);
|
||||||
|
BackendListenerContext context = new BackendListenerContext((Arguments)this.getArguments().clone());
|
||||||
|
this.listenerClientData = new BackendListener.ListenerClientData();
|
||||||
|
this.listenerClientData.queue = new ArrayBlockingQueue(queueSize);
|
||||||
|
this.listenerClientData.queueWaits = new LongAdder();
|
||||||
|
this.listenerClientData.queueWaitTime = new LongAdder();
|
||||||
|
this.listenerClientData.latch = new CountDownLatch(1);
|
||||||
|
this.listenerClientData.client = backendListenerClient;
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("{}: Starting worker with class: {} and queue capacity: {}", new Object[]{this.getName(), this.clientClass, this.getQueueSize()});
|
||||||
|
}
|
||||||
|
|
||||||
|
BackendListener.Worker worker = new BackendListener.Worker(backendListenerClient, (Arguments)this.getArguments().clone(), this.listenerClientData);
|
||||||
|
worker.setDaemon(true);
|
||||||
|
worker.start();
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("{}: Started worker with class: {}", this.getName(), this.clientClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
backendListenerClient.setupTest(context);
|
||||||
|
} catch (Exception var10) {
|
||||||
|
throw new IllegalStateException("Failed calling setupTest", var10);
|
||||||
|
}
|
||||||
|
|
||||||
|
queuesByTestElementName.put(this.myName, this.listenerClientData);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.listenerClientData.instanceCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEnded(String host) {
|
||||||
|
Object var2 = LOCK;
|
||||||
|
synchronized(LOCK) {
|
||||||
|
BackendListener.ListenerClientData listenerClientDataForName = (BackendListener.ListenerClientData)queuesByTestElementName.get(this.myName);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("testEnded called on instance {}#{}", this.myName, listenerClientDataForName.instanceCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listenerClientDataForName != null) {
|
||||||
|
listenerClientDataForName.instanceCount--;
|
||||||
|
if (listenerClientDataForName.instanceCount > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queuesByTestElementName.remove(this.myName);
|
||||||
|
} else {
|
||||||
|
log.error("No listener client data found for BackendListener {}", this.myName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.listenerClientData.queue.put(FINAL_SAMPLE_RESULT);
|
||||||
|
} catch (Exception var6) {
|
||||||
|
log.warn("testEnded() with exception: {}", var6.getMessage(), var6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.listenerClientData.queueWaits.longValue() > 0L) {
|
||||||
|
log.warn("QueueWaits: {}; QueueWaitTime: {} (nanoseconds), you may need to increase queue capacity, see property 'backend_queue_capacity'", this.listenerClientData.queueWaits, this.listenerClientData.queueWaitTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.listenerClientData.latch.await();
|
||||||
|
BackendListenerContext context = new BackendListenerContext(this.getArguments());
|
||||||
|
this.listenerClientData.client.teardownTest(context);
|
||||||
|
} catch (Exception var5) {
|
||||||
|
throw new IllegalStateException("Failed calling teardownTest", var5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEnded() {
|
||||||
|
this.testEnded("local");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sampleStarted(SampleEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sampleStopped(SampleEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArguments(Arguments args) {
|
||||||
|
args.removeArgument("useRegexpForSamplersList", "false");
|
||||||
|
this.setProperty(new TestElementProperty("arguments", args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Arguments getArguments() {
|
||||||
|
return (Arguments)this.getProperty("arguments").getObjectValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClassname(String classname) {
|
||||||
|
this.setProperty("classname", classname);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassname() {
|
||||||
|
return this.getPropertyAsString("classname");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQueueSize(String queueSize) {
|
||||||
|
this.setProperty("QUEUE_SIZE", queueSize, "5000");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQueueSize() {
|
||||||
|
return this.getPropertyAsString("QUEUE_SIZE", "5000");
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ErrorBackendListenerClient extends AbstractBackendListenerClient {
|
||||||
|
ErrorBackendListenerClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
|
||||||
|
BackendListener.log.warn("ErrorBackendListenerClient#handleSampleResult called, noop");
|
||||||
|
Thread.yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class Worker extends Thread {
|
||||||
|
private final BackendListener.ListenerClientData listenerClientData;
|
||||||
|
private final BackendListenerContext context;
|
||||||
|
private final BackendListenerClient backendListenerClient;
|
||||||
|
|
||||||
|
private Worker(BackendListenerClient backendListenerClient, Arguments arguments, BackendListener.ListenerClientData listenerClientData) {
|
||||||
|
this.listenerClientData = listenerClientData;
|
||||||
|
arguments.addArgument("TestElement.name", this.getName());
|
||||||
|
this.context = new BackendListenerContext(arguments);
|
||||||
|
this.backendListenerClient = backendListenerClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
boolean isDebugEnabled = BackendListener.log.isDebugEnabled();
|
||||||
|
ArrayList sampleResults = new ArrayList(this.listenerClientData.queue.size());
|
||||||
|
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
boolean endOfLoop = false;
|
||||||
|
|
||||||
|
while(!endOfLoop) {
|
||||||
|
if (isDebugEnabled) {
|
||||||
|
BackendListener.log.debug("Thread: {} taking SampleResult from queue: {}", Thread.currentThread().getName(), this.listenerClientData.queue.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
SampleResult sampleResult = (SampleResult)this.listenerClientData.queue.take();
|
||||||
|
if (isDebugEnabled) {
|
||||||
|
BackendListener.log.debug("Thread: {} took SampleResult: {}, isFinal: {}", new Object[]{Thread.currentThread().getName(), sampleResult, sampleResult == BackendListener.FINAL_SAMPLE_RESULT});
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!(endOfLoop = sampleResult == BackendListener.FINAL_SAMPLE_RESULT) && sampleResult != null) {
|
||||||
|
sampleResults.add(sampleResult);
|
||||||
|
if (isDebugEnabled) {
|
||||||
|
BackendListener.log.debug("Thread: {} polling from queue: {}", Thread.currentThread().getName(), this.listenerClientData.queue.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleResult = (SampleResult)this.listenerClientData.queue.poll();
|
||||||
|
if (isDebugEnabled) {
|
||||||
|
BackendListener.log.debug("Thread: {} took from queue: {}, isFinal: {}", new Object[]{Thread.currentThread().getName(), sampleResult, sampleResult == BackendListener.FINAL_SAMPLE_RESULT});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDebugEnabled) {
|
||||||
|
BackendListener.log.debug("Thread: {} exiting with FINAL EVENT: {}, null: {}", new Object[]{Thread.currentThread().getName(), sampleResult == BackendListener.FINAL_SAMPLE_RESULT, sampleResult == null});
|
||||||
|
}
|
||||||
|
|
||||||
|
BackendListener.sendToListener(this.backendListenerClient, this.context, sampleResults);
|
||||||
|
if (!endOfLoop) {
|
||||||
|
LockSupport.parkNanos(100L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException var8) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
BackendListener.sendToListener(this.backendListenerClient, this.context, sampleResults);
|
||||||
|
BackendListener.log.info("Worker ended");
|
||||||
|
} finally {
|
||||||
|
this.listenerClientData.latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ListenerClientData {
|
||||||
|
private BackendListenerClient client;
|
||||||
|
private BlockingQueue<SampleResult> queue;
|
||||||
|
private LongAdder queueWaits;
|
||||||
|
private LongAdder queueWaitTime;
|
||||||
|
private int instanceCount;
|
||||||
|
private CountDownLatch latch;
|
||||||
|
|
||||||
|
private ListenerClientData() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,7 +83,7 @@ test_case_already_exists=The test case in this project is exists
|
||||||
parse_data_error=Parse data error
|
parse_data_error=Parse data error
|
||||||
missing_header_information=Missing header information
|
missing_header_information=Missing header information
|
||||||
test_case_exist=A test case already exists under this project:
|
test_case_exist=A test case already exists under this project:
|
||||||
node_deep_limit=The node depth does not exceed 5 layers!
|
node_deep_limit=The node depth does not exceed 8 layers!
|
||||||
before_delete_plan=There is an associated test case under this plan, please unlink it first!
|
before_delete_plan=There is an associated test case under this plan, please unlink it first!
|
||||||
incorrect_format=\tincorrect format
|
incorrect_format=\tincorrect format
|
||||||
test_case_type_validate=\tmust be functional, performance, api
|
test_case_type_validate=\tmust be functional, performance, api
|
||||||
|
|
|
@ -83,7 +83,7 @@ test_case_already_exists=该项目下已存在该测试用例
|
||||||
parse_data_error=解析数据出错
|
parse_data_error=解析数据出错
|
||||||
missing_header_information=缺少头部信息
|
missing_header_information=缺少头部信息
|
||||||
test_case_exist=该项目下已存在用例:
|
test_case_exist=该项目下已存在用例:
|
||||||
node_deep_limit=节点深度不超过5层!
|
node_deep_limit=节点深度不超过8层!
|
||||||
before_delete_plan=该计划下存在关联测试用例,请先取消关联!
|
before_delete_plan=该计划下存在关联测试用例,请先取消关联!
|
||||||
incorrect_format=格式错误
|
incorrect_format=格式错误
|
||||||
test_case_type_validate=必须为functional、performance、api
|
test_case_type_validate=必须为functional、performance、api
|
||||||
|
|
|
@ -83,7 +83,7 @@ test_case_already_exists=該項目下已存在該測試用例
|
||||||
parse_data_error=解析數據出錯
|
parse_data_error=解析數據出錯
|
||||||
missing_header_information=缺少頭部信息
|
missing_header_information=缺少頭部信息
|
||||||
test_case_exist=該項目下已存在用例:
|
test_case_exist=該項目下已存在用例:
|
||||||
node_deep_limit=節點深度不超過5層!
|
node_deep_limit=節點深度不超過8層!
|
||||||
before_delete_plan=該計劃下存在關聯測試用例,請先取消關聯!
|
before_delete_plan=該計劃下存在關聯測試用例,請先取消關聯!
|
||||||
incorrect_format=格式錯誤
|
incorrect_format=格式錯誤
|
||||||
test_case_type_validate=必須為functional、performance、api
|
test_case_type_validate=必須為functional、performance、api
|
||||||
|
|
|
@ -555,14 +555,6 @@ export class TCPRequest extends Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
isValid() {
|
||||||
if (this.enable) {
|
|
||||||
if (!this.server) {
|
|
||||||
return {
|
|
||||||
isValid: false,
|
|
||||||
info: 'api_test.request.tcp.server_cannot_be_empty'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
isValid: true
|
isValid: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,7 @@
|
||||||
:label="$t('load_test.file_type')">
|
:label="$t('load_test.file_type')">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
:label="$t('load_test.last_modify_time')">
|
:label="$t('test_track.case.upload_time')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<i class="el-icon-time"/>
|
<i class="el-icon-time"/>
|
||||||
<span class="last-modified">{{ scope.row.updateTime | timestampFormatDate }}</span>
|
<span class="last-modified">{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||||
|
@ -664,7 +664,7 @@ export default {
|
||||||
name: file.name,
|
name: file.name,
|
||||||
size: file.size + ' Bytes', /// todo: 按照大小显示Byte、KB、MB等
|
size: file.size + ' Bytes', /// todo: 按照大小显示Byte、KB、MB等
|
||||||
type: type.toUpperCase(),
|
type: type.toUpperCase(),
|
||||||
updateTime: file.lastModified,
|
updateTime: new Date().getTime(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -401,8 +401,7 @@ export default {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
this.updateTestCases(param);
|
this.updateTestCases(param);
|
||||||
this.setPlanStatus(this.testCase.planId);
|
this.setPlanStatus(this.testCase.planId);
|
||||||
// 结果为Pass时 自动跳转到下一用例
|
if (this.index < this.testCases.length - 1) {
|
||||||
if (this.testCase.status === 'Pass' && this.index < this.testCases.length - 1) {
|
|
||||||
this.handleNext();
|
this.handleNext();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,11 +39,11 @@
|
||||||
<el-divider direction="vertical"></el-divider>
|
<el-divider direction="vertical"></el-divider>
|
||||||
|
|
||||||
<el-button type="success" size="mini"
|
<el-button type="success" size="mini"
|
||||||
:disabled="isReadOnly" :plain="testCase.reviewStatus !== 'Pass'" @click="saveCase('Pass')">
|
:disabled="isReadOnly" :icon="testCase.reviewStatus === 'Pass' ? 'el-icon-check' : ''" @click="saveCase('Pass')">
|
||||||
{{ $t('test_track.review.pass') }}
|
{{ $t('test_track.review.pass') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="danger" size="mini"
|
<el-button type="danger" size="mini"
|
||||||
:disabled="isReadOnly" :plain="testCase.reviewStatus !== 'UnPass'" @click="saveCase('UnPass')">
|
:disabled="isReadOnly" :icon="testCase.reviewStatus === 'UnPass' ? 'el-icon-check' : ''" @click="saveCase('UnPass')">
|
||||||
{{ $t('test_track.review.un_pass') }}
|
{{ $t('test_track.review.un_pass') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -296,6 +296,9 @@ export default {
|
||||||
this.testCase.reviewStatus = status;
|
this.testCase.reviewStatus = status;
|
||||||
// 修改当前用例在整个用例列表的状态
|
// 修改当前用例在整个用例列表的状态
|
||||||
this.testCases[this.index].reviewStatus = status;
|
this.testCases[this.index].reviewStatus = status;
|
||||||
|
if (this.index < this.testCases.length - 1) {
|
||||||
|
this.handleNext();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
updateTestCases(param) {
|
updateTestCases(param) {
|
||||||
|
|
|
@ -748,6 +748,7 @@ export default {
|
||||||
pdf_loading_fail: "PDF loading failed",
|
pdf_loading_fail: "PDF loading failed",
|
||||||
upload_tip: "Only jpg, jpeg, png, docx, doc, pdf, xlsx files can be uploaded",
|
upload_tip: "Only jpg, jpeg, png, docx, doc, pdf, xlsx files can be uploaded",
|
||||||
attachment: "Attachment",
|
attachment: "Attachment",
|
||||||
|
upload_time: "Upload Time",
|
||||||
import: {
|
import: {
|
||||||
import: "Import test case",
|
import: "Import test case",
|
||||||
case_import: "Import test case",
|
case_import: "Import test case",
|
||||||
|
|
|
@ -752,6 +752,7 @@ export default {
|
||||||
pdf_loading_fail: "PDF加载失败",
|
pdf_loading_fail: "PDF加载失败",
|
||||||
upload_tip: "只能上传jpg、jpeg、png、docx、doc、pdf、xlsx文件",
|
upload_tip: "只能上传jpg、jpeg、png、docx、doc、pdf、xlsx文件",
|
||||||
attachment: "附件",
|
attachment: "附件",
|
||||||
|
upload_time: "上传时间",
|
||||||
import: {
|
import: {
|
||||||
import: "导入用例",
|
import: "导入用例",
|
||||||
case_import: "导入测试用例",
|
case_import: "导入测试用例",
|
||||||
|
|
|
@ -752,6 +752,7 @@ export default {
|
||||||
pdf_loading_fail: "PDF加載失敗",
|
pdf_loading_fail: "PDF加載失敗",
|
||||||
upload_tip: "只能上傳jpg、jpeg、png、docx、doc、pdf、xlsx文件",
|
upload_tip: "只能上傳jpg、jpeg、png、docx、doc、pdf、xlsx文件",
|
||||||
attachment: "附件",
|
attachment: "附件",
|
||||||
|
upload_time: "上傳時間",
|
||||||
import: {
|
import: {
|
||||||
import: "導入用例",
|
import: "導入用例",
|
||||||
case_import: "導入測試用例",
|
case_import: "導入測試用例",
|
||||||
|
|
Loading…
Reference in New Issue