package com.samknows.measurement.schedule; import android.util.Log; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.samknows.libcore.SKPorting; import com.samknows.libcore.SKConstants; import com.samknows.measurement.schedule.TestDescription.*; import com.samknows.measurement.TestRunner.ManualTestRunner; import com.samknows.measurement.schedule.condition.ConditionGroup; import com.samknows.measurement.environment.BaseDataCollector; import com.samknows.measurement.schedule.failaction.RetryFailAction; import com.samknows.measurement.util.OtherUtils; import com.samknows.measurement.util.XmlUtils; public class ScheduleConfig implements Serializable { //strings found in the schedule config public static final String CONFIG = "config"; public static final String GLOBAL = "global"; public static final String BACKGROUND_TEST = "background-test"; public static final String SCHEDULE_VERSION = "schedule-version"; public static final String SUBMIT_DCS = "submit-dcs"; public static final String TESTS_ALARM_TYPE = "tests-alarm-type"; public static final String LOCATION_SERVICE = "location-service"; public static final String ONFAIL_TEST_ACTION = "onfail-test-action"; public static final String INIT = "init"; public static final String TYPE = "type"; public static final String HOSTS = "hosts"; public static final String HOST = "host"; public static final String DNSNAME = "dnsName"; public static final String DISPLAYNAME = "displayName"; public static final String DATA_CAP_DEFAULT = "data-cap-default"; public static final String VALUE = "value"; public static final String COMMUNICATIONS = "communications"; public static final String COMMUNICATION = "communication"; public static final String DATA_COLLECTOR = "data-collector"; public static final String TIME = "time"; public static final String RANDOM_INTERVAL = "random-interval"; public static final String LISTENERDELAY = "listenerDelay"; public static final String ENABLED = "enabled"; public static final String DISABLED = "disabled"; public static final String CONDITIONS = "conditions"; public static final String CONDITION = "condition"; public static final String CONDITION_GROUP = "condition-group"; public static final String CONDITION_GROUP_ID = "condition-group-id"; public static final String FAIL_QUIET = "fail-quiet"; public static final String ID = "id"; public static final String TESTS = "tests"; public static final String TEST = "test"; public static final String SCHEDULED_TESTS = "scheduled-tests"; public static final String CONTINUOUS_TESTS = "continuous-tests"; public static final String BATCH = "batch"; public static final String MANUAL_TESTS = "manual-tests"; private static final long serialVersionUID = 1L; public String version = ""; public String submitHost = null; // submitHost/mobile/submit public long downloadedTime = 0; public long dataCapDefault = -1; public TestAlarmType testAlamType = TestAlarmType.WAKEUP; public LocationType locationType = LocationType.gps; //location type for data collectors public RetryFailAction retryFailAction = null; private boolean backgroundTest = true; public List<ConditionGroup> conditionGroups = new ArrayList<>(); public List<TestDescription> tests = new ArrayList<>(); public List<TestGroup> backgroundTestGroups = new ArrayList<>(); public final List<TestDescription> manual_tests = new ArrayList<>(); public final List<TestDescription> continuous_tests = new ArrayList<>(); public String manual_test_condition_group_id = null; public List<BaseDataCollector> dataCollectors = new ArrayList<>(); public final HashMap<String, String> hosts = new HashMap<>(); public final HashMap<String, Communication> communications = new HashMap<>(); public long maximumTestUsage = 0; public enum TestAlarmType { WAKEUP, NO_WAKEUP } public boolean getBackgroundTest() { return backgroundTest; } public enum LocationType { gps, network } public ConditionGroup getConditionGroup(String conditionGroupId) { for (ConditionGroup cg : conditionGroups) { if (cg.id.equals(conditionGroupId)) { return cg; } } SKPorting.sAssertE(this, "condition group not found for id: " + conditionGroupId); return new ConditionGroup(); } public TestDescription findTest(long testId) { for (TestDescription td : tests) { if (td.id == testId) return td; } return null; } public TestGroup findBackgroundTestGroup(long id) { for (TestGroup tg : backgroundTestGroups) { if (tg.id == id) { return tg; } } // Nothing yet found, for some reason! Log.w("ScheduleConfig", "WARNING: no schedule test group found, returning first item"); if (backgroundTestGroups.size() > 0) { return backgroundTestGroups.get(0); } SKPorting.sAssert(false); return null; } public TestDescription findTestById(SCHEDULE_TEST_ID id) { for (TestDescription td : tests) { if (td.testId == id) { return td; } } // Unrecognized test id! SKPorting.sAssert(getClass(), false); return null; } public TestDescription findTestForType(String type) { for (TestDescription td : tests) { if (td.type.equals(type)) return td; } return null; } /* * Returns the test batch to be run in the RunTestActivity */ public List<TestDescription> testGroup() { List<TestDescription> ret = new ArrayList<>(); //Closest Target TestDescription td = findTestForType(SKConstants.TEST_TYPE_CLOSEST_TARGET); if (td != null) { ret.add(td); } td = findTestForType(SKConstants.TEST_TYPE_DOWNLOAD); if (td != null) { ret.add(td); } td = findTestForType(SKConstants.TEST_TYPE_UPLOAD); if (td != null) { ret.add(td); } td = findTestForType(SKConstants.TEST_TYPE_LATENCY); if (td != null) { ret.add(td); } return ret; } public Communication findCommunication(String id) { return communications.get(id); } public String findHostName(String dnsName) { String result = hosts.get(dnsName); if (result == null) { return dnsName; } return result; } //------------------------------------------------------------------------ //parsing from xml public static ScheduleConfig parseXml(InputStream is) { if (is == null) { return new ScheduleConfig(); } DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { Element root = factory.newDocumentBuilder().parse(is).getDocumentElement(); return sCreateScheduleConfigByParsingXmlElement(root); } catch (Exception e) { SKPorting.sAssert(false); } return new ScheduleConfig(); } public ScheduleConfig() { downloadedTime = System.currentTimeMillis(); } public static ScheduleConfig sCreateScheduleConfigByParsingXmlElement(Element node) { ScheduleConfig c = new ScheduleConfig(); if (node == null) { SKPorting.sAssert(false); return c; } //version c.version = XmlUtils.getNodeAttrValue(node, SCHEDULE_VERSION, VALUE); //base properties c.submitHost = XmlUtils.getNodeAttrValue(node, SUBMIT_DCS, HOST); String dataCapValue = XmlUtils.getNodeAttrValue(node, DATA_CAP_DEFAULT, VALUE); if (dataCapValue != null && !dataCapValue.equals("")) { c.dataCapDefault = Long.parseLong(dataCapValue); } else { c.dataCapDefault = -1; } String type = XmlUtils.getNodeAttrValue(node, TESTS_ALARM_TYPE, TYPE); c.testAlamType = TestAlarmType.valueOf(type); c.locationType = LocationType.valueOf(XmlUtils.getNodeAttrValue(node, LOCATION_SERVICE, TYPE)); c.retryFailAction = RetryFailAction.parseXml((Element) node.getElementsByTagName(ONFAIL_TEST_ACTION).item(0)); //conditions c.conditionGroups = new ArrayList<>(); NodeList conditionGroups = node.getElementsByTagName(CONDITION_GROUP); for (int i = 0; i < conditionGroups.getLength(); i++) { Element conditionGroupNode = (Element) conditionGroups.item(i); ConditionGroup cg = ConditionGroup.parseXml(conditionGroupNode); if (cg != null) { c.conditionGroups.add(cg); } } //tests c.tests = new ArrayList<>(); NodeList tests = null; for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof Element && child.getNodeName().equals(ScheduleConfig.TESTS)) { tests = ((Element) child).getElementsByTagName(ScheduleConfig.TEST); break; } } if (tests != null) { for (int i = 0; i < tests.getLength(); i++) { Element e = (Element) tests.item(i); c.tests.add(TestDescription.parseXml(e)); } } //tests groups c.backgroundTestGroups = new ArrayList<>(); NodeList tests_groups = node.getElementsByTagName(SCHEDULED_TESTS); if (tests_groups.getLength() == 1) { tests_groups = ((Element) tests_groups.item(0)).getElementsByTagName(BATCH); for (int i = 0; i < tests_groups.getLength(); i++) { TestGroup curr = TestGroup.parseXml((Element) tests_groups.item(i)); curr.setUsage(c.tests); c.maximumTestUsage = Math.max(c.maximumTestUsage, curr.netUsage); c.backgroundTestGroups.add(curr); } } //continuous tests NodeList continuous_tests = node.getElementsByTagName(CONTINUOUS_TESTS); if (continuous_tests != null && continuous_tests.getLength() == 1) { NodeList c_tests = ((Element) continuous_tests.item(0)).getElementsByTagName(TEST); for (int i = 0; i < c_tests.getLength(); i++) { int testIdAsInt = Integer.parseInt(((Element) c_tests.item(i)).getAttribute(ID)); SCHEDULE_TEST_ID testId = SCHEDULE_TEST_ID.sGetTestIdForInt(testIdAsInt); boolean bMatched = false; for (TestDescription td : c.tests) { if (td.testId == testId) { bMatched = true; c.continuous_tests.add(td); } } SKPorting.sAssert(ScheduleConfig.class, bMatched); } } //tests run manually NodeList manual_tests = node.getElementsByTagName(MANUAL_TESTS); if (manual_tests.getLength() == 1) { //Get condition group for manual test NodeList condition_manual_test = ((Element) manual_tests.item(0)).getElementsByTagName(CONDITION_GROUP_ID); if (condition_manual_test.getLength() == 1) { c.manual_test_condition_group_id = ((Element) manual_tests.item(0)).getAttribute(CONDITION_GROUP_ID); } //Get the test ids for the manual test manual_tests = ((Element) manual_tests.item(0)).getElementsByTagName(TEST); for (int i = 0; i < manual_tests.getLength(); i++) { int testIdAsInt = Integer.parseInt(((Element) manual_tests.item(i)).getAttribute(ID)); SCHEDULE_TEST_ID testId = SCHEDULE_TEST_ID.sGetTestIdForInt(testIdAsInt); boolean bMatched = false; for (TestDescription td : c.tests) { if (td.testId.equals(testId)) { bMatched = true; c.manual_tests.add(td); } } SKPorting.sAssert(ScheduleConfig.class, bMatched); } } //data-collectors c.dataCollectors = new ArrayList<>(); NodeList dataCollectors = node.getElementsByTagName(DATA_COLLECTOR); for (int i = 0; i < dataCollectors.getLength(); i++) { Element e = (Element) dataCollectors.item(i); c.dataCollectors.add(BaseDataCollector.sParseXml(e)); } NodeList list = null; //init tests // NodeList list = ((Element)node.getElementsByTagName(GLOBAL).item(0)).getElementsByTagName(INIT); // if (list.getLength() == 1) { // NodeList initTests = ((Element)list.item(0)).getElementsByTagName(TEST); // for (int i = 0; i < initTests.getLength(); i++) { // Element e = (Element) initTests.item(i); // c.initTestTypes.add(e.getAttribute(TYPE)); // } // } else { // throw new RuntimeException("more than one init section or none"); // } //hosts list = ((Element) node.getElementsByTagName(GLOBAL).item(0)).getElementsByTagName(HOSTS); if (list.getLength() == 1) { NodeList initTests = ((Element) list.item(0)).getElementsByTagName(HOST); for (int i = 0; i < initTests.getLength(); i++) { Element e = (Element) initTests.item(i); c.hosts.put(e.getAttribute(DNSNAME), OtherUtils.stringEncoding(e.getAttribute(DISPLAYNAME))); } } else { throw new RuntimeException("more than one hosts section or none"); } //background test list = ((Element) node.getElementsByTagName(GLOBAL).item(0)).getElementsByTagName(BACKGROUND_TEST); if (list != null && list.getLength() == 1) { Element e = (Element) list.item(0); String value = e.getAttribute(VALUE); if (value != null && value.equalsIgnoreCase(DISABLED)) { c.backgroundTest = false; } } //Communications list = ((Element) node.getElementsByTagName(GLOBAL).item(0)).getElementsByTagName(COMMUNICATIONS); if (list.getLength() == 1) { NodeList communicationList = ((Element) list.item(0)).getElementsByTagName(COMMUNICATION); for (int i = 0; i < communicationList.getLength(); i++) { Communication comm = Communication.parseXml((Element) communicationList.item(i)); c.communications.put(comm.id, comm); } } return c; } public int getNumberOfBackgroundTestGroups() { int ret = 0; for (TestGroup tg : backgroundTestGroups) { ret += tg.times.size(); } return ret; } public boolean toUpdate(ScheduleConfig config) { if (version.equals("")) { return true; } if (config.version.equals("")) { return true; } return !version.equals(config.version); } public String getConfigVersion() { return version; } public void forManualOrContinuousTestEnsureClosestTargetIsRunAtStart(List<TestDescription> theTests) { if (!(continuous_tests == theTests || theTests == manual_tests)) { // Must be run EITHER for continuous or manual test. SKPorting.sAssert(getClass(), false); return; } if (theTests.get(0).type.equals(SKConstants.TEST_TYPE_CLOSEST_TARGET)) { // All is OK! } else { // Need to add a closest target test to the start! int i; for (i = 0; i < tests.size(); i++) { TestDescription theTest = tests.get(i); if (theTest.type.equals(SKConstants.TEST_TYPE_CLOSEST_TARGET)) { theTests.add(0, theTest); SKPorting.sAssert(ManualTestRunner.class, theTests.get(0).type.equals(SKConstants.TEST_TYPE_CLOSEST_TARGET)); break; } } } } }