|
15 | 15 | */
|
16 | 16 | package com.mongodb.internal.async;
|
17 | 17 |
|
18 |
| -import com.mongodb.client.TestListener; |
19 | 18 | import org.junit.jupiter.api.Test;
|
20 |
| -import org.opentest4j.AssertionFailedError; |
21 | 19 |
|
22 |
| -import java.util.ArrayList; |
23 |
| -import java.util.List; |
24 |
| -import java.util.concurrent.atomic.AtomicBoolean; |
25 |
| -import java.util.concurrent.atomic.AtomicReference; |
26 | 20 | import java.util.function.BiConsumer;
|
27 | 21 | import java.util.function.Consumer;
|
28 | 22 | import java.util.function.Supplier;
|
29 | 23 |
|
30 | 24 | import static com.mongodb.assertions.Assertions.assertNotNull;
|
31 | 25 | import static com.mongodb.internal.async.AsyncRunnable.beginAsync;
|
32 |
| -import static org.junit.jupiter.api.Assertions.assertEquals; |
33 |
| -import static org.junit.jupiter.api.Assertions.assertFalse; |
34 | 26 | import static org.junit.jupiter.api.Assertions.assertThrows;
|
35 |
| -import static org.junit.jupiter.api.Assertions.assertTrue; |
36 |
| -import static org.junit.jupiter.api.Assertions.fail; |
37 | 27 |
|
38 |
| -final class AsyncFunctionsTest { |
39 |
| - private final TestListener listener = new TestListener(); |
40 |
| - private final InvocationTracker invocationTracker = new InvocationTracker(); |
41 |
| - private boolean isTestingAbruptCompletion = false; |
| 28 | +final class AsyncFunctionsTest extends AsyncFunctionsTestAbstract { |
42 | 29 |
|
43 | 30 | @Test
|
44 | 31 | void test1Method() {
|
@@ -877,275 +864,4 @@ void testDerivation() {
|
877 | 864 | });
|
878 | 865 | }
|
879 | 866 |
|
880 |
| - // invoked methods: |
881 |
| - |
882 |
| - private void plain(final int i) { |
883 |
| - int cur = invocationTracker.getNextOption(2); |
884 |
| - if (cur == 0) { |
885 |
| - listener.add("plain-exception-" + i); |
886 |
| - throw new RuntimeException("affected method exception-" + i); |
887 |
| - } else { |
888 |
| - listener.add("plain-success-" + i); |
889 |
| - } |
890 |
| - } |
891 |
| - |
892 |
| - private int plainReturns(final int i) { |
893 |
| - int cur = invocationTracker.getNextOption(2); |
894 |
| - if (cur == 0) { |
895 |
| - listener.add("plain-exception-" + i); |
896 |
| - throw new RuntimeException("affected method exception-" + i); |
897 |
| - } else { |
898 |
| - listener.add("plain-success-" + i); |
899 |
| - return i; |
900 |
| - } |
901 |
| - } |
902 |
| - |
903 |
| - private boolean plainTest(final int i) { |
904 |
| - int cur = invocationTracker.getNextOption(3); |
905 |
| - if (cur == 0) { |
906 |
| - listener.add("plain-exception-" + i); |
907 |
| - throw new RuntimeException("affected method exception-" + i); |
908 |
| - } else if (cur == 1) { |
909 |
| - listener.add("plain-false-" + i); |
910 |
| - return false; |
911 |
| - } else { |
912 |
| - listener.add("plain-true-" + i); |
913 |
| - return true; |
914 |
| - } |
915 |
| - } |
916 |
| - |
917 |
| - private void sync(final int i) { |
918 |
| - assertFalse(invocationTracker.isAsyncStep); |
919 |
| - affected(i); |
920 |
| - } |
921 |
| - |
922 |
| - |
923 |
| - private Integer syncReturns(final int i) { |
924 |
| - assertFalse(invocationTracker.isAsyncStep); |
925 |
| - return affectedReturns(i); |
926 |
| - } |
927 |
| - |
928 |
| - private void async(final int i, final SingleResultCallback<Void> callback) { |
929 |
| - assertTrue(invocationTracker.isAsyncStep); |
930 |
| - if (isTestingAbruptCompletion) { |
931 |
| - affected(i); |
932 |
| - callback.complete(callback); |
933 |
| - |
934 |
| - } else { |
935 |
| - try { |
936 |
| - affected(i); |
937 |
| - callback.complete(callback); |
938 |
| - } catch (Throwable t) { |
939 |
| - callback.onResult(null, t); |
940 |
| - } |
941 |
| - } |
942 |
| - } |
943 |
| - |
944 |
| - private void asyncReturns(final int i, final SingleResultCallback<Integer> callback) { |
945 |
| - assertTrue(invocationTracker.isAsyncStep); |
946 |
| - if (isTestingAbruptCompletion) { |
947 |
| - callback.complete(affectedReturns(i)); |
948 |
| - } else { |
949 |
| - try { |
950 |
| - callback.complete(affectedReturns(i)); |
951 |
| - } catch (Throwable t) { |
952 |
| - callback.onResult(null, t); |
953 |
| - } |
954 |
| - } |
955 |
| - } |
956 |
| - |
957 |
| - private void affected(final int i) { |
958 |
| - int cur = invocationTracker.getNextOption(2); |
959 |
| - if (cur == 0) { |
960 |
| - listener.add("affected-exception-" + i); |
961 |
| - throw new RuntimeException("exception-" + i); |
962 |
| - } else { |
963 |
| - listener.add("affected-success-" + i); |
964 |
| - } |
965 |
| - } |
966 |
| - |
967 |
| - private int affectedReturns(final int i) { |
968 |
| - int cur = invocationTracker.getNextOption(2); |
969 |
| - if (cur == 0) { |
970 |
| - listener.add("affected-exception-" + i); |
971 |
| - throw new RuntimeException("exception-" + i); |
972 |
| - } else { |
973 |
| - listener.add("affected-success-" + i); |
974 |
| - return i; |
975 |
| - } |
976 |
| - } |
977 |
| - |
978 |
| - // assert methods: |
979 |
| - |
980 |
| - private void assertBehavesSameVariations(final int expectedVariations, final Runnable sync, |
981 |
| - final Consumer<SingleResultCallback<Void>> async) { |
982 |
| - assertBehavesSameVariations(expectedVariations, |
983 |
| - () -> { |
984 |
| - sync.run(); |
985 |
| - return null; |
986 |
| - }, |
987 |
| - (c) -> { |
988 |
| - async.accept((v, e) -> c.onResult(v, e)); |
989 |
| - }); |
990 |
| - } |
991 |
| - |
992 |
| - private <T> void assertBehavesSameVariations(final int expectedVariations, final Supplier<T> sync, |
993 |
| - final Consumer<SingleResultCallback<T>> async) { |
994 |
| - // run the variation-trying code twice, with direct/indirect exceptions |
995 |
| - for (int i = 0; i < 2; i++) { |
996 |
| - isTestingAbruptCompletion = i != 0; |
997 |
| - |
998 |
| - // the variation-trying code: |
999 |
| - invocationTracker.reset(); |
1000 |
| - do { |
1001 |
| - invocationTracker.startInitialStep(); |
1002 |
| - assertBehavesSame( |
1003 |
| - sync, |
1004 |
| - () -> invocationTracker.startMatchStep(), |
1005 |
| - async); |
1006 |
| - } while (invocationTracker.countDown()); |
1007 |
| - assertEquals(expectedVariations, invocationTracker.getVariationCount(), |
1008 |
| - "number of variations did not match"); |
1009 |
| - } |
1010 |
| - |
1011 |
| - } |
1012 |
| - |
1013 |
| - private <T> void assertBehavesSame(final Supplier<T> sync, final Runnable between, |
1014 |
| - final Consumer<SingleResultCallback<T>> async) { |
1015 |
| - |
1016 |
| - T expectedValue = null; |
1017 |
| - Throwable expectedException = null; |
1018 |
| - try { |
1019 |
| - expectedValue = sync.get(); |
1020 |
| - } catch (Throwable e) { |
1021 |
| - expectedException = e; |
1022 |
| - } |
1023 |
| - List<String> expectedEvents = listener.getEventStrings(); |
1024 |
| - |
1025 |
| - listener.clear(); |
1026 |
| - between.run(); |
1027 |
| - |
1028 |
| - AtomicReference<T> actualValue = new AtomicReference<>(); |
1029 |
| - AtomicReference<Throwable> actualException = new AtomicReference<>(); |
1030 |
| - AtomicBoolean wasCalled = new AtomicBoolean(false); |
1031 |
| - try { |
1032 |
| - async.accept((v, e) -> { |
1033 |
| - actualValue.set(v); |
1034 |
| - actualException.set(e); |
1035 |
| - if (wasCalled.get()) { |
1036 |
| - fail(); |
1037 |
| - } |
1038 |
| - wasCalled.set(true); |
1039 |
| - }); |
1040 |
| - } catch (Throwable e) { |
1041 |
| - fail("async threw instead of using callback"); |
1042 |
| - } |
1043 |
| - |
1044 |
| - // The following code can be used to debug variations: |
1045 |
| -// System.out.println("===VARIATION START"); |
1046 |
| -// System.out.println("sync: " + expectedEvents); |
1047 |
| -// System.out.println("callback called?: " + wasCalled.get()); |
1048 |
| -// System.out.println("value -- sync: " + expectedValue + " -- async: " + actualValue.get()); |
1049 |
| -// System.out.println("excep -- sync: " + expectedException + " -- async: " + actualException.get()); |
1050 |
| -// System.out.println("exception mode: " + (isTestingAbruptCompletion |
1051 |
| -// ? "exceptions thrown directly (abrupt completion)" : "exceptions into callbacks")); |
1052 |
| -// System.out.println("===VARIATION END"); |
1053 |
| - |
1054 |
| - // show assertion failures arising in async tests |
1055 |
| - if (actualException.get() != null && actualException.get() instanceof AssertionFailedError) { |
1056 |
| - throw (AssertionFailedError) actualException.get(); |
1057 |
| - } |
1058 |
| - |
1059 |
| - assertTrue(wasCalled.get(), "callback should have been called"); |
1060 |
| - assertEquals(expectedEvents, listener.getEventStrings(), "steps should have matched"); |
1061 |
| - assertEquals(expectedValue, actualValue.get()); |
1062 |
| - assertEquals(expectedException == null, actualException.get() == null, |
1063 |
| - "both or neither should have produced an exception"); |
1064 |
| - if (expectedException != null) { |
1065 |
| - assertEquals(expectedException.getMessage(), actualException.get().getMessage()); |
1066 |
| - assertEquals(expectedException.getClass(), actualException.get().getClass()); |
1067 |
| - } |
1068 |
| - |
1069 |
| - listener.clear(); |
1070 |
| - } |
1071 |
| - |
1072 |
| - /** |
1073 |
| - * Tracks invocations: allows testing of all variations of a method calls |
1074 |
| - */ |
1075 |
| - private static class InvocationTracker { |
1076 |
| - public static final int DEPTH_LIMIT = 50; |
1077 |
| - private final List<Integer> invocationOptionSequence = new ArrayList<>(); |
1078 |
| - private boolean isAsyncStep; // async = matching, vs initial step = populating |
1079 |
| - private int currentInvocationIndex; |
1080 |
| - private int variationCount; |
1081 |
| - |
1082 |
| - public void reset() { |
1083 |
| - variationCount = 0; |
1084 |
| - } |
1085 |
| - |
1086 |
| - public void startInitialStep() { |
1087 |
| - variationCount++; |
1088 |
| - isAsyncStep = false; |
1089 |
| - currentInvocationIndex = -1; |
1090 |
| - } |
1091 |
| - |
1092 |
| - public int getNextOption(final int myOptionsSize) { |
1093 |
| - /* |
1094 |
| - This method creates (or gets) the next invocation's option. Each |
1095 |
| - invoker of this method has the "option" to behave in various ways, |
1096 |
| - usually just success (option 1) and exceptional failure (option 0), |
1097 |
| - though some callers might have more options. A sequence of method |
1098 |
| - outcomes (options) is one "variation". Tests automatically test |
1099 |
| - all possible variations (up to a limit, to prevent infinite loops). |
1100 |
| -
|
1101 |
| - Methods generally have labels, to ensure that corresponding |
1102 |
| - sync/async methods are called in the right order, but these labels |
1103 |
| - are unrelated to the "variation" logic here. There are two "modes" |
1104 |
| - (whether completion is abrupt, or not), which are also unrelated. |
1105 |
| - */ |
1106 |
| - |
1107 |
| - currentInvocationIndex++; // which invocation result we are dealing with |
1108 |
| - |
1109 |
| - if (currentInvocationIndex >= invocationOptionSequence.size()) { |
1110 |
| - if (isAsyncStep) { |
1111 |
| - fail("result should have been pre-initialized: steps may not match"); |
1112 |
| - } |
1113 |
| - if (isWithinDepthLimit()) { |
1114 |
| - invocationOptionSequence.add(myOptionsSize - 1); |
1115 |
| - } else { |
1116 |
| - invocationOptionSequence.add(0); // choose "0" option, should always be an exception |
1117 |
| - } |
1118 |
| - } |
1119 |
| - return invocationOptionSequence.get(currentInvocationIndex); |
1120 |
| - } |
1121 |
| - |
1122 |
| - public void startMatchStep() { |
1123 |
| - isAsyncStep = true; |
1124 |
| - currentInvocationIndex = -1; |
1125 |
| - } |
1126 |
| - |
1127 |
| - private boolean countDown() { |
1128 |
| - while (!invocationOptionSequence.isEmpty()) { |
1129 |
| - int lastItemIndex = invocationOptionSequence.size() - 1; |
1130 |
| - int lastItem = invocationOptionSequence.get(lastItemIndex); |
1131 |
| - if (lastItem > 0) { |
1132 |
| - // count current digit down by 1, until 0 |
1133 |
| - invocationOptionSequence.set(lastItemIndex, lastItem - 1); |
1134 |
| - return true; |
1135 |
| - } else { |
1136 |
| - // current digit completed, remove (move left) |
1137 |
| - invocationOptionSequence.remove(lastItemIndex); |
1138 |
| - } |
1139 |
| - } |
1140 |
| - return false; |
1141 |
| - } |
1142 |
| - |
1143 |
| - public int getVariationCount() { |
1144 |
| - return variationCount; |
1145 |
| - } |
1146 |
| - |
1147 |
| - public boolean isWithinDepthLimit() { |
1148 |
| - return invocationOptionSequence.size() < DEPTH_LIMIT; |
1149 |
| - } |
1150 |
| - } |
1151 | 867 | }
|
0 commit comments