chromedriver working, verbs alpha

This commit is contained in:
Jonathan Shook 2020-04-15 09:37:47 -05:00
parent 42a3a2f0af
commit 281542f42e
73 changed files with 1490 additions and 67 deletions

View File

@ -0,0 +1,16 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="NBCLI web foreground dryrun" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="io.nosqlbench.engine.cli.NBCLI" />
<module name="nb" />
<option name="PROGRAM_PARAMETERS" value="run type=webdriver yaml=local/webtest cycles=1000 cyclerate=100 threads=1 dryrun=true -vv" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="io.nosqlbench.engine.cli.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -157,7 +157,7 @@ public class StdoutActivity extends SimpleActivity implements ActivityDefObserve
StringBindingsTemplate sbt = new StringBindingsTemplate(stmt.getStmt(), bt);
StringBindings sb = sbt.resolve();
sequencer.addOp(sb,Long.valueOf(stmt.getParams().getOrDefault("ratio","1")));
sequencer.addOp(sb,Long.parseLong(stmt.getParams().getOrDefault("ratio","1")));
}
} else {
logger.error("Unable to create a stdout statement if you have no active statements or bindings configured.");

View File

@ -1,12 +0,0 @@
package io.nosqlbench.driver.web;
import io.nosqlbench.engine.api.activityapi.core.ActivityType;
public class NBWebDriver implements ActivityType<WebDriverActivity> {
@Override
public String getName() {
return null;
}
}

View File

@ -1,30 +0,0 @@
package io.nosqlbench.driver.web;
import io.nosqlbench.engine.api.activityapi.core.BaseAsyncAction;
import io.nosqlbench.engine.api.activityapi.core.ops.fluent.opfacets.TrackedOp;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.function.LongFunction;
/**
* Holds the definition and tracking state for a web driver command.
*/
public class WebDriverAction extends BaseAsyncAction<WebDriverCmdState,WebDriverActivity> {
public WebDriverAction(WebDriverActivity activity, int slot) {
super(activity,slot);
}
@Override
public void startOpCycle(TrackedOp<WebDriverCmdState> opc) {
// WebDriver driver = new ChromeDriver();
// driver.get("http://docs.nosqlbench.io/");
// opc.start();
}
@Override
public LongFunction<WebDriverCmdState> getOpInitFunction() {
return (cycle) -> new WebDriverCmdState(this,cycle);
}
}

View File

@ -1,12 +0,0 @@
package io.nosqlbench.driver.web;
import io.nosqlbench.engine.api.activityimpl.ActivityDef;
import io.nosqlbench.engine.api.activityimpl.SimpleActivity;
public class WebDriverActivity extends SimpleActivity{
public WebDriverActivity(ActivityDef activityDef) {
super(activityDef);
}
}

View File

@ -0,0 +1,56 @@
package io.nosqlbench.driver.webdriver;
import io.nosqlbench.engine.api.activityconfig.yaml.StmtDef;
import io.nosqlbench.engine.api.activityimpl.motor.ParamsParser;
import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.virtdata.core.bindings.BindingsTemplate;
import io.nosqlbench.virtdata.core.templates.ParsedTemplate;
import io.nosqlbench.virtdata.core.templates.StringBindings;
import io.nosqlbench.virtdata.core.templates.StringBindingsTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.InvalidParameterException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Use the {@link StmtDef} template form as a property template for parameterized
* commands. This is a general purpose template which uses a map of named parameters.
* The {@code command} property designates the verb component of the command.
*/
public class CommandTemplate {
private final static Logger logger = LoggerFactory.getLogger(CommandTemplate.class);
private LinkedHashMap<String, StringBindings> cmdspec = new LinkedHashMap<>();
public CommandTemplate(StmtDef stmt) {
Map<String,String> cmdMap = ParamsParser.parse("command="+stmt.getStmt());
Map<String, String> paramsMap = stmt.getParams();
paramsMap.forEach((k,v) -> {
if (cmdMap.containsKey(k)) {
logger.warn("command property override: '" + k + "' superseded by param form with value '" + v + "'");
}
cmdMap.put(k,v);
});
cmdMap.forEach((param,value) -> {
ParsedTemplate paramTemplate = new ParsedTemplate(value, stmt.getBindings());
BindingsTemplate paramBindings = new BindingsTemplate(paramTemplate.getBindPoints());
StringBindings paramStringBindings = new StringBindingsTemplate(value, paramBindings).resolve();
cmdspec.put(param,paramStringBindings);
});
}
public Map<String,String> getCommand(long cycle) {
LinkedHashMap<String, String> cmd = new LinkedHashMap<>(cmdspec.size());
cmdspec.forEach((k,v) -> {
cmd.put(k,v.bind(cycle));
});
return cmd;
}
}

View File

@ -0,0 +1,93 @@
package io.nosqlbench.driver.webdriver;
import org.openqa.selenium.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
public class WebContext {
private final static Logger logger = LoggerFactory.getLogger(WebContext.class);
private final WebDriver rootwindow;
WebDriver focus;
LinkedList<WebElement> elements = new LinkedList<>();
private LinkedList<Cookie> cookies = new LinkedList<>();
private HashMap<String,Object> vars = new HashMap<>();
private Alert alert;
public WebContext(WebDriver initial) {
this.focus = initial;
this.rootwindow = initial;
}
public void pushElement(WebElement element) {
elements.push(element);
}
public WebElement peekElement() {
return elements.peek();
}
public LinkedList<Cookie> getCookies() {
return cookies;
}
public LinkedList<WebElement> getElements() {
return elements;
}
public void setElements(List<WebElement> elements) {
this.elements.clear();
this.elements.addAll(elements);
}
public void pushCookie(Cookie cookie) {
this.cookies.push(cookie);
}
public void setCookies(Collection<Cookie> cookies) {
this.cookies.clear();
this.cookies.addAll(cookies);
}
public void setAlert(Alert alert) {
this.alert = alert;
}
public Alert getAlert() {
return alert;
}
public WebDriver driver() {
return focus;
}
public void setFocus(WebDriver driver) {
this.focus =driver;
}
public void clearAlert() {
this.alert=null;
}
public void setVar(String key, Object value) {
this.vars.put(key,value);
logger.debug("context vars: '" + key + "'='" + value.toString() + "'");
}
public <T> T getVar(String name, Class<? extends T> type) {
Object o = this.vars.get(name);
if (o==null) { return null; }
if (type.isAssignableFrom(o.getClass())) {
return type.cast(o);
}
throw new RuntimeException("Could not cast named var '" + name + "' to a " + type.getCanonicalName());
}
}

View File

@ -0,0 +1,54 @@
package io.nosqlbench.driver.webdriver;
import io.nosqlbench.driver.webdriver.verbs.WebDriverVerbs;
import io.nosqlbench.engine.api.activityapi.core.ActivityDefObserver;
import io.nosqlbench.engine.api.activityapi.core.SyncAction;
import io.nosqlbench.engine.api.activityimpl.ActivityDef;
import org.openqa.selenium.WebDriver;
/**
* Holds the definition and tracking state for a web driver command.
*/
public class WebDriverAction implements SyncAction, ActivityDefObserver {
private final WebDriverActivity activity;
private final int slot;
// warn or count, or stop
private String errors;
private boolean dryrun;
private WebContext context;
public WebDriverAction(WebDriverActivity activity, int slot) {
super();
this.activity = activity;
this.slot = slot;
}
@Override
public void init() {
onActivityDefUpdate(activity.getActivityDef());
}
@Override
public void onActivityDefUpdate(ActivityDef activityDef) {
this.errors = activityDef.getParams().getOptionalString("errors").orElse("stop");
this.dryrun = activityDef.getParams().getOptionalBoolean("dryrun").orElse(false);
this.context = activity.getWebContext(slot);
}
// TODO: resolve inner templates early, perhaps optionally
// As it is right now, all commands are resolved dynamically, which is still not going to be the limiting
// factor.
@Override
public int runCycle(long value) {
try {
CommandTemplate commandTemplate = activity.getOpSequence().get(value);
WebDriverVerbs.execute(value, commandTemplate, context, dryrun);
return 0;
} catch (Exception e) {
return 1;
}
}
}

View File

@ -0,0 +1,101 @@
package io.nosqlbench.driver.webdriver;
import io.nosqlbench.engine.api.activityapi.planning.OpSequence;
import io.nosqlbench.engine.api.activityapi.planning.SequencePlanner;
import io.nosqlbench.engine.api.activityapi.planning.SequencerType;
import io.nosqlbench.engine.api.activityconfig.StatementsLoader;
import io.nosqlbench.engine.api.activityconfig.yaml.StmtDef;
import io.nosqlbench.engine.api.activityconfig.yaml.StmtsDocList;
import io.nosqlbench.engine.api.activityimpl.ActivityDef;
import io.nosqlbench.engine.api.activityimpl.SimpleActivity;
import io.nosqlbench.engine.api.templating.StrInterpolator;
import io.nosqlbench.nb.api.errors.BasicError;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
public class WebDriverActivity extends SimpleActivity {
private final static Logger logger = LoggerFactory.getLogger(WebDriverActivity.class);
private final StmtsDocList stmtsDocList;
private OpSequence<CommandTemplate> opSequence;
private static ThreadLocal<WebContext> TL_WebContext = new ThreadLocal<>();
private ConcurrentHashMap<Integer,WebContext> contexts = new ConcurrentHashMap<>();
public WebDriverActivity(ActivityDef activityDef) {
super(activityDef);
StrInterpolator interp = new StrInterpolator(activityDef);
String yaml_loc = activityDef.getParams().getOptionalString("yaml", "workload").orElse("default");
this.stmtsDocList = StatementsLoader.load(logger, yaml_loc, interp, "activities");
}
@Override
public void initActivity() {
super.initActivity();
this.opSequence = initOpSequence();
onActivityDefUpdate(activityDef);
}
private OpSequence<CommandTemplate> initOpSequence() {
SequencerType sequencerType = getParams()
.getOptionalString("seq")
.map(SequencerType::valueOf)
.orElse(SequencerType.bucket);
SequencePlanner<CommandTemplate> planner = new SequencePlanner<>(sequencerType);
String tagfilter = activityDef.getParams().getOptionalString("tags").orElse("");
List<StmtDef> stmts = stmtsDocList.getStmts(tagfilter);
if (stmts.size() == 0) {
throw new BasicError("There were no active statements with tag filter '" + tagfilter + "'");
}
for (StmtDef optemplate : stmts) {
long ratio = Long.parseLong(optemplate.getParams().getOrDefault("ratio", "1"));
CommandTemplate cmd = new CommandTemplate(optemplate);
planner.addOp(cmd, ratio);
}
return planner.resolve();
}
public OpSequence<CommandTemplate> getOpSequence() {
return opSequence;
}
public synchronized WebContext getWebContext(int slot) {
try {
WebContext context = TL_WebContext.get();
if (context == null) {
logger.info("initializing chromedriver for thread " + slot);
System.setProperty("webdriver.http.factory", "okhttp");
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setHeadless(activityDef.getParams().getOptionalBoolean("headless").orElse(false));
WebDriver webdriver = new ChromeDriver(chromeOptions);
context = new WebContext(webdriver);
contexts.put(slot,context);
TL_WebContext.set(context);
} else {
logger.info("using cached chromedriver for thread " + slot);
}
return context;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void shutdownActivity() {
contexts.forEach((s, d) -> {
logger.debug("closing driver for thread " + s);
d.driver().quit();
});
}
}

View File

@ -1,4 +1,4 @@
package io.nosqlbench.driver.web;
package io.nosqlbench.driver.webdriver;
import io.nosqlbench.engine.api.activityapi.core.Action;
import io.nosqlbench.engine.api.activityapi.core.ActionDispenser;

View File

@ -1,4 +1,4 @@
package io.nosqlbench.driver.web;
package io.nosqlbench.driver.webdriver;
public class WebDriverCmdState {

View File

@ -0,0 +1,21 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Alert;
import java.security.InvalidParameterException;
public class AcceptAlert implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Alert alert = context.getAlert();
if (alert==null) {
alert = context.driver().switchTo().alert();
}
if (alert==null) {
throw new InvalidParameterException("Alert is not present");
}
alert.accept();
context.clearAlert();
}
}

View File

@ -0,0 +1,18 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Cookie;
public class AddCookie implements WebDriverVerb {
private final Cookie cookie;
public AddCookie(Cookie cookie) {
this.cookie = cookie;
}
@Override
public void execute(WebContext context) {
context.driver().manage().addCookie(this.cookie);
}
}

View File

@ -0,0 +1,26 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import io.nosqlbench.nb.api.errors.BasicError;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AssertElement implements WebDriverVerb {
private final static Logger logger = LoggerFactory.getLogger(AssertElement.class);
private final By by;
public AssertElement(By by) {
this.by = by;
}
@Override
public void execute(WebContext context) {
WebElement element = context.driver().findElement(by);
context.pushElement(element);
}
}

View File

@ -0,0 +1,31 @@
package io.nosqlbench.driver.webdriver.verbs;
import org.openqa.selenium.By;
import java.util.function.Function;
public enum Bys {
id(By::id),
link(By::linkText),
name(By::name),
css(By::cssSelector),
xpath(By::xpath),
classname(By::className);
private Function<String, By> initializer;
Bys(Function<String,By> initializer) {
this.initializer = initializer;
}
public static By get(String by) {
Bys bys =classname;
String[] parts = by.split("=", 2);
if (parts.length==2) {
bys= Bys.valueOf(parts[0]);
by = parts[1];
}
return bys.initializer.apply(by);
}
}

View File

@ -0,0 +1,10 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class ClearElement implements WebDriverVerb {
@Override
public void execute(WebContext context) {
context.peekElement().clear();
}
}

View File

@ -0,0 +1,17 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.By;
public class ClearElementBy implements WebDriverVerb {
private final By by;
public ClearElementBy(By by) {
this.by = by;
}
@Override
public void execute(WebContext context) {
context.peekElement().findElement(by).clear();
}
}

View File

@ -0,0 +1,18 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.By;
public class ClickElementBy implements WebDriverVerb {
private final By by;
public ClickElementBy(By by){
this.by = by;
}
@Override
public void execute(WebContext context) {
context.driver().findElement(by).click();
}
}

View File

@ -0,0 +1,22 @@
package io.nosqlbench.driver.webdriver.verbs;
import org.openqa.selenium.Cookie;
import java.sql.Date;
import java.util.Map;
import java.util.Optional;
public class CookieJar {
public static Cookie cookie(Map<String,String> props) {
String name = props.get("name");
String value = props.getOrDefault("value","");
Cookie.Builder builder = new Cookie.Builder(name, value);
Optional.ofNullable(props.get("domain")).ifPresent(builder::domain);
Optional.ofNullable(props.get("expiry")).map(Date::valueOf).ifPresent(builder::expiresOn);
Optional.ofNullable(props.get("ishttponly")).map(Boolean::valueOf).ifPresent(builder::isHttpOnly);
Optional.ofNullable(props.get("issecure")).map(Boolean::valueOf).ifPresent(builder::isSecure);
Optional.ofNullable(props.get("path")).ifPresent(builder::path);
return builder.build();
}
}

View File

@ -0,0 +1,11 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class DeleteAllCookies implements WebDriverVerb {
@Override
public void execute(WebContext context) {
context.driver().manage().deleteAllCookies();
}
}

View File

@ -0,0 +1,18 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Cookie;
public class DeleteCookie implements WebDriverVerb {
private final Cookie cookie;
public DeleteCookie(Cookie cookie) {
this.cookie = cookie;
}
@Override
public void execute(WebContext context) {
context.driver().manage().deleteCookie(cookie);
}
}

View File

@ -0,0 +1,17 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class DeleteCookieNamed implements WebDriverVerb {
private final String cookieName;
public DeleteCookieNamed(String cookieName) {
this.cookieName = cookieName;
}
@Override
public void execute(WebContext context) {
context.driver().manage().deleteCookieNamed(cookieName);
}
}

View File

@ -0,0 +1,21 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Alert;
import java.security.InvalidParameterException;
public class DismissAlert implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Alert alert = context.getAlert();
if (alert==null) {
alert = context.driver().switchTo().alert();
}
if (alert==null) {
throw new InvalidParameterException("Alert is not present");
}
alert.dismiss();
context.clearAlert();
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.OutputType;
public class ElementScreenShot implements WebDriverVerb {
@Override
public void execute(WebContext context) {
String screenshotAs = context.peekElement().getScreenshotAs(OutputType.BASE64);
// This needs more work
}
}

View File

@ -0,0 +1,16 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class ElementSendKeys implements WebDriverVerb {
private final CharSequence keys;
public ElementSendKeys(CharSequence keys) {
this.keys = keys;
}
@Override
public void execute(WebContext context) {
context.peekElement().sendKeys(keys);
}
}

View File

@ -0,0 +1,10 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class ElementSubmit implements WebDriverVerb {
@Override
public void execute(WebContext context) {
context.peekElement().submit();
}
}

View File

@ -0,0 +1,30 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FindElement implements WebDriverVerb {
private final static Logger logger = LoggerFactory.getLogger(FindElement.class);
private final By by;
public FindElement(String by) {
this.by = Bys.get(by);
}
@Override
public void execute(WebContext context) {
try {
WebElement element = context.driver().findElement(by);
context.pushElement(element);
} catch (NoSuchElementException nsee) {
context.pushElement(null);
}
}
}

View File

@ -0,0 +1,19 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
public class FindElementInElementBy implements WebDriverVerb {
private final By by;
public FindElementInElementBy(By by) {
this.by = by;
}
@Override
public void execute(WebContext context) {
WebElement element = context.peekElement().findElement(by);
context.pushElement(element);
}
}

View File

@ -0,0 +1,32 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public class FindElements implements WebDriverVerb {
private final static Logger logger = LoggerFactory.getLogger(FindElements.class);
private final By by;
public FindElements(String by) {
this.by = Bys.get(by);
}
@Override
public void execute(WebContext context) {
try {
List<WebElement> elements = context.driver().findElements(by);
context.setElements(elements);
} catch (NoSuchElementException nsee) {
context.pushElement(null);
}
}
}

View File

@ -0,0 +1,22 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import java.util.List;
public class FindElementsInElementBy implements WebDriverVerb {
private final By by;
public FindElementsInElementBy(By by) {
this.by = by;
}
@Override
public void execute(WebContext context) {
List<WebElement> elements = context.peekElement().findElements(by);
context.setElements(elements);
}
}

View File

@ -0,0 +1,10 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class FullScreen implements WebDriverVerb {
@Override
public void execute(WebContext context) {
context.driver().manage().window().fullscreen();
}
}

View File

@ -0,0 +1,21 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Get implements WebDriverVerb {
private final static Logger logger = LoggerFactory.getLogger(Get.class);
private final String target;
public Get(String target) {
this.target = target;
}
@Override
public void execute(WebContext context) {
context.driver().get(target);
}
}

View File

@ -0,0 +1,18 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Cookie;
public class GetCookieNamed implements WebDriverVerb {
private final String cookieName;
public GetCookieNamed(String cookieName) {
this.cookieName = cookieName;
}
@Override
public void execute(WebContext context) {
Cookie cookie = context.driver().manage().getCookieNamed(cookieName);
context.pushCookie(cookie);
}
}

View File

@ -0,0 +1,14 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Cookie;
import java.util.Set;
public class GetCookies implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Set<Cookie> cookies = context.driver().manage().getCookies();
context.setCookies(cookies);
}
}

