/**************************************************************** * 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.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.List; 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.lamsfoundation.testharness.TestUtil; import org.xml.sax.SAXException; import com.allaire.wddx.WddxDeserializationException; import com.meterware.httpunit.Button; import com.meterware.httpunit.WebForm; import com.meterware.httpunit.WebResponse; /** * @version * *

* 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