/******************************************************************************* * Copyright (c) 2010, 2014 Frank Becker and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Frank Becker - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.bugzilla.tests.core; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.xmlrpc.XmlRpcException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.mylyn.bugzilla.tests.AbstractBugzillaTest; import org.eclipse.mylyn.bugzilla.tests.support.BugzillaFixture; import org.eclipse.mylyn.bugzilla.tests.support.BugzillaHarness; import org.eclipse.mylyn.commons.net.AuthenticationType; import org.eclipse.mylyn.commons.net.WebLocation; import org.eclipse.mylyn.internal.bugzilla.core.AbstractBugzillaOperation; import org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttribute; import org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttributeMapper; import org.eclipse.mylyn.internal.bugzilla.core.BugzillaVersion; import org.eclipse.mylyn.internal.bugzilla.core.CustomTransitionManager; import org.eclipse.mylyn.internal.bugzilla.core.RepositoryConfiguration; import org.eclipse.mylyn.internal.bugzilla.core.service.BugzillaXmlRpcClient; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; import org.eclipse.mylyn.tasks.core.ITask; import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler; import org.eclipse.mylyn.tasks.core.data.ITaskDataWorkingCopy; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskAttributeMetaData; import org.eclipse.mylyn.tasks.core.data.TaskData; import org.eclipse.mylyn.tasks.core.data.TaskDataCollector; import org.eclipse.mylyn.tasks.core.data.TaskDataModel; import org.eclipse.mylyn.tasks.core.sync.SubmitJob; /** * Tests should be run against Bugzilla 3.6 or greater * * @author Frank Becker */ public class BugzillaXmlRpcClientTest extends AbstractBugzillaTest { private static final String BUGZILLA_LE_4_0 = "<4.0"; private static final String BUGZILLA_GE_4_0 = ">=4.0"; private BugzillaXmlRpcClient bugzillaClient; @SuppressWarnings("serial") private final Map<String, Map<String, ArrayList<String>>> fixtureTransitionsMap = new HashMap<String, Map<String, ArrayList<String>>>() { { put(BUGZILLA_LE_4_0, new HashMap<String, ArrayList<String>>() { { put("NEW", new ArrayList<String>() { { add("resolve"); add("accept"); add("duplicate"); } }); put("UNCONFIRMED", new ArrayList<String>() { { add("resolve"); add("accept"); add("duplicate"); add("markNew"); } }); put("ASSIGNED", new ArrayList<String>() { { add("resolve"); add("duplicate"); add("markNew"); } }); put("REOPENED", new ArrayList<String>() { { add("resolve"); add("accept"); add("duplicate"); add("markNew"); } }); put("RESOLVED", new ArrayList<String>() { { add("verify"); add("reopen"); add("close"); } }); put("VERIFIED", new ArrayList<String>() { { add("reopen"); add("resolve"); add("duplicate"); add("close"); } }); put("CLOSED", new ArrayList<String>() { { add("reopen"); add("resolve"); add("duplicate"); } }); } }); put(BUGZILLA_GE_4_0, new HashMap<String, ArrayList<String>>() { { put("UNCONFIRMED", new ArrayList<String>() { { add("resolve"); add("CONFIRMED"); add("duplicate"); add("IN_PROGRESS"); } }); put("IN_PROGRESS", new ArrayList<String>() { { add("resolve"); add("duplicate"); add("CONFIRMED"); } }); put("CONFIRMED", new ArrayList<String>() { { add("resolve"); add("duplicate"); add("IN_PROGRESS"); } }); put("RESOLVED", new ArrayList<String>() { { add("verify"); add("unconfirmed"); add("CONFIRMED"); } }); put("VERIFIED", new ArrayList<String>() { { add("unconfirmed"); add("CONFIRMED"); } }); } }); put(BugzillaFixture.CUSTOM_WF, new HashMap<String, ArrayList<String>>() { { put("UNCONFIRMED", new ArrayList<String>() { { add("resolve"); add("CONFIRMED"); add("IN_PROGRESS"); add("duplicate"); } }); put("CONFIRMED", new ArrayList<String>() { { add("resolve"); add("verify"); add("IN_PROGRESS"); add("duplicate"); } }); put("IN_PROGRESS", new ArrayList<String>() { { add("unconfirmed"); add("resolve"); add("duplicate"); } }); put("RESOLVED", new ArrayList<String>() { { add("unconfirmed"); add("CONFIRMED"); add("verify"); } }); put("VERIFIED", new ArrayList<String>() { { add("unconfirmed"); add("CONFIRMED"); add("resolve"); } }); } }); put(BugzillaFixture.CUSTOM_WF_AND_STATUS, new HashMap<String, ArrayList<String>>() { { put("UNCONFIRMED", new ArrayList<String>() { { add("resolve"); add("CONFIRMED"); add("IN_PROGRESS"); add("duplicate"); add("verify"); } }); put("CONFIRMED", new ArrayList<String>() { { add("resolve"); add("verify"); add("IN_PROGRESS"); add("duplicate"); } }); put("IN_PROGRESS", new ArrayList<String>() { { add("CONFIRMED"); add("resolve"); add("duplicate"); add("verify"); } }); put("RESOLVED", new ArrayList<String>() { { add("unconfirmed"); add("CONFIRMED"); add("verify"); } }); put("VERIFIED", new ArrayList<String>() { { add("MODIFIED"); add("CONFIRMED"); } }); put("ON_DEV", new ArrayList<String>() { { add("verify"); add("POST"); } }); put("POST", new ArrayList<String>() { { add("verify"); } }); put("MODIFIED", new ArrayList<String>() { { add("verify"); add("ON_DEV"); } }); } }); } }; private BugzillaHarness harness; @Override public void setUp() throws Exception { super.setUp(); harness = BugzillaFixture.current().createHarness(); WebLocation webLocation = new WebLocation(BugzillaFixture.current().getRepositoryUrl() + "/xmlrpc.cgi"); webLocation.setCredentials(AuthenticationType.REPOSITORY, "tests@mylyn.eclipse.org", "mylyntest"); bugzillaClient = new BugzillaXmlRpcClient(webLocation, client); bugzillaClient.setContentTypeCheckingEnabled(true); } @Override protected void tearDown() throws Exception { super.tearDown(); } @Override protected ITaskDataWorkingCopy getWorkingCopy(ITask task) throws CoreException { return TasksUiPlugin.getTaskDataManager().getWorkingCopy(task); } @Override protected void submit(TaskDataModel model) { SubmitJob submitJob = TasksUiInternal.getJobFactory().createSubmitTaskJob(connector, model.getTaskRepository(), model.getTask(), model.getTaskData(), model.getChangedOldAttributes()); submitJob.schedule(); try { submitJob.join(); } catch (InterruptedException e) { fail(e.getMessage()); } } public void testGetVersion() throws Exception { if (!BugzillaFixture.current().isXmlRpcEnabled()) { return; } else { IProgressMonitor monitor = new NullProgressMonitor(); String version = bugzillaClient.getVersion(monitor); assertEquals(0, new BugzillaVersion(BugzillaFixture.current().getVersion()) .compareMajorMinorOnly(new BugzillaVersion(version))); } } @SuppressWarnings("unchecked") public void testUserInfo() throws Exception { if (!BugzillaFixture.current().isXmlRpcEnabled()) { return; } else { IProgressMonitor monitor = new NullProgressMonitor(); BugzillaVersion version = BugzillaFixture.current().getBugzillaVersion(); bugzillaClient.logout(monitor); int uID = bugzillaClient.login(monitor); assertEquals(2, uID); Object[] userList0 = bugzillaClient.getUserInfoFromIDs(monitor, new Integer[] { 1, 2 }); assertNotNull(userList0); assertEquals(2, userList0.length); assertEquals(((Integer) 1), ((HashMap<String, Integer>) userList0[0]).get("id")); if (BugzillaFixture.current().isBugzilla51OrGreater()) { assertEquals("admin@mylyn.eclipse.org", ((HashMap<String, String>) userList0[0]).get("email")); } assertEquals("admin@mylyn.eclipse.org", ((HashMap<String, String>) userList0[0]).get("name")); assertEquals("Mylyn Admin", ((HashMap<String, String>) userList0[0]).get("real_name")); assertEquals(((Boolean) true), ((HashMap<String, Boolean>) userList0[0]).get("can_login")); assertEquals(((Integer) 2), ((HashMap<String, Integer>) userList0[1]).get("id")); if (BugzillaFixture.current().isBugzilla51OrGreater()) { assertEquals("tests@mylyn.eclipse.org", ((HashMap<String, String>) userList0[1]).get("email")); } assertEquals("tests@mylyn.eclipse.org", ((HashMap<String, String>) userList0[1]).get("name")); assertEquals("Mylyn Test", ((HashMap<String, String>) userList0[1]).get("real_name")); assertEquals(((Boolean) true), ((HashMap<String, Boolean>) userList0[1]).get("can_login")); Object[] userList1 = bugzillaClient.getUserInfoFromNames(monitor, new String[] { "tests@mylyn.eclipse.org" }); assertNotNull(userList1); assertEquals(1, userList1.length); assertEquals(((Integer) 2), ((HashMap<String, Integer>) userList1[0]).get("id")); if (version.compareTo(BugzillaVersion.BUGZILLA_5_1) < 0) { assertEquals("tests@mylyn.eclipse.org", ((HashMap<String, String>) userList1[0]).get("email")); } assertEquals("tests@mylyn.eclipse.org", ((HashMap<String, String>) userList1[0]).get("name")); assertEquals("Mylyn Test", ((HashMap<String, String>) userList1[0]).get("real_name")); assertEquals(((Boolean) true), ((HashMap<String, Boolean>) userList1[0]).get("can_login")); } } @SuppressWarnings("unchecked") public void testProductInfo() throws Exception { if (!BugzillaFixture.current().isXmlRpcEnabled()) { return; } else { IProgressMonitor monitor = new NullProgressMonitor(); int uID = bugzillaClient.login(monitor); assertEquals(2, uID); Object[] selProductIDs = bugzillaClient.getSelectableProducts(monitor); assertNotNull(selProductIDs); assertEquals(3, selProductIDs.length); Object[] enterProductIDs = bugzillaClient.getEnterableProducts(monitor); assertNotNull(enterProductIDs); assertEquals(3, enterProductIDs.length); Object[] accessibleProductIDs = bugzillaClient.getAccessibleProducts(monitor); assertNotNull(accessibleProductIDs); assertEquals(3, accessibleProductIDs.length); Object[] productDetails = bugzillaClient.getProducts(monitor, new Integer[] { 1, 3 }); assertNotNull(productDetails); assertEquals(2, productDetails.length); assertTrue(((HashMap<String, Integer>) productDetails[0]).get("id") == 1 || ((HashMap<String, Integer>) productDetails[1]).get("id") == 1); assertTrue(((HashMap<String, Integer>) productDetails[0]).get("id") == 3 || ((HashMap<String, Integer>) productDetails[1]).get("id") == 3); int idx = ((HashMap<String, Integer>) productDetails[0]).get("id") == 1 ? 0 : 1; assertEquals(((Integer) 1), ((HashMap<String, Integer>) productDetails[idx]).get("id")); assertEquals( "This is a test product. This ought to be blown away and replaced with real stuff in a finished installation of bugzilla.", ((HashMap<String, String>) productDetails[idx]).get("description")); idx = (idx + 1) % 2; assertEquals(((Integer) 3), ((HashMap<String, Integer>) productDetails[idx]).get("id")); assertEquals("Product for manual testing", ((HashMap<String, String>) productDetails[idx]).get("description")); } } public void testXmlRpcInstalled() throws Exception { int uID = -1; IProgressMonitor monitor = new NullProgressMonitor(); if (!BugzillaFixture.current().isXmlRpcEnabled()) { try { uID = bugzillaClient.login(monitor); fail("Never reach this! We should get an XmlRpcException"); } catch (XmlRpcException e) { assertEquals("The server returned an unexpected content type: 'text/html; charset=UTF-8'", e.getMessage()); } } else { uID = bugzillaClient.login(monitor); assertEquals(2, uID); } } public void testTransitionManagerWithXml() throws Exception { if (BugzillaFixture.current().getBugzillaVersion().isSmaller(BugzillaVersion.BUGZILLA_3_6)) { return; } else if (!BugzillaFixture.current().isXmlRpcEnabled()) { return; } else { CustomTransitionManager ctm = new CustomTransitionManager(); ctm.parse(new NullProgressMonitor(), bugzillaClient); ArrayList<String> transitions = new ArrayList<String>(); Map<String, ArrayList<String>> expectTransitions; /* * Copy and paste this block to test valid transitions for different start statuses * * We check that only valid operations are returned. There is no * way to determine (using the operation 'reopen') whether "REOPEN" or "UNCONFIRMED" * is valid. */ if (BugzillaFixture.current().isCustomWorkflow()) { expectTransitions = fixtureTransitionsMap.get(BugzillaFixture.CUSTOM_WF); } else if (BugzillaFixture.current().isCustomWorkflowAndStatus()) { expectTransitions = fixtureTransitionsMap.get(BugzillaFixture.CUSTOM_WF_AND_STATUS); } else if (BugzillaFixture.current().getBugzillaVersion().isSmaller(BugzillaVersion.BUGZILLA_4_0)) { expectTransitions = fixtureTransitionsMap.get(BUGZILLA_LE_4_0); } else { expectTransitions = fixtureTransitionsMap.get(BUGZILLA_GE_4_0); } for (String start : expectTransitions.keySet()) { transitions.clear(); ArrayList<String> expectedStateTransition = expectTransitions.get(start); for (AbstractBugzillaOperation s : ctm.getValidTransitions(start)) { String end = s.toString(); if (expectedStateTransition.contains(end)) { transitions.add(end); } else { fail("The status " + start + " is not expected to transition to " + end.toString()); } } assertEquals("Missing transitions for " + start + ", only found " + transitions, transitions.size(), ctm.getValidTransitions(start).size()); } } } public void testXmlRpcBugGet() throws Exception { if (!BugzillaFixture.current().isXmlRpcEnabled()) { return; } else { Set<String> taskIds = new HashSet<String>(); String taskId = harness.taskXmlRpcExists(); if (taskId == null) { taskId = harness.createXmlRpcTask(); } taskIds.add(taskId); final Map<String, TaskData> results = new HashMap<String, TaskData>(); final Map<String, TaskData> resultsXMLRPC = new HashMap<String, TaskData>(); TaskDataCollector collector = new TaskDataCollector() { @Override public void accept(TaskData taskData) { results.put(taskData.getTaskId(), taskData); } }; TaskDataCollector collectorXMLRPC = new TaskDataCollector() { @Override public void accept(TaskData taskData) { resultsXMLRPC.put(taskData.getTaskId(), taskData); } }; final CoreException[] collectionException = new CoreException[1]; final Boolean[] updateConfig = new Boolean[1]; class CollectorWrapper extends TaskDataCollector { private final IProgressMonitor monitor2; private final TaskDataCollector collector; @Override public void failed(String taskId, IStatus status) { collector.failed(taskId, status); } public CollectorWrapper(TaskDataCollector collector, IProgressMonitor monitor2) { this.collector = collector; this.monitor2 = monitor2; } @Override public void accept(TaskData taskData) { try { AbstractTaskDataHandler taskDataHandler = connector.getTaskDataHandler(); taskDataHandler.initializeTaskData(repository, taskData, null, new SubProgressMonitor(monitor2, 1)); } catch (CoreException e) { // this info CoreException is only used internal if (e.getStatus().getCode() == IStatus.INFO && e.getMessage().contains("Update Config")) { //$NON-NLS-1$ if (updateConfig[0] == null) { updateConfig[0] = new Boolean(true); } } else if (collectionException[0] == null) { collectionException[0] = e; } } collector.accept(taskData); monitor2.worked(1); } } TaskDataCollector collector2 = new CollectorWrapper(collector, new NullProgressMonitor()); TaskDataCollector collector3 = new CollectorWrapper(collectorXMLRPC, new NullProgressMonitor()); client.getTaskData(taskIds, collector2, new BugzillaAttributeMapper(repository, connector), new NullProgressMonitor()); if (collectionException[0] != null) { throw collectionException[0]; } bugzillaClient.getTaskData(taskIds, collector3, new BugzillaAttributeMapper(repository, connector), new NullProgressMonitor()); if (collectionException[0] != null) { throw collectionException[0]; } assertEquals(results.size(), resultsXMLRPC.size()); @SuppressWarnings("unused") String div = ""; for (String taskID : results.keySet()) { TaskData taskDataHTML = results.get(taskID); TaskData taskDataXMLRPC = resultsXMLRPC.get(taskID); assertNotNull(taskDataHTML); assertNotNull(taskDataXMLRPC); Map<String, TaskAttribute> attributesHTML = taskDataHTML.getRoot().getAttributes(); Map<String, TaskAttribute> attributesXMLRPC = taskDataXMLRPC.getRoot().getAttributes(); div += compareAttributes(attributesHTML, attributesXMLRPC, "", "Root-" + taskID + ": "); //$NON-NLS-1$ // TaskAttribute aa0 = taskDataHTML.getRoot().getAttribute("estimated_time"); // TaskAttribute aa1 = taskDataXMLRPC.getRoot().getAttribute("estimated_time"); // TaskAttribute ab0 = taskDataHTML.getRoot().getAttribute("remaining_time"); // TaskAttribute ab1 = taskDataXMLRPC.getRoot().getAttribute("remaining_time"); // TaskAttribute ac0 = taskDataHTML.getRoot().getAttribute("actual_time"); // TaskAttribute ac1 = taskDataXMLRPC.getRoot().getAttribute("actual_time"); // TaskAttribute ad0 = taskDataHTML.getRoot().getAttribute("deadline"); // TaskAttribute ad1 = taskDataXMLRPC.getRoot().getAttribute("deadline"); // @SuppressWarnings("unused") // int i = 9; // i++; } @SuppressWarnings("unused") // set breakpoint to see what is the div between HTML and XMLRPC int i = 9; i++; } } private String compareAttributes(Map<String, TaskAttribute> attributesHTML, Map<String, TaskAttribute> attributesXMLRPC, String div, String prefix) { for (String attributeNameHTML : attributesHTML.keySet()) { TaskAttribute attributeHTML = attributesHTML.get(attributeNameHTML); TaskAttribute attributeXMLRPC = attributesXMLRPC.get(attributeNameHTML); if (attributeXMLRPC == null) { div += (prefix + attributeNameHTML + " not in XMLRPC\n"); continue; } if (attributeHTML.getValues().size() > 1) { List<String> i1 = attributeHTML.getValues(); List<String> i2 = attributeXMLRPC.getValues(); if (i1.size() != i2.size()) { div += (prefix + attributeNameHTML + " has size " + i1.size() + " but got " + i2.size() + "\n"); } for (String string : i1) { if (!i2.contains(string)) { div += (prefix + attributeNameHTML + " did not have " + string + "\n"); } } } if (attributeHTML.getValue().compareTo(attributeXMLRPC.getValue()) != 0) { div += (prefix + attributeNameHTML + " value not equal HTML = \'" + attributeHTML.getValue() + "\' XMLRPC = \'" + attributeXMLRPC.getValue() + "\'\n"); } TaskAttributeMetaData metaHTML = attributeHTML.getMetaData(); TaskAttributeMetaData metaXMLRPC = attributeXMLRPC.getMetaData(); if (metaHTML != null && metaXMLRPC == null) { div += (prefix + attributeNameHTML + " MetaData not in XMLRPC\n"); } if (metaHTML != null && metaXMLRPC != null) { if (metaHTML.getKind() != null && metaXMLRPC.getKind() == null) { div += (prefix + attributeNameHTML + " MetaData Kind not in XMLRPC\n"); } else if (metaHTML.getKind() != null && metaHTML.getKind().compareTo(metaXMLRPC.getKind()) != 0) { div += (prefix + attributeNameHTML + " Meta Kind not equal HTML = \'" + metaHTML.getKind() + "\' XMLRPC = \'" + metaXMLRPC.getKind() + "\'\n"); } if (metaHTML.getType() != null && metaXMLRPC.getType() == null) { div += (prefix + attributeNameHTML + " MetaData Type not in XMLRPC\n"); } else if (metaHTML.getType() != null && metaHTML.getType().compareTo(metaXMLRPC.getType()) != 0) { div += (prefix + attributeNameHTML + " Meta Type not equal HTML = \'" + metaHTML.getType() + "\' XMLRPC = \'" + metaXMLRPC.getType() + "\'\n"); } if (metaHTML.getLabel() != null && metaXMLRPC.getLabel() == null) { div += (prefix + attributeNameHTML + " MetaData Label not in XMLRPC\n"); } else if (metaHTML.getLabel() != null && metaHTML.getLabel().compareTo(metaXMLRPC.getLabel()) != 0) { div += (prefix + attributeNameHTML + " Meta Label not equal HTML = \'" + metaHTML.getLabel() + "\' XMLRPC = \'" + metaXMLRPC.getLabel() + "\'\n"); } } Map<String, TaskAttribute> subAttribHTML = attributeHTML.getAttributes(); if (!subAttribHTML.isEmpty()) { Map<String, TaskAttribute> subAttribXMLRPC = attributeXMLRPC.getAttributes(); div = compareAttributes(subAttribHTML, subAttribXMLRPC, div, prefix + attributeNameHTML + ": "); } } return div; } public void testUpdateProductInfo() throws Exception { if (!BugzillaFixture.current().isXmlRpcEnabled()) { return; } RepositoryConfiguration repositoryConfiguration = connector .getRepositoryConfiguration(repository.getRepositoryUrl()); for (String product : repositoryConfiguration.getOptionValues(BugzillaAttribute.PRODUCT)) { repositoryConfiguration.setDefaultMilestone(product, null); } bugzillaClient.updateProductInfo(new NullProgressMonitor(), repositoryConfiguration); for (String product : repositoryConfiguration.getOptionValues(BugzillaAttribute.PRODUCT)) { if (product.equals("ManualTest") || product.equals("Product with Spaces") || product.equals("TestProduct")) { assertEquals("---", repositoryConfiguration.getDefaultMilestones(product)); } else { fail("never reach this"); } } } }