blob: 400f710192fba01bda0f0fa0e64227a3753f7e5b [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
tom931af4e2014-09-13 12:00:57 -070016package org.onlab.junit;
17
Thomas Vachuska02aeb032015-01-06 22:36:30 -080018import com.google.common.collect.ImmutableList;
19import com.google.common.io.Files;
20
21import java.io.File;
22import java.io.IOException;
23import java.util.List;
24import java.util.Random;
25
tom931af4e2014-09-13 12:00:57 -070026import static com.google.common.base.Preconditions.checkArgument;
27import static org.junit.Assert.fail;
28
29/**
30 * Utilities to aid in producing JUnit tests.
31 */
32public final class TestTools {
33
Thomas Vachuska02aeb032015-01-06 22:36:30 -080034 private static final Random RANDOM = new Random();
35
tom931af4e2014-09-13 12:00:57 -070036 // Prohibit construction
37 private TestTools() {
38 }
39
toma7083182014-09-25 21:38:03 -070040 public static void print(String msg) {
41 System.out.print(msg);
42 }
43
tom931af4e2014-09-13 12:00:57 -070044 /**
45 * Suspends the current thread for a specified number of millis.
46 *
47 * @param ms number of millis
48 */
49 public static void delay(int ms) {
50 try {
51 Thread.sleep(ms);
52 } catch (InterruptedException e) {
53 fail("test interrupted");
54 }
55 }
56
57 /**
58 * Returns the current time in millis since epoch.
59 *
60 * @return current time
61 */
62 public static long now() {
63 return System.currentTimeMillis();
64 }
65
66 /**
67 * Runs the specified runnable until it completes successfully or until the
68 * specified time expires. If the latter occurs, the first encountered
69 * assertion on the last attempt will be re-thrown. Errors other than
70 * assertion errors will be propagated immediately.
71 * <p>
72 * Assertions attempts will not be closer than 10 millis apart and no
73 * further than 50 millis.
74 * </p>
75 *
76 * @param delay number of millis to delay before the first attempt
77 * @param duration number of milliseconds beyond the current time
78 * @param assertions test assertions runnable
79 */
80 public static void assertAfter(int delay, int duration, Runnable assertions) {
81 checkArgument(delay < duration, "delay >= duration");
82 long start = now();
83 int step = Math.max(Math.min((duration - delay) / 100, 50), 10);
84
85 // Is there an initial delay?
86 if (delay > 0) {
87 delay(delay);
88 }
89
90 // Keep going until the assertions succeed or until time runs-out.
91 while (true) {
92 try {
93 assertions.run();
94 break;
95 } catch (AssertionError e) {
96 // If there was an error and time ran out, re-throw it.
97 if (now() - start > duration) {
98 throw e;
99 }
100 }
101 delay(step);
102 }
103 }
104
105 /**
106 * Runs the specified runnable until it completes successfully or until the
107 * specified time expires. If the latter occurs, the first encountered
108 * assertion on the last attempt will be re-thrown. Errors other than
109 * assertion errors will be propagated immediately.
110 * <p>
111 * Assertions attempts will not be closer than 10 millis apart and no
112 * further than 50 millis.
113 * </p>
114 *
115 * @param duration number of milliseconds beyond the current time
116 * @param assertions test assertions runnable
117 */
118 public static void assertAfter(int duration, Runnable assertions) {
119 assertAfter(0, duration, assertions);
120 }
121
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800122
123 /**
124 * Creates a directory tree of test files. To signify creating a directory
125 * file path should end with '/'.
126 *
127 * @param paths list of file paths
128 * @return list of created files
129 * @throws java.io.IOException if there is an issue
130 */
131 public static List<File> createTestFiles(List<String> paths) throws IOException {
132 return createTestFiles(paths, 32, 1024);
133 }
134
135 /**
136 * Creates a directory tree of test files. To signify creating a directory
137 * file path should end with '/'.
138 *
139 * @param paths list of file paths
140 * @param minSize minimum file size in bytes
141 * @param maxSize maximum file size in bytes
142 * @return list of created files
143 * @throws java.io.IOException if there is an issue
144 */
145 public static List<File> createTestFiles(List<String> paths,
146 int minSize, int maxSize) throws IOException {
147 ImmutableList.Builder<File> files = ImmutableList.builder();
148 for (String p : paths) {
149 File f = new File(p);
150 if (p.endsWith("/")) {
151 if (f.mkdirs()) {
152 files.add(f);
153 }
154 } else {
155 Files.createParentDirs(f);
156 if (f.createNewFile()) {
157 writeRandomFile(f, minSize, maxSize);
158 files.add(f);
159 }
160 }
161 }
162 return files.build();
163 }
164
165 /**
166 * Writes random binary content into the specified file. The number of
167 * bytes will be random between the given minimum and maximum.
168 *
169 * @param file file to write data to
170 * @param minSize minimum number of bytes to write
171 * @param maxSize maximum number of bytes to write
172 * @throws IOException if there is an issue
173 */
174 public static void writeRandomFile(File file, int minSize, int maxSize) throws IOException {
175 int size = minSize + (minSize == maxSize ? 0 : RANDOM.nextInt(maxSize - minSize));
176 byte[] data = new byte[size];
177 tweakBytes(RANDOM, data, size / 4);
178 Files.write(data, file);
179 }
180
181
182 /**
183 * Tweaks the given number of bytes in a byte array.
184 *
185 * @param random random number generator
186 * @param data byte array to be tweaked
187 * @param count number of bytes to tweak
188 */
189 public static void tweakBytes(Random random, byte[] data, int count) {
190 tweakBytes(random, data, count, 0, data.length);
191 }
192
193 /**
194 * Tweaks the given number of bytes in the specified range of a byte array.
195 *
196 * @param random random number generator
197 * @param data byte array to be tweaked
198 * @param count number of bytes to tweak
199 * @param start index at beginning of range (inclusive)
200 * @param end index at end of range (exclusive)
201 */
202 public static void tweakBytes(Random random, byte[] data, int count,
203 int start, int end) {
204 int len = end - start;
205 for (int i = 0; i < count; i++) {
206 data[start + random.nextInt(len)] = (byte) random.nextInt();
207 }
208 }
209
tom931af4e2014-09-13 12:00:57 -0700210}