1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import javax.naming.Context; 25 import javax.naming.NamingException; 26 import javax.naming.directory.Attributes; 27 import java.io.PrintStream; 28 import java.nio.file.Files; 29 import java.nio.file.Path; 30 import java.nio.file.Paths; 31 import java.util.Hashtable; 32 33 /** 34 * This is utility class for DNS test, it contains many helper methods to 35 * support test construction. 36 * 37 * For basic test sequence see TestBase and DNSTestBase 38 */ 39 public class DNSTestUtils { 40 public static final String TEST_DNS_SERVER_THREAD = "test.dns.server.thread"; 41 public static final String TEST_DNS_ROOT_URL = "test.dns.root.url"; 42 public static final int HOSTS_LOOKUP_MAX_DEPTH = 3; 43 44 protected static boolean debug = true; 45 46 /** 47 * Check that attributes contains the mandatory attributes and the right 48 * objectclass attribute 49 * 50 * @param attrs given attributes to verify 51 * @param mandatory given mandatory for verification 52 * @param optional given optional for verification 53 * @return <tt>true</tt> if check ok 54 */ 55 public static boolean checkSchema(Attributes attrs, String[] mandatory, 56 String[] optional) { 57 // Check mandatory attributes 58 for (String mandatoryAttr : mandatory) { 59 if (attrs.get(mandatoryAttr) == null) { 60 debug("missing mandatory attribute: " + mandatoryAttr); 61 return false; 62 } 63 } 64 65 // Check optional attributes 66 int optMissing = 0; 67 for (String optionalAttr : optional) { 68 if (attrs.get(optionalAttr) == null) { 69 debug("warning: missing optional attribute: " + optionalAttr); 70 ++optMissing; 71 } 72 } 73 74 if (attrs.size() > (mandatory.length + (optional.length 75 - optMissing))) { 76 debug("too many attributes: " + attrs); 77 return false; 78 } 79 80 return true; 81 } 82 83 /** 84 * Process command line arguments and init env 85 * This method will prepare default environments which to be used to initial 86 * DirContext 87 * 88 * @param localServer <tt>true</tt> if this test will run against with local 89 * server against dump message playback 90 * @param testname test case name to identify playback file 91 * @param args additional arguments for env preparation 92 * @return prepared env which will be used later to initial DirContext 93 */ 94 public static Hashtable<Object, Object> initEnv(boolean localServer, 95 String testname, String[] args) { 96 97 Hashtable<Object, Object> env = new Hashtable<>(); 98 99 // set some default parameters if no additional specified 100 env.put("DNS_DOMAIN", "domain1.com."); 101 env.put("FOREIGN_DOMAIN", "Central.Sun.COM."); 102 env.put("FOREIGN_LEAF", "sunweb"); 103 104 // set defaults for some JNDI properties 105 env.put(Context.INITIAL_CONTEXT_FACTORY, 106 "com.sun.jndi.dns.DnsContextFactory"); 107 108 boolean traceEnable = false; 109 boolean loopPlayback = false; 110 for (String arg : args) { 111 if (arg.startsWith("-D")) { 112 extractProperty(arg.substring(2), env); 113 } else if (arg.equalsIgnoreCase("-trace")) { 114 traceEnable = true; 115 } else if (arg.equalsIgnoreCase("-loop")) { 116 loopPlayback = true; 117 } 118 } 119 120 debug = Boolean.valueOf(System.getProperty("debug", "true")); 121 122 if (env.get("DNS_SERVER") != null) { 123 String port = (String) env.get("DNS_PORT"); 124 String portSuffix = (port == null) ? "" : ":" + port; 125 String url = "dns://" + env.get("DNS_SERVER") + portSuffix; 126 env.put(Context.PROVIDER_URL, url); 127 env.put(Context.PROVIDER_URL, url + "/" + env.get("DNS_DOMAIN")); 128 } 129 130 Thread inst = null; 131 if (traceEnable) { 132 // if trace is enabled, create DNSTracer to dump those message 133 inst = createDNSTracer(testname, env); 134 } else { 135 if (localServer) { 136 // if use local server, create local DNSServer for playback 137 inst = createDNSServer(testname, loopPlayback); 138 } else { 139 // for tests which run against remote server 140 // or no server required 141 debug("Skip local DNS Server creation "); 142 } 143 } 144 145 if (inst != null) { 146 inst.start(); 147 env.put(TEST_DNS_SERVER_THREAD, inst); 148 String url = "dns://localhost:" + ((Server) inst).getPort(); 149 150 env.put(TEST_DNS_ROOT_URL, url); 151 env.put(Context.PROVIDER_URL, url + "/" + env.get("DNS_DOMAIN")); 152 } 153 154 return env; 155 } 156 157 /** 158 * Clean-up the given directory context. 159 * 160 * @param ctx given context object 161 */ 162 public static void cleanup(Context ctx) { 163 if (ctx != null) { 164 try { 165 ctx.close(); 166 } catch (NamingException e) { 167 // ignore 168 } 169 } 170 } 171 172 private static void extractProperty(String propString, 173 Hashtable<Object, Object> env) { 174 int index; 175 176 if ((index = propString.indexOf('=')) > 0) { 177 env.put(propString.substring(0, index), 178 propString.substring(index + 1)); 179 } else { 180 throw new RuntimeException( 181 "Failed to extract test args property from " + propString); 182 } 183 } 184 185 /** 186 * Return new created DNS tracer 187 * 188 * @param testname test case name to identify playback file 189 * @param env given env for initialization 190 * @return created DNS tracer 191 * @see DNSTracer 192 */ 193 public static DNSTracer createDNSTracer(String testname, 194 Hashtable<Object, Object> env) { 195 try { 196 PrintStream outStream = new PrintStream(getCaptureFile(testname)); 197 return new DNSTracer(outStream, (String) env.get("DNS_SERVER"), 198 Integer.parseInt((String) env.get("DNS_PORT"))); 199 } catch (Exception e) { 200 throw new RuntimeException( 201 "Error: failed to create DNSTracer : " + e.getMessage(), e); 202 } 203 } 204 205 /** 206 * Return new created local DNS Server 207 * 208 * @param testname test case name to identify playback file 209 * @param loop <tt>true</tt> if DNS server required playback message in loop 210 * @return created local DNS Server 211 * @see DNSServer 212 */ 213 public static DNSServer createDNSServer(String testname, boolean loop) { 214 String path = getCaptureFile(testname); 215 if (Files.exists(Paths.get(path))) { 216 try { 217 return new DNSServer(path, loop); 218 } catch (Exception e) { 219 throw new RuntimeException( 220 "Error: failed to create DNSServer : " + e.getMessage(), 221 e); 222 } 223 } else { 224 throw new RuntimeException( 225 "Error: failed to create DNSServer, not found dns " 226 + "cache file " + path); 227 } 228 } 229 230 /** 231 * Return dns message capture file path 232 * 233 * @param testname test case name to identify playback file 234 * @return capture file path 235 */ 236 public static String getCaptureFile(String testname) { 237 return Paths.get(System.getProperty("test.src")) 238 .resolve(testname + ".dns").toString(); 239 } 240 241 /** 242 * Enable hosts file 243 * 244 * @param hostsFile given hosts file 245 */ 246 public static void enableHostsFile(String hostsFile) { 247 System.out.println("Enable jdk.net.hosts.file = " + hostsFile); 248 System.setProperty("jdk.net.hosts.file", hostsFile); 249 } 250 251 /** 252 * Enable hosts file by given searching depth 253 * 254 * @param depth given depth for searching hosts file 255 */ 256 public static void enableHostsFile(int depth) { 257 Path path = Paths.get(System.getProperty("test.src", ".")) 258 .toAbsolutePath(); 259 for (int i = depth; i >= 0; i--) { 260 Path filePath = path.resolve("hosts"); 261 if (Files.exists(filePath) && !Files.isDirectory(filePath)) { 262 enableHostsFile(filePath.toString()); 263 break; 264 } 265 266 path = path.getParent(); 267 if (path == null) { 268 break; 269 } 270 } 271 } 272 273 /** 274 * Print given object if debug enabled 275 * 276 * @param object given object to print 277 */ 278 public static void debug(Object object) { 279 if (debug) { 280 System.out.println(object); 281 } 282 } 283 284 /** 285 * Verify attributes contains the mandatory attributes and the right 286 * objectclass attribute, will throw RuntimeException if verify failed 287 * 288 * @param attrs given attributes to verify 289 * @param mandatory given mandatory for verification 290 * @param optional given optional for verification 291 */ 292 public static void verifySchema(Attributes attrs, String[] mandatory, 293 String[] optional) { 294 debug(attrs); 295 if (!checkSchema(attrs, mandatory, optional)) { 296 throw new RuntimeException("Check schema failed."); 297 } 298 } 299 300 /** 301 * Return dns root url 302 * 303 * @param env given env 304 * @return dns root url 305 */ 306 public static String getRootUrl(Hashtable<Object, Object> env) { 307 return (String) env.get(TEST_DNS_ROOT_URL); 308 } 309 310 /** 311 * Assemble a fully-qualified domain name from the base component and the 312 * domain name. 313 * 314 * @param base given base component 315 * @param env given env 316 * @param primary <tt>true</tt> if primary domain 317 * @return assembled fully-qualified domain name 318 */ 319 public static String buildFqdn(String base, Hashtable<Object, Object> env, 320 boolean primary) { 321 String domain = (String) (primary ? 322 env.get("DNS_DOMAIN") : 323 env.get("FOREIGN_DOMAIN")); 324 325 return base + "." + domain; 326 } 327 }