View File

@ -0,0 +1,18 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class GetElementAttribute implements WebDriverVerb {
private final String name;
public GetElementAttribute(String name) {
this.name = name;
}
@Override
public void execute(WebContext context) {
String attribute = context.peekElement().getAttribute(name);
context.setVar("element.attribute",attribute);
}
}

View File

@ -0,0 +1,16 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
class GetElementCssValue implements WebDriverVerb {
private final String propname;
public GetElementCssValue(String propname) {
this.propname = propname;
}
@Override
public void execute(WebContext context) {
String cssValue = context.peekElement().getCssValue(propname);
context.setVar("element.cssvalue",cssValue);
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Point;
public class GetElementLocation implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Point location = context.peekElement().getLocation();
context.setVar("element.location",location);
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Rectangle;
public class GetElementRect implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Rectangle rect = context.peekElement().getRect();
context.setVar("element.rect",rect);
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Dimension;
public class GetElementSize implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Dimension size = context.peekElement().getSize();
context.setVar("element.size",size);
}
}

View File

@ -0,0 +1,11 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class GetElementTagname implements WebDriverVerb {
@Override
public void execute(WebContext context) {
String tagName = context.peekElement().getTagName();
context.setVar("element.tagname",tagName);
}
}

View File

@ -0,0 +1,11 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class GetElementText implements WebDriverVerb {
@Override
public void execute(WebContext context) {
String text = context.peekElement().getText();
context.setVar("element.text",text);
}
}

