Index: TestHarness4LAMS2/.classpath =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/.classpath,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/.classpath 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + Index: TestHarness4LAMS2/.project =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/.project,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/.project 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,17 @@ + + + TestHarness4LAMS2 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + Index: TestHarness4LAMS2/20bs.zip =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/Attic/20bs.zip,v diff -u Binary files differ Index: TestHarness4LAMS2/2nbs.zip =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/Attic/2nbs.zip,v diff -u Binary files differ Index: TestHarness4LAMS2/5tools.zip =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/Attic/5tools.zip,v diff -u Binary files differ Index: TestHarness4LAMS2/AllInOneBenchmark.zip =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/AllInOneBenchmark.zip,v diff -u Binary files differ Index: TestHarness4LAMS2/adminTest1.properties =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/adminTest1.properties,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/adminTest1.properties 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,62 @@ +#------------------------------------------------------ +# CallType has 3 valid values: RMI,WS and WEB +# RMI means Remote Method Invocation call; EJB remote interface call is an example. +# WS means Web Service call. +# WEB means URL call. +#------------------------------------------------------- +CallType = WEB +#CallType = WS +#CallType = RMI + +#----------------------------------------------------------------------- +# The value of RMIRegistryName is used when CallType is RMI. +#----------------------------------------------------------------------- +# RMIRegistryName = UserManagementService + +#----------------------------------------------------------------- +# This WebServiceAddress value is used when CallType is WS. +#----------------------------------------------------------------- +# WebServiceAddress = /services/UserManagementService + +#----------------------------------------------------------------- +# 2 URLs to be used have to be defined if CallType is WEB +# Don't change %orgId% as the part to be replaced with the real course Id +#----------------------------------------------------------------- +CreateCourseURL = /admin/organisation.do?method=edit&typeId=2&parentId=1&parentName=Root +CreateUserURL = /admin/user.do?method=edit&orgId=%orgId% + +#--------------------------------------------------------------- +# Set course name for this test. +# The course name created will be prefixed with _ +# If it's not specified, "Course" will be used +#--------------------------------------------------------------- +# CourseName = Course + +#----------------------------------------------------------------- +# If CourseId is set, +# All the settings regarding course creation will be ignored +# This property is used to test against an existing course +#----------------------------------------------------------------- +# CourseId = 1 + +#----------------------------------------------------------------- +# If UserCreated is set to true, all the settings regarding user creation will be ignored +# If not specified, the value of the property will be false. +# If CourseId is not set, this value will be always considered false +#----------------------------------------------------------------- +# UserCreated = true + +#-------------------------------------------------------------- +# sysadmin login info +#-------------------------------------------------------------- +SysadminUsername=sysadmin +SysadminPassword=sysadmin + +#------------------------------------------------------------ +# Set delays (in secounds) which are the amount of idle time between calls to the server +# Delay is used to emulate the time admins spent on viewing other users' age, gender and address ;-) +# delay = MinDelay*1000 + random.nextInt((MaxDelay-MinDelay+1)*1000) +# If not specified, 0 will be used for both. +#------------------------------------------------------------ +# MinDelay = 1 +# MaxDelay = 5 Index: TestHarness4LAMS2/authorTest1.properties =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/authorTest1.properties,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/authorTest1.properties 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,52 @@ +#------------------------------------------------------ +# CallType has 3 valid values: RMI,WS and WEB +# RMI means Remote Method Invocation call; EJB remote interface call is an example. +# WS means Web Service call. +# WEB means URL call. +#------------------------------------------------------- +CallType = WEB +#CallType = WS +#CallType = RMI + +#----------------------------------------------------------------------- +# The value of RMIRegistryName is used when CallType is RMI. +#----------------------------------------------------------------------- +# RMIRegistryName = AuthorService + +#----------------------------------------------------------------- +# This WebServiceAddress value is used when CallType is WS. +#----------------------------------------------------------------- +# WebServiceAddress = /services/LearningDesignService + +#----------------------------------------------------------------- +# This LearningDesignUploadURL value is used when CallType is WEB. +#----------------------------------------------------------------- +LearningDesignUploadURL = /authoring/importToolContent.do?method=import + +#----------------------------------------------------------------- +# This LearningDesignFile is uploaded to import a Learning Design +# It could be relative path or absolute path or any valid URL +#----------------------------------------------------------------- +LearningDesignFile = 2nbs.zip + +#----------------------------------------------------------------- +# If LearningDesignId is set, +# All the settings above will be ignored +# This property is used to test against an existing learning design +#----------------------------------------------------------------- +# LearningDesignId = 1 + +#------------------------------------------------------------------ +# Set the base name of the author +# If it's not specified, "Author" will be used +#------------------------------------------------------------------ +# BaseAuthorName = Shaun + +#------------------------------------------------------------ +# Set delays (in secounds) which are the amount of idle time between calls to the server +# Delay is used to emulate the time authors spent on going to toilet during composing sequences ;-) +# delay = MinDelay*1000 + random.nextInt((MaxDelay-MinDelay+1)*1000) +# If not specified, 0 will be used for both. +#------------------------------------------------------------ +# MinDelay = 1 +# MaxDelay = 5 Index: TestHarness4LAMS2/build.xml =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/build.xml,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/build.xml 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: TestHarness4LAMS2/learnerTest1.properties =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/learnerTest1.properties,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/learnerTest1.properties 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,71 @@ +#------------------------------------------------------ +# CallType has 3 valid values: RMI,WS and WEB +# RMI means Remote Method Invocation call; EJB remote interface call is an example. +# WS means Web Service call. +# WEB means URL call. +#------------------------------------------------------- +CallType = WEB +#CallType = WS +#CallType = RMI + +#----------------------------------------------------------------------- +# The value of RMIRegistryName is used when CallType is RMI. +#----------------------------------------------------------------------- +# RMIRegistryName = LearnerService + +#----------------------------------------------------------------- +# This WebServiceAddress value is used when CallType is WS. +#----------------------------------------------------------------- +# WebServiceAddress = /services/LearnerService + +#------------------------------------------------------------------- +# A bunch of URLs to be used have to be defined if CallType is WEB +#------------------------------------------------------------------- +GetLessonURL = /learning/learner.do?method=getLesson&lessonID=%lsId% +GetLearningDesignURL = /authoring/author.do?method=getLearningDesignDetails&learningDesignID=%ldId% +JoinLessonURL = /learning/learner.do?method=joinLesson&lessonID=%lsId% +GetFlashProgressDataURL = /learning/learner.do?method=getFlashProgressData&lessonID=%lsId% +LessonEntryURL = /learning/DisplayActivity.do?lessonID=%lsId% + +#------------------------------------------------------------------- +# Paths of the files for learner to choose from when he/she need +# upload a file to finish any activity. +# They could be relative or absolute path and are seperated by a semicolon +#------------------------------------------------------------------- +FilesToUpload = lib/wddx.jar;lib/js.jar;lib/httpunit.jar;test.properties;AllInOneBenchmark.zip;readme.txt + +#------------------------------------------------------------------ +# Set the number of learners to be created or updated for this test +# If it's not specified, 1 will be used +#------------------------------------------------------------------ +# NumberOfLearners = 3 + +#------------------------------------------------------------------ +# Set the starting number in numbering the learners +# If it's not specified, 1 will be used +#------------------------------------------------------------------ +# LearnerOffset = 101 + +#------------------------------------------------------------------ +# Set the base name of the learners +# If it's not specified, "Learner" will be used +#------------------------------------------------------------------ +# BaseLearnerName = Dolly + +#----------------------------------------------------------------------- +# If you have defined 3 learners (see NumberOfLearners) you will have +# user password +# _Learner1 _Learner1 +# _Learner2 _Learner2 +# _Learner3 _Learner3 +# +#----------------------------------------------------------------------- + +#------------------------------------------------------------ +# Set delays (in secounds) which are the amount of idle time between calls to the server +# Delay is used to emulate the time learners spent on thinking over how to answer the questions :-( +# delay = MinDelay*1000 + random.nextInt((MaxDelay-MinDelay+1)*1000) +# If not specified, 0 will be used for both. +#------------------------------------------------------------ +MinDelay = 1 +MaxDelay = 5 Index: TestHarness4LAMS2/log.properties =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/log.properties,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/log.properties 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,19 @@ +# default: log all messages ERROR and FATAL to the console and to file +log4j.rootLogger=ERROR, A1, R +log4j.appender.A1=org.apache.log4j.ConsoleAppender +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} %p [%t] %c{1} - %m%n + +# test.log +log4j.appender.R=org.apache.log4j.RollingFileAppender +log4j.appender.R.File=test.log +log4j.appender.R.MaxFileSize=4096KB +log4j.appender.R.MaxBackupIndex=5 +log4j.appender.R.layout=org.apache.log4j.PatternLayout +log4j.appender.R.layout.ConversionPattern=%d{HH:mm:ss,SSS} %p [%t] %c{1} - %m%n + +# package overrides +# change INFO to DEBUG to see more detailed output in log +log4j.logger.org.lamsfoundation.testharness=INFO + + Index: TestHarness4LAMS2/monitorTest1.properties =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/monitorTest1.properties,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/monitorTest1.properties 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,65 @@ +#------------------------------------------------------ +# CallType has 3 valid values: RMI,WS and WEB +# RMI means Remote Method Invocation call; EJB remote interface call is an example. +# WS means Web Service call. +# WEB means URL call. +#------------------------------------------------------- +CallType = WEB +# CallType = WS +# CallType = RMI + +#----------------------------------------------------------------------- +# The value of RMIRegistryName is used CallType is RMI. +#----------------------------------------------------------------------- +# RMIRegistryName = StaffService + +#----------------------------------------------------------------- +# This WebServiceAddress value is used when CallType is WS. +#----------------------------------------------------------------- +# WebServiceAddress = /services/LearningSessionService + +#----------------------------------------------------------------------- +# If not specified, "Lesson" will be used +#----------------------------------------------------------------------- +# LessonName = BenchmarkLesson + +#----------------------------------------------------------------- +# A few URLs have to be defined when CallType is WEB. +#----------------------------------------------------------------- +InitLessonURL = /monitoring/monitoring.do?method=initializeLesson&learningDesignID=%ldId%&userID=%uid%&lessonName=%name%&lessonDescription= +CreateLessonClassURL = /monitoring/createLessonClass?userID=%uid% +StartLessonURL = /monitoring/monitoring.do?method=startLesson&lessonID=%lsId%&userID=%uid% + +GetLessonDetailsURL = /monitoring/monitoring.do?method=getLessonDetails&lessonID=%lsId% +GetContributeActivitiesURL = /monitoring/monitoring.do?method=getAllContributeActivities&lessonID=%lsId% +GetLearningDesignDetailsURL = /authoring/author.do?method=getLearningDesignDetails&learningDesignID=%ldId% +GetAllLearnersProgressURL = /monitoring/monitoring.do?method=getAllLearnersProgress&lessonID=%lsId% + + +#----------------------------------------------------------------- +# If LessonId is set, +# All the settings above and AuthorTest will be ignored +# This property is used to test against an existing lesson +#----------------------------------------------------------------- +# LessonId = 1 + +#------------------------------------------------------------------ +# Set the base name of the monitor +# If it's not specified, "Monitor" will be used +#------------------------------------------------------------------ +# BaseMonitorName = Ernie + +#------------------------------------------------------------------ +# Set the user id of the monitor. +# It should be set if and only if LessonId is not set and UserCreated is true in adminTest +#------------------------------------------------------------------ +# UserId = 100 + +#------------------------------------------------------------ +# Set delays (in secounds) which are the amount of idle time between calls to the server +# Delay is used to emulate the time monitors spent on watching where the learners are stuck ;-) +# delay = MinDelay*1000 + random.nextInt((MaxDelay-MinDelay+1)*1000) +# If not specified, 0 will be used for both. +#------------------------------------------------------------ +MinDelay = 2 +MaxDelay = 10 Index: TestHarness4LAMS2/optional.zip =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/optional.zip,v diff -u Binary files differ Index: TestHarness4LAMS2/readme.txt =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/readme.txt,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/readme.txt 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,54 @@ +Usage steps: + +1.Take a look at the properties files in this folder first and edit them as you need. + Usually you need only modify the following properties : + * TargetServer and httpPort in the master test properties file called test.properties usually + * NumberOfLearners in learner test properties file + * LearningDesignFile in author test properties file + +2.Execute "run" ant target on any platform with Apache Ant installed, + or go to TestHarness4LAMS2 dir in windows explorer or on command line, + and execute run.bat if you are on Microsoft Windows platform. + +* Modify log.properties according to the comments in it to change level of log details + +Disclaimer : + + This program is created in the hope that it will help estimate how many concurrent + users a LAMS 2.x server can handle, but WITHOUT ANY GARANTEE the server can support + that number of users in service use. + + This program is more a load test tool than a functional test tool, + so it does NOT GARANTEE there is no functional bug in the target server. + + +TODO list: + +1. Add support for any kind of activitis. + + Currently only support activities which consists of pages only with only one + "standard" form whose submit are not triggered by javascript. + These activities include: + + 1) noticeboard + 2) grouping + 3) notebook + 4) multiple choice + + Not supported are parallel activities and activities which has pages without + forms (such as Share Resources) or forms whose submission are triggered by + javascript or with multiple forms ( such as Chat and Optional) + +2. Generate formal test report document + + +TODO JUST FOR FUN list: + +1. Add Master/Slave mode support so that a few PCs can collaborate on one testsuite. + Persisting test records in Master PC's database could be the easiest way to + implement that. + +2. Implement GUI based test manager + +3. Implement RMI and WS tests if they are implemented in LAMS 2 in future. + \ No newline at end of file Index: TestHarness4LAMS2/run.bat =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/run.bat,v diff -u Binary files differ Index: TestHarness4LAMS2/test.properties =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/test.properties,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/test.properties 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,92 @@ +#----------------------------------------------------------------- +# Test report file name. +# Timestamp will be added to the name by the application +#----------------------------------------------------------------- +ReportFileName = testReport + +#----------------------------------------------------------------- +# Test report file template. +# The file path could be relative or absolute +#----------------------------------------------------------------- +ReportFileTemplate = testReport.html; + +#----------------------------------------------------------------- +# index page +#----------------------------------------------------------------- +IndexPageURL = /index.jsp + +#------------------------------------------------------------------ +# This is the master property file. +# It organises single tests into test suites. +# +# Each test suite definition typically involves: +# one TargetServer., +# one ContextRoot., +# one RMIRegistryServicePort., +# one HttpPort., +# one AdminTestPropertyFile., +# one AuthorTestPropertyFile., +# one MonitorTestPropertyFile., +# one LearnerTestPropertyFile., +# +# To avoid any test, just do not specify the corresponding xxxTestPropertyFile +# +# +# Example : +# NumberOfTestSuites=2 +# +# TargetServer.1=saturn.melcoe.mq.edu.au +# ContextRoot.1=/lams +# RMIRegistryServicePort.1=12345 +# HttpPort.1=8080 +# AdminTestPropertyFile.1=adminTest1.properties +# AuthorTestPropertyFile.1=authorTest1.properties +# MonitorTestPropertyFile.1=monitorTest1.properties +# LearnerTestPropertyFile.1=learnerTest1.properties +# +# TargetServer.2=lams.melcoe.mq.edu.au +# ContextRoot.2=/ +# RMIRegistryServicePort.2=54321 +# HttpPort.2=1080 +# MonitorTestPropertyFile.2=monitorTest2.properties +# LearnerTestPropertyFile.2=learnerTest2.properties +# +# Note: in the second test suite, there are only 2 tests, in which case +# Either LessonId or UserId must be set in monitorTest2.properties file +# +#------------------------------------------------------------------- + +NumberOfTestSuites=1 + +#--------------------------------------------------------- +# if TargetServer is not specified, localhost will be used. +#--------------------------------------------------------- +# TargetServer.1=shaun.melcoe.mq.edu.au + +#---------------------------------------------------------- +# LAMS central web application context root +# If not specified, empty context root will be used +# other modules's context roots must be: +# /admin +# /learning +# /monitoring +# Since "admin","learning","monitoring" are hard coded in +# lams-central JSPs as part of relative path +#---------------------------------------------------------- +ContextRoot.1=/lams + +#-------------------------------------------------------------- +# if RMIRegistryServicePort is not specified, 1099 will be used. +#-------------------------------------------------------------- +# RMIRegistryServicePort.1=12345 + +#-------------------------------------------------------------- +# if HttpPort is not specified, 80 will be used. +#-------------------------------------------------------------- +HttpPort.1=8080 + +AdminTestPropertyFile.1=adminTest1.properties +AuthorTestPropertyFile.1=authorTest1.properties +MonitorTestPropertyFile.1=monitorTest1.properties +LearnerTestPropertyFile.1=learnerTest1.properties + Index: TestHarness4LAMS2/testReport.html =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/Attic/testReport.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/testReport.html 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,33 @@ + + + + + LAMS::Testharness Report + + + + + + + + + + Testharness Report generated at ${time} +
    + <#list testsuites as testsuite> +
  • Test Suite ${testsuite.index} : ${testsuite.finished} +
      +
    • ${testsuite.adminTest.testName} : <#if ${testsuite.adminTest.finished}>Finished<#else>Aborted<#/if>
    • +
    • ${testsuite.authorTest.testName} : <#if ${testsuite.authorTest.finished}>Finished<#else>Aborted<#/if>
    • +
    • ${testsuite.monitorTest.testName} : <#if ${testsuite.monitorTest.finished}>Finished<#else>Aborted<#/if>
    • +
    • ${testsuite.learnerTest.testName} : <#if ${testsuite.learnerTest.finished}>Finished<#else>Aborted<#/if>
    • +

      ${testsuite.learnerTest.users.length} Learners attended, + in which ${testsuite.learnerTest.countFinished} learner(s) finished, + and ${testsuite.learnerTest.countAborted} learner(s) aborted.

      +
    +
  • + +
