From b89eac3ca21e8b2717223e7405ad060a30eb32b9 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Fri, 17 Feb 2017 14:58:07 +0000 Subject: [PATCH 1/2] [FIXED JENKINS-42150] Add latency options to mock scm impl in SCM API's test artifact --- .../jenkins/scm/impl/mock/MockLatency.java | 85 +++++++++++++++++++ .../scm/impl/mock/MockSCMController.java | 17 +++- 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/test/java/jenkins/scm/impl/mock/MockLatency.java diff --git a/src/test/java/jenkins/scm/impl/mock/MockLatency.java b/src/test/java/jenkins/scm/impl/mock/MockLatency.java new file mode 100644 index 00000000..a548adbd --- /dev/null +++ b/src/test/java/jenkins/scm/impl/mock/MockLatency.java @@ -0,0 +1,85 @@ +/* + * The MIT License + * + * Copyright (c) 2017 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package jenkins.scm.impl.mock; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +/** + * Represents latency in connecting to the {@link MockSCM}. + * + * @since 2.0.5 + */ +public abstract class MockLatency { + public abstract void apply() throws InterruptedException; + + /** + * A fixed latency. + * @param time the latency. + * @param units the units. + * @return a fixed latency. + */ + public static MockLatency fixed(final long time, final TimeUnit units) { + return new MockLatency() { + @Override + public void apply() throws InterruptedException { + units.sleep(time); + } + }; + } + + /** + * A random latency that has an expected average time. + * + * @param time the expected average latency. + * @param units the units. + * @return a fixed latency. + */ + public static MockLatency average(final long time, final TimeUnit units) { + return new MockLatency() { + final Random entropy = new Random(); + @Override + public void apply() throws InterruptedException { + long ms = units.toMillis(time); + ms = Math.min(ms * 3L, Math.max((long) (ms + (ms * entropy.nextGaussian())), 1L)); + Thread.sleep(ms); + } + }; + } + /** + * A latency that just forces the thread scheduler to yield. + * + * @return a minimal latency that causes background threads to run. + */ + public static MockLatency yield() { + return new MockLatency() { + @Override + public void apply() throws InterruptedException { + Thread.yield(); + } + }; + } +} diff --git a/src/test/java/jenkins/scm/impl/mock/MockSCMController.java b/src/test/java/jenkins/scm/impl/mock/MockSCMController.java index 12c69d4b..a8308615 100644 --- a/src/test/java/jenkins/scm/impl/mock/MockSCMController.java +++ b/src/test/java/jenkins/scm/impl/mock/MockSCMController.java @@ -26,6 +26,7 @@ package jenkins.scm.impl.mock; import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.FilePath; import java.io.ByteArrayInputStream; import java.io.Closeable; @@ -58,6 +59,7 @@ public class MockSCMController implements Closeable { private Map repositories = new TreeMap(); private List faults = new ArrayList(); + private MockLatency latency = null; private String displayName; private String description; private String url; @@ -80,6 +82,16 @@ public static MockSCMController create() { return c; } + public MockSCMController withLatency(@NonNull MockLatency latency) { + this.latency = latency; + return this; + } + + public MockSCMController withoutLatency() { + this.latency = null; + return this; + } + /** * (Re)creates a {@link MockSCMController} for use when you are running a data migration test. * It will be the callers responsibility to restore the state of the {@link MockSCMController} accordingly. @@ -178,7 +190,10 @@ public synchronized void clearFaults() { public synchronized void checkFaults(@CheckForNull String repository, @CheckForNull String branch, @CheckForNull String revision, boolean actions) - throws IOException { + throws IOException, InterruptedException { + if (latency != null) { + latency.apply(); + } for (MockFailure fault: faults) { fault.check(repository, branch, revision, actions); } From a6d46f93d1deafc6ecee5af6092c7800aa5b33a9 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Fri, 17 Feb 2017 15:15:32 +0000 Subject: [PATCH 2/2] [JENKINS-42150] Some minor improvements --- .../jenkins/scm/impl/mock/MockLatency.java | 47 ++++++++++++++++--- .../scm/impl/mock/MockSCMController.java | 12 ++--- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/test/java/jenkins/scm/impl/mock/MockLatency.java b/src/test/java/jenkins/scm/impl/mock/MockLatency.java index a548adbd..96071c4a 100644 --- a/src/test/java/jenkins/scm/impl/mock/MockLatency.java +++ b/src/test/java/jenkins/scm/impl/mock/MockLatency.java @@ -34,6 +34,19 @@ * @since 2.0.5 */ public abstract class MockLatency { + + private static final MockLatency NONE = new MockLatency() { + @Override + public void apply() throws InterruptedException { + } + }; + private static final MockLatency YIELD = new MockLatency() { + @Override + public void apply() throws InterruptedException { + Thread.yield(); + } + }; + public abstract void apply() throws InterruptedException; /** @@ -51,6 +64,25 @@ public void apply() throws InterruptedException { }; } + /** + * A fixed latency for all threads except the current thread. + * + * @param time the latency. + * @param units the units. + * @return a fixed latency. + */ + public static MockLatency fixedForOtherThreads(final long time, final TimeUnit units) { + final Thread safe = Thread.currentThread(); + return new MockLatency() { + @Override + public void apply() throws InterruptedException { + if (Thread.currentThread() != safe) { + units.sleep(time); + } + } + }; + } + /** * A random latency that has an expected average time. * @@ -75,11 +107,14 @@ public void apply() throws InterruptedException { * @return a minimal latency that causes background threads to run. */ public static MockLatency yield() { - return new MockLatency() { - @Override - public void apply() throws InterruptedException { - Thread.yield(); - } - }; + return YIELD; + } + /** + * A latency that just forces the thread scheduler to yield. + * + * @return a minimal latency that causes background threads to run. + */ + public static MockLatency none() { + return NONE; } } diff --git a/src/test/java/jenkins/scm/impl/mock/MockSCMController.java b/src/test/java/jenkins/scm/impl/mock/MockSCMController.java index a8308615..1de23cb0 100644 --- a/src/test/java/jenkins/scm/impl/mock/MockSCMController.java +++ b/src/test/java/jenkins/scm/impl/mock/MockSCMController.java @@ -59,7 +59,8 @@ public class MockSCMController implements Closeable { private Map repositories = new TreeMap(); private List faults = new ArrayList(); - private MockLatency latency = null; + @NonNull + private MockLatency latency = MockLatency.none(); private String displayName; private String description; private String url; @@ -87,11 +88,6 @@ public MockSCMController withLatency(@NonNull MockLatency latency) { return this; } - public MockSCMController withoutLatency() { - this.latency = null; - return this; - } - /** * (Re)creates a {@link MockSCMController} for use when you are running a data migration test. * It will be the callers responsibility to restore the state of the {@link MockSCMController} accordingly. @@ -191,9 +187,7 @@ public synchronized void clearFaults() { public synchronized void checkFaults(@CheckForNull String repository, @CheckForNull String branch, @CheckForNull String revision, boolean actions) throws IOException, InterruptedException { - if (latency != null) { - latency.apply(); - } + latency.apply(); for (MockFailure fault: faults) { fault.check(repository, branch, revision, actions); }