Selenium 2 Grid - Knowing which node your test is using - selenium-webdriver

Is it possible to know which node the selenium grid hub assigned to your test? My tests need to talk to other services on the node machine in order to perform configurations which are not supported by selenium.
Mark

Generally you shouldn't rely on knowing what machine your test is running on. Grid 2 provides a series of callback listeners that you could implement to provide machine configuration. But, if you really want to see what node a test is running on, you could use one of the API calls. Both endpoints can be found on the hub:
http://localhost:4444/grid/api/proxy
http://localhost:4444/grid/api/testsession
Neither are documented yet. But if you view the source, it's straightforward to see how they work. You want to look at the ProxyStatusServlet and TestSessionStatusServlet.

String hub = "grid_server_host"; //IP or hostname of GRID
int port = 4444; // port no.
HttpHost host = new HttpHost(hub,port);
DefaultHttpClient client = new DefaultHttpClient();
String url = host + "/grid/api/testsession?session=";
URL session = new URL(url + ((RemoteWebDriver) webdriver).getSessionId());
BasicHttpEntityEnclosingRequest req;
req = new BasicHttpEntityEnclosingRequest("POST", session.toExternalForm());
org.apache.http.HttpResponse response = client.execute(host,req);
JSONObject object = new JSONObject(EntityUtils.toString(response.getEntity()));
String proxyID = (String) object.get("proxyId");
String node = (proxyID.split("//")[1].split(":")[0]);

Related

WebView2 Fixed Version not working when binaries stored on network share

I want to save the Fixed Version binaries on a network share path, but the WebView2 does not display the web page and does not throw an error.
I set the BrowserExecutableFolder path in the form designer:
CoreWebView2CreationProperties1.BrowserExecutableFolder = "j:\Utilities\Microsoft.WebView2.FixedVersionRuntime.90.0.818.66.x64\"
CoreWebView2CreationProperties1.Language = Nothing
CoreWebView2CreationProperties1.UserDataFolder = Nothing
Me.WebView21.CreationProperties = CoreWebView2CreationProperties1
Me.WebView21.DefaultBackgroundColor = System.Drawing.Color.White
Me.WebView21.Dock = System.Windows.Forms.DockStyle.Fill
Me.WebView21.Location = New System.Drawing.Point(0, 25)
Me.WebView21.Name = "WebView21"
Me.WebView21.Size = New System.Drawing.Size(800, 425)
Me.WebView21.TabIndex = 6
Me.WebView21.ZoomFactor = 1.0R
Setting to a UNC path, doesn't work -
CoreWebView2CreationProperties1.BrowserExecutableFolder = "\UNCFile1\private\Utilities\Microsoft.WebView2.FixedVersionRuntime.90.0.818.66.x64"
Setting to the mapped drive, doesn't work -
CoreWebView2CreationProperties1.BrowserExecutableFolder = "j:\Utilities\Microsoft.WebView2.FixedVersionRuntime.90.0.818.66.x64"
This will work -
CoreWebView2CreationProperties1.BrowserExecutableFolder = "C:\Utilities\Microsoft.WebView2.FixedVersionRuntime.90.0.818.66.x64"
We run the application from a network share path instead of deploying to each users work station and would like to also store the fixed version binaries in the same network share path. Is there a way to make this work?
This is a known issue, according to Microsoft.
It seems WebView2's sandbox environement does not work (yet?) when launched from a network storage.
As an workarround, may disable sandbox using the additional browser arguments or set the environement variable WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS as --no-sandbox before webview initialization.
Sample code in Delphi:
SetEnvironmentVariable('WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS', '--no-sandbox');
EdgeBrowser.BrowserExecutableFolder := '\\unc\path\or\network\drive';
EdgeBrowser.CreateWebView;
Note, this might be a security risk in case if you will access untrusted websites.

How to configure Ignite to work as a full distributed database?

