1 /*
2 * Copyright (c) 2012-2024, jcabi.com
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met: 1) Redistributions of source code must retain the above
8 * copyright notice, this list of conditions and the following
9 * disclaimer. 2) Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution. 3) Neither the name of the jcabi.com nor
13 * the names of its contributors may be used to endorse or promote
14 * products derived from this software without specific prior written
15 * permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 package com.jcabi.aspects;
31
32 import java.io.Closeable;
33 import java.util.concurrent.TimeUnit;
34 import java.util.concurrent.atomic.AtomicLong;
35 import org.hamcrest.MatcherAssert;
36 import org.hamcrest.Matchers;
37 import org.junit.jupiter.api.Test;
38
39 /**
40 * Test case for {@link ScheduleWithFixedDelay} annotation
41 * and its implementation.
42 * @since 0.0.0
43 */
44 @SuppressWarnings("PMD.DoNotUseThreads")
45 final class ScheduleWithFixedDelayTest {
46
47 @Test
48 void runsRoutineOperations() throws Exception {
49 final AtomicLong counter = new AtomicLong();
50 final ScheduleWithFixedDelayTest.Sample sample =
51 new ScheduleWithFixedDelayTest.Sample(counter);
52 TimeUnit.SECONDS.sleep(1L);
53 MatcherAssert.assertThat(counter.get(), Matchers.greaterThan(0L));
54 sample.close();
55 TimeUnit.MILLISECONDS.sleep(10);
56 MatcherAssert.assertThat(counter.get(), Matchers.lessThan(0L));
57 }
58
59 @Test
60 void canStopBeforeFirstScheduledRun() throws Exception {
61 final AtomicLong counter = new AtomicLong();
62 final ScheduleWithFixedDelayTest.LongDelaySample sample =
63 new ScheduleWithFixedDelayTest.LongDelaySample(counter);
64 sample.close();
65 TimeUnit.MILLISECONDS.sleep(100);
66 MatcherAssert.assertThat(counter.get(), Matchers.is(0L));
67 }
68
69 /**
70 * Sample annotated class.
71 * @since 0.0.0
72 */
73 @ScheduleWithFixedDelay(unit = TimeUnit.MILLISECONDS)
74 private static final class Sample implements Runnable, Closeable {
75
76 /**
77 * Encapsulated counter.
78 */
79 private final transient AtomicLong counter;
80
81 /**
82 * Public ctor.
83 * @param cnt Counter to encapsulate
84 */
85 Sample(final AtomicLong cnt) {
86 this.counter = cnt;
87 }
88
89 @Override
90 public void run() {
91 this.counter.addAndGet(1L);
92 }
93
94 @Override
95 public void close() {
96 this.counter.set(-1L);
97 }
98 }
99
100 /**
101 * Sample class with long delay.
102 * @since 0.0.0
103 */
104 @ScheduleWithFixedDelay()
105 private static final class LongDelaySample implements Runnable, Closeable {
106
107 /**
108 * Encapsulated counter.
109 */
110 private final transient AtomicLong counter;
111
112 /**
113 * Public ctor.
114 * @param cnt Counter to encapsulate
115 */
116 LongDelaySample(final AtomicLong cnt) {
117 this.counter = cnt;
118 }
119
120 @Override
121 public void run() {
122 this.counter.addAndGet(1L);
123 }
124
125 @Override
126 public void close() {
127 // Nothing to do.
128 }
129 }
130
131 }