-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduced @ResourceLock(target = SELF | CHILDREN)
#3220
base: main
Are you sure you want to change the base?
Changes from 4 commits
43605a2
e6801ff
b559ee5
a23cae2
95b323a
9fe9dca
baccd68
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* Copyright 2015-2023 the original author or authors. | ||
* | ||
* All rights reserved. This program and the accompanying materials are | ||
* made available under the terms of the Eclipse Public License v2.0 which | ||
* accompanies this distribution and is available at | ||
* | ||
* https://www.eclipse.org/legal/epl-v20.html | ||
*/ | ||
|
||
package example; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNull; | ||
import static org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT; | ||
import static org.junit.jupiter.api.parallel.ResourceAccessMode.READ; | ||
import static org.junit.jupiter.api.parallel.ResourceAccessMode.READ_WRITE; | ||
import static org.junit.jupiter.api.parallel.Resources.SYSTEM_PROPERTIES; | ||
import static org.junit.jupiter.api.parallel.Resources.TIME_ZONE; | ||
|
||
import java.util.Properties; | ||
import java.util.TimeZone; | ||
|
||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.parallel.Execution; | ||
import org.junit.jupiter.api.parallel.ResourceLock; | ||
import org.junit.jupiter.api.parallel.ResourceLockTarget; | ||
|
||
// tag::user_guide[] | ||
@Execution(CONCURRENT) | ||
@ResourceLock(value = TIME_ZONE, mode = READ, target = ResourceLockTarget.CHILDREN) | ||
class SharedResourcesChildrenTargetDemo { | ||
|
||
private Properties backup; | ||
|
||
@BeforeEach | ||
void backup() { | ||
backup = new Properties(); | ||
backup.putAll(System.getProperties()); | ||
} | ||
|
||
@AfterEach | ||
void restore() { | ||
System.setProperties(backup); | ||
} | ||
|
||
@Test | ||
@ResourceLock(value = SYSTEM_PROPERTIES, mode = READ) | ||
void usePropertiesAndTimeZoneWithoutModification() { | ||
assertNull(System.getProperty("my.prop")); | ||
} | ||
|
||
@Test | ||
@ResourceLock(value = SYSTEM_PROPERTIES, mode = READ) | ||
void usePropertiesAndTimeZoneWithoutModificationAgain() { | ||
assertNull(System.getProperty("my.prop")); | ||
} | ||
|
||
@Test | ||
@ResourceLock(value = SYSTEM_PROPERTIES, mode = READ_WRITE) | ||
void canSetCustomPropertyToTimeZone() { | ||
String timezone = TimeZone.getDefault().getDisplayName(); | ||
System.setProperty("my.timezone", timezone); | ||
assertEquals(timezone, System.getProperty("my.timezone")); | ||
} | ||
|
||
} | ||
// end::user_guide[] |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,36 @@ | ||||||
/* | ||||||
* Copyright 2015-2023 the original author or authors. | ||||||
* | ||||||
* All rights reserved. This program and the accompanying materials are | ||||||
* made available under the terms of the Eclipse Public License v2.0 which | ||||||
* accompanies this distribution and is available at | ||||||
* | ||||||
* https://www.eclipse.org/legal/epl-v20.html | ||||||
*/ | ||||||
|
||||||
package org.junit.jupiter.api.parallel; | ||||||
|
||||||
import static org.apiguardian.api.API.Status.EXPERIMENTAL; | ||||||
|
||||||
import org.apiguardian.api.API; | ||||||
|
||||||
/** | ||||||
* Indicates the target of a {@link ResourceLock}. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
* | ||||||
* @since 5.10 | ||||||
* @see ResourceLock | ||||||
*/ | ||||||
@API(status = EXPERIMENTAL, since = "5.10") | ||||||
public enum ResourceLockTarget { | ||||||
|
||||||
/** | ||||||
* Point to the test descriptor itself | ||||||
*/ | ||||||
SELF, | ||||||
|
||||||
/** | ||||||
* Skip the test descriptor itself and apply annotation {@link ResourceLock} to all its children | ||||||
*/ | ||||||
CHILDREN | ||||||
|
||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,18 +52,34 @@ public class ExclusiveResource { | |
|
||
private final String key; | ||
private final LockMode lockMode; | ||
private final LockScope lockScope; | ||
private int hash; | ||
|
||
/** | ||
* Create a new {@code ExclusiveResource}. | ||
* Create a new {@code ExclusiveResource} with a default lock scope {@link LockScope#SELF} | ||
* | ||
* @param key the identifier of the resource; never {@code null} or blank | ||
* @param lockMode the lock mode to use to synchronize access to the | ||
* resource; never {@code null} | ||
* | ||
*/ | ||
public ExclusiveResource(String key, LockMode lockMode) { | ||
this(key, lockMode, LockScope.SELF); | ||
} | ||
|
||
/** | ||
* Create a new {@code ExclusiveResource}. | ||
* | ||
* @param key the identifier of the resource; never {@code null} or blank | ||
* @param lockMode the lock mode to use to synchronize access to the | ||
* resource; never {@code null} | ||
* @param lockScope the lock scope to use to synchronize access to the | ||
* resource; never {@code null} | ||
*/ | ||
public ExclusiveResource(String key, LockMode lockMode, LockScope lockScope) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this should be a Platform concept. Instead, Jupiter should return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds good, no need to bother Platform with those details :) I drafted how it may look in https://github.com/junit-team/junit5/pull/3220/files#diff-63a01db8dd78b02e05c3888eb786c656af0cd3dc8263c816530003f2d7069daeR188 |
||
this.key = Preconditions.notBlank(key, "key must not be blank"); | ||
this.lockMode = Preconditions.notNull(lockMode, "lockMode must not be null"); | ||
this.lockScope = Preconditions.notNull(lockScope, "lockScope must not be null"); | ||
} | ||
|
||
/** | ||
|
@@ -80,6 +96,13 @@ public LockMode getLockMode() { | |
return lockMode; | ||
} | ||
|
||
/** | ||
* Get the lock scope of this resource. | ||
*/ | ||
public LockScope getLockScope() { | ||
return lockScope; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
|
@@ -89,21 +112,26 @@ public boolean equals(Object o) { | |
return false; | ||
} | ||
ExclusiveResource that = (ExclusiveResource) o; | ||
return Objects.equals(key, that.key) && lockMode == that.lockMode; | ||
return Objects.equals(key, that.key) && lockMode == that.lockMode && lockScope == that.lockScope; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
int h = hash; | ||
if (h == 0) { | ||
h = hash = Objects.hash(key, lockMode); | ||
h = hash = Objects.hash(key, lockMode, lockScope); | ||
} | ||
return h; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return new ToStringBuilder(this).append("key", key).append("lockMode", lockMode).toString(); | ||
return new ToStringBuilder(this).append("key", key).append("lockMode", lockMode).append("lockScope", | ||
lockScope).toString(); | ||
} | ||
|
||
public ExclusiveResource convertToSelfTarget() { | ||
return new ExclusiveResource(key, lockMode, LockScope.SELF); | ||
} | ||
|
||
/** | ||
|
@@ -131,4 +159,21 @@ public enum LockMode { | |
|
||
} | ||
|
||
/** | ||
* {@code LockTarget} defines the scope of the lock. | ||
*/ | ||
public enum LockScope { | ||
|
||
/** | ||
* Lock the resource for the node itself. | ||
*/ | ||
SELF, | ||
|
||
/** | ||
* Lock the resource for all children of the node. Bypass the node itself. | ||
*/ | ||
CHILDREN | ||
|
||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if a class has a
@ResourceLock
annotation with targetCHILDREN
and a method has one for the same resource? Does the one from the method override the one from the class? This should be documented here.