package me.osm.gazetteerweb.test; import java.io.IOException; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import me.osm.gazetteer.web.GazetteerWeb; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestSearch { private static final String SEARCH_LOCATION = "http://localhost:8080/api/location/_search"; private static final Logger log = LoggerFactory.getLogger(TestSearch.class.getName()); public static void main(String[] args) { try { if(TestSearchUtils.available(8080)) { GazetteerWeb.main(args); } TestSearch me = new TestSearch(); //me.doTest("/test_cityes.json"); //me.doTest("/test_addresses.json"); me.doTest("/test_uik.json"); } catch (Exception e) { e.printStackTrace(); } System.exit(0); } private void doTest(String resourceName) { JSONObject task = readJSON(resourceName); log.info("Run {}", task.optString("name")); boolean success = true; List<String> fails = new ArrayList<String>(); JSONArray cases = task.optJSONArray("cases"); for (int i = 0; i < cases.length(); i++) { JSONObject caze = cases.getJSONObject(i); boolean caseSuccess = doCase(caze, i, cases.length()); if(!caseSuccess) { fails.add(caze.optString("name")); } success = caseSuccess && success; } if (success) { log.trace("DONE {}", task.optString("name")); } else { if(fails.size() < 10) { log.warn("FAILS: {}", fails); } else { log.warn("{} from {} are failed", fails.size(), cases.length()); } log.warn("FAILED {}", task.optString("name")); } } private boolean doCase(JSONObject caze, int i, int total) { if(caze.optBoolean("skip")) { log.info("Skip {} {}", caze.optString("name"), caze.optString("comment")); return true; } log.info("Run {} from {}. Case {}", new Object[]{i + 1, total, caze.optString("name")}); JSONObject jsonObject = caze.getJSONObject("request"); JSONObject answer = getRequestResult(jsonObject); if(answer == null) { log.error("failed to get answer"); } boolean success = checkAnswer(caze, answer); if(success) { log.trace("\tCase {} OK", caze.optString("name")); return true; } else { log.warn("\tCase {} FAILED", caze.optString("name")); return false; } } private boolean checkAnswer(JSONObject caze, JSONObject answer) { if(caze.has("first_result")) { JSONObject fr = getFirstResult(answer); if(fr == null) { log.warn("\tFAILED Empty answer"); return false; } JSONObject check = caze.getJSONObject("first_result"); if(false == firstResultCheck(fr, check)) { return false; } } if(caze.has("first_page")) { for(int i = 0; i < 20; i++) { JSONObject fr = getNthResult(answer, i); if(fr == null) { return false; } JSONObject check = caze.getJSONObject("first_page"); if(firstResultCheck(fr, check)) { return true; } } return false; } return true; } private boolean firstResultCheck(JSONObject obj, JSONObject check) { if(check.has("location")) { if(false == checkLocation(obj, check)) { return false; } } if(check.has("type")) { if(false == checkType(obj, check)) { return false; } } return true; } private boolean checkType(JSONObject obj, JSONObject check) { Object type = check.get("type"); Set<String> types = new HashSet<String>(); if(type instanceof String) { types.add((String) type); } else if(type instanceof JSONArray) { for(int i = 0; i < ((JSONArray)type).length(); i++) { types.add(((JSONArray)type).getString(i)); } } String objType = obj.optString("type"); if(types.contains(objType)) { log.trace("\tType OK"); return true; } else { log.warn("\tType FAILED Unexpected type {}", objType); return false; } } private boolean checkLocation(JSONObject obj, JSONObject check) { String mapKey = check.getString("location"); if(mapKey != null) { String[] split = StringUtils.split(mapKey, "/"); double delta = Double.valueOf(split[0]); Double lat = Double.valueOf(split[1]); Double lon = Double.valueOf(split[2]); JSONObject cp = obj.optJSONObject("center_point"); double aLon = cp.getDouble("lon"); double aLat = cp.getDouble("lat"); if(Math.abs(lat - aLat) > delta || Math.abs(lon - aLon) > delta) { log.warn("\tLocation: FAILED"); return false; } } log.trace("\tLocation: OK"); return true; } private JSONObject getFirstResult(JSONObject answer) { if(answer == null) { return null; } JSONArray features = answer.optJSONArray("features"); if(features == null) { log.error("Answer doesnt have features"); return null; } return features.optJSONObject(0); } private JSONObject getNthResult(JSONObject answer, int index) { if(answer == null) { return null; } JSONArray features = answer.optJSONArray("features"); if(features == null) { log.error("Answer doesnt have features"); return null; } if(features.length() > index) { return features.optJSONObject(index); } return null; } @SuppressWarnings("unchecked") private JSONObject getRequestResult(JSONObject jsonObject) { HttpMethod method = new GetMethod(SEARCH_LOCATION); NameValuePair[] opts = new NameValuePair[jsonObject.length() + 1]; int index = 0; for(String key : (Set<String>)jsonObject.keySet()) { opts[index++] = new NameValuePair(key, jsonObject.getString(key)); } opts[index] = new NameValuePair("explain", "true"); method.setQueryString(opts); return get(method); } private JSONObject readJSON(String resource) { JSONObject settings; try { settings = new JSONObject(IOUtils.toString(getClass() .getResourceAsStream(resource))); } catch (IOException e) { throw new RuntimeException("couldn't read index settings", e); } return settings; } private JSONObject get(HttpMethod method) { try { URL url = new URL(method.getURI().getEscapedURI()); byte[] byteArray = IOUtils.toByteArray(url.openStream()); return new JSONObject(new String(byteArray, "UTF8")); } catch (Exception e) { e.printStackTrace(); } return null; } public static class TestSearchUtils { private static final int MIN_PORT_NUMBER = 1; private static final int MAX_PORT_NUMBER = 65535; /** * Checks to see if a specific port is available. * * @param port * the port to check for availability */ public static boolean available(int port) { if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) { throw new IllegalArgumentException("Invalid start port: " + port); } ServerSocket ss = null; DatagramSocket ds = null; try { ss = new ServerSocket(port); ss.setReuseAddress(true); ds = new DatagramSocket(port); ds.setReuseAddress(true); return true; } catch (IOException e) { } finally { if (ds != null) { ds.close(); } if (ss != null) { try { ss.close(); } catch (IOException e) { /* should not be thrown */ } } } return false; } } }