I'm trying to manage a decentralized DB around a huge number of partial DB instances. Each instance has a subset of the whole data and they are all nodes and clients, thus asking for some data the query must be spread to every (group) instance and which one have it will return the data.
Due to avoid lost of data if one instance goes down, I figured out they must replicate its contents with some others. How this scenario can be configured with Ignite?
Supose I have a table with the name and last access datetime of users in a distributed application, like ...
class UserLogOns
{
string UserName;
DateTime LastAccess;
}
Now when the program starts I prepare Ingite for work as a decentralizad DB ...
static void Main(string[] args)
{
TcpCommunicationSpi commSpi = new TcpCommunicationSpi();
// Override local port.
commSpi.LocalPort = 44444;
commSpi.LocalPortRange = 0;
IgniteConfiguration cfg = new IgniteConfiguration();
// Override default communication SPI.
cfg.CommunicationSpi = commSpi;
using (var ignite = Ignition.Start(cfg))
{
var cfgCache = new CacheConfiguration("mio");
cfgCache.AtomicityMode = CacheAtomicityMode.Transactional;
var cache = ignite.GetOrCreateCache<string, UserLogOns>(cfgCache);
cache.Put(Environment.MachineName, new UserLogOns { UserName = Environment.MachineName, LastAccess = DateTime.UtcNow });
}
}
And now ... I want to get LastAccess of other "computerB" when ever it was ..
Is this correct? How can it be implemented?
It depends on the exact use-case that you want to implement. In general, Ignite provides out of the box everything that you mentioned here.
This is a good way to start with using SQL in Ignite: https://apacheignite-sql.readme.io/docs
Create table with "template=partitioned" instead of "replicated" as it is shown in the example here: https://apacheignite-sql.readme.io/docs/getting-started#section-creating-tables, configure number of backups and select a field to be affinity key (a field that is used to map specific entries to cluster node) and just run some queries.
Also check out the concept of baseline topology if you are going to use native persistence: https://apacheignite.readme.io/docs/baseline-topology.
In-memory mode will trigger rebalance between nodes on each server topology change (node that can store data in/out) automatically.

Change webclient proxy with every new request

How can I change the proxy every time when I make a new request?
If I start the application and run this request multiple times, I can see it uses the first proxy used, even if I change the parameters for proxy from a list of proxy servers every time I call this function. I tried to dispose of the client and also to set the client proxy to null, but it didn't help.
If I close the program and restart it, the proxy uses a different IP address.
string GetRequest()
{
WebClient client = new WebClient();
WebProxy wp = new WebProxy(randomProxyAddress + ":" + portNum);
wp.UseDefaultCredentials = false;
wp.Credentials = new NetworkCredential(username, password);
client.Proxy = wp;
string str = client.DownloadString("http://www.example.com");
client.Proxy = null;
client.Dispose();
return str;
}
I found out I had to set request.KeepAlive = false in WebClient.

How to execute blocking calls within a Spring Webflux / Reactor Netty web application

In my use case where I have a Spring Webflux microservice with Reactor Netty, I have the following dependencies:
org.springframework.boot.spring-boot-starter-webflux (2.0.1.RELEASE)
org.springframework.boot.spring-boot-starter-data-mongodb-reactive (2.0.1.RELEASE)
org.projectreactor.reactor-spring (1.0.1.RELEASE)
For a very specific case I need to retrieve some information from my Mongo database, and process this into query parameters send with my reactive WebClient. As the WebClient nor the UriComponentsBuilder accepts a Publisher (Mono / Flux) I used a #block() call to receive the results.
Since reactor-core (version 0.7.6.RELEASE) which has been included in the latest spring-boot-dependencies (version 2.0.1.RELEASE) it is not possible anymore to use: block()/blockFirst()/blockLast() are blocking, which is not supported in thread xxx, see -> https://github.com/reactor/reactor-netty/issues/312
My code snippet:
public Mono<FooBar> getFooBar(Foo foo) {
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.add("size", foo.getSize());
parameters.addAll("bars", barReactiveCrudRepository.findAllByIdentifierIn(foo.getBarIdentifiers()) // This obviously returns a Flux
.map(Bar::toString)
.collectList()
.block());
String url = UriComponentsBuilder.fromHttpUrl("https://base-url/")
.port(8081)
.path("/foo-bar")
.queryParams(parameters)
.build()
.toString();
return webClient.get()
.uri(url)
.retrieve()
.bodyToMono(FooBar.class);
}
This worked with spring-boot version 2.0.0.RELEASE, but since the upgrade to version 2.0.1.RELEASE and hence the upgrade from reactor-core to version 0.7.6.RELEASE it is not allowed anymore.
The only real solution I see is to include a block (non-reactive) repository / mongo client as well, but I'm not sure if that is encouraged. Any suggestions?
The WebClient does not accept a Publisher type for its request URL, but nothing prevents you from doing the following:
public Mono<FooBar> getFooBar(Foo foo) {
Mono<List<String>> bars = barReactiveCrudRepository
.findAllByIdentifierIn(foo.getBarIdentifiers())
.map(Bar::toString)
.collectList();
Mono<FooBar> foobar = bars.flatMap(b -> {
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.add("size", foo.getSize());
parameters.addAll("bars", b);
String url = UriComponentsBuilder.fromHttpUrl("https://base-url/")
.port(8081)
.path("/foo-bar")
.queryParams(parameters)
.build()
.toString();
return webClient.get()
.uri(url)
.retrieve()
.bodyToMono(FooBar.class);
});
return foobar;
}
If anything, this new reactor-core inspection saved you from crashing your whole application with this blocking call in the middle of a WebFlux handler.

