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.util.concurrent.BlockingQueue;
33 import java.util.concurrent.Future;
34 import java.util.concurrent.LinkedBlockingQueue;
35 import java.util.concurrent.TimeUnit;
36 import org.hamcrest.Matcher;
37 import org.hamcrest.MatcherAssert;
38 import org.hamcrest.Matchers;
39 import org.junit.jupiter.api.Assertions;
40 import org.junit.jupiter.api.Test;
41
42 /**
43 * Test case for {@link Async} annotation and its implementation.
44 * @since 0.0.0
45 */
46 final class AsyncTest {
47
48 /**
49 * Thread name matcher.
50 */
51 private static final Matcher<String> THREAD_NAME = Matchers.allOf(
52 Matchers.not(Thread.currentThread().getName()),
53 Matchers.startsWith("jcabi-async")
54 );
55
56 @Test
57 @SuppressWarnings("PMD.DoNotUseThreads")
58 void executesAsynchronously() throws Exception {
59 final BlockingQueue<String> queue = new LinkedBlockingQueue<>();
60 final Runnable runnable = new Runnable() {
61 @Async
62 @Override
63 public void run() {
64 queue.offer(Thread.currentThread().getName());
65 }
66 };
67 runnable.run();
68 // @checkstyle MultipleStringLiterals (5 lines)
69 MatcherAssert.assertThat(
70 queue.poll(30, TimeUnit.SECONDS),
71 AsyncTest.THREAD_NAME
72 );
73 }
74
75 @Test
76 void returnsFutureValue() throws Exception {
77 MatcherAssert.assertThat(
78 new AsyncTest.Foo().asyncMethodWithReturnValue()
79 .get(5, TimeUnit.MINUTES),
80 AsyncTest.THREAD_NAME
81 );
82 }
83
84 @Test
85 void throwsWhenMethodDoesNotReturnVoidOrFuture() {
86 Assertions.assertThrows(
87 IllegalStateException.class,
88 () -> new AsyncTest.Foo().asyncMethodThatReturnsInt()
89 );
90 }
91
92 /**
93 * Dummy class for test purposes.
94 * @since 0.0.0
95 */
96 private static final class Foo {
97
98 /**
99 * Async method that returns a Future containing the thread name.
100 * @return The future.
101 */
102 @Async
103 public Future<String> asyncMethodWithReturnValue() {
104 // @checkstyle AnonInnerLength (23 lines)
105 return new Future<String>() {
106
107 @Override
108 public boolean cancel(final boolean interruptible) {
109 return false;
110 }
111
112 @Override
113 public boolean isCancelled() {
114 return false;
115 }
116
117 @Override
118 public boolean isDone() {
119 return true;
120 }
121
122 @Override
123 public String get() {
124 return Thread.currentThread().getName();
125 }
126
127 @Override
128 public String get(final long timeout, final TimeUnit unit) {
129 return Thread.currentThread().getName();
130 }
131 };
132 }
133
134 /**
135 * Async method that does not return void or Future. Should throw
136 * exception.
137 * @return An int value
138 */
139 @Async
140 public int asyncMethodThatReturnsInt() {
141 return 0;
142 }
143 }
144
145 }