To explain the title.. Selenium RC keeps insisting that
A system shutdown has already been scheduled
and refusing to conduct automated tests because of this.. I can understand the logic here, I mean you're not going to do your homework if you thought the world would end with a nuclear holocaust...
However.. this is not the Cold War and when I inspect several basic things (such as using shutdown \a, completing a full restart) I find that this is actually not the case!
How can I convince selenium that the world is not going to end and that it should probably do the work I'm telling it to?
N.B. Here, selenium has "refused" to initialise any instance of IE, and will continue to hang until it times out, regardless of clicking Yes or No. I'm using NUnit, c#/.net4.0 to control the tests.
To fix this I replaced the default "runSeleniumTest" function with the below patched version as a user extension:
function runSeleniumTest() {
runOptions = new RemoteRunnerOptions();
var testAppWindow;
if (runOptions.isMultiWindowMode()) {
try{
testAppWindow = openSeparateApplicationWindow('Blank.html', true);
}
catch (e) {
window.onunload = function () { };
window.location.reload();
return;
}
} else if (sel$('selenium_myiframe') != null) {
var myiframe = sel$('selenium_myiframe');
if (myiframe) {
testAppWindow = myiframe.contentWindow;
}
}
else {
proxyInjectionMode = true;
testAppWindow = window;
}
selenium = Selenium.createForWindow(testAppWindow, proxyInjectionMode);
if (runOptions.getBaseUrl()) {
selenium.browserbot.baseUrl = runOptions.getBaseUrl();
}
if (!debugMode) {
debugMode = runOptions.isDebugMode();
}
if (proxyInjectionMode) {
LOG.logHook = logToRc;
selenium.browserbot._modifyWindow(testAppWindow);
}
else if (debugMode) {
LOG.logHook = logToRc;
}
window.selenium = selenium;
commandFactory = new CommandHandlerFactory();
commandFactory.registerAll(selenium);
currentTest = new RemoteRunner(commandFactory);
var doContinue = runOptions.getContinue();
if (doContinue != null) postResult = "OK";
currentTest.start();
}
I found that the "a system shutdown has already been scheduled" error occurred inside of "openSeparateApplicationWindow". I also found that refreshing the selenium test runner window after the error occurred would "restart" the test without the error. Therefore, I patched the "runSeleniumTest" with the following try catch statement so the test runner window reloads if there's an error in "openSeparateApplicationWindow":
try{
testAppWindow = openSeparateApplicationWindow('Blank.html', true);
}
catch (e) {
window.onunload = function () { };
window.location.reload();
return;
}
I also used my blog post for a more specific example of selenium user extensions
Selenium isn't doing anything in this case. That's the IE HTA agent (a built-in Windows process) that's preventing you from doing anything. Perhaps rebooting the machine will do the trick? It looks like you may just have a pending Windows update that's scheduled a future reboot.
Related
Scratching my head on this one.
I've got a background task in my UWP application which is registered to run every 15 minutes (using TimeTrigger) and whenever the internet becomes available (using a SystemTrigger). I know for a fact that these are registered correctly as both appear in the "Lifecycle Events" when debugging using visual studio. Nevertheless, my code for registering them is below:
bool registered1 = false;
bool registered2 = false;
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == "BackgroundGPS")
{
registered1 = true;
}
if (task.Value.Name == "InternetAvailGPS")
{
registered2 = true;
}
}
await BackgroundExecutionManager.RequestAccessAsync();
if (!registered1)
{
var builder1 = new BackgroundTaskBuilder();
builder1.Name = "BackgroundGPS";
builder1.TaskEntryPoint = "BackgroundTasks.BackgroundGPSTask";
var triggerTime = new TimeTrigger(15, false);
builder1.SetTrigger(triggerTime);
BackgroundTaskRegistration task1 = builder1.Register();
}
if (!registered2)
{
var builder2 = new BackgroundTaskBuilder();
builder2.Name = "InternetAvailGPS";
builder2.TaskEntryPoint = "BackgroundTasks.BackgroundGPSTask";
var triggerIA = new SystemTrigger(SystemTriggerType.InternetAvailable, false);
builder2.SetTrigger(triggerIA);
BackgroundTaskRegistration task2 = builder2.Register();
}
I have ensured that the tasks are declared correctly in my manifest. If they weren't, my app would be throwing an exception when trying to register them.
If I run in debug mode I can see that both BackgroundGPS and InternetAvailGPS are shown in the Lifecycle Events. However, when I click on either of them to force them to execute, I get the following in the output window:
The program '[4728] backgroundTaskHost.exe' has exited with code 1 (0x1).
I have a breakpoint set at the first line of code in my 'Run' method of the background task but this is never hit. The background task is never loaded nor run, and I've no idea why. This probably isn't an issue with my Run method, but it looks like this (I've omitted much of the meat of it, and just included the beginning and end)
public async void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("GPS Started");
int errCode = 0;
try
{
_deferral = taskInstance.GetDeferral();
saveGPSStatus(DateTime.Now.ToString(), "", " ");
var access = await Geolocator.RequestAccessAsync();
if (access != GeolocationAccessStatus.Allowed)
{
Debug.WriteLine("No access");
saveGPSStatus("", "", "No GPS Access");
return;
}
Geolocator locator = new Geolocator();
locator.DesiredAccuracyInMeters = 100;
Geoposition position = await locator.GetGeopositionAsync();
//Stuff goes on in here
_deferral.Complete();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
saveGPSStatus("", "", "Unexpected error. Err code "+errCode+". " + e.Message);
_deferral.Complete();
}
}
I have tried this both on a Windows Phone and a Windows Tablet both running build 10.0.10586.164, and they both do not execute my background task.
As I said above, these were working perfectly a few weeks ago and have only realised something was wrong as some of the app's users have been complaining!
Any help is greatly appreciated.
Got it working in the end, I was simply missing a reference to my background task project within my main project. I must have deleted it by accident at some point before that.
Just to expand on not having it referenced, not having the correct TaskEntryPoint namespace and class name will also cause this error. For me, I misspelt the class name.
I'm working on an asp.net project (written awhile ago), and users say they want to be able to log out on "x'ing" out the tab or browser.
I've been looking around this site and have tried a few things with no luck. It doesn't seem like there is an easy way about this with there being different browsers.
First, here's a logout function which is called from a logout button.
public void LoginStatus1_LoggingOut(object sender, LoginCancelEventArgs e)
{
Response.Cookies.Clear();
Session.Clear();
HttpContext.Current.User = null;
FormsAuthentication.SignOut();
}
It would be nice if I could somehow call that when closing the tab/browser.
There is this javascript in the master page:
<script type="text/javascript">
// Copyright 2006-2007 javascript-array.com
var timeout = 500;
var closetimer = 0;
var ddmenuitem = 0;
// open hidden layer
function mopen(id)
{
// cancel close timer
mcancelclosetime();
// close old layer
if(ddmenuitem) ddmenuitem.style.visibility = 'hidden';
// get new layer and show it
ddmenuitem = document.getElementById(id);
ddmenuitem.style.visibility = 'visible';
}
// close showed layer
function mclose()
{
if(ddmenuitem) ddmenuitem.style.visibility = 'hidden';
}
// go close timer
function mclosetime()
{
closetimer = window.setTimeout(mclose, timeout);
}
// cancel close timer
function mcancelclosetime()
{
if(closetimer)
{
window.clearTimeout(closetimer);
closetimer = null;
}
}
// close layer when click-out
document.onclick = mclose;
</script>
However, it doesn't seem to work. I messed around w/ the timeout variable and no matter how long I wait after I exit the tab/browser, the cookies/session do not clear out. I know chrome has a "continue where you left off" feature, and other browsers have similar I'm sure. Unfortunately, all of the users don't use the same browsers.
Any ideas would be most welcome!
One of my iOS applications seems to have the symptoms of a classic Heisenbug. The application tracks a user's home location so certain events happen when the user enters and exits their home location.
While I'm testing the application, it works great. I walk in and out of a CLCircularRegion and it works every which way I try it. It works with the application in the background. It works with the application closed. It works with the application in the foreground. It works with green eggs and ham.
Unfortunately, users are reporting issues where it will be delayed by 15 minutes or so. The users will enter their homes, but the event will not occur until later. In some cases, the event does not occur at all. The pattern seems to be that when the user first starts using the application, it works great. After a day or so, the application doesn't seem to work as well. The events are delayed.
I'll be the first to admit that I'm no expert on the inner workings of CLLocationManager and CLCircularRegion. I believe I have everything set up properly though and I'm having a really hard time trying to figure out how I can debug something like this.
At any rate, I'll show some of my code here. Keep in mind this is developed with Xamarin so it's in C#.
AppDelegate.cs
public static AppDelegate self;
private CLLocationManager locationManager;
private CLCircularRegion[] locationFences;
private void initializeLocationManager()
{
this.locationManager = new CLLocationManager();
// iOS 8 additional permissions requirements
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
locationManager.RequestAlwaysAuthorization();
}
locationManager.AuthorizationChanged += (sender, e) =>
{
var status = e.Status;
// Location services was turned off or turned off for this specific application.
if (status == CLAuthorizationStatus.Denied)
{
stopLocationUpdates();
}
else if (status == CLAuthorizationStatus.AuthorizedAlways &&
iOSMethods.getKeyChainBool(OptionsViewController.GENERIC, OptionsViewController.SERVICE_GEOLOCATION_ENABLED))
{
startLocationUpdates();
}
};
if (CLLocationManager.IsMonitoringAvailable(typeof(CLCircularRegion)))
{
locationManager.RegionEntered += (sender, e) =>
{
setRegionStatus(e, "Inside");
};
locationManager.RegionLeft += (sender, e) =>
{
setRegionStatus(e, "Outside");
};
locationManager.DidDetermineState += (sender, e) =>
{
setRegionStatus(e);
};
}
else
{
// cant do it with this device
}
init();
}
public void init()
{
var data = SQL.query<SQLTables.RoomLocationData>("SELECT * FROM RoomLocationData").ToArray();
int dLen = data.Length;
if (dLen > 0)
{
locationFences = new CLCircularRegion[dLen];
for (int x = 0; x < dLen; x++)
{
var d = data[x];
CLCircularRegion locationFence = new CLCircularRegion(new CLLocationCoordinate2D(d.Latitude, d.Longitude), d.Radius, d.SomeID.ToString() + ":" + d.AnotherID.ToString());
locationFence.NotifyOnEntry = true;
locationFence.NotifyOnExit = true;
locationFences[x] = locationFence;
}
}
}
private void setRegionStatus(CLRegionEventArgs e, string status, bool calledFromDidDetermineState = false)
{
string identifier = e.Region.Identifier;
string lastStatus = iOSMethods.getKeyChainItem(OptionsViewController.GENERIC, OptionsViewController.SERVICE_LAST_GEO_STATUS);
if (lastStatus == status + ":" + identifier)
{
return;
}
iOSMethods.setKeychainItem(OptionsViewController.GENERIC, OptionsViewController.SERVICE_LAST_GEO_STATUS, status + ":" + identifier);
string[] split = identifier.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries);
if (split.Length == 2)
{
try
{
int someID = Convert.ToInt32(split[0]);
int anotherID = Convert.ToInt32(split[1]);
// Notifies our API of a change.
updateGeofenceStatus(someID, anotherID, status);
if (iOSMethods.getKeyChainBool(OptionsViewController.GENERIC, OptionsViewController.SERVICE_GEOLOCATION_NOTIFICATIONS) &&
(status == "Inside" || status == "Outside" || status == "Unknown"))
{
var rm = SQL.query<SQLTables.KeyRoomPropertyData>("SELECT * FROM KeyRoomPropertyData WHERE SomeID ID = ? AND AnotherID = ?",
new object[] { someID, anotherID }).ToArray();
if (rm.Length > 0)
{
if (status == "Unknown")
{
return;
}
var rmD = rm[0];
UILocalNotification notification = new UILocalNotification();
notification.AlertAction = "Geolocation Event";
notification.AlertBody = status == "Inside" ? "Entered " + rmD.SomeName + ": " + rmD.AnotherName :
status == "Outside" ? "Exited " + rmD.SomeName + ": " + rmD.AnotherName :
"Geolocation update failed. If you would like to continue to use Geolocation, please make sure location services are enabled and are allowed for this application.";
notification.SoundName = UILocalNotification.DefaultSoundName;
notification.FireDate = NSDate.Now;
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
}
}
}
catch (Exception er)
{
// conversion failed. we don't have ints for some reason.
}
}
}
private void setRegionStatus(CLRegionStateDeterminedEventArgs e)
{
string state = "";
if (e.State == CLRegionState.Inside)
{
state = "Inside";
}
else if (e.State == CLRegionState.Outside)
{
state = "Outside";
}
else
{
state = "Unknown";
}
CLRegionEventArgs ee = new CLRegionEventArgs(e.Region);
setRegionStatus(ee, state, true);
}
public void startLocationUpdates()
{
if (CLLocationManager.LocationServicesEnabled)
{
init();
if (locationFences != null)
{
foreach (CLCircularRegion location in locationFences)
{
locationManager.StartMonitoring(location);
Timer t = new Timer(new TimerCallback(delegate(object o) { locationManager.RequestState(location); }), null, TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(-1));
}
}
}
}
public void stopLocationUpdates(bool isRestarting = false)
{
if (locationFences != null)
{
foreach (CLCircularRegion location in locationFences)
{
locationManager.StopMonitoring(location);
}
}
if (!isRestarting)
{
var rooms = SQL.query<SQLTables.KeyRoomPropertyData>("SELECT * FROM KeyRoomPropertyData").ToArray();
foreach (SQLTables.KeyRoomPropertyData room in rooms)
{
// notifies our API of a change
updateGeofenceStatus(room.SomeID, room.AnotherID, "Unknown");
}
}
}
I know it's a lot of code for anyone to sift through, but I really have no good theory at this point as to what is causing this bug or if it is even possible to fix with the limitations of iOS.
A few theories that I have are if the CLLocationManager.PausesLocationUpdatesAutomatically property may have something to do with it, or some other property of CLLocationManager such as ActivityType, DesiredAccuracy, or DistanceFilter. I've left all of these at their defaults which I would assume would be fine, but I'm not really sure.
Another theory is that there is an uncaught exception being thrown some time after the "service" has been running in the background for some time. If that is the case, is there anything iOS does that would give me a stack trace or something? In all of my tests, I never ran across any exceptions being thrown from this code so I kind of doubt that's the issue. At this point though, I'm willing to entertain any ideas or suggestions.
Also, please keep in mind that in order for this application to work the way it was intended, the location update events MUST occur as soon as the user enters or exist the CLCircularRegion (within a minute or so at least). Obviously I have to leave it to the user to keep their location services enabled and allow the app to have the appropriate permissions.
You are most likely right on target with your diagnosis - it is classic observer effect.
When you test the app, when users play with a new app, the iphone is being actively used. It is not given a chance to fall asleep. What happens on a next day, when users return home - their phones most likely are not in use for extended time right before reaching home location: normally we do not use phones during "last mile" walk after leaving public transportation, or while driving back home. iOS notices this extended inactivity period and adjusts its own behavior to optimize battery life.
The easiest way to observe this is to put together a simple breadcrumbs app - set geofence at your location and keep doing that every time you get exit event. Depending on the way you use (or not use) your phone results will be very different while walking the same route.
And when you get home, the phone is usually the last thing you reach for as well.
You may want to ask users to give more details on how exactly they used phones last 15 minutes before and after entering home, what other apps they use, if they drive do they keep turn by turn navigation app running etc. You will spot the pattern.
re. Also, please keep in mind that in order for this application to
work the way it was intended, the location update events MUST occur as
soon as the user enters or exist the CLCircularRegion (within a minute
or so at least).
You can't do this with geofencing only, especially taking into account different arrival/departure patterns - walking vs driving, "descend" paths (e.g. arrivals with U-turns). You have to anticipate both delays longer than 1 minute and "premature" triggering. I am afraid there is no workaround.
Some things to check:
What are some typical values for radius? You may want to consider reducing that.
iOS Location Services will provide a quicker response if the device has WiFi enabled even if the user is not connected to a network. Check if the problem users have wifi disabled and if you haven't done so already maybe test your device w/o wifi.
Is there a delay in the notification? That is, does the region event occur correctly but for some reason there is a delay in the notification?
How many RoomLocationData entries are there? iOS limits each app to 20 regions max.
Presuming the users are driving to/from their house, you may want to try the following settings (code is Swift):
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest // or kCLLocationAccuracyBestForNavigation
locationManager.pausesLocationUpdatesAutomatically = true // try false if nothing else works
locationManager.allowsBackgroundLocationUpdates = true
locationManager.activityType = CLActivityType.AutomotiveNavigation
I open a page and at the end of the test attempt to close it by calling my CelanUp() in a finally block but sometimes IEDriverServer and the browser are left open. There are no open popups when this happens.
public void CelanUp ()
{
string dialogResponse = string.Empty;
if (m_Driver != null)
{
//Dismiss all dialogs:
dialogResponse = CloseLogonDialog();
dialogResponse = CloseConfirmDialog();
m_Driver.Quit();
m_Driver = null;
}
if (dialogResponse != string.Empty)
{
throw new ApplicationException(dialogResponse);
}
}
What else can I do the close the browser and IEDriverServer?
Edit:
because Selenium's Quit is letting me down by leaving windows open i have looked at other solutions:
try
{
foreach (Process proc in Process.GetProcessesByName("IEDriverServer.exe"))
{
proc.Kill();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
Depending on what unit testing software you're using, instead of doing the logic like this, i'd recommend delegating the browser to the unit testing framework.
Put the cleanup method in an After method. as in, After each test... do this.
In java, using jUnit, it'd be written like this.
#After
public void cleanUp() {
driver.quit();
}
This means, after each test, call driver.quit()
I had a general question about extracting code from a visual studio web test. I used the "generate code" option of a web test and got the following:
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.WebTesting;
using Microsoft.VisualStudio.TestTools.WebTesting.Rules;
namespace SignsOfLife
{
public class SignsOfLifeCoded : WebTest {
public SignsOfLifeCoded() {
this.PreAuthenticate = true;
}
public override IEnumerator<WebTestRequest> GetRequestEnumerator() {
// Initialize validation rules that apply to all requests in the WebTest
if ((this.Context.ValidationLevel >= Microsoft.VisualStudio.TestTools.WebTesting.ValidationLevel.Low)) {
ValidateResponseUrl validationRule1 = new ValidateResponseUrl();
this.ValidateResponse += new EventHandler<ValidationEventArgs>(validationRule1.Validate);
}
WebTestRequest request1 = new WebTestRequest("http://localhost/site/client/default.aspx");
yield return request1;
request1 = null;
WebTestRequest request2 = new WebTestRequest("http://localhost/site/login.aspx");
request2.ThinkTime = 5;
request2.QueryStringParameters.Add("c", "clientcode", false, false);
ExtractHiddenFields extractionRule1 = new ExtractHiddenFields();
extractionRule1.Required = true;
extractionRule1.HtmlDecode = true;
extractionRule1.ContextParameterName = "1";
request2.ExtractValues += new EventHandler<ExtractionEventArgs>(extractionRule1.Extract);
yield return request2;
request2 = null;
WebTestRequest request3 = new WebTestRequest("http://localhost/site/login.aspx");
request3.Method = "POST";
request3.ExpectedResponseUrl = "http://localhost/site/user/home.aspx";
request3.QueryStringParameters.Add("c", "clientcode", false, false);
FormPostHttpBody request3Body = new FormPostHttpBody();
request3Body.FormPostParameters.Add("__LASTFOCUS", this.Context["$HIDDEN1.__LASTFOCUS"].ToString());
request3Body.FormPostParameters.Add("__EVENTTARGET", this.Context["$HIDDEN1.__EVENTTARGET"].ToString());
request3Body.FormPostParameters.Add("__EVENTARGUMENT", this.Context["$HIDDEN1.__EVENTARGUMENT"].ToString());
request3Body.FormPostParameters.Add("__VIEWSTATE", this.Context["$HIDDEN1.__VIEWSTATE"].ToString());
request3Body.FormPostParameters.Add("__EVENTVALIDATION", this.Context["$HIDDEN1.__EVENTVALIDATION"].ToString());
request3Body.FormPostParameters.Add("Login1$UserName", "username");
request3Body.FormPostParameters.Add("Login1$Password", "password");
request3Body.FormPostParameters.Add("Login1$LoginButton", "Log In");
request3.Body = request3Body;
yield return request3;
request3 = null;
}
}
}
What I wanted to do is basically put this test into a separate service to run throughout the day for purposes of health checking. I basically want to make sure that users are able to log in throughout the day. What process should I use to get the test into something like a console app? I was running into issues with debugging the webtest code. Like how would I correctly call the GetRequestEnumerator method and respond to it from code?
First suggestion:
assumption: you want to run this on a daily basis and make it reusable/extensible for new tests
Throw your test code into a web service and link it appropriately.
Then create a windows service that consumes the service on a daily basis based on whatever interval of time and store the results in some fashion.
If my assumption is incorrect then this is an unnecessary amount of work for something that will not be reused later.
Second suggestion:
assumption: your tests will only be executed for a period of one day
Simply write a console app to execute the tests at a given interval
write the console app to run a timer class and register a callback event for when the time interval has elapsed. In the callback method you defined, perform the tests needed and record the results.
There is a threading issue that can be handled in a number of ways ... you want you app to continue running all day so you could just use something like this
public class tester
{
public tester()
{
//setup timer logic here
//..
//..
var ts = new ThreadStart(run);
var thread = new Thread(ts);
thread.start();
}
public void run()
{
while (ShouldContinue);
{
//do nothing execute keep app going
}
}
}
then toggle ShouldContinue when you meet your exiting condition ... i would assume the condition would be if the app is running for 24 hours + in this scenario
The second solution really shouldn't take you very long to design and manufacture. But the first will be more time consuming.
hopefully that answers your question or sparks another idea =D