View File

@ -0,0 +1,11 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class IsElementDisplayed implements WebDriverVerb {
@Override
public void execute(WebContext context) {
boolean displayed = context.peekElement().isDisplayed();
context.setVar("element.displayed",displayed);
}
}

View File

@ -0,0 +1,11 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class IsElementEnabled implements WebDriverVerb {
@Override
public void execute(WebContext context) {
boolean enabled = context.peekElement().isEnabled();
context.setVar("element.enabled",enabled);
}
}

View File

@ -0,0 +1,11 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class IsElementSelected implements WebDriverVerb {
@Override
public void execute(WebContext context) {
boolean selected = context.peekElement().isSelected();
context.setVar("element.selected",selected);
}
}

View File

@ -0,0 +1,11 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class NavigateBack implements WebDriverVerb {
@Override
public void execute(WebContext context) {
context.driver().navigate().back();
}
}

View File

@ -0,0 +1,10 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class NavigateForward implements WebDriverVerb {
@Override
public void execute(WebContext context) {
context.driver().navigate().forward();
}
}

View File

@ -0,0 +1,10 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class NavigateRefresh implements WebDriverVerb {
@Override
public void execute(WebContext context) {
context.driver().navigate().refresh();
}
}

View File

@ -0,0 +1,24 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import java.net.MalformedURLException;
import java.net.URL;
public class NavigateTo implements WebDriverVerb {
private final URL url;
public NavigateTo(String to) {
try {
this.url = new URL(to);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
@Override
public void execute(WebContext context) {
context.driver().navigate().to(url);
}
}

View File

@ -0,0 +1,27 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Alert;
import java.security.InvalidParameterException;
public class SendKeysToAlert implements WebDriverVerb {
private final String keys;
public SendKeysToAlert(String keys) {
this.keys = keys;
}
@Override
public void execute(WebContext context) {
Alert alert = context.getAlert();
if (alert==null) {
alert = context.driver().switchTo().alert();
}
if (alert==null) {
throw new InvalidParameterException("Alert is not present");
}
alert.sendKeys(keys);
context.clearAlert();
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.WebElement;
public class SwitchToActiveElement implements WebDriverVerb {
@Override
public void execute(WebContext context) {
WebElement webElement = context.driver().switchTo().activeElement();
context.pushElement(webElement);
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Alert;
public class SwitchToAlert implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Alert alert = context.driver().switchTo().alert();
context.setAlert(alert);
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.WebDriver;
public class SwitchToDefaultContent implements WebDriverVerb {
@Override
public void execute(WebContext context) {
WebDriver driver = context.driver().switchTo().defaultContent();
context.setFocus(driver);
}
}

View File

@ -0,0 +1,18 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.WebDriver;
public class SwitchToFrameByName implements WebDriverVerb {
private String name;
public SwitchToFrameByName(String name) {
this.name = name;
}
@Override
public void execute(WebContext context) {
WebDriver frame = context.driver().switchTo().frame(this.name);
context.setFocus(frame);
}
}

View File

@ -0,0 +1,19 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import java.security.InvalidParameterException;
public class SwitchToFrameElement implements WebDriverVerb {
@Override
public void execute(WebContext context) {
WebElement webElement = context.peekElement();
if (webElement==null) {
throw new InvalidParameterException("There was no previously found element to switch to.");
}
WebDriver frame = context.driver().switchTo().frame(webElement);
context.setFocus(frame);
}
}

View File

@ -0,0 +1,22 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class SwitchToFrameElementBy implements WebDriverVerb {
private final By by;
public SwitchToFrameElementBy(String by) {
this.by = Bys.get(by);
}
@Override
public void execute(WebContext context) {
WebElement element = context.driver().findElement(by);
WebDriver frame = context.driver().switchTo().frame(element);
context.setFocus(frame);
}
}

View File

@ -0,0 +1,18 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.WebDriver;
public class SwitchToFrameIdx implements WebDriverVerb {
private final int index;
public SwitchToFrameIdx(int index) {
this.index = index;
}
@Override
public void execute(WebContext context) {
WebDriver frame = context.driver().switchTo().frame(index);
context.setFocus(frame);
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.WebDriver;
public class SwitchToParentFrame implements WebDriverVerb {
@Override
public void execute(WebContext context) {
WebDriver webDriver = context.driver().switchTo().parentFrame();
context.setFocus(webDriver);
}
}

View File

@ -0,0 +1,18 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.WebDriver;
public class SwitchToWindow implements WebDriverVerb {
private final String windowName;
public SwitchToWindow(String windowName) {
this.windowName = windowName;
}
@Override
public void execute(WebContext context) {
WebDriver window = context.driver().switchTo().window(this.windowName);
context.setFocus(window);
}
}

View File

@ -0,0 +1,17 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.WebDriver;
/**
* All WebDriverVerb implementations are executable commands.
*/
public interface WebDriverVerb {
/**
* Execute the command.
*
* @param context The context object allows verbs to do have state from one command to the next. It is a
* {@link ThreadLocal} object which can be modified by any verb.
*/
void execute(WebContext context);
}

View File

@ -0,0 +1,120 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.CommandTemplate;
import io.nosqlbench.driver.webdriver.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.InvalidParameterException;
import java.util.Map;
import java.util.function.Function;
public class WebDriverVerbs {
private final static Logger logger = LoggerFactory.getLogger(WebDriverVerbs.class);
public final static String COMMAND = "command";
public enum Verb {
get(Get.class, (m) -> new Get(m.get("target"))),
find_element(FindElement.class, (m) -> new FindElement(m.get("by"))),
find_elements(FindElements.class, (m) -> new FindElements(m.get("by"))),
// navigation
back(NavigateBack.class, (m) -> new NavigateBack()),
forward(NavigateForward.class, (m) -> new NavigateForward()),
refresh(NavigateRefresh.class, (m) -> new NavigateRefresh()),
to(NavigateTo.class, (m) -> new NavigateTo(m.get("to"))),
// options
add_cookie(AddCookie.class, (m) -> new AddCookie(CookieJar.cookie(m))),
delete_cookie(DeleteCookie.class, (m) -> new DeleteCookie(CookieJar.cookie(m))),
delete_all_cookies(DeleteAllCookies.class, (m) -> new DeleteAllCookies()),
delete_cookie_named(DeleteCookieNamed.class, (m) -> new DeleteCookieNamed(m.get("name"))),
get_cookie_named(GetCookieNamed.class, (m) -> new GetCookieNamed(m.get("name"))),
get_cookies(GetCookies.class, (m) -> new GetCookies()),
// TargetLocator (switchTo)
switchto_active_element(SwitchToActiveElement.class, (m) -> new SwitchToActiveElement()),
switchto_alert(SwitchToAlert.class, (m) -> new SwitchToAlert()),
switchto_default_content(SwitchToDefaultContent.class, (m) -> new SwitchToDefaultContent()),
switchto_frame_idx(SwitchToFrameIdx.class, (m) -> new SwitchToFrameIdx(Integer.parseInt(m.get("index")))),
switchto_frame_elem_by(SwitchToFrameElementBy.class, (m) -> new SwitchToFrameElementBy(m.get("by"))),
switchto_frame_elem(SwitchToFrameElement.class, (m) -> new SwitchToFrameElement()),
switchto_frame_name(SwitchToFrameByName.class, (m) -> new SwitchToFrameByName(m.get("name"))),
switchto_parent_frame(SwitchToParentFrame.class, (m) -> new SwitchToParentFrame()),
switchto_window(SwitchToWindow.class, (m) -> new SwitchToWindow(m.get("name"))),
// Alert
dismiss_alert(DismissAlert.class, (m) -> new DismissAlert()),
accept_alert(AcceptAlert.class, (m) -> new AcceptAlert()),
send_keys_to_alert(SendKeysToAlert.class, (m) -> new SendKeysToAlert(m.get("keys"))),
// Window
window_full_screen(FullScreen.class, (m) -> new FullScreen()),
window_get_size(WindowGetSize.class, (m) -> new WindowGetSize()),
window_set_size(WindowSetSize.class, (m) -> new WindowSetSize(m.get("width"), m.get("height"))),
window_maximize(WindowMaximize.class, (m) -> new WindowMaximize()),
window_set_position(WindowSetPosition.class, (m) -> new WindowSetPosition(m.get("x"),m.get("y"))),
window_get_position(WindowGetPosition.class, (m) -> new WindowGetPosition()),
// Elements
click_element_by(ClickElementBy.class, (m) -> new ClickElementBy(Bys.get(m.get("by")))),
clearElement(ClearElement.class, (m) -> new ClearElement()),
clearElement_by(ClearElementBy.class, (m) -> new ClearElementBy(Bys.get(m.get("by")))),
element_find_element_by(FindElementInElementBy.class, (m) -> new FindElementInElementBy(Bys.get(m.get("by")))),
element_find_elements_by(FindElementsInElementBy.class, (m)->new FindElementsInElementBy(Bys.get(m.get("by")))),
element_find_elements(FindElementsInElementBy.class, (m)->new FindElementsInElementBy(Bys.get(m.get("by")))),
element_get_attribute(GetElementAttribute.class, (m) -> new GetElementAttribute(m.get("name"))),
element_get_css_value(GetElementCssValue.class, (m) -> new GetElementCssValue(m.get("name"))),
element_get_location(GetElementLocation.class, (m) -> new GetElementLocation()),
element_get_rect(GetElementRect.class, (m) ->new GetElementRect()),
element_get_size(GetElementSize.class, (m) -> new GetElementSize()),
element_get_tagname(GetElementTagname.class, (m) -> new GetElementTagname()),
element_get_text(GetElementText.class, (m) -> new GetElementText()),
is_element_displayed(IsElementDisplayed.class, (m) -> new IsElementDisplayed()),
is_element_enabled(IsElementEnabled.class, (m) -> new IsElementEnabled()),
is_element_selected(IsElementSelected.class, (m) -> new IsElementSelected()),
element_send_keys(ElementSendKeys.class, (m) -> new ElementSendKeys(m.get("keys"))),
element_submit(ElementSubmit.class, (m) -> new ElementSubmit()),
element_get_screenshot(ElementScreenShot.class, (m) -> new ElementScreenShot())
;
private final Class<? extends WebDriverVerb> verbClass;
private final Function<Map<String, String>, WebDriverVerb> initializer;
Verb(Class<? extends WebDriverVerb> verbClass, Function<Map<String, String>, WebDriverVerb> initializer) {
this.verbClass = verbClass;
this.initializer = initializer;
}
public WebDriverVerb resolve(Map<String, String> commandProps) {
String cmd = commandProps.get(COMMAND);
if (cmd == null) {
throw new InvalidParameterException("command properties must always contain a 'command' entry'");
}
Verb verb = valueOf(cmd);
return verb.initializer.apply(commandProps);
}
}
public static void execute(
long cycle,
CommandTemplate commandTemplate,
WebContext context,
boolean dryrun
) {
Map<String, String> cmdprops = commandTemplate.getCommand(cycle);
logger.debug("cycle:" + cmdprops + " command:" + cmdprops);
String command = cmdprops.get("command");
Verb verb = Verb.valueOf(command);
WebDriverVerb resolve = verb.resolve(cmdprops);
if (dryrun) {
logger.info("skipping cycle " + cycle + " because dryrun is set to true");
return;
} else {
logger.info("running cycle " + cycle + " because dryrun is set to false");
}
resolve.execute(context);
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Point;
public class WindowGetPosition implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Point position = context.driver().manage().window().getPosition();
context.setVar("window.position", position);
}
}

View File

@ -0,0 +1,12 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Dimension;
public class WindowGetSize implements WebDriverVerb {
@Override
public void execute(WebContext context) {
Dimension size = context.driver().manage().window().getSize();
context.setVar("window.size",size);
}
}

View File

@ -0,0 +1,10 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
public class WindowMaximize implements WebDriverVerb {
@Override
public void execute(WebContext context) {
context.driver().manage().window().maximize();
}
}

View File

@ -0,0 +1,19 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Point;
public class WindowSetPosition implements WebDriverVerb {
private final int x;
private final int y;
public WindowSetPosition(String x, String y) {
this.x = Integer.parseInt(x);
this.y = Integer.parseInt(y);
}
@Override
public void execute(WebContext context) {
context.driver().manage().window().setPosition(new Point(x, y));
}
}

View File

@ -0,0 +1,24 @@
package io.nosqlbench.driver.webdriver.verbs;
import io.nosqlbench.driver.webdriver.WebContext;
import org.openqa.selenium.Dimension;
public class WindowSetSize implements WebDriverVerb {
private final int width;
private final int height;
public WindowSetSize(int width, int height) {
this.width = width;
this.height = height;
}
public WindowSetSize(String width, String height) {
this.width = Integer.parseInt(width);
this.height = Integer.parseInt(height);
}
@Override
public void execute(WebContext context) {
context.driver().manage().window().setSize(new Dimension(width, height));
}
}

View File

@ -0,0 +1,3 @@
# WebDriver Driver
welcome to the experimental webdriver prototype for nosqlbench.

View File

@ -1,13 +1,11 @@
package io.nosqlbench.driver.web;
package io.nosqlbench.driver.webdriver;
import io.nosqlbench.nb.api.testutils.Perf;
import org.junit.Ignore;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.remote.RemoteWebElement;
/**

View File

@ -21,14 +21,65 @@ import java.util.LinkedHashMap;
import java.util.Map;
/**
* <H2>Synopsis</H2>
* <p>
* This is a multi-purpose <em>special</em> parser for parameters in a command or
* other map. It is called special because it does take a few liberties which are not
* commonly found in regular languages, but which may be desirable for casual use.
* This is done in a very specific way such that interpretation is unambiguous.
* </p>
*
* <h2>Basic Format</h2>
* <p>
* The input line consists of a sequence of names and values, called assignments.
* These occur as {@code name=value}, and may be delimited by spaces or semicolons, like
* {@code name1=value1 name2=value2} or {@code name1=value1;name2=value2}.
* Values can even contain spaces, even though space is a possible delimiter.
* Thus, {@code name1= value foo bar
* name2=baz} works, with the values {@code value foo bar} and {@code baz}.
* </p>
*
* <h3>Names</h3>
* The name of a parameter must appear in raw literal form, with no escaping. A name may not
* contain spaces, semicolons or equals signs, and may not start with quotes of any kind.
* Otherwise, there are no restrictions placed on the characters that may appear in
* a name. Even escaped characters are allowed.
*
* <h3>Values</h3>
* Values can appear as single quoted values, double quoted values, or literal values.
* The way the value is parsed is determined by the leading character, respectively.
*
* <h4>Single Quoted</h4>
* <p>If the leading character is a single quote, then all following characters up to the next single quote
* are taken as the value, except for escape characters which work as expected. Double quotes,
* spaces, equals or any other characters have no special meaning within a single quoted value.
* </p>
*
* <H4>Double Quoted</H4>
* <p>If the leading character is a double quote, then all following characters up to the next double quote
* are taken as the value, except for escape characters which work as expected. Single quotes,
* spaces, equals or other characters have no special meaning within double quotes.</p>
*
* <H4>Literal</H4>
* <p>Otherwise, the value is taken as every single character, including spaces, single quotes,
* and double quotes, up to the end of the command line or the next parameter assignment.
* Any occurrence of semicolons which is not escaped will be treated as a delimiter. The next occurrence
* of a name and equals pattern after a space will be taken as the next named parameter. Otherwise, all
* spaces and partial word are included in the last value assigment found. Leading spaces on literal
* values are skipped unless escaped.</p>
*
*/
public class ParamsParser {
public static Map<String, String> parse(String input) {
ParseState s = ParseState.expectingName;
Map<String, String> parms = new LinkedHashMap<>();
StringBuilder varname = new StringBuilder(128);
StringBuilder value = new StringBuilder(128);
StringBuilder varname = new StringBuilder(512);
StringBuilder value = new StringBuilder(512);
String lastVarname = null;
boolean isEscaped = false;
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
@ -53,7 +104,10 @@ public class ParamsParser {
switch (s) {
case expectingName:
if (c != ' ' && c != ';') {
if (c =='\'' || c=='"') {
throw new RuntimeException("Unable to parse a name starting with character '" + c + "'. Names" +
" must be literaal values.");
} else if (c != ' ' && c != ';') {
s = ParseState.readingName;
varname.append(c);
}
@ -61,6 +115,14 @@ public class ParamsParser {
case readingName:
if (c == '\\') {
isEscaped = true;
} else if (c == ' ') {
String partial = parms.get(lastVarname);
if (partial==null) {
throw new RuntimeException("space continuation while reading name or value, but no prior " +
"for " + lastVarname + " exists");
}
parms.put(lastVarname,partial+" "+varname);
varname.setLength(0);
} else if (c != '=') {
varname.append(c);
} else {
@ -68,7 +130,9 @@ public class ParamsParser {
}
break;
case expectingVal:
if (c == '\\') {
if (c == ' ') {
} else if (c == '\\') {
isEscaped = true;
} else if (c == '\'') {
s = ParseState.readingSquotedVal;
@ -86,10 +150,11 @@ public class ParamsParser {
case readingRawVal:
if (c == '\\') {
isEscaped = true;
} else if (c != ';') {
} else if (c != ';' && c != ' ') {
value.append(c);
} else {
parms.put(varname.toString(), value.toString());
lastVarname=varname.toString();
varname.setLength(0);
value.setLength(0);
s = ParseState.expectingName;
@ -139,6 +204,10 @@ public class ParamsParser {
varname.setLength(0);
s = ParseState.expectingName;
break;
case readingName:
parms.put(lastVarname,parms.get(lastVarname)+' '+varname.toString());
varname.setLength(0);
break;
default:
}

View File

@ -118,5 +118,59 @@ public class ParamsParserTest {
assertThat(p.get("b")).isEqualTo("2");
}
@Test
public void testSpaceDelimiter() {
Map<String, String> p = ParamsParser.parse("a=1 b=2");
assertThat(p).hasSize(2);
assertThat(p).containsKey("a");
assertThat(p).containsKey("b");
assertThat(p.get("a")).isEqualTo("1");
assertThat(p.get("b")).isEqualTo("2");
}
@Test
public void testSpaceDelimiterGappedFirst() {
Map<String, String> p = ParamsParser.parse("a=1 2 3 b=2");
assertThat(p).hasSize(2);
assertThat(p).containsKey("a");
assertThat(p).containsKey("b");
assertThat(p.get("a")).isEqualTo("1 2 3");
assertThat(p.get("b")).isEqualTo("2");
}
@Test
public void testSpaceDelimiterGappedLast() {
Map<String, String> p = ParamsParser.parse("a=1 b=2 3 4");
assertThat(p).hasSize(2);
assertThat(p).containsKey("a");
assertThat(p).containsKey("b");
assertThat(p.get("a")).isEqualTo("1");
assertThat(p.get("b")).isEqualTo("2 3 4");
}
@Test(expected = RuntimeException.class)
public void testValidNameException() {
Map<String, String> p = ParamsParser.parse("a=1\\\\;'\";b=2 3 4");
assertThat(p).hasSize(2);
assertThat(p).containsKey("a");
assertThat(p).containsKey("b");
assertThat(p.get("a")).isEqualTo("1\\;'\"");
assertThat(p.get("b")).isEqualTo("2 3 4");
}
@Test
public void testSkippingLiteralLeadingSpaces() {
Map<String, String> p = ParamsParser.parse("a= fiver b=\\ sixer");
assertThat(p).hasSize(2);
assertThat(p).containsKey("a");
assertThat(p).containsKey("b");
assertThat(p.get("a")).isEqualTo("fiver");
assertThat(p.get("b")).isEqualTo(" sixer");
}
}

View File

@ -45,6 +45,12 @@
<version>3.12.83-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.nosqlbench</groupId>
<artifactId>driver-web</artifactId>
<version>3.12.83-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.nosqlbench</groupId>
<artifactId>activitytype-stdout</artifactId>

View File

@ -333,8 +333,9 @@ public class ParsedTemplate {
*/
public String getPositionalStatement(Function<String, String> tokenFormatter) {
StringBuilder sb = new StringBuilder(spans[0]);
for (int i = 1; i < spans.length; i += 2) {
sb.append(tokenFormatter.apply(spans[i]));
sb.append(tokenFormatter!=null ? tokenFormatter.apply(spans[i]) : spans[i]);
sb.append(spans[i + 1]);
}
return sb.toString();

View File

@ -1,9 +1,13 @@
package io.nosqlbench.virtdata.core.templates;
//import io.nosqlbench.engine.api.activityconfig.ParsedStmt;
//import io.nosqlbench.engine.api.activityconfig.yaml.StmtDef;
import io.nosqlbench.virtdata.core.bindings.Bindings;
import io.nosqlbench.virtdata.core.bindings.BindingsTemplate;
import java.util.HashSet;
import java.util.List;
import java.util.function.Function;
/**
* Uses a string template and a bindings template to create instances of {@link StringBindings}.
@ -18,6 +22,30 @@ public class StringBindingsTemplate {
this.bindingsTemplate = bindingsTemplate;
}
// /**
// * Build a default string bindings template using the standard representation
// * for a string template in NoSQLBench, which is a literal string interspersed
// * with named anchors in {@code {{curlybraces}}} form.
// * @param stmtDef A stmtDef
// */
// public StringBindingsTemplate(StmtDef stmtDef) {
// this(stmtDef, s->"{{"+s+"}}");
// }
//
// /**
// * Build a string bindings template using a custom representation that maps
// * the named anchors to a different form than the default {@code {{curlybraces}}} form.
// * The mapping function provides the textual substitution which is used to composite
// * the normative representation of the statement.
// * @param stmtdef The {@link StmtDef} which provides the bindpoints
// * @param tokenMapper A custom named anchor formatting function
// */
// public StringBindingsTemplate(StmtDef stmtdef, Function<String,String> tokenMapper) {
// ParsedStmt parsedStmt = stmtdef.getParsed().orError();
// this.stringTemplate = parsedStmt.getPositionalStatement(tokenMapper);
// this.bindingsTemplate = new BindingsTemplate(parsedStmt.getBindPoints());
// }
/**
* Create a new instance of {@link StringBindings}, preferably in the thread context that will use it.
* @return a new StringBindings

View File

@ -332,7 +332,7 @@ from his cigarette.
“Precisely. And the man who wrote the note is a German. Do you note the
peculiar construction of the sentence—This account of you we have
from all quarters received. A Frenchman or Russian could not have
written that. It is the German who is so uncourteous to his verbs. It
written that. It is the German who is so uncourteous to his verb. It
only remains, therefore, to discover what is wanted by this German
who writes upon Bohemian paper, and prefers wearing a mask to showing
his face. And here he comes, if I am not mistaken, to resolve all our