1
2
3
4
5
6
7
8
9
10
11
12
13
14 package de.softwareforge.testing.postgres.embedded;
15
16 import static com.google.common.base.Preconditions.checkArgument;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.net.ServerSocket;
21 import java.nio.file.Files;
22 import java.nio.file.Path;
23 import java.time.Duration;
24 import java.util.Comparator;
25 import java.util.Locale;
26 import java.util.Objects;
27 import java.util.concurrent.ThreadLocalRandom;
28 import java.util.stream.Stream;
29
30 import com.google.common.base.Joiner;
31 import com.google.common.base.Strings;
32 import com.google.common.collect.ImmutableList;
33 import edu.umd.cs.findbugs.annotations.NonNull;
34 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35
36 final class EmbeddedUtil {
37
38 static final String OS_NAME;
39 static final String OS_ARCH;
40
41 static final boolean IS_OS_WINDOWS;
42 static final boolean IS_OS_MAC;
43 static final boolean IS_OS_LINUX;
44 static final boolean IS_ALPINE_LINUX;
45
46 static final boolean IS_ARCH_X86_64;
47 static final boolean IS_ARCH_AARCH64;
48 static final boolean IS_ARCH_AARCH32;
49
50 private static final String ALPHANUM;
51 private static final String LOWERCASE;
52
53 static {
54 OS_NAME = getSystemProperty("os.name");
55 OS_ARCH = getSystemProperty("os.arch");
56
57 IS_OS_WINDOWS = getOsMatchesName("Windows");
58 IS_OS_LINUX = getOsMatchesName("Linux");
59 IS_OS_MAC = getOsMatchesName("Mac");
60
61 IS_ARCH_X86_64 = OS_ARCH.equals("x86_64") || OS_ARCH.equals("amd64");
62 IS_ARCH_AARCH64 = OS_ARCH.equals("aarch64");
63 IS_ARCH_AARCH32 = OS_ARCH.equals("aarch32") || OS_ARCH.equals("arm");
64
65
66 IS_ALPINE_LINUX = new File("/etc/alpine-release").exists();
67
68 String numbers = sequence('0', 10);
69 LOWERCASE = sequence('a', 26);
70 String uppercase = sequence('A', 26);
71 ALPHANUM = numbers + LOWERCASE + uppercase;
72 }
73
74 private EmbeddedUtil() {
75 throw new AssertionError("EmbeddedUtil can not be instantiated");
76 }
77
78 static File getWorkingDirectory() {
79 File tmpDir = new File(System.getProperty("java.io.tmpdir"));
80
81 return new File(tmpDir, "embedded-pg-" + Objects.requireNonNullElse(System.getProperty("user.name"), "unknown"));
82 }
83
84
85
86
87 static String getFileBaseName(final String fileName) {
88 if (fileName == null) {
89 return null;
90 }
91 failIfNullBytePresent(fileName);
92 final int index = indexOfLastSeparator(fileName);
93 return fileName.substring(index + 1);
94 }
95
96 private static void failIfNullBytePresent(final String path) {
97 final int len = path.length();
98 for (int i = 0; i < len; i++) {
99 checkArgument(path.charAt(i) != 0,
100 "Null byte present in file/path name.");
101 }
102 }
103
104 private static int indexOfLastSeparator(final String fileName) {
105 if (fileName == null) {
106 return -1;
107 }
108 final int lastUnixPos = fileName.lastIndexOf('/');
109 final int lastWindowsPos = fileName.lastIndexOf('\\');
110 return Math.max(lastUnixPos, lastWindowsPos);
111 }
112
113
114
115
116
117 static void mkdirs(@NonNull File dir) {
118 if (!dir.mkdirs() && !(dir.isDirectory() && dir.exists())) {
119 throw new IllegalStateException("could not create " + dir);
120 }
121 }
122
123 @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE")
124 static void rmdirs(File dir) throws IOException {
125 try (Stream<Path> walk = Files.walk(dir.toPath())) {
126 walk.sorted(Comparator.reverseOrder())
127 .map(Path::toFile)
128 .forEach(File::delete);
129 }
130 }
131
132 static String formatDuration(Duration duration) {
133 long millis = duration.toMillis();
134 long hours;
135 long minutes;
136 long secs;
137 long ms;
138 ImmutableList.Builder<String> builder = ImmutableList.builder();
139 if (millis == 0) {
140 builder.add("0 ms");
141 } else {
142 long seconds = millis / 1000L;
143 hours = seconds / 3600L;
144 minutes = (seconds % 3600L) / 60L;
145 secs = (seconds % 60L);
146 ms = millis % 1000L;
147
148 if (hours != 0) {
149 builder.add(hours + " hours");
150 }
151 if (minutes != 0) {
152 builder.add(minutes + " minutes");
153 }
154 if (secs != 0) {
155 builder.add(secs + " seconds");
156 }
157 if (ms != 0) {
158 builder.add(ms + " ms");
159 }
160 }
161
162 return Joiner.on(' ').join(builder.build());
163 }
164
165 static int allocatePort() throws IOException {
166 try (ServerSocket socket = new ServerSocket(0)) {
167 while (!socket.isBound()) {
168 Thread.sleep(50);
169 }
170 return socket.getLocalPort();
171 } catch (InterruptedException e) {
172 Thread.currentThread().interrupt();
173 throw new IOException("Thread interrupted!", e);
174 }
175 }
176
177 static String randomAlphaNumeric(int length) {
178 return randomString(ALPHANUM, length);
179 }
180
181 static String randomLowercase(int length) {
182 return randomString(LOWERCASE, length);
183 }
184
185 private static String sequence(char start, int count) {
186 StringBuilder sb = new StringBuilder();
187 for (int i = 0; i < count; i++) {
188 sb.append((char) (start + i));
189 }
190 return sb.toString();
191 }
192
193 private static String randomString(String alphabet, int length) {
194 StringBuilder sb = new StringBuilder();
195 for (int i = 0; i < length; i++) {
196 int random = ThreadLocalRandom.current().nextInt(alphabet.length());
197 sb.append(alphabet.charAt(random));
198 }
199 return sb.toString();
200 }
201
202 private static String getSystemProperty(String propertyName) {
203 try {
204 return Strings.nullToEmpty(System.getProperty(propertyName, ""));
205 } catch (SecurityException e) {
206 return "<unknown>";
207 }
208 }
209
210 private static boolean getOsMatchesName(final String osNamePrefix) {
211 return OS_NAME.toLowerCase(Locale.ROOT).startsWith(osNamePrefix.toLowerCase(Locale.ROOT));
212 }
213 }