ServiceTest2.java [src/csip/test] Revision: 9f8d9f2ecc2cd2580651ae87c22c9a2a4dfcac15 Date: Fri Apr 08 13:28:49 MDT 2016
/*
* $Id$
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* 2010-2013, Olaf David and others, Colorado State University.
*
* CSIP is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1.
*
* CSIP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OMS. If not, see <http://www.gnu.org/licenses/lgpl.txt>.
*/
package csip.test;
import csip.Client;
import csip.ModelDataService;
import csip.utils.JSONUtils;
import csip.utils.Services;
import java.io.File;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import org.apache.commons.io.FileUtils;
import org.apache.http.client.utils.URIBuilder;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.skyscreamer.jsonassert.JSONAssert;
/**
* Service Testing.
*
* @author odavid
*/
public class ServiceTest2 {
static final String KEYSONLY = "keysonly";
static final String STRICT = "strict";
static final String KEYVALUE = "keyvalue";
static final String NONE = "none";
static final List<String> VALIDTESTING = Arrays.asList(KEYSONLY, KEYVALUE, STRICT, NONE);
File folder;
File[] files;
File target;
String testing;
int concurrent = 1;
int timeout = 1000;
int delay = 0;
int rounds = 1;
String contextUrl = null;
boolean downloadFiles = true;
String logLevel = "WARNING";
final JSONArray reports = new JSONArray();
static final Logger log = Logger.getLogger("ServiceTest");
static {
log.setLevel(Level.SEVERE);
SimpleFormatter fmt = new SimpleFormatter();
StreamHandler sh = new StreamHandler(System.out, fmt);
log.addHandler(sh);
}
private ServiceTest2(File target, Properties config) throws Exception {
if (!target.exists()) {
throw new IllegalArgumentException("Not a folder or file: " + target);
}
this.target = target;
if (target.getName().endsWith(".json") && target.isFile()) {
folder = target.getParentFile();
files = new File[]{target};
} else if (target.isDirectory()) {
folder = target;
files = folder.listFiles((File pathname) -> pathname.getName().endsWith(".json"));
Arrays.sort(files);
} else {
throw new IllegalArgumentException("Invalid argument: " + target);
}
// load the service testing settings.
testing = config.getProperty("verify", NONE); // strict, keys
if (!VALIDTESTING.contains(testing)) {
throw new RuntimeException("invalid testing method: " + testing);
}
String d = config.getProperty("contextURL", System.getProperty("csip.test.contexturl"));
if (d != null && !d.equals("${csip.test.contexturl}")) {
contextUrl = d;
}
d = config.getProperty("concurrency", System.getProperty("csip.test.concurrency"));
if (d != null) {
concurrent = Integer.parseInt(d);
}
d = config.getProperty("timeout", System.getProperty("csip.test.timeout"));
if (d != null) {
timeout = Integer.parseInt(d);
}
d = config.getProperty("delay", System.getProperty("csip.test.delay"));
if (d != null) {
delay = Integer.parseInt(d);
}
d = config.getProperty("rounds", System.getProperty("csip.test.rounds"));
if (d != null) {
rounds = Integer.parseInt(d);
}
// warmup phase: 0-off, 1-on
d = config.getProperty("download_files", System.getProperty("csip.test.downloadfiles"));
if (d != null) {
downloadFiles = Boolean.parseBoolean(d);
}
logLevel = config.getProperty("logLevel", "WARNING");
if ((logLevel != null) && (logLevel.length() > 0)) {
log.setLevel(Level.parse(logLevel));
}
}
/**
* Execute the test.
*
* @return
*/
JSONObject test() {
int attempts = 4;
int bq_size = 4;
final Stats stats = new Stats();
for (int i = 0; i < rounds; i++) {
Services.runParallel(files.length, concurrent, attempts, bq_size, new Services.CallableFactory() {
@Override
public Callable create(final int i) {
return (Callable) () -> {
if (delay > 0) {
try {
Thread.sleep(delay);
} catch (InterruptedException ex) {
}
}
JSONObject report = new JSONObject();
JSONObject result = null;
try {
File f = files[i];
JSONObject json = new JSONObject(FileUtils.readFileToString(f));
String url = JSONUtils.getMetaInfo(json).getString("service_url");
if (contextUrl != null) {
url = contextUrl + getServicePath(url);
}
System.out.println(f.getName() + " >>>>>>>>> " + url + " ");
report.put("file", f.toString());
report.put("service", url);
long p = Client.ping(url, timeout);
if (p == -1) {
throw new Exception("Url not reachable.");
}
// System.out.println(req);
// new request
JSONObject req = JSONUtils.newRequest();
JSONObject req_meta = new JSONObject();
if (JSONUtils.getMetaInfo(json).has("request-results")) {
JSONArray a = JSONUtils.getMetaInfo(json).getJSONArray("request-results");
for (int j = 0; j < a.length(); j++) {
req_meta.accumulate("request-results", a.getString(j));
}
}
req.put("parameter", json.getJSONArray("parameter"));
req.put("metainfo", req_meta);
System.out.println("REQ>>>>>>>>>>>>>>>>>>>>>> " + req.toString(4));
Client client = new Client(timeout, log);
JSONObject response = client.doPOST(url, req);
System.out.println("RES>>>>>>>>>>>>>>>>>>>>>> " + response.toString(4));
if (response.has("metainfo")) {
report.put("metainfo", response.getJSONObject("metainfo"));
}
if (!JSONUtils.hasResult(response)) {
throw new Exception("No 'result' in response.");
}
if (JSONUtils.getStatus(response).equals("Failed")) {
JSONObject respose_metainfo = response.getJSONObject("metainfo");
throw new Exception("Failed, " + respose_metainfo.getString("error"));
}
// if (downloadFiles) {
// download(res, getResFolder(reqFile), client);
// }
//
result = runtest(json, response);
report.put("test", result);
stats.incSuccess();
} catch (Exception E) {
try {
report.put("test", E.getMessage());
stats.incFailed();
} catch (JSONException ex) {
Logger.getLogger(ServiceTest2.class.getName()).log(Level.SEVERE, null, ex);
}
} finally {
synchronized (reports) {
reports.put(report);
}
}
return null;
};
}
});
}
JSONObject r = new JSONObject();
try {
r.put("target", target.toString());
r.put("date", new Date());
r.put("total", stats.getTotal());
r.put("successful", stats.getSucceeded());
r.put("failed", stats.getFailed());
r.put("tests", reports);
} catch (JSONException ex) {
ex.printStackTrace();
}
return r;
}
/**
*
*/
static class Stats {
int succeeded;
int failed;
void add(Stats other) {
succeeded += other.getSucceeded();
failed += other.getFailed();
}
public int getTotal() {
return succeeded + failed;
}
public int getFailed() {
return failed;
}
public int getSucceeded() {
return succeeded;
}
synchronized void incSuccess() {
succeeded++;
}
synchronized void incFailed() {
failed++;
}
}
JSONObject runtest(JSONObject golden, JSONObject response) throws Exception {
JSONArray response_result = response.getJSONArray("result");
JSONArray response_golden = golden.getJSONArray("result");
Map<String, JSONObject> rmap = JSONUtils.preprocess(response_result);
Map<String, JSONObject> golmap = JSONUtils.preprocess(response_golden);
for (String key : rmap.keySet()) {
JSONObject val = rmap.get(key);
String url = val.getString("value");
if (url.startsWith("http") && url.endsWith(key)) {
response_result.remove(golmap.get(key));
response_golden.remove(golmap.get(key));
}
}
JSONObject o = new JSONObject();
o.put("testing", testing);
switch (testing) {
case KEYVALUE:
o.put("result", compareKeyValues(response_result, response_golden));
break;
case STRICT:
o.put("result", compareStrict(response_result, response_golden));
break;
case KEYSONLY:
o.put("result", compareKeys(response_result, response_golden));
break;
default:
o.put("result", "unknown testing config: " + testing);
}
return o;
}
// static void download(JSONObject resp, File resultFolder, Client client) throws Exception {
// JSONArray arr = resp.getJSONArray("reports");
// // download files using the 'q' service.
// Map<String, JSONObject> rmap = JSONUtils.preprocess(arr);
// for (String key : rmap.keySet()) {
// JSONObject val = rmap.get(key);
// String url = val.getString("value");
// if (url == null) {
// throw new Exception("Expecting file in reports: " + key);
// }
// if (url.startsWith("http") && url.contains("/q/") && url.endsWith(key)) {
// if (!resultFolder.exists()) {
// resultFolder.mkdirs();
// }
// File outFile = new File(resultFolder, key);
// client.doGET(url, outFile);
// if (!outFile.exists()) {
// throw new Exception("Missing output file: " + key);
// }
// }
// }
// }
static JSONObject compareKeyValues(JSONArray res, JSONArray golden) throws Exception {
Map<String, JSONObject> pres = JSONUtils.preprocess(res);
Map<String, JSONObject> pgol = JSONUtils.preprocess(golden);
JSONObject r = new JSONObject();
for (String name : pgol.keySet()) {
System.out.println(" .... " + name);
if (!pres.containsKey(name)) {
r.accumulate("missing", name);
continue;
}
String resval = pres.get(name).get(ModelDataService.KEY_VALUE).toString();
String golval = pgol.get(name).get("value").toString();
if (resval.startsWith("http:") || resval.startsWith("https:") || resval.startsWith("file:")) {
r.accumulate("ignored", name);
continue;
}
try {
double dgolval = Double.parseDouble(resval);
double dresval = Double.parseDouble(golval);
if (dgolval != dresval) {
r.accumulate("differ", "'" + name + "': " + dgolval + " != " + dresval + " \n");
} else {
r.accumulate("ok", name);
}
} catch (NumberFormatException E) {
if (!golval.equals(resval)) {
r.accumulate("differ", "'" + name + "': '" + golval + "' != '" + resval + "' \n");
} else {
r.accumulate("ok", name);
}
}
}
return r;
}
static JSONObject compareKeys(JSONArray res, JSONArray golden) throws Exception {
JSONObject r = new JSONObject();
Map<String, JSONObject> pres = JSONUtils.preprocess(res);
Map<String, JSONObject> pgol = JSONUtils.preprocess(golden);
for (String key : pgol.keySet()) {
if (!pres.containsKey(key)) {
r.append("missing", key);
}
pres.remove(key);
}
if (!pres.keySet().isEmpty()) {
r.append("extra", pres.keySet().toString());
}
return r;
}
static JSONObject compareStrict(JSONArray res, JSONArray gol) throws Exception {
JSONObject o = new JSONObject();
try {
JSONAssert.assertEquals(gol.toString(), res.toString(), false);
o.put("result", "ok");
return o;
} catch (AssertionError E) {
o.put("differ", E.getMessage());
}
return o;
}
public static JSONArray run(Properties p, String... targets) throws Exception {
JSONArray summary = new JSONArray();
for (String target : targets) {
JSONObject result = new ServiceTest2(new File(target), p).test();
summary.put(result);
}
return summary;
}
static String getServicePath(String url) throws URISyntaxException {
// URIBuilder b = new URIBuilder("http://localhost:8080/csip-example/m/simpleservice/2.0");
URIBuilder b = new URIBuilder(url);
return b.getPath().substring(b.getPath().indexOf('/', 1));
}
public static void main(String[] args) throws Exception {
//// args = new String[]{"/od/projects/csip-all/csip-example/test/service_tests/all"};
// args = new String[]{"/od/tmp/csip-testing"};
// Properties config = new Properties();
// config.setProperty("concurrency", "1");
// config.setProperty("verify", "keyvalue");
//// config.setProperty("rounds", "3");
//// config.setProperty("delay", "3000");
// System.out.println(run(config, args).toString(4).replace("\\/", "/"));
}
}