View Javadoc
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 }