+ + + Index: TestHarness4LAMS2/lib/BrowserLauncher2-all-10rc4.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/BrowserLauncher2-all-10rc4.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/Tidy.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/Attic/Tidy.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/commons-codec-1.1.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/commons-codec-1.1.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/httpunit.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/httpunit.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/jars.txt =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/Attic/jars.txt,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/lib/jars.txt 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,8 @@ +Jars used: + +(runtime) +httpunit 1.6 +junit 3.8.1 +servlet 2.3 +jtidy 04aug2000r7-dev +rhino(js.jar) 1.5R4.1 Index: TestHarness4LAMS2/lib/js.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/Attic/js.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/junit.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/Attic/junit.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/log4j-1.2.13.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/log4j-1.2.13.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/nekohtml-0.9.5.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/nekohtml-0.9.5.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/servlet.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/Attic/servlet.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/wddx.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/Attic/wddx.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/xercesImpl.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/Attic/xercesImpl.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/lib/xml-apis.jar =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/lib/Attic/xml-apis.jar,v diff -u Binary files differ Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/AbstractTest.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/AbstractTest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/AbstractTest.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,144 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness; + +import org.apache.log4j.Logger; +import org.lamsfoundation.testharness.Call.CallType; + + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public abstract class AbstractTest +{ + + private static final Logger log = Logger.getLogger(AbstractTest.class); + + protected TestSuite testSuite; + protected final String testName; + protected final CallType callType; + protected String rmiRegistryName; + protected String webServiceAddress; + protected final Integer minDelay; + protected final Integer maxDelay; + protected MockUser[] users; + protected boolean finished = false; + + protected AbstractTest(String name, CallType type, String rmiRegistryName, String address, Integer minDelay, Integer maxDelay) { + this.testName = name; + this.callType = type; + this.rmiRegistryName = rmiRegistryName; + this.webServiceAddress = address; + this.minDelay = minDelay==null? 0 : minDelay; + this.maxDelay = maxDelay==null? 0 : maxDelay; + } + + public final void start(){ + try{ + log.info("Starting "+testName+"..."); + switch (callType) { + case WEB: + startWEB(); + break; + case WS: + startWS(); + break; + case RMI: + startRMI(); + break; + default: + break; + } + finished = true; + log.info(testName+" is finished"); + }catch(RuntimeException e){ + log.info(testName+" aborted"); + //Since latter tests depend on precedent tests in a test suite, + //propagate the exception to let the test suite stop executing the latter tests + throw e; + } + } + + protected abstract void startWEB(); + + protected abstract void startWS(); + + protected abstract void startRMI(); + + /** + * @return Returns the testSuite. + */ + public final TestSuite getTestSuite() { + return testSuite; + } + + /** + * @param testSuite The testSuite to set. + */ + public final void setTestSuite(TestSuite testSuite) { + this.testSuite = testSuite; + } + + public final MockUser[] getUsers() { + return users; + } + + public final void setUsers(MockUser[] users) { + this.users = users; + } + + public final CallType getCallType() { + return callType; + } + + public final String getRmiRegistryName() { + return rmiRegistryName; + } + + public final String getTestName() { + return testName; + } + + public final String getWebServiceAddress() { + return webServiceAddress; + } + + public final Integer getMaxDelay() { + return maxDelay; + } + + public final Integer getMinDelay() { + return minDelay; + } + + public final boolean isFinished() { + return finished; + } + +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/AbstractTestManager.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/Attic/AbstractTestManager.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/AbstractTestManager.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,134 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import org.apache.log4j.Logger; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public abstract class AbstractTestManager { + + private static final Logger log = Logger.getLogger(AbstractTestManager.class); + + protected List testSuites = new LinkedList(); + + protected static final Integer MAX_USERNAME_LENGTH = 20; + + protected CountDownLatch allDoneSignal; + + /** + * This is where test manager initializes the test suites. + * Must set TestReport's reportFileName and reportFileTemplate here. + */ + protected abstract void init(); + + protected final void kickOff(){ + init(); + if(!TestReporter.initialized()){ + throw new TestHarnessException("TestReport class is not initialized! It should be a bug in the AbstractTestManager implementation"); + } + log.info(composeStartInfo()); + for (int i = 0; i < testSuites.size(); i++) { + new Thread(testSuites.get(i),"TestSuite-"+testSuites.get(i).getSuiteIndex()).start(); + } + if(testSuites.size()>0){ + allDoneSignal = new CountDownLatch(testSuites.size()); + try{ + allDoneSignal.await(); + }catch(InterruptedException e){ + log.fatal(e.getMessage(), e); + //what to do? + } + } + log.info(composeEndInfo()); + } + + private String composeStartInfo() { + switch (testSuites.size()) { + case 0: + return "There is no test suite found on the list"; + case 1: + return "Kicking off the test suite..."; + default: + return "Kicking off the " + testSuites.size() + " test suites..."; + } + } + + private String composeEndInfo() { + switch (testSuites.size()) { + case 0: + return "So we can play the game now"; + case 1: + if(countAborted()==0) + return "The only test suite is finished"; + else + return "The only test suite aborted"; + case 2: + switch(countAborted()){ + case 0: + return "Both the test suites are finished"; + case 1: + return "One test suite is finished, and the other aborted"; + case 2: + return "Both the test suites aborted"; + default: + return "Impossible! "+countAborted()+" out of "+testSuites.size()+" testSuites aborted!"; + } + default: + if(countAborted() == 0) + return "All the test suites are finished"; + else if(countAborted() == testSuites.size()) + return "All the test suites aborted"; + else{ + int abortedCounter = countAborted(); + int finishedCounter = testSuites.size()-countAborted(); + return finishedCounter+" test suite"+(finishedCounter>1? "s are finished and " : " is finished and ") + + abortedCounter + "test suite"+(abortedCounter>1? "s aborted":" aborted"); + } + } + } + + protected final void addTestSuite(TestSuite suite) { + testSuites.add(suite); + } + + protected final int countAborted(){ + int amount = 0; + for(TestSuite suite : testSuites){ + if (!suite.isFinished()) + amount++; + } + return amount; + } +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/Call.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/Call.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/Call.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,339 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.xml.sax.SAXException; + +import com.meterware.httpunit.GetMethodWebRequest; +import com.meterware.httpunit.PostMethodWebRequest; +import com.meterware.httpunit.SubmitButton; +import com.meterware.httpunit.WebConversation; +import com.meterware.httpunit.WebForm; +import com.meterware.httpunit.WebRequest; +import com.meterware.httpunit.WebResponse; + + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class Call { + + private static final Logger log = Logger.getLogger(Call.class); + + private static final String HTTP = "http://"; + + private static final String GET = "GET "; + + private static final String POST = "POST "; + + private static final char COLON = ':'; + + private static final char SPACE = ' '; + + private static final String NON_HTTP_ERROR = "Check the log for the error message"; + + private WebConversation wc; //for WEB + + private AbstractTest test; + + private String description; + + @SuppressWarnings("unused") + private String method; //for RMI and WS + + @SuppressWarnings("unused") + private Map parameters; //for RMI or WS + + private String url; //for WEB + + private WebForm form; //for WEB + + private InputStream is; //for WEB POST method + + private String contentType; //for WEB POST method + + public Call(WebConversation wc, AbstractTest test, String description, WebForm form) { + this.wc = wc; + this.test = test; + this.description = description; + this.form = form; + } + + public Call(AbstractTest test, String description, String method, Map parameters) { + this.test = test; + this.description = description; + this.method = method; + this.parameters = parameters; + } + + public Call(WebConversation wc, AbstractTest test, String description, String url, InputStream is, String contentType) { + this.wc = wc; + this.test = test; + this.description = description; + this.url = url; + this.is = is; + this.contentType = contentType; + } + + public Call(WebConversation wc, AbstractTest test, String description, String url) { + this.wc = wc; + this.test = test; + this.description = description; + this.url = url; + } + + public AbstractTest getTest() { + return test; + } + + /** + * need add CallRecord to TestReport + */ + public Object execute(){ + switch(test.callType){ + case RMI: return executeRMI(); + case WS: return executeWS(); + case WEB: return executeHttpRequest(); + default: return null; + } + } + + private Object executeHttpRequest(){ + String message = null; + String callee = null; + Integer httpStatusCode = null; + long start =0, end = 0; + try{ + WebResponse resp; + if(form!=null){ + SubmitButton[] submitButtons = filterCancelButton(form.getSubmitButtons()); + log.debug(submitButtons.length+" non-cancel submit button(s) in the form"); + WebRequest req; + if(submitButtons.length <= 1){ + req = form.getRequest(); + }else{ + req = form.getRequest(submitButtons[TestUtil.generateRandomIndex(submitButtons.length)]); + } + callee = form.getMethod().toUpperCase() + SPACE + form.getAction(); + log.debug(callee); + start = System.currentTimeMillis(); + resp = wc.getResponse(req); + end = System.currentTimeMillis(); + }else{ + String absoluteURL = getAbsoluteURL(url); + WebRequest req; + if(is==null){ + callee = GET+url; + req = new GetMethodWebRequest(absoluteURL); + }else{ + callee = POST+url; + req = new PostMethodWebRequest(absoluteURL,is,contentType); + } + log.debug(callee); + start = System.currentTimeMillis(); + resp = wc.getResponse( req ); + end = System.currentTimeMillis(); + } + httpStatusCode = resp.getResponseCode(); + message = resp.getResponseMessage(); + + /*if(callee.indexOf("passon.swf")==-1) + log.debug(resp.getText());*/ + + if(resp.getResponseCode() >= 400){ + log.debug(resp.getText()); + throw new TestHarnessException(test.testName + " Got http error code "+httpStatusCode); + } + return resp; + }catch(IOException e){ + message = NON_HTTP_ERROR; + log.debug(e.getMessage(),e); + throw new RuntimeException(e); + } catch (SAXException e) { + message = NON_HTTP_ERROR; + log.debug(e.getMessage(),e); + throw new RuntimeException(e); + }finally{ + TestReporter.addCallRecord(new CallRecord(test.getTestSuite().getSuiteIndex(),test.testName,test.callType,callee,description,end,end-start,httpStatusCode,message)); + } + } + + + private SubmitButton[] filterCancelButton(SubmitButton[] sbmtBtns){ + boolean found = false; + int i = 0; + for(; i < sbmtBtns.length; i++){ + if(isCancelButton(sbmtBtns[i])){ + found = true; + break; + } + } + if(found){ + SubmitButton[] btns = new SubmitButton[sbmtBtns.length-1]; + int j = 0; + for(int k = 0; k < sbmtBtns.length; k++){ + if( k != i ){ + btns[j] = sbmtBtns[k]; + j++; + } + } + return btns; + }else{ + return sbmtBtns; + } + } + + private boolean isCancelButton(SubmitButton button) { + if(button.getName().contains("CANCEL")||button.getName().contains("Cancel")||button.getName().contains("cancel") + ||button.getValue().contains("cancel")||button.getValue().contains("Cancel")||button.getValue().contains("CANCEL")) + return true; + return false; + } + + /** + * TODO implement me + * @param + * @return + */ + private Object executeWS() { + return null; + } + + /** + * TODO implement me + * @param + * @return + */ + private Object executeRMI() { + return null; + } + + private String getAbsoluteURL(String url){ + if(test.getTestSuite().getHttpPort()!=80) + return HTTP+test.getTestSuite().getTargetServer()+COLON+test.getTestSuite().getHttpPort()+test.getTestSuite().getContextRoot()+url; + else + return HTTP+test.getTestSuite().getTargetServer()+test.getTestSuite().getContextRoot()+url; + } + + protected static class CallRecord { + + private int suiteIndex; + private String testName; + private CallType type; + private String callee; + private String description; + private long snapShotTime; + private long timeInMillis; + private Integer httpStatusCode;//for Web Call only + private String message; + + + public CallRecord(){ + //empty constructor + } + + public CallRecord(int suiteIndex, String testName, CallType type, String callee, String description, long snapShotTime, long timeInMillis, Integer httpStatusCode, String message) { + this.suiteIndex = suiteIndex; + this.testName = testName; + this.type = type; + this.callee = callee; + this.description = description; + this.snapShotTime = snapShotTime; + this.timeInMillis = timeInMillis; + this.httpStatusCode = httpStatusCode; + this.message = message; + } + + public String getMessage() { + return message; + } + + public long getSnapShotTime() { + return snapShotTime; + } + + public long getTimeInMillis() { + return timeInMillis; + } + + public String getCallee() { + return callee; + } + + public CallType getType() { + return type; + } + + public String getTestName() { + return testName; + } + + public int getSuiteIndex() { + return suiteIndex; + } + + public String getDescription() { + return description; + } + + public final Integer getHttpStatusCode() { + return httpStatusCode; + } + } + + public enum CallType { + + RMI,WS,WEB,UNKNOWN; + + public static CallType get(String value){ + if(value.equals("RMI")) + return CallType.RMI; + else if(value.equals("WS")) + return CallType.WS; + else if(value.equals("WEB")) + return CallType.WEB; + else return CallType.UNKNOWN; + } + + public String getName(){ + switch(this){ + case RMI: return "RMI"; + case WS: return "WS"; + case WEB: return "WEB"; + default: return "Unknown"; + } + } + } + +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/Main.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/Main.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/Main.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,75 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.testharness; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; + +import com.meterware.httpunit.HttpUnitOptions; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + * + */ +public class Main { + + static { + // configure log4j + PropertyConfigurator.configure("log.properties"); + // configure HttpUnit + // stops the unsupported javascript stuff from throwing an exception + HttpUnitOptions.setExceptionsThrownOnScriptError(false); + //WebClient.getResponse does not throw an exception when it receives an error status. + HttpUnitOptions.setExceptionsThrownOnErrorStatus(false); + } + + private static final Logger log = Logger.getLogger(Main.class); + + /** + * @param args + */ + public static void main(String[] args) { + log.info("Starting..."); + if (args.length == 0) { + log.error("No argument supplied! Please refer to readme.txt"); + System.exit(1); + } + // create test manager and hand over the control to him. + AbstractTestManager manager = new PropertyFileTestManager(args[0]); + try{ + manager.kickOff(); + TestReporter.generateReport(manager); + log.info("It's done, anyway"); + }catch(Exception e){ + log.error(e.getMessage(),e); + System.exit(1); + } + } +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/MockUser.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/MockUser.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/MockUser.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,194 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness; + +import java.io.File; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.codec.binary.Hex; +import org.apache.log4j.Logger; +import org.xml.sax.SAXException; + +import com.meterware.httpunit.UploadFileSpec; +import com.meterware.httpunit.WebConversation; +import com.meterware.httpunit.WebForm; +import com.meterware.httpunit.WebResponse; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class MockUser{ + + private static final Logger log = Logger.getLogger(MockUser.class); + + private static final String[] DELAY_MESSAGES = {" is deserting ", " is napping ", " is pondering ", " is in a daze ", " will have a cup of coffee for ", " is away for toilet "}; + + private static final String LOGIN_PAGE_FLAG = "j_security_check"; + private static final String INDEX_PAGE_FLAG = "Math.random()"; + + private static final String USERNAME = "j_username"; + private static final String PASSWORD = "j_password"; + + private static String indexPage; + + protected AbstractTest test; + protected String userId; + protected String username; + protected String password; + protected WebConversation wc; + + public MockUser(AbstractTest test, String username, String password, String userId) { + this.test = test; + this.username = username; + this.password = password; + this.userId = userId; + } + + public static final void setIndexPage(String indexPageURL){ + indexPage = indexPageURL; + } + + /** + * Login to the system. + * + * @exception TestHarnessException:failure + */ + public final void login() + { + try{ + wc = new WebConversation(); + WebResponse resp = (WebResponse)new Call(wc,test,username+" fetch index page",indexPage).execute(); + if(!checkPageContains(resp,LOGIN_PAGE_FLAG)){ + log.debug(resp.getText()); + throw new TestHarnessException(username +" didn't get login page when hitting LAMS the first time!"); + } + Map params = new HashMap(); + params.put(USERNAME,username); + params.put(PASSWORD,HashUtil.sha1(password)); + resp = (WebResponse)new Call(wc, test,"User login",fillForm(resp,0,params)).execute(); + if(!checkPageContains(resp,INDEX_PAGE_FLAG)){ + log.debug(resp.getText()); + throw new TestHarnessException(username+" failed to login with password "+password); + } + }catch(IOException e){ + throw new RuntimeException(e); + }catch(SAXException e){ + throw new RuntimeException(e); + }catch(NoSuchAlgorithmException e){ + throw new RuntimeException(e); + } + } + + protected final WebForm fillForm(WebResponse resp, int formIndex, Map params) throws SAXException, IOException{ + WebForm[] forms = resp.getForms(); + if((forms==null)||(forms.length<=formIndex)){ + log.debug(resp.getText()); + throw new TestHarnessException(username + " cannot find the form whose index is "+formIndex+" in the page"); + } + WebForm form = forms[formIndex]; + if (params != null) { + for (Map.Entry entry : params.entrySet()) { + Object value = entry.getValue(); + if (value instanceof String) { + form.setParameter(entry.getKey(), (String) entry.getValue()); + } else if (value instanceof File) { + form.setParameter(entry.getKey(), (File) entry.getValue()); + } else if (value instanceof String[]) { + form.setParameter(entry.getKey(), (String[]) entry.getValue()); + } else if (value instanceof UploadFileSpec[]) { + form.setParameter(entry.getKey(), (UploadFileSpec[]) entry.getValue()); + } else { + throw new TestHarnessException("Unsupported parameter value type:" + entry.getValue().getClass().getName()); + } + } + } + return form; + } + + protected final boolean checkPageContains(WebResponse resp,String flag) throws IOException + { + return resp.getText().indexOf(flag)!=-1; + } + + protected final void delay(){ + try{ + int seconds; + if(test.getMaxDelay() <= test.getMinDelay()){//to avoid IllegalArgumentException in nextInt method on Random object + seconds = test.getMinDelay(); + }else{ + seconds = test.getMinDelay() + TestUtil.generateRandomIndex(test.getMaxDelay() - test.getMinDelay() + 1 ); + } + if(seconds>0){ + log.info(composeDelayInfo(seconds)); + Thread.sleep(seconds * 1000); + } + }catch (InterruptedException e){ + //ignore + } + } + + private String composeDelayInfo(int seconds) { + return username+DELAY_MESSAGES[TestUtil.generateRandomIndex(DELAY_MESSAGES.length)] + seconds + (seconds==1? " second" : " seconds"); + } + + private static class HashUtil { + + static String sha1(String plaintext) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA1"); + return new String(Hex.encodeHex(md.digest(plaintext.getBytes()))); + } + + static String md5(String plaintext) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("MD5"); + return new String(Hex.encodeHex(md.digest(plaintext.getBytes()))); + } + + } + + public final String getPassword() { + return password; + } + + public final String getUsername() { + return username; + } + + public final String getUserId() { + return userId; + } + + public final void setUserId(String userId) { + this.userId = userId; + } + +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/PropertyFileTestManager.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/Attic/PropertyFileTestManager.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/PropertyFileTestManager.java 31 Jul 2006 02:04:29 -0000 1.1 @@ -0,0 +1,422 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.apache.log4j.Logger; + +import org.lamsfoundation.testharness.admin.AdminTest; +import org.lamsfoundation.testharness.admin.MockAdmin; +import org.lamsfoundation.testharness.author.AuthorTest; +import org.lamsfoundation.testharness.author.MockAuthor; +import org.lamsfoundation.testharness.learner.LearnerTest; +import org.lamsfoundation.testharness.learner.MockLearner; +import org.lamsfoundation.testharness.monitor.MockMonitor; +import org.lamsfoundation.testharness.monitor.MonitorTest; + +import org.lamsfoundation.testharness.Call.CallType; +import static org.lamsfoundation.testharness.Call.CallType.*; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class PropertyFileTestManager extends AbstractTestManager { + + private static final Logger log = Logger.getLogger(PropertyFileTestManager.class); + + // property keys of the master property file + private static final String REPORT_FILE_NAME = "ReportFileName"; + private static final String REPORT_FILE_TEMPLATE = "ReportFileTemplate"; + private static final String INDEX_PAGE_URL = "IndexPageURL"; + private static final String NUMBER_OF_TEST_SUITES = "NumberOfTestSuites"; + private static final String TARGET_SERVER = "TargetServer"; + private static final String CONTEXT_ROOT = "ContextRoot"; + private static final String RMI_REGISTRY_SERVICE_PORT = "RMIRegistryServicePort"; + private static final String HTTP_PORT = "HttpPort"; + private static final String ADMIN_PROPERTY_FILE = "AdminTestPropertyFile"; + private static final String AUTHOR_PROPERTY_FILE = "AuthorTestPropertyFile"; + private static final String MONITOR_PROPERTY_FILE = "MonitorTestPropertyFile"; + private static final String LEARNER_PROPERTY_FILE = "LearnerTestPropertyFile"; + + //common property keys of all the single tests(admin test, author test, monitor test, learner test) + private static final String CALL_TYPE = "CallType"; + private static final String WEB_SERVICE_ADDRESS = "WebServiceAddress"; + private static final String RMI_REGISTRY_NAME = "RMIRegistryName"; + private static final String MIN_DELAY = "MinDelay"; + private static final String MAX_DELAY = "MaxDelay"; + + //property keys of admin test + private static final String CREATE_COURSE_URL = "CreateCourseURL"; + private static final String CREATE_USER_URL = "CreateUserURL"; + private static final String COURSE_NAME = "CourseName"; + private static final String COURSE_ID = "CourseId"; + private static final String USER_CREATED = "UserCreated"; + private static final String SYSADMIN_USERNAME = "SysadminUsername"; + private static final String SYSADMIN_PASSWORD = "SysadminPassword"; + + //property keys of author test + private static final String LEARNING_DESIGN_UPLOAD_URL = "LearningDesignUploadURL"; + private static final String LEARNING_DESIGN_FILE = "LearningDesignFile"; + private static final String LEARNING_DESIGN_ID = "LearningDesignId"; + private static final String BASE_AUTHOR_NAME = "BaseAuthorName"; + + //property keys of monitor test + private static final String INIT_LESSON_URL = "InitLessonURL"; + private static final String CREATE_LESSON_CLASS_URL = "CreateLessonClassURL"; + private static final String START_LESSON_URL = "StartLessonURL"; + private static final String LESSON_ID = "LessonId"; + private static final String LESSON_NAME = "LessonName"; + private static final String USER_ID = "UserId"; + private static final String BASE_MONITOR_NAME = "BaseMonitorName"; + private static final String GET_LESSON_DETAILS_URL = "GetLessonDetailsURL"; + private static final String GET_CA_URL = "GetContributeActivitiesURL"; + private static final String GET_LD_DETAILS_URL = "GetLearningDesignDetailsURL"; + private static final String GET_ALL_PROGRESS_URL = "GetAllLearnersProgressURL"; + + //property keys of learner test + private static final String NUMBER_LEARNERS = "NumberOfLearners"; + private static final String LEARNER_OFFSET = "LearnerOffset"; + private static final String BASE_LEARNER_NAME = "BaseLearnerName"; + private static final String GET_LESSON_URL = "GetLessonURL"; + private static final String GET_LD_URL = "GetLearningDesignURL"; + private static final String JOIN_LESSON_URL = "JoinLessonURL"; + private static final String GET_PROGRESS_URL = "GetFlashProgressDataURL"; + private static final String LESSON_ENTRY_URL = "LessonEntryURL"; + private static final String FILES_TO_UPLOAD = "FilesToUpload"; + + private String testPropertyFileName; + + public PropertyFileTestManager(String name) { + this.testPropertyFileName = name; + } + + /** + * + * @see org.lamsfoundation.testharness.AbstractTestManager#init() + */ + protected void init(){ + log.info("Initializing..."); + Properties testProperties = PropertyUtil.loadProperties(testPropertyFileName); + TestReporter.setFileName(PropertyUtil.getStringProperty(testPropertyFileName,testProperties,REPORT_FILE_NAME,false)); + MockUser.setIndexPage(PropertyUtil.getStringProperty(testPropertyFileName,testProperties,INDEX_PAGE_URL,false)); + String fileTemplate = PropertyUtil.getStringProperty(testPropertyFileName,testProperties,REPORT_FILE_TEMPLATE,false); + TestReporter.setFileTemplate(fileTemplate); + int numberOfTestSuites = PropertyUtil.getIntegerProperty(testPropertyFileName, + testProperties, NUMBER_OF_TEST_SUITES, false); + for (int i = 1; i < numberOfTestSuites+1; i++) { + addTestSuite(createTestSuite(testProperties, i)); + } + log.info("Finished initialization"); + } + /** + * @return Returns the propertyFileName. + */ + public String getTestPropertyFileName() { + return testPropertyFileName; + } + + + private String buildPropertyKey(String basePropertyKey, int suiteIndex){ + return basePropertyKey+"."+suiteIndex; + } + + private String extractTestName(String propertyFileName){ + return propertyFileName.substring(0,propertyFileName.indexOf(".properties")); + } + + private TestSuite createTestSuite(Properties testProperties, int suiteIndex){ + log.info("Creating test suite " + suiteIndex+ "..."); + String targetServer = PropertyUtil.getStringProperty(testPropertyFileName,testProperties,buildPropertyKey(TARGET_SERVER,suiteIndex),true); + String contextRoot = PropertyUtil.getStringProperty(testPropertyFileName,testProperties,buildPropertyKey(CONTEXT_ROOT,suiteIndex),true); + Integer rmiRegistryServicePort = PropertyUtil.getIntegerProperty(testPropertyFileName,testProperties,buildPropertyKey(RMI_REGISTRY_SERVICE_PORT,suiteIndex),true); + Integer httpPort = PropertyUtil.getIntegerProperty(testPropertyFileName,testProperties,buildPropertyKey(HTTP_PORT,suiteIndex),true); + String adminTestPropertyFileName = PropertyUtil.getStringProperty(testPropertyFileName,testProperties,buildPropertyKey(ADMIN_PROPERTY_FILE,suiteIndex),true); + AdminTest adminTest = adminTestPropertyFileName==null? null : createAdminTest(adminTestPropertyFileName); + String authorTestPropertyFileName = PropertyUtil.getStringProperty(testPropertyFileName,testProperties,buildPropertyKey(AUTHOR_PROPERTY_FILE,suiteIndex),true); + AuthorTest authorTest = authorTestPropertyFileName==null? null : createAuthorTest(authorTestPropertyFileName); + String monitorTestPropertyFileName = PropertyUtil.getStringProperty(testPropertyFileName,testProperties,buildPropertyKey(MONITOR_PROPERTY_FILE,suiteIndex),true); + MonitorTest monitorTest = monitorTestPropertyFileName==null? null : createMonitorTest(monitorTestPropertyFileName); + String learnerTestPropertyFileName = PropertyUtil.getStringProperty(testPropertyFileName,testProperties,buildPropertyKey(LEARNER_PROPERTY_FILE,suiteIndex),true); + LearnerTest learnerTest = learnerTestPropertyFileName==null? null : createLearnerTest(learnerTestPropertyFileName); + TestSuite suite = new TestSuite(this, suiteIndex,targetServer,contextRoot,rmiRegistryServicePort,httpPort,adminTest,authorTest,monitorTest,learnerTest); + log.info("Finished creating test suite " + suite.toString()); + return suite; + } + + private LearnerTest createLearnerTest(String learnerTestPropertyFileName){ + String testName = extractTestName(learnerTestPropertyFileName); + log.info("Creating learner test:"+testName+"..."); + Properties learnerTestProperties = PropertyUtil + .loadProperties(learnerTestPropertyFileName); + CallType callType = get(PropertyUtil.getStringProperty(learnerTestPropertyFileName, + learnerTestProperties, CALL_TYPE, false)); + String learnerRMIRegistryName = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, RMI_REGISTRY_NAME, + !callType.equals(Call.CallType.RMI)); + String webServiceAddress = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, WEB_SERVICE_ADDRESS, + !callType.equals(Call.CallType.WS)); + Integer minDelay = PropertyUtil.getIntegerProperty( + learnerTestPropertyFileName, learnerTestProperties, MIN_DELAY, true); + Integer maxDelay = PropertyUtil.getIntegerProperty( + learnerTestPropertyFileName, learnerTestProperties, MAX_DELAY,true); + Integer numberOfLearners = PropertyUtil.getIntegerProperty( + learnerTestPropertyFileName, learnerTestProperties, NUMBER_LEARNERS,true); + Integer learnerOffset = PropertyUtil.getIntegerProperty( + learnerTestPropertyFileName, learnerTestProperties, LEARNER_OFFSET,true); + String baseLearnerName = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, BASE_LEARNER_NAME, true); + String getLessonURL = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, GET_LESSON_URL, !callType.equals(Call.CallType.WEB)); + String getLearningDesignURL = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, GET_LD_URL, !callType.equals(Call.CallType.WEB)); + String joinLessonURL = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, JOIN_LESSON_URL, !callType.equals(Call.CallType.WEB)); + String getProgressURL = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, GET_PROGRESS_URL, !callType.equals(Call.CallType.WEB)); + String lessonEntryURL = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, LESSON_ENTRY_URL, !callType.equals(Call.CallType.WEB)); + String filesToUpload = PropertyUtil.getStringProperty( + learnerTestPropertyFileName, learnerTestProperties, FILES_TO_UPLOAD, !callType.equals(Call.CallType.WEB)); + LearnerTest test = new LearnerTest(testName,callType,learnerRMIRegistryName,webServiceAddress,minDelay,maxDelay, getLessonURL,getLearningDesignURL,joinLessonURL,getProgressURL,lessonEntryURL, filesToUpload==null? null : filesToUpload.split(";")); + numberOfLearners = numberOfLearners == null? 1 : numberOfLearners; + learnerOffset = learnerOffset==null? 1 : learnerOffset; + MockLearner[] learners = new MockLearner[numberOfLearners]; + for(int i=0; i + * View Source + *

+ * + * @author Fei Yang + */ +public class TestHarnessException extends RuntimeException { + + private static final long serialVersionUID = 6481839981681761094L; + + /** + * Constructor for TestHarnessException. + */ + public TestHarnessException() { + super(); + } + + /** + * Constructor for TestHarnessException. + * @param message + */ + public TestHarnessException(String message) { + super(message); + } + + /** + * Constructor for TestHarnessException. + * @param message + * @param cause + */ + public TestHarnessException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructor for TestHarnessException. + * @param cause + */ + public TestHarnessException(Throwable cause) { + super(cause); + } + +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestReporter.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestReporter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestReporter.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,139 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.lamsfoundation.testharness.Call.CallRecord; +import org.lamsfoundation.testharness.learner.LearnerTest; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class TestReporter { + + private static final Logger log = Logger.getLogger(TestReporter.class); + private static List callRecords = new LinkedList(); + private static String fileName; + private static String fileTemplate; + + public static boolean initialized(){ + return ((fileName!=null)&&(fileTemplate!=null)); + } + + public static List getCallRecords() { + return callRecords; + } + + + public static void setCallRecords(List callRecords) { + TestReporter.callRecords = callRecords; + } + + + public static String getFileName() { + return fileName; + } + + + public static void setFileName(String fileName) { + TestReporter.fileName = fileName; + } + + + public static String getFileTemplate() { + return fileTemplate; + } + + + public static void setFileTemplate(String fileTemplate) { + TestReporter.fileTemplate = fileTemplate; + } + + + public static synchronized void addCallRecord(CallRecord callRecord){ + callRecords.add(callRecord); + } + + public static void report(AbstractTestManager manager) { + final String NEW_LINE = "\n* "; + final String NEW_LINE_INDENT = "\n* "; + StringBuilder report = new StringBuilder(); + report.append("See below\n\n**********************************Brief Report*******************************************"); + + //disclaimer + report.append(NEW_LINE); + report.append(NEW_LINE).append("Disclaimer:"); + report.append(NEW_LINE_INDENT).append("This program is created in the hope that it will help estimate how many concurrent"); + report.append(NEW_LINE_INDENT).append("users a LAMS 2.x server can handle, but WITHOUT ANY GARANTEE the server can support"); + report.append(NEW_LINE_INDENT).append("that number of users in service use."); + report.append(NEW_LINE); + report.append(NEW_LINE_INDENT).append("This program is more a load test tool than a functional test tool, "); + report.append(NEW_LINE_INDENT).append("so it does NOT GARANTEE there is no functional bug in the target server."); + report.append(NEW_LINE); + + report.append(NEW_LINE).append("Test Result Summary:"); + report.append(NEW_LINE_INDENT).append(manager.testSuites.size()).append(" test suite(s) launched. "); + report.append(manager.testSuites.size()-manager.countAborted()).append(" test suite(s) finished, and ").append(manager.countAborted()).append(" test suite(s) aborted."); + for (TestSuite testSuite : manager.testSuites){ + report.append(NEW_LINE_INDENT).append("Test Suite ").append(testSuite.getSuiteIndex()).append(testSuite.isFinished()? " finished" : " aborted").append(", in which"); + report.append(NEW_LINE_INDENT); + AbstractTest[] tests = new AbstractTest[]{testSuite.getAdminTest(),testSuite.getAuthorTest(),testSuite.getMonitorTest(),testSuite.getLearnerTest()}; + boolean first = true; + for(AbstractTest test : tests){ + if(test!=null){ + if(!first) + report.append(", "); + report.append(test.getTestName()).append(test.isFinished()? " finished" : " aborted"); + first = false; + } + } + report.append(NEW_LINE_INDENT); + LearnerTest learnerTest = testSuite.getLearnerTest(); + report.append("In ").append(learnerTest.getTestName()).append(", "); + report.append(learnerTest.countLearners()).append(" learner(s) attended, "); + report.append(learnerTest.countLearners()-learnerTest.countAborted()).append(" finished and "); + report.append(learnerTest.countAborted()).append(" aborted."); + report.append(NEW_LINE); + } + report.append(NEW_LINE).append("Refer to the formal test report document for the details."); + report.append(NEW_LINE).append("\n*****************************************************************************************\n"); + log.info(report.toString()); + } + + public static void generateReport(AbstractTestManager manager) { + report(manager); + log.info("Generating the formal test report document..."); + //TODO implement me + log.info("Sorry, this feature is not ready yet. It should come soon."); + } + +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestSuite.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestSuite.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestSuite.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,176 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness; + +import java.util.concurrent.CountDownLatch; + +import org.apache.log4j.Logger; +import org.lamsfoundation.testharness.admin.AdminTest; +import org.lamsfoundation.testharness.author.AuthorTest; +import org.lamsfoundation.testharness.learner.LearnerTest; +import org.lamsfoundation.testharness.monitor.MonitorTest; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class TestSuite implements Runnable { + + private static final Logger log = Logger.getLogger(TestSuite.class); + + private AbstractTestManager manager; + private int suiteIndex; + private String targetServer; + private String contextRoot; + private Integer rmiRegistryServicePort; + private Integer httpPort; + private AdminTest adminTest; + private AuthorTest authorTest; + private MonitorTest monitorTest; + private LearnerTest learnerTest; + private boolean finished = false; + + public TestSuite(AbstractTestManager manager, int suiteIndex, String targetServer, String contextRoot, Integer rmiRegistryServicePort, Integer httpPort, AdminTest adminTest, AuthorTest authorTest, MonitorTest monitorTest, + LearnerTest learnerTest) { + this.manager = manager; + this.suiteIndex = suiteIndex; + this.targetServer = targetServer == null ? "localhost" : targetServer; + this.contextRoot = contextRoot == null || contextRoot.equals("/") ? "" : contextRoot; + this.rmiRegistryServicePort = rmiRegistryServicePort == null ? 1099 : rmiRegistryServicePort; + this.httpPort = httpPort == null ? 80 : httpPort; + this.adminTest = adminTest; + adminTest.setTestSuite(this); + this.authorTest = authorTest; + authorTest.setTestSuite(this); + this.monitorTest = monitorTest; + monitorTest.setTestSuite(this); + this.learnerTest = learnerTest; + learnerTest.setTestSuite(this); + } + + /** + * The order is important, not to be changed + */ + public void run() { + try{ + log.info("Starting test suite " + suiteIndex + "..."); + if (adminTest != null) + adminTest.start(); + if (authorTest != null) + authorTest.start(); + if (monitorTest != null) + monitorTest.start(); + if (learnerTest != null) + learnerTest.start(); + CountDownLatch stopSignal = new CountDownLatch(1); + monitorTest.notifyMonitorToStop(stopSignal); + stopSignal.await(); + finished = true; + log.info("Finished test suite "+suiteIndex); + } catch(Exception e) {//All the exceptions which happened during test stop propagation here + log.debug(e.getMessage(),e); + log.info("Test suite " + suiteIndex + " aborted"); + //Exception is not propagated so that other testsuite will not be affected + }finally{ + manager.allDoneSignal.countDown(); + } + } + + public final int getSuiteIndex() { + return suiteIndex; + } + + /** + * @return Returns the adminTest. + */ + public final AdminTest getAdminTest() { + return adminTest; + } + + /** + * @return Returns the authorTest. + */ + public final AuthorTest getAuthorTest() { + return authorTest; + } + + /** + * @return Returns the httpPort. + */ + public final int getHttpPort() { + return httpPort; + } + + /** + * @return Returns the learnerTest. + */ + public final LearnerTest getLearnerTest() { + return learnerTest; + } + + /** + * @return Returns the rmiRegistryServicePort. + */ + public final int getRmiRegistryServicePort() { + return rmiRegistryServicePort; + } + + /** + * @return Returns the monitorTest. + */ + public final MonitorTest getMonitorTest() { + return monitorTest; + } + + /** + * @return Returns the targetServer. + */ + public final String getTargetServer() { + return targetServer; + } + + public final String getContextRoot() { + return contextRoot; + } + + public final void setContextRoot(String contextRoot) { + this.contextRoot = contextRoot; + } + + public String toString(){ + return "suiteIndex:"+suiteIndex+" targetServer:"+targetServer; + } + + public final AbstractTestManager getManager() { + return manager; + } + + public final boolean isFinished() { + return finished; + } +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestUtil.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestUtil.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/TestUtil.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,136 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Random; + +import org.apache.log4j.Logger; +import org.xml.sax.InputSource; + +import com.allaire.wddx.WddxDeserializationException; +import com.allaire.wddx.WddxDeserializer; +import com.allaire.wddx.WddxSerializer; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class TestUtil { + + private static final Logger log = Logger.getLogger(TestUtil.class); + + private static String machineName; + + protected static final char NAME_SEPERATOR = '_'; + + public static String getMachineName() { + try { + if (machineName == null) + return machineName = InetAddress.getLocalHost().getHostName(); + else + return machineName; + } catch (UnknownHostException e) { + return "UnknownHost"; + } + + } + + public static String serialize(Object data) throws IOException { + WddxSerializer tempws = new WddxSerializer(); + StringWriter tempsw = new StringWriter(); + tempws.serialize(data, tempsw); + return tempsw.toString(); + } + + public static Object deserialize(String wddxPacket) throws WddxDeserializationException { + + log.debug("WDDX packet from the server:"+wddxPacket); + + // Create an input source (org.xml.sax.InputSource) bound to the packet + InputSource tempSource = new InputSource(new StringReader(wddxPacket)); + + // Create a WDDX deserializer (com.allaire.wddx.WddxDeserializer) + WddxDeserializer tempDeserializer = new WddxDeserializer("org.apache.xerces.parsers.SAXParser"); + + // Deserialize the WDDX packet + Object result; + try { + result = tempDeserializer.deserialize(tempSource); + log.debug("Object deserialized from the WDDX packet:"+result); + } catch (IOException e) { + throw new WddxDeserializationException(e); + } + + return result; + } + + public static String buildName(String testName, String simpleName) { + return TestUtil.getMachineName() + NAME_SEPERATOR + testName + NAME_SEPERATOR + simpleName; + } + + public static String buildName(String testName, String simpleName, int maxLength) { + return truncate(buildName(truncate(testName,1,true),simpleName), maxLength, true); + } + + private static String truncate(String name, int length, boolean leftToRight) { + if(name.length()<=length) + return name; + if(leftToRight) + return name.substring(name.length()-length); + else + return name.substring(0,length); + } + + public static String extractString(String text, String startFlag, char endFlag){ + String target = null; + try{ + int index = text.indexOf(startFlag); + if(index!=-1){ + int startIndex = index + startFlag.length(); + int endIndex = text.indexOf(endFlag, startIndex); + target = text.substring(startIndex, endIndex); + } + }catch(IndexOutOfBoundsException e){ + log.debug(e.getMessage()); + log.debug("startFlag: "+startFlag+" endFlag: "+endFlag); + log.debug(text); + } + return target; + } + + public static int generateRandomIndex(int length){ + return new Random().nextInt(length); + } + + +} \ No newline at end of file Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/admin/AdminTest.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/admin/AdminTest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/admin/AdminTest.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,129 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness.admin; + +import org.lamsfoundation.testharness.AbstractTest; +import org.lamsfoundation.testharness.TestUtil; +import org.lamsfoundation.testharness.Call.CallType; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class AdminTest extends AbstractTest { + + private static final String DEFAULT_COURSE_NAME = "Course"; + + private String createCourseURL; + private String createUserURL; + private Boolean userCreated; + private String courseName; + private String courseId; + + /** + * @param testName + * @param callType + * @param adminRMIRegistryName + * @param webServiceAddress + * @param userCreated + * @param courseName + * @param courseId + */ + public AdminTest(String testName, CallType callType, String adminRMIRegistryName, String webServiceAddress, Integer minDelay, Integer maxDelay, String createCourseURL, String createUserURL, String courseId, Boolean userCreated, String courseName) { + + super(testName,callType,adminRMIRegistryName, webServiceAddress, minDelay, maxDelay); + this.createCourseURL = createCourseURL; + this.createUserURL = createUserURL; + this.courseName = courseName==null? TestUtil.buildName(testName,DEFAULT_COURSE_NAME):TestUtil.buildName(testName,courseName); + this.courseId = courseId; + this.userCreated = userCreated; + } + + /** + * let MockAdmin do what he should do + * login, create course and then create users + * + * @exception TestHarnessExcepton + * @exception RuntimeException + */ + protected void startWEB(){ + if((courseId!=null)&&userCreated) + return; + MockAdmin admin = (MockAdmin) users[0]; + admin.login(); + if(courseId == null){ + setCourseId(admin.createCourse(createCourseURL, courseName)); + } + admin.createUsers(createUserURL, courseId); + } + + @Override + protected void startWS(){ + //TODO implement me + } + + @Override + protected void startRMI(){ + //TODO implement me + } + + public final void setCourseName(String courseName) { + this.courseName = courseName; + } + + public final String getCourseName() { + return courseName; + } + + + public final String getCreateCourseURL() { + return createCourseURL; + } + + + public final String getCreateUserURL() { + return createUserURL; + } + + public final String getCourseId() { + return courseId; + } + + public final void setCourseId(String courseId) { + this.courseId = courseId; + } + + public final Boolean getUserCreated() { + return userCreated; + } + + public final void setUserCreated(Boolean userCreated) { + this.userCreated = userCreated; + } + +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/admin/MockAdmin.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/admin/MockAdmin.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/admin/MockAdmin.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,222 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness.admin; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.lamsfoundation.testharness.AbstractTest; +import org.lamsfoundation.testharness.Call; +import org.lamsfoundation.testharness.MockUser; +import org.lamsfoundation.testharness.TestHarnessException; +import org.lamsfoundation.testharness.author.AuthorTest; +import org.lamsfoundation.testharness.learner.LearnerTest; +import org.lamsfoundation.testharness.monitor.MonitorTest; +import org.xml.sax.SAXException; + +import com.meterware.httpunit.TableCell; +import com.meterware.httpunit.WebLink; +import com.meterware.httpunit.WebResponse; +import com.meterware.httpunit.WebTable; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class MockAdmin extends MockUser { + + private static final Logger log = Logger.getLogger(MockAdmin.class); + + private static final String COURSE_FORM_FLAG = "OrganisationForm"; + private static final String COURSE_NAME = "name"; + private static final String COURSE_ID_START_FLAG = "orgId="; + private static final String COURSE_ID_PATTERN = "%orgId%"; + private static final String USER_FORM_FLAG = "UserForm"; + private static final String LOGIN = "login"; + private static final String PASSWORD = "password"; + private static final String PASSWORD2 = "password2"; + private static final String FIRST_NAME = "firstName"; + private static final String LAST_NAME = "lastName"; + private static final String COMMON_LAST_NAME = "Testharness"; + private static final String ROLES = "roles"; + private static final String AUTHOR_ROLE = "3"; + private static final String MONITOR_ROLE = "4"; + private static final String LEARNER_ROLE = "5"; + private static final String USER_ID_START_FLAG = "userId="; + private static final char USER_ID_END_FLAG = '&'; + + + public MockAdmin(AbstractTest test, String username, String password, String userId) { + super(test, username, password, userId); + + } + + public String createCourse(String createCourseURL, String courseName){ + try{ + delay(); + WebResponse resp = (WebResponse)new Call(wc, test,"Creating Course:"+courseName,createCourseURL).execute(); + if(!checkPageContains(resp,COURSE_FORM_FLAG)){ + log.debug(resp.getText()); + throw new TestHarnessException(username+" did not get course creation page with the url:"+createCourseURL); + } + Map params = new HashMap(); + params.put(COURSE_NAME,courseName); + //fill the form and submit it and return the course id + resp = (WebResponse)new Call(wc, test,"Submit Course Creation Form",fillForm(resp,0,params)).execute(); + WebTable[] tables = resp.getTables(); + if((tables==null)||(tables.length==0)){ + log.debug(resp.getText()); + throw new TestHarnessException(username + " failed to get an course table after submitting course creation form"); + } + WebTable table = tables[0]; + String idAsString = null; + for (int i = table.getRowCount()-1; i >= 0; i--){ + if(table.getCellAsText(i,1).indexOf(courseName)!=-1){//found the organisation created just now + TableCell cell = table.getTableCell(i+1,1); + WebLink link = cell.getLinks()[0]; + String cellText = link.getAttribute("href"); + log.debug(cellText); + int startIndex = cellText.indexOf(COURSE_ID_START_FLAG); + idAsString = cellText.substring(startIndex+COURSE_ID_START_FLAG.length()); + break; + } + } + if(idAsString == null){ + log.debug(resp.getText()); + throw new TestHarnessException("Failed to get the course id for "+courseName); + } + log.info(username + " created course "+courseName+" and the id is "+idAsString); + return idAsString; + }catch(IOException e){ + throw new RuntimeException(e); + }catch(SAXException e){ + throw new RuntimeException(e); + } + } + + public void createUsers(String createUserURL, String courseId){ + try{ + String url = createUserURL.replace(COURSE_ID_PATTERN,courseId.toString()); + AuthorTest authorTest = test.getTestSuite().getAuthorTest(); + MonitorTest monitorTest = test.getTestSuite().getMonitorTest(); + LearnerTest learnerTest = test.getTestSuite().getLearnerTest(); + AbstractTest[] tests = new AbstractTest[]{authorTest, monitorTest, learnerTest}; + MockUserWithRoles[] users = getMockUsersWithRoles(tests); + + for(int i=0; i < users.length; i++){ + delay(); + String name = users[i].user.getUsername(); + log.info(username+" creating user "+name); + WebResponse resp = (WebResponse)new Call(wc, test, username + " creating user "+name,url).execute(); + if(!checkPageContains(resp,USER_FORM_FLAG)){ + log.debug(resp.getText()); + throw new TestHarnessException(username+" did not get user creation page with the url "+url); + } + Map params = new HashMap(); + params.put(LOGIN,name); + params.put(PASSWORD,name); + params.put(PASSWORD2,name); + params.put(FIRST_NAME,name); + params.put(LAST_NAME,COMMON_LAST_NAME); + params.put(ROLES,users[i].roles); + resp = (WebResponse)new Call(wc, test, username + " submit user creation form",fillForm(resp,0,params)).execute(); + WebTable[] tables = resp.getTables(); + if((tables==null)||(tables.length==0)){ + log.debug(resp.getText()); + throw new TestHarnessException(username + " failed to get an user table after submitting user creation form"); + } + WebTable table = tables[0]; + String idAsString = null; + for(int j = table.getRowCount()-1; j >= 0; j--){ + if(table.getCellAsText(j,1).indexOf(name)!=-1){ + TableCell cell = table.getTableCell(j,6); + WebLink link = cell.getLinks()[0]; + String cellText = link.getAttribute("href"); + int startIndex = cellText.indexOf(USER_ID_START_FLAG); + int endIndex = cellText.indexOf(USER_ID_END_FLAG,startIndex); + idAsString = cellText.substring(startIndex+USER_ID_START_FLAG.length(),endIndex); + break; + } + } + if(idAsString == null){ + log.debug(resp.getText()); + throw new TestHarnessException("Failed to get the user id for "+name); + } + log.info(username + " created user "+name+" and the id is "+idAsString); + users[i].user.setUserId(idAsString); + } + }catch(IOException e){ + throw new RuntimeException(e); + } catch (SAXException e) { + throw new RuntimeException(e); + } + } + + private int getUserAmount(AbstractTest[] tests){ + int amount = 0; + for(AbstractTest test: tests){ + amount += test==null? 0 : test.getUsers().length; + } + return amount; + } + + private MockUserWithRoles[] getMockUsersWithRoles(AbstractTest[] tests){ + MockUserWithRoles[] users = new MockUserWithRoles[getUserAmount(tests)]; + int i = 0; + for(AbstractTest test: tests){ + if( test != null){ + MockUser[] mockUsers = test.getUsers(); + String[] roles; + if(test instanceof AuthorTest){ + roles = new String[]{AUTHOR_ROLE}; + }else if(test instanceof MonitorTest){ + roles = new String[]{MONITOR_ROLE}; + }else{ + roles = new String[]{LEARNER_ROLE}; + } + for(MockUser mockUser: mockUsers){ + users[i] = new MockUserWithRoles(mockUser,roles); + i++; + } + } + } + return users; + } + + private static class MockUserWithRoles{ + MockUser user; + String[] roles; + + public MockUserWithRoles(MockUser user, String[] roles) { + this.user = user; + this.roles = roles; + } + } +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/author/AuthorTest.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/author/AuthorTest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/author/AuthorTest.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,109 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness.author; + +import java.io.File; + +import org.lamsfoundation.testharness.AbstractTest; +import org.lamsfoundation.testharness.Call.CallType; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class AuthorTest extends AbstractTest { + + private String learningDesignUploadURL; + + private String learningDesignFile; + + private String ldId; + + /** + * AuthorTest Constructor + * + * @param testName + * @param callType + * @param rmiRegistryName + * @param webServiceAddress + * @param learningDesignUploadURL + * @param learningDesignFile + * @param ldId + */ + public AuthorTest(String testName, CallType callType, String rmiRegistryName, String webServiceAddress, Integer minDelay, Integer maxDelay, String learningDesignUploadURL, String learningDesignFile, String ldId) { + super(testName,callType,rmiRegistryName,webServiceAddress, minDelay, maxDelay); + this.learningDesignUploadURL = learningDesignUploadURL; + this.learningDesignFile = learningDesignFile; + this.ldId = ldId; + } + + @Override + protected void startWEB(){ + if(ldId==null){ + MockAuthor author = (MockAuthor) users[0]; + author.login(); + File file = new File(learningDesignFile); + ldId = author.importLearningDesign(learningDesignUploadURL,file); + } + } + + @Override + protected void startWS(){ + //TODO implement me + } + + @Override + protected void startRMI(){ + //TODO implement me + } + + public final String getLearningDesignFile() { + return learningDesignFile; + } + + public final void setLearningDesignFile(String learningDesignFile) { + this.learningDesignFile = learningDesignFile; + } + + public final String getLearningDesignUploadURL() { + return learningDesignUploadURL; + } + + public final void setLearningDesignUploadURL(String learningDesignUploadURL) { + this.learningDesignUploadURL = learningDesignUploadURL; + } + + public final String getLdId() { + return ldId; + } + + public final void setLdId(String ldId) { + this.ldId = ldId; + } + +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/author/MockAuthor.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/author/MockAuthor.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/author/MockAuthor.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,96 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness.author; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.lamsfoundation.testharness.Call; +import org.lamsfoundation.testharness.MockUser; +import org.lamsfoundation.testharness.TestHarnessException; +import org.xml.sax.SAXException; + +import com.meterware.httpunit.WebResponse; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class MockAuthor extends MockUser { + + private static final Logger log = Logger.getLogger(MockAuthor.class); + + public static final String DEFAULT_NAME = "Author"; + + private static final String IMPORT_FORM_FLAG = "UPLOAD_FILE"; + private static final String UPLOAD_FILE_PARAM = "UPLOAD_FILE"; + private static final String IMPORT_SUCCESS_FLAG = "movie"; + private static final String LD_START_TAG = "learningDesignID="; + private static final char LD_END_TAG = '&'; + + /** + * MockAuthor Constructor + * + * @param + */ + public MockAuthor(AuthorTest test, String username, String password, String userId) { + super(test, username, password, userId); + } + + public String importLearningDesign(String learningDesignUploadURL, File file){ + try{ + delay(); + WebResponse resp = (WebResponse)new Call(wc, test,"Import Learning Design", learningDesignUploadURL).execute(); + if(!checkPageContains(resp,IMPORT_FORM_FLAG)){ + log.debug(resp.getText()); + throw new TestHarnessException(username+" did not get learning design import page with the url:"+learningDesignUploadURL); + } + Map params = new HashMap(); + params.put(UPLOAD_FILE_PARAM,file); + resp = (WebResponse)new Call(wc, test,"Submit Learning Design Import Form", fillForm(resp,0,params)).execute(); + if(!checkPageContains(resp,IMPORT_SUCCESS_FLAG)){ + log.debug(resp.getText()); + throw new TestHarnessException(username+" failed to upload file:"+file.getAbsolutePath()); + } + String text = resp.getText(); + int startIndex = text.indexOf(LD_START_TAG); + int endIndex = text.indexOf(LD_END_TAG,startIndex); + String idAsString = text.substring(startIndex+LD_START_TAG.length(),endIndex); + log.info(username + " imported learning design " + file.getName()+" and the id is " + idAsString); + return idAsString; + }catch(IOException e){ + throw new RuntimeException(e); + } catch (SAXException e) { + throw new RuntimeException(e); + } + } + +} Index: TestHarness4LAMS2/src/org/lamsfoundation/testharness/learner/LearnerTest.java =================================================================== RCS file: /usr/local/cvsroot/TestHarness4LAMS2/src/org/lamsfoundation/testharness/learner/LearnerTest.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestHarness4LAMS2/src/org/lamsfoundation/testharness/learner/LearnerTest.java 31 Jul 2006 02:04:30 -0000 1.1 @@ -0,0 +1,136 @@ +/**************************************************************** + * Copyright (C) 2006 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +package org.lamsfoundation.testharness.learner; + +import java.util.concurrent.CountDownLatch; + +import org.apache.log4j.Logger; +import org.lamsfoundation.testharness.AbstractTest; +import org.lamsfoundation.testharness.Call.CallType; + +/** + * @version + * + *

+ * View Source + *

+ * + * @author Fei Yang + */ +public class LearnerTest extends AbstractTest { + + private static final Logger log = Logger.getLogger(LearnerTest.class); + + protected String getLessonURL; + protected String getLearningDesignURL; + protected String joinLessonURL; + protected String getFlashProgressDataURL; + protected String lessonEntryURL; + protected String[] filesToUpload; + protected String subContextRoot; // usually "/learning/", this is set to figure out passon.swf url + protected CountDownLatch allDoneSignal; + + /** + * LearnerTest Constructor + * + */ + public LearnerTest(String testName, CallType callType, String rmiRegistryName, String webServiceAddress, Integer minDelay, Integer maxDelay, String getLessonURL, String getLearningDesignURL, String joinLessonURL, String getFlashProgressDataURL, String lessonEntryURL, String[] filesToUpload) { + super(testName,callType,rmiRegistryName,webServiceAddress, minDelay, maxDelay); + this.getLessonURL = getLessonURL; + this.getLearningDesignURL = getLearningDesignURL; + this.joinLessonURL = joinLessonURL; + this.getFlashProgressDataURL = getFlashProgressDataURL; + this.lessonEntryURL = lessonEntryURL; + this.subContextRoot = '/'+ getLessonURL.split("/")[1] + '/'; + this.filesToUpload = filesToUpload; + } + + @Override + protected void startWEB(){ + log.info(users.length+(users.length==1? " learner begins studying..." : " learners begin studying...")); + allDoneSignal = new CountDownLatch(users.length); + for(int i=0; i + * View Source + *

+ * + * @author Fei Yang + */ +public class MockLearner extends MockUser implements Runnable { + + private static final Logger log = Logger.getLogger(MockLearner.class); + + public static final String DEFAULT_NAME = "Learner"; + + private static final String ARBITRARY_TEXT_ALPHABET = "`1234567890-=qwertyuiop[]\\asdfghjkl;'\tzxcvbnm,./ ~!@#$%^&*()_+}{POIUYTREWQASDFGHJKL:\"?> + *
  • fetch entry url
  • + *
  • get passon.swf url and the next activity url
  • + *
  • fetch the next activity url and get activity page with form
  • + *
  • fill the form and submit it + *
  • + *
  • repeat step 2-4 until lesson completed or error happened
  • + * + * + * Note: httpunit will automatically redirect url if there is a redirect + * http header in response. In this case, the redirect url won't be recorded + * in access log or testharness log. + * + * @param lessonEntryURL + * @param lsId + * @return void + * @throws IOException + * @throws SAXException + */ + private void progressThroughActivities(String lessonEntryURL, String lsId) throws SAXException, IOException { + delay(); + WebResponse resp = (WebResponse) new Call(wc, test, username + " enters lesson", lessonEntryURL.replace(LESSON_ID_PATTERN, lsId)).execute(); + String[] nextURLs = parseOutNextURLs(resp); + boolean lessonFinished = false; + while (!lessonFinished) { + if ((nextURLs[0] != null) && (nextURLs[1]!=null)) { + new Call(wc, test, username + " requests flash", nextURLs[0]).execute(); + resp = takeActivity(nextURLs[1]); + nextURLs = parseOutNextURLs(resp); + }else if ((nextURLs[0]==null) && (nextURLs[1]!=null)){ + log.debug("It's a bit wierd! passon.swf url was not found while tool url found!"); + log.debug(resp.getText()); + }else if ((nextURLs[0]==null) && (nextURLs[1]==null)){ + log.debug("Neither passon.swf or tool url was found. "+username + " may have got an error!"); + log.debug(resp.getText()); + }else{//(nextURLs[0] != null) && (nextURLs[1]==null) + if(isOptionalActivity(resp)){ + resp = handleActivity(resp); + nextURLs = parseOutNextURLs(resp); + }else{ + new Call(wc, test, username + " requests flash", nextURLs[0]).execute(); + lessonFinished = true; + } + } + + } + } + + private boolean isOptionalActivity(WebResponse resp) throws IOException { + return resp.getText().indexOf(OPTIONAL_ACTIVITY_FLAG)!=-1; + } + + + /** + * Retrieve the toolURL and play with it + * + * @param toolURL + * @return WebResponse + */ + private WebResponse takeActivity(String toolURL) { + try { + delay(); + WebResponse resp = (WebResponse) new Call(wc, test, "", toolURL).execute(); + delay(); + return handleActivity(resp); + } catch (Exception e) { + throw new TestHarnessException(e.getMessage(), e); + } + } + + private WebResponse handleActivity(WebResponse resp) throws SAXException, IOException { + if (resp.getFrameNames().length == 2) { + return handleParallelActivity(resp); + } + WebResponse nextResp; + WebForm[] forms = resp.getForms(); + if ((forms != null) && (forms.length > 0)) { + log.debug("There "+(forms.length==1? "is ":"are ")+forms.length+(forms.length==1? " form in the page ":" forms in the page")); + nextResp = handlePageWithForms(forms); + } else { + nextResp = handlePageWithoutForms(resp); + } + if (isAcitivityFinished(nextResp)) + return nextResp; + else + return handleActivity(nextResp); + + } + + private boolean isAcitivityFinished(WebResponse resp) throws IOException { + return resp.getText().indexOf(ACTIVITY_FINISHED_FLAG) != -1; + } + + private WebResponse handlePageWithoutForms(WebResponse resp) { + // TODO implement me + return null; + } + + private WebResponse handleParallelActivity(WebResponse resp) { + // TODO implement me + return null; + } + + private WebResponse handlePageWithForms(WebForm[] forms) throws IOException, SAXException { + int index = 0; + WebForm form = forms[index]; + while((form.getAction() == null)||(form.getAction().trim().length()==0)){ + index++; + if(index >= forms.length){ + throw new TestHarnessException(username+" don't know how to finish the activity now"); + } + form = forms[index]; + } + return (WebResponse) new Call(wc, test, "", fillFormArbitrarily(form)).execute(); + } + + private String getLesson(String getLessonURL, String lsId) throws WddxDeserializationException, IOException { + delay(); + String url = getLessonURL.replace(LESSON_ID_PATTERN, lsId); + WebResponse resp = (WebResponse) new Call(wc, test, username + " get lesson", url).execute(); + Hashtable hashtable = (Hashtable) TestUtil.deserialize(resp.getText()); + hashtable = (Hashtable) hashtable.get(MESSAGE_VALUE_KEY); + return new Integer(((Double) hashtable.get(LD_ID_KEY)).intValue()).toString(); + } + + private void getLearningDesign(String getLearningDesignURL, String ldId) { + delay(); + String url = getLearningDesignURL.replace(LD_ID_PATTERN, ldId); + new Call(wc, test, username + " get learning design", url).execute(); + } + + private void joinLesson(String joinLessonURL, String lsId) { + delay(); + String url = joinLessonURL.replace(LESSON_ID_PATTERN, lsId); + new Call(wc, test, username + " join lesson", url).execute(); + } + + private void getFlashProgessData(String getFlashProgressDataURL, String lsId) { + delay(); + String url = getFlashProgressDataURL.replace(LESSON_ID_PATTERN, lsId); + new Call(wc, test, username + " get flash progress data", url).execute(); + } + + private String[] parseOutNextURLs(WebResponse resp) throws SAXException, IOException { + String text = resp.getText(); + String passonSwfURL = TestUtil.extractString(text, SWF_URL_START_FLAG, SWF_URL_END_FLAG); + String toolURL = TestUtil.extractString(text, NEXT_URL_START_FLAG, NEXT_URL_END_FLAG); + + if (passonSwfURL != null) + passonSwfURL = ((LearnerTest) test).subContextRoot + passonSwfURL; + + if ((toolURL != null) && !toolURL.startsWith("/")) + toolURL = '/' + toolURL; + + log.debug("passonSwfURL:"+passonSwfURL); + log.debug("toolURL:"+toolURL); + return new String[] { passonSwfURL, toolURL }; + } + + private WebForm fillFormArbitrarily(WebForm form) throws IOException, SAXException { + String[] params = form.getParameterNames(); + if ((params != null) && (params.length > 0)) { + for (String param : params) { + if (!form.isDisabledParameter(param) && !form.isHiddenParameter(param) && !form.isReadOnlyParameter(param)) { + if (form.isTextParameter(param)) { + String text = composeArbitraryText(); + form.setParameter(param, text); + log.debug(username+ " input " + text + " for form field " + param); + } else if (form.isMultiValuedParameter(param)) { + String[] values = chooseArbitraryValues(form.getOptionValues(param)); + form.setParameter(param, values); + log.debug(username+" set " + values.length + " value(s) for form field " + param); + log.debug(values); + } else if (form.isFileParameter(param)) { + File file = selectArbitraryFile(((LearnerTest) test).getFilesToUpload()); + form.setParameter(param, file); + log.debug(username + " uploaded file "+ file.getName()+" for form field "+param); + } + }else{ + log.debug("disabled or hidden or readonly parameter "+param); + } + } + } + + Map> buttonGroups = groupButtonsByName(form.getButtons(), Button.RADIO_BUTTON_TYPE); + for (Map.Entry> entry : buttonGroups.entrySet()){ + entry.getValue().get(TestUtil.generateRandomIndex(entry.getValue().size())).click(); + log.debug(username+" clicked a radio button "+entry.getKey()); + } + return form; + } + + + private Map> groupButtonsByName(Button[] btns, String buttonType ){ + log.debug(btns.length); + Map> buttonGroups = new HashMap>(); + if (btns!=null) { + for (Button btn : btns){ + if(buttonType.equals(btn.getType())){ + String name = btn.getName(); + log.debug("Got "+buttonType+" "+name+" and its value is "+btn.getValue()); + if(!buttonGroups.containsKey(name)){ + buttonGroups.get(name).add(btn); + }else{ + List