requests-simulator

extended syntax. added variables inside properties, process

3/2/2019 4:15:01 PM

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/LogExecutor.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/LogExecutor.java
index 4309215..dfde57c 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/LogExecutor.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/LogExecutor.java
@@ -5,6 +5,7 @@
  */
 package br.ufrgs.inf.prosoft.requestssimulator;
 
+import br.ufrgs.inf.prosoft.requestssimulator.requests.DeleteRequest;
 import br.ufrgs.inf.prosoft.requestssimulator.requests.GetRequest;
 import br.ufrgs.inf.prosoft.requestssimulator.requests.PostRequest;
 import br.ufrgs.inf.prosoft.requestssimulator.requests.MultipartRequest;
@@ -60,6 +61,8 @@ public class LogExecutor {
                         Request request;
                         if (requestPlan.getMethod().equals("GET")) {
                             request = gson.fromJson(jsonObject, GetRequest.class);
+                        } else if (requestPlan.getMethod().equals("DELETE")) {
+                            request = gson.fromJson(jsonObject, DeleteRequest.class);
                         } else {
                             JsonElement headers = jsonObject.get("headers");
                             if (headers != null && headers.getAsString().contains("multipart")) {
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java
index e7af81d..7cf014f 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/ProfileReader.java
@@ -7,7 +7,6 @@ package br.ufrgs.inf.prosoft.requestssimulator;
 
 import br.ufrgs.inf.prosoft.requestssimulator.requests.RequestPlan;
 import com.google.gson.Gson;
-import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/DeleteRequest.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/DeleteRequest.java
index 00486d7..d3ca315 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/DeleteRequest.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/DeleteRequest.java
@@ -12,6 +12,7 @@ import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Collection;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
@@ -30,6 +31,10 @@ public class DeleteRequest extends Request {
         super(requestPlan, session, URL, headers);
     }
 
+    protected DeleteRequest(RequestPlan requestPlan, Session session, String URL, String headers, Collection<String> storeFields) {
+        super(requestPlan, session, URL, headers, storeFields);
+    }
+
     @Override
     public void fireRequest() {
         HttpURLConnection httpURLConnection = null;
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java
index 48b47d8..5ff0844 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/GetRequest.java
@@ -12,6 +12,7 @@ import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Collection;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
@@ -30,6 +31,10 @@ public class GetRequest extends Request {
         super(requestPlan, session, URL, headers);
     }
 
+    protected GetRequest(RequestPlan requestPlan, Session session, String URL, String headers, Collection<String> storeFields) {
+        super(requestPlan, session, URL, headers, storeFields);
+    }
+
     @Override
     public void fireRequest() {
         HttpURLConnection httpURLConnection = null;
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java
index ad1357e..600699c 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/MultipartRequest.java
@@ -10,6 +10,7 @@ import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.logging.Level;
@@ -41,6 +42,11 @@ public class MultipartRequest extends Request {
         this.forms = forms;
     }
 
+    protected MultipartRequest(RequestPlan requestPlan, Session session, String URL, String headers, String forms, Collection<String> storeFields) {
+        super(requestPlan, session, URL, headers, storeFields);
+        this.forms = forms;
+    }
+
     protected String getForms() {
         return this.forms;
     }
@@ -68,7 +74,7 @@ public class MultipartRequest extends Request {
                     File file = new File(entry.getValue());
                     multipartEntityBuilder.addBinaryBody(entry.getKey(), file);
                 } else {
-                    multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue());
+                    multipartEntityBuilder.addTextBody(entry.getKey(), fillPropertyVariable(entry.getValue()));
                 }
             });
             HttpEntity httpEntity = multipartEntityBuilder.build();
@@ -80,7 +86,7 @@ public class MultipartRequest extends Request {
             try (CloseableHttpResponse closeableHttpResponse = httpClient.execute(httpPost)) {
                 int responseCode = closeableHttpResponse.getStatusLine().getStatusCode();
                 if (responseCode < 400) {
-                Logger.getGlobal().log(Level.INFO, "{0} on {1} {2}", new Object[]{responseCode, getMethod(), stringURL});
+                    Logger.getGlobal().log(Level.INFO, "{0} on {1} {2}", new Object[]{responseCode, getMethod(), stringURL});
                     try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(closeableHttpResponse.getEntity().getContent()))) {
                         String response = bufferedReader.lines().collect(Collectors.joining());
                         processResponse(response);
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java
index 43bb371..7ab2cbf 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/PostRequest.java
@@ -13,6 +13,7 @@ import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Collection;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
@@ -35,6 +36,11 @@ public class PostRequest extends Request {
         this.data = data;
     }
 
+    protected PostRequest(RequestPlan requestPlan, Session session, String URL, String data, String headers, Collection<String> storeFields) {
+        super(requestPlan, session, URL, headers, storeFields);
+        this.data = data;
+    }
+
     protected String getData() {
         return this.data;
     }
@@ -54,7 +60,8 @@ public class PostRequest extends Request {
             });
             connection.setDoOutput(true);
             try (OutputStream outputStream = connection.getOutputStream()) {
-                outputStream.write(this.data.getBytes());
+                String data = fillPropertyVariable(this.data);
+                outputStream.write(data.getBytes());
             }
             int responseCode = connection.getResponseCode();
             if (responseCode < 400) {
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java
index c936610..d89a717 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/Request.java
@@ -6,14 +6,19 @@
 package br.ufrgs.inf.prosoft.requestssimulator.requests;
 
 import br.ufrgs.inf.prosoft.requestssimulator.Session;
+import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.function.Consumer;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
 /**
@@ -25,6 +30,7 @@ public abstract class Request {
     private final RequestPlan requestPlan;
     private final String URL;
     private final String headers;
+    private final Collection<String> storeFields;
     private final Session session;
 
     protected Request(RequestPlan requestPlan, Session session, String URL) {
@@ -32,6 +38,15 @@ public abstract class Request {
         this.session = session;
         this.URL = URL;
         this.headers = null;
+        this.storeFields = null;
+    }
+
+    protected Request(RequestPlan requestPlan, Session session, String URL, Collection<String> storeFields) {
+        this.requestPlan = requestPlan;
+        this.session = session;
+        this.URL = URL;
+        this.headers = null;
+        this.storeFields = storeFields;
     }
 
     protected Request(RequestPlan requestPlan, Session session, String URL, String headers) {
@@ -39,6 +54,15 @@ public abstract class Request {
         this.session = session;
         this.URL = URL;
         this.headers = headers;
+        this.storeFields = null;
+    }
+
+    protected Request(RequestPlan requestPlan, Session session, String URL, String headers, Collection<String> storeFields) {
+        this.requestPlan = requestPlan;
+        this.session = session;
+        this.URL = URL;
+        this.headers = headers;
+        this.storeFields = storeFields;
     }
 
     public String getMethod() {
@@ -69,6 +93,17 @@ public abstract class Request {
         return headers.entrySet().stream();
     }
 
+    protected Collection<String> getStoreFields() {
+        return storeFields;
+    }
+
+    private Stream<String> storeFields() {
+        if (this.storeFields == null || this.storeFields.isEmpty()) {
+            return Stream.empty();
+        }
+        return this.storeFields.stream();
+    }
+
     public Request pickNextRequest(Session session) {
         return this.requestPlan.pickNextRequest(session);
     }
@@ -78,36 +113,102 @@ public abstract class Request {
             Logger.getGlobal().log(Level.SEVERE, "empty response");
             return;
         }
-        this.requestPlan.storeFields().forEach(new Consumer<String>() {
+        storeFields().forEach(new Consumer<String>() {
 
             private final JsonParser jsonParser;
-            private final JsonObject jsonObject;
+            private final JsonElement jsonElement;
 
             {
                 this.jsonParser = new JsonParser();
-                JsonElement jsonElement = this.jsonParser.parse(response);
-                if (jsonElement.isJsonObject()) {
-                    this.jsonObject = this.jsonParser.parse(response).getAsJsonObject();
-                } else {
-                    this.jsonObject = null;
+                this.jsonElement = this.jsonParser.parse(response);
+            }
+
+            class Tokenizer {
+
+                private int index;
+                private final String string;
+
+                public Tokenizer(String string) {
+                    this.index = 0;
+                    this.string = string;
+                }
+
+                private String getNextToken() {
+                    if (!hasMoreTokens()) {
+                        return null;
+                    }
+                    StringBuilder nextToken = new StringBuilder();
+                    while (true) {
+                        char nextChar = this.string.charAt(this.index);
+                        this.index++;
+                        nextToken.append(nextChar);
+                        if (nextChar == ']') {
+                            break;
+                        }
+                        if (this.index == this.string.length()) {
+                            break;
+                        }
+                        char futureChar = this.string.charAt(this.index);
+                        if (futureChar == '#' || futureChar == '[') {
+                            break;
+                        }
+                    }
+                    return nextToken.toString();
+                }
+
+                protected boolean hasMoreTokens() {
+                    if (this.string == null) {
+                        return false;
+                    }
+                    if (this.string.isEmpty()) {
+                        return false;
+                    }
+                    return this.index < string.length();
                 }
             }
 
             @Override
             public void accept(String storeField) {
-                String[] storeSequence = storeField.split("#");
-                JsonObject jsonObject = this.jsonObject;
-                JsonElement jsonElement = null;
-
-                for (String storeLevel : storeSequence) {
-                    jsonElement = jsonObject.get(storeLevel);
+                String tokenVariable;
+                if (storeField.contains("@")) {
+                    tokenVariable = storeField.split("@")[1];
+                } else {
+                    tokenVariable = storeField;
+                }
+                Tokenizer tokenizer = new Tokenizer(tokenVariable);
+                JsonElement jsonElement = this.jsonElement;
+                while (tokenizer.hasMoreTokens()) {
+                    String nextToken = tokenizer.getNextToken();
+                    if (nextToken.charAt(0) == '[') {
+                        try {
+                            Integer index = Integer.valueOf(nextToken.substring(1, nextToken.length() - 1));
+                            JsonArray jsonArray = jsonElement.getAsJsonArray();
+                            if (index >= jsonArray.size()) {
+                                Logger.getGlobal().log(Level.SEVERE, "index error {0}", storeField);
+                                return;
+                            }
+                            jsonElement = jsonArray.get(index);
+                        } catch (NumberFormatException ex) {
+                            Logger.getGlobal().log(Level.SEVERE, "NumberFormatException {0}", storeField);
+                            return;
+                        }
+                    } else {
+                        if (nextToken.charAt(0) == '#') {
+                            nextToken = nextToken.substring(1, nextToken.length());
+                        }
+                        JsonObject jsonObject = jsonElement.getAsJsonObject();
+                        jsonElement = jsonObject.get(nextToken);
+                    }
                     if (jsonElement == null) {
                         Logger.getGlobal().log(Level.SEVERE, "field {0} not present", storeField);
                         return;
                     }
-                    if (jsonElement.isJsonObject()) {
-                        jsonObject = jsonElement.getAsJsonObject();
-                    }
+                }
+                Pattern pattern = Pattern.compile("#\\[(.*?)\\]");
+                Matcher matcher = pattern.matcher(storeField);
+                while (matcher.find()) {
+                    String found = matcher.group();
+                    storeField = storeField.replace(found, "[$]");
                 }
                 String storedValue = jsonElement.getAsString();
                 storeValue(storeField, storedValue);
@@ -122,13 +223,21 @@ public abstract class Request {
 
     protected String fillPropertyVariable(String property) {
         String filledProperty = property;
-        if (filledProperty.contains("#")) {
-            String storedField = filledProperty.substring(filledProperty.indexOf("#") + 1);
-            String storedValue = this.session.getStoredValue(storedField);
-            if (storedValue == null) {
-                Logger.getGlobal().log(Level.SEVERE, "variable {0} not stored", property);
-            } else {
-                filledProperty = filledProperty.replace("#" + storedField, storedValue);
+        if (filledProperty.contains("#{")) {
+            Collection<String> matches = new ArrayList<>();
+            Pattern pattern = Pattern.compile("#\\{(.*?)\\}");
+            Matcher matcher = pattern.matcher(property);
+            while (matcher.find()) {
+                matches.add(matcher.group());
+            }
+            for (String storedField : matches) {
+                String fieldName = storedField.substring(2, storedField.length() - 1);
+                String storedValue = this.session.getStoredValue(fieldName);
+                if (storedValue == null) {
+                    Logger.getGlobal().log(Level.SEVERE, "variable {0} not stored", storedField);
+                    continue;
+                }
+                filledProperty = filledProperty.replace(storedField, storedValue);
             }
         }
         return filledProperty;
@@ -152,6 +261,13 @@ public abstract class Request {
         jsonObject.addProperty("reference", this.requestPlan.getReference());
         jsonObject.addProperty("URL", getURL());
         jsonObject.addProperty("headers", getHeaders());
+        if (storeFields().count() > 0) {
+            JsonArray storeFields = new JsonArray();
+            storeFields().forEach(storeField -> {
+                storeFields.add(storeField);
+            });
+            jsonObject.add("storeFields", storeFields);
+        }
         if (this instanceof PostRequest) {
             PostRequest postRequest = (PostRequest) this;
             jsonObject.addProperty("data", postRequest.getData());
diff --git a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java
index e36c1b6..b889e5b 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/requestssimulator/requests/RequestPlan.java
@@ -11,6 +11,9 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.Random;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
@@ -22,8 +25,8 @@ public class RequestPlan {
     private final String method;
     private final String URL;
     private final String data;
-    private List<RequestPlan> getLinks;
-    private List<RequestPlan> postLinks;
+    private List<RequestPlan> readLinks;
+    private List<RequestPlan> writeLinks;
     private Collection<String> storeFields;
     private Collection<RequestPlan> requirements;
     private String headers;
@@ -92,29 +95,29 @@ public class RequestPlan {
     }
 
     public Stream<RequestPlan> links() {
-        if (this.getLinks == null && this.postLinks == null) {
+        if (this.readLinks == null && this.writeLinks == null) {
             return Stream.empty();
         }
-        if (this.getLinks != null && this.postLinks != null) {
-            return Stream.concat(this.getLinks.stream(), this.postLinks.stream());
+        if (this.readLinks != null && this.writeLinks != null) {
+            return Stream.concat(this.readLinks.stream(), this.writeLinks.stream());
         }
-        if (this.getLinks != null) {
-            return this.getLinks.stream();
+        if (this.readLinks != null) {
+            return this.readLinks.stream();
         }
-        return this.postLinks.stream();
+        return this.writeLinks.stream();
     }
 
     public RequestPlan addLink(RequestPlan requestPlan) {
         if (requestPlan.getMethod().equals("GET")) {
-            if (this.getLinks == null) {
-                this.getLinks = new ArrayList<>();
+            if (this.readLinks == null) {
+                this.readLinks = new ArrayList<>();
             }
-            this.getLinks.add(requestPlan);
+            this.readLinks.add(requestPlan);
         } else {
-            if (this.postLinks == null) {
-                this.postLinks = new ArrayList<>();
+            if (this.writeLinks == null) {
+                this.writeLinks = new ArrayList<>();
             }
-            this.postLinks.add(requestPlan);
+            this.writeLinks.add(requestPlan);
         }
         return this;
     }
@@ -149,21 +152,21 @@ public class RequestPlan {
     public Request pickNextRequest(Session session) {
         Random random = new Random();
         int probability = random.nextInt(100);
-        if ((this.getLinks == null || this.getLinks.isEmpty()) && (this.postLinks == null || this.postLinks.isEmpty())) {
+        if ((this.readLinks == null || this.readLinks.isEmpty()) && (this.writeLinks == null || this.writeLinks.isEmpty())) {
             throw new RuntimeException("GET and POST links empty");
         }
         RequestPlan chosen;
-        if (this.getLinks == null || this.getLinks.isEmpty()) {
+        if (this.readLinks == null || this.readLinks.isEmpty()) {
             probability = 100;
-        } else if (this.postLinks == null || this.postLinks.isEmpty()) {
+        } else if (this.writeLinks == null || this.writeLinks.isEmpty()) {
             probability = 0;
         }
         if (probability < 80) {
-            int chosenIndex = random.nextInt(this.getLinks.size());
-            chosen = this.getLinks.get(chosenIndex);
+            int chosenIndex = random.nextInt(this.readLinks.size());
+            chosen = this.readLinks.get(chosenIndex);
         } else {
-            int chosenIndex = random.nextInt(this.postLinks.size());
-            chosen = this.postLinks.get(chosenIndex);
+            int chosenIndex = random.nextInt(this.writeLinks.size());
+            chosen = this.writeLinks.get(chosenIndex);
         }
         return chosen.build(session);
     }
@@ -175,31 +178,50 @@ public class RequestPlan {
             throw new RuntimeException("URL is empty");
         }
         String URL = this.URL.replace("$", String.valueOf(randomInt));
+        Pattern pattern = Pattern.compile("#\\{(.*?)\\}");
+        Matcher originalMatcher = pattern.matcher(this.URL);
+        Matcher randomMatcher = pattern.matcher(URL);
+        while (originalMatcher.find() && randomMatcher.find()) {
+            String originalFound = originalMatcher.group();
+            String randomFound = randomMatcher.group();
+            URL = URL.replace(randomFound, originalFound);
+        }
+        Collection<String> storeFields = storeFields()
+                .map(storeField -> storeField.replace("$", String.valueOf(randomInt)))
+                .collect(Collectors.toList());
         String headers = null;
         if (this.headers != null) {
             headers = this.headers.replace("$", String.valueOf(randomInt));
             if (this.headers.contains("multipart")) {
                 String forms = this.forms;
-                return new MultipartRequest(this, session, URL, headers, forms);
+                return new MultipartRequest(this, session, URL, headers, forms, storeFields);
             }
         }
+        if (this.method.equals("DELETE")) {
+            return new DeleteRequest(this, session, URL, headers, storeFields);
+        }
         if (this.method.equals("GET")) {
-            return new GetRequest(this, session, URL, headers);
+            return new GetRequest(this, session, URL, headers, storeFields);
         }
         String data = this.data.replace("$", String.valueOf(randomInt));;
-        return new PostRequest(this, session, URL, data, headers);
+        return new PostRequest(this, session, URL, data, headers, storeFields);
     }
 
     public Request bind(Request request, Session session) {
+        if (request instanceof DeleteRequest) {
+            DeleteRequest deleteRequest = (DeleteRequest) request;
+            return new DeleteRequest(this, session, deleteRequest.getURL(), deleteRequest.getHeaders(), deleteRequest.getStoreFields());
+        }
         if (request instanceof GetRequest) {
-            return new GetRequest(this, session, request.getURL(), request.getHeaders());
+            GetRequest getRequest = (GetRequest) request;
+            return new GetRequest(this, session, getRequest.getURL(), getRequest.getHeaders(), getRequest.getStoreFields());
         }
         if (request instanceof PostRequest) {
             PostRequest postRequest = (PostRequest) request;
-            return new PostRequest(this, session, postRequest.getURL(), postRequest.getData(), postRequest.getHeaders());
+            return new PostRequest(this, session, postRequest.getURL(), postRequest.getData(), postRequest.getHeaders(), postRequest.getStoreFields());
         }
         MultipartRequest multipartRequest = (MultipartRequest) request;
-        return new MultipartRequest(this, session, multipartRequest.getURL(), multipartRequest.getHeaders(), multipartRequest.getForms());
+        return new MultipartRequest(this, session, multipartRequest.getURL(), multipartRequest.getHeaders(), multipartRequest.getForms(), multipartRequest.getStoreFields());
     }
 
     @Override