From 43346579b4cd799e832114a0c2e069412617c911 Mon Sep 17 00:00:00 2001 From: Felix Schumacher Date: Sun, 6 Jun 2021 13:22:37 +0200 Subject: [PATCH] Don't mark enclosed properties of TestElementProperty as temporary The inner properties of a MultiProperty are marked as temporary by the AbstractTestElement setTemporary implementation. This is needed, since the MultiProperty default implementation of mergeIn is recursive on MultiProperties. The TestElementProperty does not implement this method recursively and therefore must not have marked the enclosed properties as temporary. --- .../testelement/AbstractTestElement.java | 10 +- .../AbstractTestElementSpec.groovy | 99 +++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/core/src/test/groovy/org/apache/jmeter/testelement/AbstractTestElementSpec.groovy diff --git a/src/core/src/main/java/org/apache/jmeter/testelement/AbstractTestElement.java b/src/core/src/main/java/org/apache/jmeter/testelement/AbstractTestElement.java index 94364f26b9..93f8369515 100644 --- a/src/core/src/main/java/org/apache/jmeter/testelement/AbstractTestElement.java +++ b/src/core/src/main/java/org/apache/jmeter/testelement/AbstractTestElement.java @@ -546,13 +546,21 @@ public abstract class AbstractTestElement implements TestElement, Serializable, temporaryProperties = new LinkedHashSet<>(); } temporaryProperties.add(property); - if (property instanceof MultiProperty) { + if (isMergingEnclosedProperties(property)) { for (JMeterProperty jMeterProperty : (MultiProperty) property) { setTemporary(jMeterProperty); } } } + // While TestElementProperty is implementing MultiProperty, it works differently. + // It doesn't merge the inner properties one by one as MultiProperty would do. + // Therefore we must not mark the enclosed properties of TestElementProperty as + // temporary (Bug 65336) + private boolean isMergingEnclosedProperties(JMeterProperty property) { + return property instanceof MultiProperty && !(property instanceof TestElementProperty); + } + /** * @return Returns the threadContext. */ diff --git a/src/core/src/test/groovy/org/apache/jmeter/testelement/AbstractTestElementSpec.groovy b/src/core/src/test/groovy/org/apache/jmeter/testelement/AbstractTestElementSpec.groovy new file mode 100644 index 0000000000..c258cc3633 --- /dev/null +++ b/src/core/src/test/groovy/org/apache/jmeter/testelement/AbstractTestElementSpec.groovy @@ -0,0 +1,99 @@ +/* + * 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.jmeter.testelement + +import org.apache.jmeter.junit.spock.JMeterSpec +import org.apache.jmeter.testelement.property.JMeterProperty +import org.apache.jmeter.testelement.property.MultiProperty +import org.apache.jmeter.testelement.property.PropertyIterator +import org.apache.jmeter.testelement.property.TestElementProperty + +import spock.lang.Unroll +import sun.reflect.generics.reflectiveObjects.NotImplementedException + +@Unroll +class AbstractTestElementSpec extends JMeterSpec { + + def "set outer properties as temporary when using a TestElementProperty"() { + given: + AbstractTestElement sut = Spy(AbstractTestElement.class) + def outerElement = Mock(TestElement.class) + def innerElement = Mock(TestElement.class) + def outerProp = new TestElementProperty("outerProp", outerElement) + def innerProp = new TestElementProperty("innerProp", innerElement) + outerProp.addProperty(innerProp) + when: + sut.setTemporary(outerProp) + then: + sut.isTemporary(outerProp) + !sut.isTemporary(innerProp) + } + + def "set all properties as temporary when using a MultiProperty"() { + given: + AbstractTestElement sut = Spy(AbstractTestElement.class) + def outerProp = new MinimalMultiProperty() + def innerProp = new MinimalMultiProperty() + outerProp.addProperty(innerProp) + when: + sut.setTemporary(outerProp) + then: + sut.isTemporary(outerProp) + sut.isTemporary(innerProp) + } + + private class MinimalMultiProperty extends MultiProperty { + + Set props = new HashSet<>() + + @Override + void recoverRunningVersion(TestElement owner) { + throw new NotImplementedException() + } + + @Override + String getStringValue() { + throw new NotImplementedException() + } + + @Override + Object getObjectValue() { + return null + } + + @Override + void setObjectValue(Object value) { + throw new NotImplementedException() + } + + @Override + PropertyIterator iterator() { + return props.iterator() as PropertyIterator + } + + @Override + void addProperty(JMeterProperty prop) { + props.add(prop) + } + + @Override + void clear() { + props.clear() + } + } +} -- 2.25.1