For what design reason is Asp.Net Core SessionKey different than the SessionId?

Some Background
In asp.net core when using SqlServer to store sessions, oddly enough the Id column in the SqlServer table gets set to the value of sessionKey which is a Guid generated by the SessionMiddleware. I say oddly enough because there is a SessionId but the Id in the table isn't set to that, it is set to the SessionKey. (I'm not making this up)
This sessionKey used for the Id in the table is also the value that is encrypted and placed in the session cookie. Here is that SessionMiddleware code:
var guidBytes = new byte[16];
CryptoRandom.GetBytes(guidBytes);
sessionKey = new Guid(guidBytes).ToString();
cookieValue = CookieProtection.Protect(_dataProtector, sessionKey);
var establisher = new SessionEstablisher(context, cookieValue, _options);
tryEstablishSession = establisher.TryEstablishSession;
isNewSessionKey = true;
The SessionId however, is a Guid generated by the DistributedSession object in the following line of code:
_sessionId = new Guid(IdBytes).ToString();
Interestingly the ISession interface provides a property for the SessionId but not the SessionKey. So it's often much easier in code to get access to a SessionId then a SessionKey, for example when you have access to an HttpContext object.
This makes it hard to match up the session to the database record if you desire to do that. This was noted by another user on stackoverflow as well How to Determine Session ID when using SQL Sever session storage.
Why?
What I want to know is why is the system designed this way? Why isn't the SessionId and SessionKey the one and the same? Why use two different Guids? I ask because I'm creating my own implementation of ISession and I'm tempted to use the SessionKey as the SessionId in my implementation so that it's easier to match up a record in the database to a session. Would that be a bad idea? Why wan't DistributedSession object designed that way rather than generating a SessionId that is different than the SessionKey? The only reason I can think of is perhaps trying increase security by obfuscating the linkage between the database record and the session it belongs to. But in general security professionals don't find security through obfuscation effective. So I'm left wondering why such a design was implemented?
I also posted the question on GitHub https://github.com/aspnet/Session/issues/151#issuecomment-287894321 to try to get an answer as well.
#Tratcher answered the question there so I'm pasting his answer below so that it's available here on stackoveflow too.
The lifetimes are different. The true lifetime of a session (and SessionId) is controlled by the server. SessionKey is stored in the cookie and lives on the client for an indeterminate amount of time. If the session expires on the server and then the client sends a new request with the old SessionKey, a new session instance with a new SessionId is created, but stored using the old SessionKey so that we don't have to issue a new cookie.
Put another way, don't depend on things outside of your control. The client can keep and replay their SessionKey indefinitely, but it's the server that decides if that is really still the same session.
In case someone need to get the sessionkey in asp.net core 3
Add DI for IDataProtector (IMPORTANT! when create protector it should be nameof(SessionMiddleware))
public IDataProtector _dataProtector;
public TestController( IDataProtectionProvider dataProtectionProvider )
{
_dataProtector = dataProtectionProvider.CreateProtector(nameof(SessionMiddleware));
}
Create method which will get proper value for the session cookie
private string Pad(string text)
{
var padding = 3 - ((text.Length + 3) % 4);
if (padding == 0)
{
return text;
}
return text + new string('=', padding);
}
Use it
public ActionResult TestSession( )
{
var protectedText = HttpContext.Request.Cookies[ ".AspNetCore.Session" ];
var sessionKey = "";
var protectedData = Convert.FromBase64String(Pad(protectedText));
if (protectedData == null)
{
sessionKey = string.Empty;
}
var userData = _dataProtector.Unprotect(protectedData);
if (userData == null)
{
sessionKey = string.Empty;
}
sessionKey = Encoding.UTF8.GetString(userData);
return Content( sessionKey );
}

Resources