I have a question about deleting cookies using webdriver.
Should I create additional code that will wait when deleting cookies is finished or this function will do it for me?
driver.Manage().Cookies.DeleteAllCookies();
I meam test will not go to next steps until all cookies will be deleted?
In my tests, the driver.manage().deleteAllCookies() is non blocking.
So i got issues that some cookies were deleted in the middle of the test.
So maybe you want to do the deleteAllCookies() in a tearDown method,
or you need to wait after the call:
driver.manage().deleteAllCookies();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
That depends on how the Application Under Test(AUT) handles the session.Usually when we do
driver.quit (see here) it should close the browser window which automatically closes the session.
If that doesn't happen then the AUT must be handling it in a different way and as you mentioned
driver.Manage().Cookies.DeleteAllCookies() should clear all the cookies.You should also use clear cookies if you are running multiple tests on the same webdriver session, in that case the browser is not closed and hence session is not cleared.
In general, it is good practice to use the logout functionality of the AUT and then use clear cookies or driver.quit() as part of test cleanup.
As it's non-blocking, if you're reusing the same browser it can continue onto the next test before all cookies have been cleared, you can poll for the current count and if necessary attempt to clear again:
C#
while (_driver.Manage().Cookies.AllCookies.Count > 0)
{
driver.Manage().Cookies.DeleteAllCookies();
Thread.Sleep(100);
}
Related
So we have an app were the user needs to login. During the login data were downloaded from the internet and created into the Realm database.
If the app were closed and reopened we want the app to retain the user that has been logged-in so they don't need to relogin again. Everything is fine and ok during the first user login. When the app were closed and reopen the Realm database throws an error "Accessed from incorrect thread"...
I can't provide much of the code as I don't know where the issue is. I would like to know if rerunning the app again is it on different thread than before? and if it's then the how data created from previous thread can be accessed in the new thread without encountering the said error?
Any help will be appreciated... Thanks in advance
As you have encountered, you can't access a realm from a different thread than the thread it was opened. It is possible however to open multiple instances of the same realm on different threads (or the same thread if that's needed). Opening a realm is not an expensive operation, so there's not a performance issue in opening realms.
I'm guessing in your case that you're downloading the data on a background thread. I'm also guessing the realm is first opened in the callback to that network request. That means the realm is opened on the thread that callback is on. If you try to access that realm on the main thread when reopening the app (or any other thread that's not the same thread as before) you'll get an error.
Best practice is to open a new realm every time you know your doing work on a different thread. As I mentioned, this is not an expensive operation and should be used liberally.
If you have some sort of RealmService or RealmManager as a singleton, I'd recommend against it. If the realm is initialised on the main thread, you won't be able to add records to it from a background thread.
In short: whenever you are doing operations on a realm in a callback, unless you are 100% certain you are going to be on the same thread as you opened a realm on, create a new realm instance and use that to do your operatations.
I have an older Ember-cli app that I've just updated to all the latest dependencies and file formats, I've run ember init with ember-cli#0.2.0-beta.1, but when I try to write an acceptance test with the visit() helper, the internal wait function never resolves.
The furthest I've been able to trace the problem is into the wait function in the bower_components/ember/ember.js file, at the line
if (run.hasScheduledTimers() || run.currentRunLoop) { return; }
There is a timer on backburner, but time and time again, the loop returns here, and it never seems to have a chance to clear the timer.
I'm pretty sure the timer is supposed to make sure the wait helper waits after an ajax request, but the ajax request has long since resolved. Heck, if there were still pending requests, we would have exited this function.
Any insights into this process would be greatly appreciated!!
I had an instance of Em.run.later in my application in a loop, to recursively check for timeouts. This is not uncommon, it turns out!
My solution was to put the run.later block in a conditional check for the current environment, and disable it in testing.
I want to invoke CefV8Context::Eval function and get the returned value in browser process's UI thread. But the CEF3 C++ API Docs states that V8 handles can only be accessed from the thread on which they are created. Valid threads for creating a V8 handle include the render process main thread (TID_RENDERER) and WebWorker threads. Is that means I should use the inter-process communication (CefProcessMessage) to invoke that method and get the return value? If so, how to do this in synchronous mode?
Short answer: CefFrame::ExecuteJavaScript for simple requests will work. For more complex ones, you have to give up one level of synchronousness or use a custom message loop.
What I understand you want to do is to execute some Javascript code as part of your native App's UI Thread. There are two possibilities:
It's generic JS code, doesn't really access any variables or functions in your JS, and as such has not context. This means Cef can just spin up a new V8 context and execute your code - see CefFrame::ExecuteJavaScript(). To quote the examples on CEF's JS Integration link:
CefRefPtr browser = ...;
CefRefPtr frame = browser->GetMainFrame();
frame->ExecuteJavaScript("alert('ExecuteJavaScript works!');",
frame->GetURL(), 0);
It's JS code with a context. In this case, read on.
Yes - CEF is designed such that only the RenderProcess has access to the V8 engine, you'll have to use a CefProcessMessage to head over to the Browser and do the evaluation there. You sound like you already know how to do that. I'll link an answer of mine for others who don't and may stumble upon this later: Background process on the native function at Chromium Embedded Framework
The CEFProcessMessage from Browser to Render processes is one place where the request has to be synchronized.
So after your send your logic over to the render process, you'll need to do the actual execution of the javascript code. That, thankfully, is quite easy - the same JS integration link goes on to say:
Native code can execute JS functions by using the ExecuteFunction()
and ExecuteFunctionWithContext() methods
The best part - the execution seems to be synchronous (I say seems to, since I can't find concrete docs on this). The usage in the examples illustrates this:
if (callback_func_->ExecuteFunctionWithContext(callback_context_, NULL, args, retval, exception, false)) {
if (exception.get()) {
// Execution threw an exception.
} else {
// Execution succeeded.
}
}
You'll notice that the second line assumes that the first has finished execution and that the results of said execution are available to it. So, The CefV8Value::ExecuteFunction() call is by nature synchronous.
So the question boils down to - How do I post a CefProcessMessage from Browser to Renderer process synchronously?. Unfortunately, the class itself is not set up to do that. What's more, the IPC Wiki Page explicitly disallows it:
Some messages should be synchronous from the renderer's perspective.
This happens mostly when there is a WebKit call to us that is supposed
to return something, but that we must do in the browser. Examples of
this type of messages are spell-checking and getting the cookies for
JavaScript. Synchronous browser-to-renderer IPC is disallowed to
prevent blocking the user-interface on a potentially flaky renderer.
Is this such a big deal? Well, I don't really know since I've not come across this need - to me, it's ok since the Browser's message loop will keep spinning away waiting for something to do, and receive nothing till your renderer sends a process message with the results of JS. The only way the browser gets something else to do is when some interaction happens, which can't since the renderer is blocking.
If you really definitely need synchronousness, I'd recommend that you use your custom MessageLoop which calls CefDoMessageLoopWork() on every iteration. That way, you can set a flag to suspend loop work until your message is received from renderer. Note that CefDoMessageLoopWork() and CefRunMessageLoop() are mutually exclusive and cannot work with each other - you either manage the loop yourself, or let CEF do it for you.
That was long, and covers most of what you might want to do - hope it helps!
I have a plugin where I want to prevent the browser from closing as im saving some data that take a unknown random amount of time.
data_ready = false;
data_ready = saveData(); //using a random amount of time as the user has to specify a location
boost::unique_lock<boost::mutex> lock(mut);
while(!data_ready) {
cond.wait(lock);
}
Asking location for saving the data is prompted but crashes immediately after, which im guessing is the lock.
How could I make the browser wait for the user to be finished saving data?
You can't. It is up to you to make sure that the plugin never blocks the main thread and that all threads you start are shut down in time. Congratulations and welcome to the wonderful world of browser plugins =]
Some people have gotten around this by launching an external application that does the real work that won't close until it's done.
The communication is based on socket and the it is keep-alive connection. User use account name to log in, I need to implement a feature when two user use same account to log in, the former one need to be kicked off.
Codes need to updated:
void session::login(accountname) // callback when server recv login request
{
boost::shared_ptr<UserData> d = database.get_user_data(accountname);
this->data = d;
this->send(login success);
}
boost::shared_ptr<UserData> Database::get_user_data(accountname)
{
// read from db and return the data
}
The most simple way is improve Database::get_user_data(accountname)
boost::shared_ptr<UserData> Database::get_user_data(accountname)
{
add a boost::unqiue_lock<> here
find session has same accountname or find user data has same accountname in cache,
if found, then kick this session offline first, then execute below codes
// read from db and return the data
}
This modification has 2 problems:
1, too bad concurrency because the scenario happen rarely. However, if I need to check account online or not, I must cache it somewhere(user data or session), that means I need to write to a container which must has exclusive lock whatever the account same or not. So the concurrency can hardly improved.
2, kick other one off by calling "other_session->offline()" in "this thread" that might concurrent with other operations executing in other thread at same time.
If I add lock in offline(), that will result in all others function belong to session also need to add that lock, obviously, not good. Or, I can push a event to other_session, and let other_session handle the event, that will make sure "offline" executing in its own thread. But the problem is that will make offline executing async, codes below "other one offline" must executed after "offline" runs complete.
I use boost::asio, but I try to describe this problem in common because I think this is a common problem in server writing. Is there a pattern to solve this? Notice that this problem gets complex when there are N same account log in at same time
If this scenario rarely happens, I wouldn't worry about it. lock and release of mutex are not long actions the user would notice (if you had to do it thousands of times a second it could be a problem).
In general trying to fix performance issues that are not there is a bad idea.