1 // Copyright (c) 2014, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 package org.rocksdb.util;
6 
7 import org.junit.AfterClass;
8 import org.junit.BeforeClass;
9 import org.junit.Test;
10 
11 import java.lang.reflect.Field;
12 import java.lang.reflect.Modifier;
13 
14 import static org.assertj.core.api.Assertions.assertThat;
15 
16 public class EnvironmentTest {
17   private final static String ARCH_FIELD_NAME = "ARCH";
18   private final static String OS_FIELD_NAME = "OS";
19   private final static String MUSL_LIBC_FIELD_NAME = "MUSL_LIBC";
20 
21   private static String INITIAL_OS;
22   private static String INITIAL_ARCH;
23   private static boolean INITIAL_MUSL_LIBC;
24 
25   @BeforeClass
saveState()26   public static void saveState() {
27     INITIAL_ARCH = getEnvironmentClassField(ARCH_FIELD_NAME);
28     INITIAL_OS = getEnvironmentClassField(OS_FIELD_NAME);
29     INITIAL_MUSL_LIBC = getEnvironmentClassField(MUSL_LIBC_FIELD_NAME);
30   }
31 
32   @Test
mac32()33   public void mac32() {
34     setEnvironmentClassFields("mac", "32");
35     assertThat(Environment.isWindows()).isFalse();
36     assertThat(Environment.getJniLibraryExtension()).
37         isEqualTo(".jnilib");
38     assertThat(Environment.getJniLibraryFileName("rocksdb")).
39         isEqualTo("librocksdbjni-osx.jnilib");
40     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
41         isEqualTo("librocksdbjni.dylib");
42   }
43 
44   @Test
mac64()45   public void mac64() {
46     setEnvironmentClassFields("mac", "64");
47     assertThat(Environment.isWindows()).isFalse();
48     assertThat(Environment.getJniLibraryExtension()).
49         isEqualTo(".jnilib");
50     assertThat(Environment.getJniLibraryFileName("rocksdb")).
51         isEqualTo("librocksdbjni-osx.jnilib");
52     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
53         isEqualTo("librocksdbjni.dylib");
54   }
55 
56   @Test
nix32()57   public void nix32() {
58     // Linux
59     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
60     setEnvironmentClassFields("Linux", "32");
61     assertThat(Environment.isWindows()).isFalse();
62     assertThat(Environment.getJniLibraryExtension()).
63         isEqualTo(".so");
64     assertThat(Environment.getJniLibraryFileName("rocksdb")).
65         isEqualTo("librocksdbjni-linux32.so");
66     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
67         isEqualTo("librocksdbjni.so");
68     // Linux musl-libc (Alpine)
69     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, true);
70     assertThat(Environment.isWindows()).isFalse();
71     assertThat(Environment.getJniLibraryExtension()).
72         isEqualTo(".so");
73     assertThat(Environment.getJniLibraryFileName("rocksdb")).
74         isEqualTo("librocksdbjni-linux32-musl.so");
75     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
76         isEqualTo("librocksdbjni.so");
77     // UNIX
78     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
79     setEnvironmentClassFields("Unix", "32");
80     assertThat(Environment.isWindows()).isFalse();
81     assertThat(Environment.getJniLibraryExtension()).
82         isEqualTo(".so");
83     assertThat(Environment.getJniLibraryFileName("rocksdb")).
84         isEqualTo("librocksdbjni-linux32.so");
85     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
86         isEqualTo("librocksdbjni.so");
87   }
88 
89   @Test(expected = UnsupportedOperationException.class)
aix32()90   public void aix32() {
91     // AIX
92     setEnvironmentClassFields("aix", "32");
93     assertThat(Environment.isWindows()).isFalse();
94     assertThat(Environment.getJniLibraryExtension()).
95         isEqualTo(".so");
96     Environment.getJniLibraryFileName("rocksdb");
97   }
98 
99   @Test
nix64()100   public void nix64() {
101     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
102     setEnvironmentClassFields("Linux", "x64");
103     assertThat(Environment.isWindows()).isFalse();
104     assertThat(Environment.getJniLibraryExtension()).
105         isEqualTo(".so");
106     assertThat(Environment.getJniLibraryFileName("rocksdb")).
107         isEqualTo("librocksdbjni-linux64.so");
108     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
109         isEqualTo("librocksdbjni.so");
110     // Linux musl-libc (Alpine)
111     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, true);
112     assertThat(Environment.isWindows()).isFalse();
113     assertThat(Environment.getJniLibraryExtension()).
114         isEqualTo(".so");
115     assertThat(Environment.getJniLibraryFileName("rocksdb")).
116         isEqualTo("librocksdbjni-linux64-musl.so");
117     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
118         isEqualTo("librocksdbjni.so");
119     // UNIX
120     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
121     setEnvironmentClassFields("Unix", "x64");
122     assertThat(Environment.isWindows()).isFalse();
123     assertThat(Environment.getJniLibraryExtension()).
124         isEqualTo(".so");
125     assertThat(Environment.getJniLibraryFileName("rocksdb")).
126         isEqualTo("librocksdbjni-linux64.so");
127     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
128         isEqualTo("librocksdbjni.so");
129     // AIX
130     setEnvironmentClassFields("aix", "x64");
131     assertThat(Environment.isWindows()).isFalse();
132     assertThat(Environment.getJniLibraryExtension()).
133         isEqualTo(".so");
134     assertThat(Environment.getJniLibraryFileName("rocksdb")).
135         isEqualTo("librocksdbjni-aix64.so");
136     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
137         isEqualTo("librocksdbjni.so");
138   }
139 
140   @Test
detectWindows()141   public void detectWindows(){
142     setEnvironmentClassFields("win", "x64");
143     assertThat(Environment.isWindows()).isTrue();
144   }
145 
146   @Test
win64()147   public void win64() {
148     setEnvironmentClassFields("win", "x64");
149     assertThat(Environment.isWindows()).isTrue();
150     assertThat(Environment.getJniLibraryExtension()).
151       isEqualTo(".dll");
152     assertThat(Environment.getJniLibraryFileName("rocksdb")).
153       isEqualTo("librocksdbjni-win64.dll");
154     assertThat(Environment.getSharedLibraryFileName("rocksdb")).
155       isEqualTo("librocksdbjni.dll");
156   }
157 
158   @Test
ppc64le()159   public void ppc64le() {
160     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
161     setEnvironmentClassFields("Linux", "ppc64le");
162     assertThat(Environment.isUnix()).isTrue();
163     assertThat(Environment.isPowerPC()).isTrue();
164     assertThat(Environment.is64Bit()).isTrue();
165     assertThat(Environment.getJniLibraryExtension()).isEqualTo(".so");
166     assertThat(Environment.getSharedLibraryName("rocksdb")).isEqualTo("rocksdbjni");
167     assertThat(Environment.getJniLibraryName("rocksdb")).isEqualTo("rocksdbjni-linux-ppc64le");
168     assertThat(Environment.getJniLibraryFileName("rocksdb"))
169         .isEqualTo("librocksdbjni-linux-ppc64le.so");
170     assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.so");
171     // Linux musl-libc (Alpine)
172     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, true);
173     setEnvironmentClassFields("Linux", "ppc64le");
174     assertThat(Environment.isUnix()).isTrue();
175     assertThat(Environment.isPowerPC()).isTrue();
176     assertThat(Environment.is64Bit()).isTrue();
177     assertThat(Environment.getJniLibraryExtension()).isEqualTo(".so");
178     assertThat(Environment.getSharedLibraryName("rocksdb")).isEqualTo("rocksdbjni");
179     assertThat(Environment.getJniLibraryName("rocksdb")).isEqualTo("rocksdbjni-linux-ppc64le-musl");
180     assertThat(Environment.getJniLibraryFileName("rocksdb"))
181         .isEqualTo("librocksdbjni-linux-ppc64le-musl.so");
182     assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.so");
183     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
184   }
185 
186   @Test
aarch64()187   public void aarch64() {
188     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
189     setEnvironmentClassFields("Linux", "aarch64");
190     assertThat(Environment.isUnix()).isTrue();
191     assertThat(Environment.isAarch64()).isTrue();
192     assertThat(Environment.is64Bit()).isTrue();
193     assertThat(Environment.getJniLibraryExtension()).isEqualTo(".so");
194     assertThat(Environment.getSharedLibraryName("rocksdb")).isEqualTo("rocksdbjni");
195     assertThat(Environment.getJniLibraryName("rocksdb")).isEqualTo("rocksdbjni-linux-aarch64");
196     assertThat(Environment.getJniLibraryFileName("rocksdb"))
197         .isEqualTo("librocksdbjni-linux-aarch64.so");
198     assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.so");
199     // Linux musl-libc (Alpine)
200     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, true);
201     setEnvironmentClassFields("Linux", "aarch64");
202     assertThat(Environment.isUnix()).isTrue();
203     assertThat(Environment.isAarch64()).isTrue();
204     assertThat(Environment.is64Bit()).isTrue();
205     assertThat(Environment.getJniLibraryExtension()).isEqualTo(".so");
206     assertThat(Environment.getSharedLibraryName("rocksdb")).isEqualTo("rocksdbjni");
207     assertThat(Environment.getJniLibraryName("rocksdb")).isEqualTo("rocksdbjni-linux-aarch64-musl");
208     assertThat(Environment.getJniLibraryFileName("rocksdb"))
209         .isEqualTo("librocksdbjni-linux-aarch64-musl.so");
210     assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.so");
211     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
212   }
213 
setEnvironmentClassFields(String osName, String osArch)214   private void setEnvironmentClassFields(String osName,
215       String osArch) {
216     setEnvironmentClassField(OS_FIELD_NAME, osName);
217     setEnvironmentClassField(ARCH_FIELD_NAME, osArch);
218   }
219 
220   @AfterClass
restoreState()221   public static void restoreState() {
222     setEnvironmentClassField(OS_FIELD_NAME, INITIAL_OS);
223     setEnvironmentClassField(ARCH_FIELD_NAME, INITIAL_ARCH);
224     setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, INITIAL_MUSL_LIBC);
225   }
226 
227   @SuppressWarnings("unchecked")
getEnvironmentClassField(String fieldName)228   private static <T> T getEnvironmentClassField(String fieldName) {
229     final Field field;
230     try {
231       field = Environment.class.getDeclaredField(fieldName);
232       field.setAccessible(true);
233       /* Fails in JDK 13; and not needed unless fields are final
234       final Field modifiersField = Field.class.getDeclaredField("modifiers");
235       modifiersField.setAccessible(true);
236       modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
237       */
238       return (T)field.get(null);
239     } catch (final NoSuchFieldException | IllegalAccessException e) {
240       throw new RuntimeException(e);
241     }
242   }
243 
setEnvironmentClassField(String fieldName, Object value)244   private static void setEnvironmentClassField(String fieldName, Object value) {
245     final Field field;
246     try {
247       field = Environment.class.getDeclaredField(fieldName);
248       field.setAccessible(true);
249       /* Fails in JDK 13; and not needed unless fields are final
250       final Field modifiersField = Field.class.getDeclaredField("modifiers");
251       modifiersField.setAccessible(true);
252       modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
253       */
254       field.set(null, value);
255     } catch (final NoSuchFieldException | IllegalAccessException e) {
256       throw new RuntimeException(e);
257     }
258   }
259 }
260