[LON-CAPA-cvs] cvs: modules /goltermann/Tests Util.pm config.cfg runTests.pl /goltermann/Tests/t UserRelated.pm selenium_InterfaceTest.pm selenium_ProblemTest.pm /goltermann/Tests/template Template.pm
goltermann
goltermann at source.lon-capa.org
Wed Jul 17 08:15:25 EDT 2013
goltermann Wed Jul 17 12:15:25 2013 EDT
Added files:
/modules/goltermann/Tests/t UserRelated.pm
selenium_InterfaceTest.pm
selenium_ProblemTest.pm
Modified files:
/modules/goltermann/Tests Util.pm config.cfg runTests.pl
/modules/goltermann/Tests/template Template.pm
Log:
added new files
-------------- next part --------------
Index: modules/goltermann/Tests/Util.pm
diff -u modules/goltermann/Tests/Util.pm:1.1 modules/goltermann/Tests/Util.pm:1.2
--- modules/goltermann/Tests/Util.pm:1.1 Tue Jun 18 09:47:27 2013
+++ modules/goltermann/Tests/Util.pm Wed Jul 17 12:15:24 2013
@@ -5,16 +5,16 @@
package Util;
use Test::More;
use Test::WWW::Selenium;
-use Smart::Comments;
+# use Smart::Comments;
my $maxTimeout = 30000;
my $screenCount; # for screenshot naming
my $sel;
my $browser;
-my %user;
my %config;
# this starts a selenium instance and a browser
+# as parameters you need the string of a browser you want to start and the config hash
sub startBrowser(){
($browser, %config) = @_;
@@ -27,7 +27,7 @@
$sel->open('/'); # if you want to maximize you first have to open a page
$sel->wait_for_page_to_load($maxTimeout);
$sel->window_maximize() if $config{'maximize'};
- # $sel->set_speed(1000);
+ $sel->set_speed(500);
return $sel;
}
@@ -42,7 +42,7 @@
# Login for loncapa
sub login(){
- %user = @_;
+ #%config = @_;
# have a clean start
logout();
@@ -51,8 +51,8 @@
$sel->wait_for_page_to_load($maxTimeout);
if($sel->get_title() =~ /login/i){
- $sel->type("id=uname", $user{'user'});
- $sel->type('//div[2]/div/form/input[4]', $user{'pw'});
+ $sel->type("id=uname", $config{'user'});
+ $sel->type('//div[2]/div/form/input[4]', $config{'pw'});
$sel->submit('name=client');
}else{
@@ -117,4 +117,5 @@
}
$screenCount += 1;
}
+
1;
Index: modules/goltermann/Tests/config.cfg
diff -u modules/goltermann/Tests/config.cfg:1.1 modules/goltermann/Tests/config.cfg:1.2
--- modules/goltermann/Tests/config.cfg:1.1 Tue Jun 18 09:47:27 2013
+++ modules/goltermann/Tests/config.cfg Wed Jul 17 12:15:24 2013
@@ -22,7 +22,7 @@
# --- Customization ----------------------------------------
# to speed things up and skip some tests
-fast=1
+fast=0
# maximize the browser window on the test system
# it is recommended to maximize the window if you are taking screenshots
Index: modules/goltermann/Tests/runTests.pl
diff -u modules/goltermann/Tests/runTests.pl:1.1 modules/goltermann/Tests/runTests.pl:1.2
--- modules/goltermann/Tests/runTests.pl:1.1 Tue Jun 18 09:47:27 2013
+++ modules/goltermann/Tests/runTests.pl Wed Jul 17 12:15:24 2013
@@ -2,128 +2,227 @@
use strict;
use warnings;
use Test::More 0.98;
+use Array::Utils qw(:all);
use Smart::Comments;
-use lib('/home/httpd/lib/perl','.','./t');
+use lib( '/home/httpd/lib/perl', '.', './t' );
+
+print "\nLON-CAPA testing script v0.27-Alpha\nPlease read documentation.\n\n";
# -- LONCAPA Testsuite --
-# This will run several automated tests for the lonnet module and tests lon capa in different browsers.
-# During certains tests screenshots will be captured. These Screenshots are stored where your selenium server is located.
-# You can deactivate this feature in the config file
+#
+# The normal way to run this script is via make. But it is also possible to run it as a stand alone script.
+# this enables you to pass parameters which override some of the standard settings below.
+# You can use them to run a single testmodule and/or browser instead of the whole suite.
+# In case you want to repeat a specific test scenario to observe the behavior.
+#
+# use 'make test' to run the whole suite or use standalone mode
+# for standalone type 'perl runTests.pl' plus parameters:
+#
+# perl runTests.pl [lonnet modulename]
+# OR
+# perl runTests.pl <browser module> <browser>
+# if you want to run browser tests in standalone mode you have to give the browsers you want to run the tests in
+#
+# Examples:
+# perl runTests.pl firefox # only tests with firefox
+# perl runTests.pl UserRelated # only the module 'UserRelated' (you dont need the 'lonnet_' prefix)
+# perl runTests.pl safari InterfaceTest # module 'InterfaceTest' tested with safari
+#
+#
+#
+# During certain selenium tests screenshots will be captured.
+# These Screenshots are stored where your selenium server is located.
+# You can deactivate this feature in the config file.
#
# If you want to write your own test module you have to give your module an explicit package name.
# Also the module needs a run() function which contains all the tests included in your module.
# It is recommended to start with the Template.pm to create a your own testmodule!
# Dont forget to add it to the module list below!
+
+
+# --- START OF CONFiGURATiON -----------------------------------------------------------------------
#
-# --- START of CONFiGURATiON -----------------------------------------------------------------------
-# package names of modules you want to test:
-my @internalTestModules = ('UserRelated'); # internal tests
-my @browserTestModules = ('ProblemTest','InterfaceTest'); # browser tests
+# Specify the path on your host machine for browsers which cannot be found by selenium.
+# You might need to add pathes for other browser, depending on the system you are running
#
-# specify path on host machine for browser selenium server cannot find
-# you sometimes might need to add pathes for other browser
-my $pathToChrome='C:\Program Files\Google\Chrome\Application\chrome.exe';
+# example:
+# my $pathToChrome = 'C:\Program Files\Google\Chrome\Application\chrome.exe';
+# my @browsers = ("googlechrome $pathToChrome");
+
+# browsers you want to test:
+my @browsers = ('firefox', 'googlechrome', 'safari', 'iexplore' );
#
-# order of the browsers you want to test
-my @browsers=('firefox',"googlechrome $pathToChrome",'safari','iexplore');
-# my @browsers=('safari');
+# --- END OF CONFiGURATiON ------------------------------------------------------------------------
-my %config;
-loadConfig();
-# --- END of CONFiGURATiON ------------------------------------------------------------------------
+my %config = loadConfig();# load the configuration file
-# TODO: cvs commit
+my @seleniumTestModules; # for browser tests (need @pecial treatment)
+my @otherTestModules; # all the other tests
+generateTestLists(); # gets all the test modules from ./t and sorts them in one of the lists above
-print "\nLON-CAPA testing script v0.25-Alpha\nPlease read documentation.\n\n";
+my @parameters = @ARGV;
+handleParameters(); # gets given parameters and decides how to handle them (standalone only)
+
+# starting the clock
+my $startTime = time();
-my $selenium_unavailable = 0;
checkPrerequisites();
+runInternalTests();
+runSeleniumTests();
-if($selenium_unavailable){
- print "No Selenium tests possible. Continue anyway? [y/n]\n";
- if (<STDIN> =~ 'n') {
- die 'Aborted by user';
+# thats it, end of script
+
+# -------------------------------------------------------------------------------------------------
+
+# loads the configuration from the config file
+sub loadConfig {
+ my @toHash;
+ my %ret;
+ open FILE, "<config.cfg" or die $!;
+
+ while (<FILE>) {
+ if ( $_ =~ /^[a-z]/ ) {
+ @toHash = split( /=/, $_ );
+ $toHash[1] =~ s/\s//g;
+ $ret{ $toHash[0] } = $toHash[1];
+
+ # print $toHash[0]."=>".$config{$toHash[0]};
}
+ }
+
+ close FILE;
+ return %ret;
}
-# starting the clock
-my $startTime = time();
-runInternalTests();
-runBrowserTests() unless $selenium_unavailable; # to spare you all the error messages
+# reads all the tests from t/ and generates the list of tests to run
+sub generateTestLists {
-# end of script
-sub checkPrerequisites {
+ my $directory = './t';
+ opendir (DIR, $directory) or die $!;
+ while (my $file = readdir(DIR)) {
+
+ if ($file =~ m/^selenium_\w+\.pm$/){
+ $file =~ s/\.pm//; # remove file extension
+ push(@seleniumTestModules, $file);
+ }elsif($file =~ m/\.pm$/){
+ $file =~ s/\.pm//; # remove file extension
+ push(@otherTestModules, $file);
+ }
+ }
+ closedir(DIR);
+}
+
+# gets all the given paramters (standalone mode) and decides what to do
+sub handleParameters {
+ return if not @parameters;
+
+ my @allPossibleArguments = (@browsers, @seleniumTestModules, @otherTestModules);
+ my @validGivenArguments = &generateIntersection(\@parameters, \@allPossibleArguments);
+
+ if( scalar @validGivenArguments != scalar @parameters ){
+ print "\nInvalid arguments. Valid arguments are:\n";
+ foreach(@browsers){
+ print "$_\n";
+ }
+ foreach(@seleniumTestModules, @otherTestModules){
+ my $modName = $_;
+ print "$modName\n";
+ }
+ die;
+ }
+
+ # process valid arguments
+ @browsers = intersect(@validGivenArguments, @browsers);
+ @seleniumTestModules = intersect(@validGivenArguments, @seleniumTestModules);
+ @otherTestModules = intersect(@validGivenArguments, @otherTestModules);
+}
+
+sub checkPrerequisites {
+ my $seleniumError = '';
subtest "internal prerequisites" => sub {
use_ok('Apache::lonnet');
use_ok('Apache::Tests::Util');
- # checking if test user is valid
- ok(&Apache::lonnet::authenticate($config{'user'},$config{'pw'},$config{'domain'}) ne 'no_host', 'test user existing');
- } or die 'Error. there is no use in running more tests';
+ # checking if test user is valid
+ ok(
+ &Apache::lonnet::authenticate( $config{'user'}, $config{'pw'}, $config{'domain'} )
+ ne 'no_host', 'test user existing'
+ );
+ } or die 'Error. There is no use in running more tests';
subtest "external prerequisites" => sub {
use_ok('WWW::Selenium');
use_ok('Test::WWW::Selenium');
- } or $selenium_unavailable = 1;
+ }
}
-
sub runInternalTests {
- foreach my $module (@internalTestModules){
+ foreach my $module (@otherTestModules) {
print "\nTesting $module\n";
subtest "module $module" => sub {
use_ok($module);
$module->run(%config);
+ done_testing();
};
- }# end of foreach modules
+ } # end of foreach modules
}
-sub runBrowserTests {
+sub runSeleniumTests {
my $sel;
print "Some tests will be skiped due to fast mode\n" if $config{'fast'};
- foreach my $browser (@browsers){
- print "\nstarting $browser\n";
- $sel = &Util::startBrowser($browser, %config);
+ foreach my $browser (@browsers) {
+
+ print "\n starting $browser\n";
+ $sel = &Util::startBrowser( $browser, %config );
+ subtest 'testrun in ' . $browser => sub {
- subtest 'testrun in '.$browser => sub {
+ foreach my $module (@seleniumTestModules) {
- foreach my $module (@browserTestModules){
- subtest 'module '.$module => sub {
+ subtest 'module ' . $module => sub {
use_ok($module);
$module->run(%config);
- }
+
+ done_testing();
+ }
}
+ done_testing();
};
&Util::endBrowser();
}
$sel->stop($sel) if $sel;
}
-sub loadConfig {
- my @toHash;
- open FILE, "<config.cfg" or die $!;
- while(<FILE>){
- if( $_ =~ /^[a-z]/){
- @toHash = split(/=/,$_);
- $toHash[1] =~ s/\s//g;
- $config{$toHash[0]} = "$toHash[1]";
- # print $toHash[0]."=>".$config{$toHash[0]};
+# generate intersection of two arrays
+sub generateIntersection {
+ my ($a1, $a2) = @_;
+ my @result = ();
+
+ foreach my $a (@$a1){
+ foreach my $b (@$a2){
+
+ if ($a eq $b){
+ push (@result, $a);
+ last;
+ }
+
}
}
- close FILE;
+
+ return @result;
}
-END{
+# done testing, time measurement, the end
+END {
done_testing();
-
- my $testtime = time()-$startTime;
- my $h = ($testtime/60/60) % 24;
- my $m = ($testtime/60) % 60;
- my $s = $testtime % 60;
+ $startTime = time() unless $startTime;
+ my $testtime = time() - $startTime;
+ my $h = ( $testtime / 60 / 60 ) % 24;
+ my $m = ( $testtime / 60 ) % 60;
+ my $s = $testtime % 60;
print "Testing finished after $h h $m m $s s\n";
}
Index: modules/goltermann/Tests/template/Template.pm
diff -u modules/goltermann/Tests/template/Template.pm:1.1 modules/goltermann/Tests/template/Template.pm:1.2
--- modules/goltermann/Tests/template/Template.pm:1.1 Tue Jun 18 09:47:27 2013
+++ modules/goltermann/Tests/template/Template.pm Wed Jul 17 12:15:24 2013
@@ -6,19 +6,20 @@
-# optional
-BEGIN{
- # e.g. getting running selenium instance # OMG nein! bad example, causes bugs! dont do it
- # but using BEGIN blocks might be useful for some other things
-}
+# This is a template you can/should use to create your own test modules. Important things are:
+# You have to give your module a unique packagename which is similar to its filename, without the file extension
+# Your module _needs_ a run() subfunction, which is called by the runTests script
+# If the module is a selenium test, the file and package names have to start with "selenium_"
+
-# mandatory!
+# run method is mandatory!
sub run(){
- shift; # you need this if you pass a hash between different packages when using $module->run();
- my($sel, %config) = @_;
+ shift; # you need to dispose the first element when using $module->run();
+ my %config = @_;
# call your testfunctions here
+ myTestFunction();
# please logout after inBrowser testing, leave it tidy for the person (/test) after you
}
@@ -33,4 +34,4 @@
# e.g. logout
}
-1;
\ No newline at end of file
+1;
Index: modules/goltermann/Tests/t/UserRelated.pm
+++ modules/goltermann/Tests/t/UserRelated.pm
#! perl
use strict;
use warnings;
package UserRelated;
use Test::More;
# use Smart::Comments;
my $user;
my $pw;
my $tmppw;
my $domain;
my $homeserver;
sub run(){
shift;
my %config = @_;
$user = $config{'user'};
$pw = $config{'pw'};
$tmppw = 'tmppw12345'; # if something breaks while changing the pw (it shouldnt) you might need the temp password to set your old pw back manually
$domain = $config{'domain'};
# Trying to write a testhash
is(&Apache::lonnet::appenv(%config), 'ok', 'writing %config in appenv');
is(&Apache::lonnet::delenv(%config), 'ok', 'deleting %config in appenv');
# i dont think this is a good 'clean' test
testHomeserver();
testPwChange();
testIdChange();
newTest();
}
sub testHomeserver(){
# trying to determine hostserver of user
$homeserver = &Apache::lonnet::homeserver($user,$domain);
ok($homeserver ne 'no_host', 'host found '.$homeserver);
ok($homeserver ne 'no_account_on_host', 'account found');
}
sub testPwChange(){
# changes the password and see if it works
isnt(&Apache::lonnet::changepass($user, $domain, 'somebadpwwhichshouldnotwork', $homeserver), 'ok', 'trying wrong pw');
is(&Apache::lonnet::changepass($user,$domain,$pw,'tmppw12345',$homeserver), 'ok', 'change pw');
isnt(&Apache::lonnet::authenticate($user,$tmppw,$domain), 'no_host', 'authenticate with new pw');
is(&Apache::lonnet::changepass($user,$domain,$tmppw,$pw,$homeserver), 'ok', 'changing to old pw');
}
sub testIdChange() {
# overrides old id without asking. thats ok when using a specially created testuser, but
# DONT USE WITH A PRODUCTIVE USER
my $uniqueId = localtime;
&Apache::lonnet::idput($domain, ($user => $uniqueId));
# checks if ID successfully set
my %idrget = &Apache::lonnet::idrget($domain, ($user));
ok($idrget{$user} eq $uniqueId, 'set new id');
}
sub newTest {
print &Apache::lonnet::queryauthenticate($user,$domain);
}
END{
# TODO: test if repair function is needed
# if (errors){
# repair
# }
}
1;
Index: modules/goltermann/Tests/t/selenium_InterfaceTest.pm
+++ modules/goltermann/Tests/t/selenium_InterfaceTest.pm
#!perl
use strict;
use warnings;
package selenium_InterfaceTest;
# use Smart::Comments;
use Test::More;
use Test::WWW::Selenium;
my $maxTimeout = 30000;
my $sel;
# for now this only sends a internal msg to yourself and checks if this arrived
sub run(){
shift; # _important_ to have the right hash to work with
my %config = @_;
&Util::login(%config);
&sendmessage(%config);
}
# send and recieve of internal messages
sub sendmessage{
$sel = Util::getActiveBrowser();
my %config = @_;
my $user = $config{'user'};
my $address = $sel->{'browser_url'}; # url stem from selenium instance
my $timestamp = time;
my $uniqueText = 'Dies ist eine Testnachricht.';
# send a mail
$sel->open($address.'adm/email?compose=individual');
$sel->wait_for_page_to_load($maxTimeout);
$sel->type('recuname', $user);
$sel->type('subject', $timestamp);
$sel->type('message', $uniqueText);
&Util::takeScreenshot('send mail interface');
$sel->click_ok('send', undef, 'mail sent');
$sel->pause(2000);
# check for new mail and get value
my $htmlsource = $sel->get_html_source();
ok($htmlsource =~ m/<a href="\/adm\/email\?display=(.*?)&.*?">$timestamp/i, 'mail recieved');
my $clickme = $1;
&Util::takeScreenshot('recieved mails');
# delete mail with saved value
$sel->click_ok("name=delmark value=$clickme", undef, 'checkbox for mail set');
$sel->click_ok("name=go", undef, 'mail deleted');
$sel->wait_for_page_to_load($maxTimeout);
$sel->pause(5000);
}
1;
Index: modules/goltermann/Tests/t/selenium_ProblemTest.pm
+++ modules/goltermann/Tests/t/selenium_ProblemTest.pm
#!perl
use strict;
use warnings;
package selenium_ProblemTest;
use Test::More;
use Test::WWW::Selenium;
# use Smart::Comments;
my $problemname = 'uniqueTestProb.problem';
my $maxTimeout = 30000;
my $oldConstrSpace = 1; #set this if you use the old construction space (<version_2_11_X)
my $sel;
my %config;
my $user;
my $pass;
my $dom;
# runs all tests
sub run(){
shift; # get rid of foreign package name, _important_ to have the right hash to work with
%config = @_;
$sel = Util::getActiveBrowser();
# makes code easier to read and tidier
$user = $config{'user'};
$pass = $config{'pw'};
$dom = $config{'domain'};
# start your test functions here:
&testLogins();
&createProblem();
SKIP: {
skip "This test might fail because LONCAPA times out randomly", 2;
&testMaxima();
};
&cleanup();
}
sub testLogins(){
&badLogin();
&Util::login(%config);
ok($sel->get_html_source() !~ /href="\/adm\/loginproblems.html"/, 'Login');
}
# Creates an empty problem
# Contains 3 tests
sub createProblem(){
# check if previous login was ok
$sel->open('/adm/roles');
$sel->wait_for_page_to_load($maxTimeout);
&Util::takeScreenshot('available roles');
$sel->click("//input[\@name='au".$dom."']", undef, 'rolechoice author');
$sel->wait_for_page_to_load($maxTimeout);
if($oldConstrSpace){
$sel->open("/priv/$user/");
}else{
$sel->open("/priv/$dom/$user/");
}
$sel->wait_for_page_to_load($maxTimeout);
&Util::takeScreenshot('construction space');
$sel->select('css=select[name="action"]', 'value=newproblemfile');
$sel->type('name=newfilename', $problemname);
# Test1: create .problem file:
$sel->click_ok('//span/input[3]', undef, 'creating problem file');
$sel->wait_for_page_to_load($maxTimeout);
&Util::takeScreenshot('problem file creation');
# Test 2: confirm problem creation
if($sel->get_html_source() =~ m/LC_warning/){
# if test problem already exists
# print "Bail out! $problemname already exists. cancel to prevent data loss." unless $override;
$sel->click_ok('css=input[type="submit"]', undef, "$problemname overwritten");
}else{
# else select blank template
$sel->click('css=input[type="submit"]');
$sel->wait_for_page_to_load($maxTimeout);
$sel->check("//input[\@value='/home/httpd/html/res/adm/includes/templates/blank.problem']");
$sel->click_ok('name=newfile', undef, 'chose blank problem template');
}
# $sel->wait_for_page_to_load($maxTimeout);
}
# Inserts the XML of a maxima problem
# Contains 2 tests
sub testMaxima(){
return if $config{'fast'};
my $maxproblemxml = &Util::getProblemXML_Maxima();
# open problem in editor [Test 1]
if($oldConstrSpace){
$sel->open_ok("/priv/$user/$problemname?forceedit=1", undef, 'open XML editor');
}else{
$sel->open_ok("/priv/$dom/$user/$problemname?editmode=Edit&problemmode=editxml", undef, 'open XML editor');
}
$sel->wait_for_page_to_load($maxTimeout);
# Paste problem xml
$sel->type('name=editxmltext',$maxproblemxml);
&Util::takeScreenshot('xml editor');
# [Test 2] finish creating problem
$sel->click('name=subsaveview');
$sel->wait_for_page_to_load($maxTimeout);
# ok if no error message
&Util::takeScreenshot('finish problem creation');
unlike($sel->get_html_source(), qr/<span class="LC_error">/, 'create problem');
# calculate 20 answers, this may take a while
$sel->click('//div[3]/span/input');
$sel->pause(1000);
# waiting time per problem * nr problem * 1000ms:
$sel->wait_for_page_to_load(2.5*20*1000); #~2.5sec per answer should be fine. if there is a timeout it takes 10sec per timed out answer
}
# Deletes the created problem
# Contains 1 test
sub cleanup(){
if($oldConstrSpace){
$sel->open("/priv/$user/$problemname");
}else{
$sel->open("/priv/$dom/$user/$problemname");
}
$sel->wait_for_page_to_load($maxTimeout);
# clicking the delete button
if($oldConstrSpace){
$sel->click('//li[4]/a/span');
}else{
$sel->click('//ul/li[4]/a/span');
}
$sel->wait_for_page_to_load($maxTimeout);
# now delete problem
$sel->click_ok("css=input[type='submit']", undef, 'cleanup done');
$sel->wait_for_page_to_load($maxTimeout);
}
# Login with bad pw
# Contains 2 tests
sub badLogin(){
return if $config{'fast'};
# page opens
&Util::logout();
$sel->open_ok('/adm/roles', undef, 'login page online');
$sel->wait_for_page_to_load($maxTimeout);
$sel->pause(1000); # stabalize safari
$sel->type('id=uname', $user);
# alles kaka, einfach timestamp oder so verwenden
# my $wrongpw = '§wo at 1g3_f5z??w"i#f'; # wrong password
# # making sure that this is not an actual password...
# if ($pass ne $wrongpw) {
# $sel->type('//div[2]/div/form/input[4]', $wrongpw);
# }else{
# $sel->type('//div[2]/div/form/input[4]', 'somethingdifferent');
# }
my $wrongpw = localtime; # this is a wrong password
$sel->submit('name=client');
$sel->wait_for_page_to_load($maxTimeout);
# ok if no link to loginproblems help page
ok($sel->get_html_source() =~ /href="\/adm\/loginproblems.html"/, 'bad password rejected');
&Util::takeScreenshot('login failed');
}
1;
More information about the LON-CAPA-cvs
mailing list