Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 148089
Collapse All | Expand All

(-)src/org/eclipse/mylar/trac/tests/TracXmlRpcRepositoryTest.java (+54 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 - 2006 Mylar eclipse.org project and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Mylar project committers - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.mylar.trac.tests;
13
14
import java.net.URL;
15
16
import org.eclipse.mylar.internal.trac.core.ITracRepository;
17
import org.eclipse.mylar.internal.trac.core.TracLoginException;
18
import org.eclipse.mylar.internal.trac.core.TracRemoteException;
19
import org.eclipse.mylar.internal.trac.core.TracXmlRpcRepository;
20
import org.eclipse.mylar.internal.trac.core.ITracRepository.Version;
21
import org.eclipse.mylar.trac.tests.support.AbstractTracRepositoryFactory;
22
23
/**
24
 * @author Steffen Pingel
25
 */
26
public class TracXmlRpcRepositoryTest extends AbstractTracRepositoryTest {
27
28
	public TracXmlRpcRepositoryTest() {
29
		super(new AbstractTracRepositoryFactory() {
30
			protected ITracRepository createRepository(String url, String username, String password) throws Exception {
31
				return new TracXmlRpcRepository(new URL(url), Version.XML_RPC, username, password);
32
			}
33
		});
34
	}
35
36
	public void testValidateFailNoAuth() throws Exception {
37
		factory.connect(Constants.TEST_REPOSITORY1_URL, "", "");
38
		try {
39
			factory.repository.validate();
40
			fail("Expected TracLoginException");
41
		} catch (TracLoginException e) {
42
		}
43
	}
44
45
	public void testMulticallExceptions() throws Exception {
46
		factory.connectRepository1();
47
		try {
48
			((TracXmlRpcRepository) factory.repository).getTickets(new int[] { 1, Integer.MAX_VALUE });
49
			fail("Expected TracRemoteException");
50
		} catch (TracRemoteException e) {
51
		}
52
	}
53
54
}
(-)src/org/eclipse/mylar/trac/tests/AbstractTracRepositorySearchTest.java (+164 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 - 2006 Mylar eclipse.org project and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Mylar project committers - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.mylar.trac.tests;
13
14
import java.util.ArrayList;
15
import java.util.Hashtable;
16
import java.util.List;
17
import java.util.Map;
18
19
import junit.framework.TestCase;
20
21
import org.eclipse.mylar.internal.trac.core.TracException;
22
import org.eclipse.mylar.internal.trac.model.TracSearch;
23
import org.eclipse.mylar.internal.trac.model.TracTicket;
24
import org.eclipse.mylar.internal.trac.model.TracTicket.Key;
25
import org.eclipse.mylar.trac.tests.support.AbstractTracRepositoryFactory;
26
import org.eclipse.mylar.trac.tests.support.XmlRpcServer;
27
import org.eclipse.mylar.trac.tests.support.XmlRpcServer.Ticket;
28
29
/**
30
 * Test cases that validate search results for classes that implement
31
 * {@link ITracRepositor}.
32
 * 
33
 * @author Steffen Pingel
34
 */
35
public abstract class AbstractTracRepositorySearchTest extends TestCase {
36
37
	protected XmlRpcServer server;
38
39
	protected AbstractTracRepositoryFactory factory;
40
41
	protected static List<Ticket> tickets;
42
43
	private static boolean setupRun = false;
44
45
	public AbstractTracRepositorySearchTest(AbstractTracRepositoryFactory factory) {
46
		this.factory = factory;
47
	}
48
49
	protected void setUp() throws Exception {
50
		super.setUp();
51
52
		server = new XmlRpcServer(Constants.TEST_REPOSITORY1_URL, Constants.TEST_REPOSITORY1_ADMIN_USERNAME,
53
				Constants.TEST_REPOSITORY1_ADMIN_PASSWORD);
54
55
		if (!setupRun) {
56
			tickets = new ArrayList<Ticket>();
57
58
			server.ticket().deleteAll();
59
60
			server.ticketMilestone("m1").deleteAndCreate();
61
			Ticket ticket = add(server.ticket().create("summary1", "description1"));
62
			ticket.update("comment", "milestone", "m1");
63
64
			server.ticketMilestone("m2").deleteAndCreate();
65
			ticket = add(server.ticket().create("summary2", "description2"));
66
			ticket.update("comment", "milestone", "m2");
67
			ticket = add(server.ticket().create("summary3", "description3"));
68
			ticket.update("comment", "milestone", "m2");
69
70
			ticket = add(server.ticket().create("summary4", "description4"));
71
72
			setupRun = true;
73
		}
74
75
		factory.connectRepository1();
76
	}
77
78
	protected void tearDown() throws Exception {
79
		super.tearDown();
80
81
		// server.getFixture().cleanup();
82
	}
83
84
	protected Ticket add(Ticket ticket) {
85
		tickets.add(ticket);
86
		return ticket;
87
	}
88
89
	protected void assertTicketEquals(Ticket ticket, TracTicket tracTicket) throws Exception {
90
		assertTrue(tracTicket.isValid());
91
92
		Hashtable expectedValues = ticket.getValues();
93
		Map<String, String> values = tracTicket.getValues();
94
		for (String key : values.keySet()) {
95
			assertEquals("Values for key '" + key + "' did not match", expectedValues.get(key), values.get(key));
96
		}
97
	}
98
99
	public void testGetTicket() throws Exception {
100
		TracTicket ticket = factory.repository.getTicket(tickets.get(0).getId());
101
		assertTicketEquals(tickets.get(0), ticket);
102
103
		ticket = factory.repository.getTicket(tickets.get(1).getId());
104
		assertTicketEquals(tickets.get(1), ticket);
105
	}
106
107
	public void testGetTicketInvalidId() throws Exception {
108
		try {
109
			factory.repository.getTicket(Integer.MAX_VALUE);
110
			fail("Expected TracException");
111
		} catch (TracException e) {
112
		}
113
	}
114
115
	public void testSearchAll() throws Exception {
116
		TracSearch search = new TracSearch();
117
		List<TracTicket> result = new ArrayList<TracTicket>();
118
		factory.repository.search(search, result);
119
		assertEquals(tickets.size(), result.size());
120
	}
121
122
	public void testSearchEmpty() throws Exception {
123
		TracSearch search = new TracSearch();
124
		search.addFilter("milestone", "does not exist");
125
		List<TracTicket> result = new ArrayList<TracTicket>();
126
		factory.repository.search(search, result);
127
		assertEquals(0, result.size());
128
	}
129
130
	public void testSearchMilestone1() throws Exception {
131
		TracSearch search = new TracSearch();
132
		search.addFilter("milestone", "m1");
133
		List<TracTicket> result = new ArrayList<TracTicket>();
134
		factory.repository.search(search, result);
135
		assertEquals(1, result.size());
136
		assertTicketEquals(tickets.get(0), result.get(0));
137
	}
138
139
	public void testSearchMilestone2() throws Exception {
140
		TracSearch search = new TracSearch();
141
		search.addFilter("milestone", "m1");
142
		search.addFilter("milestone", "m2");
143
		search.setOrderBy("id");
144
		List<TracTicket> result = new ArrayList<TracTicket>();
145
		factory.repository.search(search, result);
146
		assertEquals(3, result.size());
147
		assertTicketEquals(tickets.get(0), result.get(0));
148
		assertTicketEquals(tickets.get(1), result.get(1));
149
		assertTicketEquals(tickets.get(2), result.get(2));
150
	}
151
152
	public void testSearchExactMatch() throws Exception {
153
		TracSearch search = new TracSearch();
154
		search.addFilter("milestone", "m1");
155
		search.addFilter("summary", "summary1");
156
		List<TracTicket> result = new ArrayList<TracTicket>();
157
		factory.repository.search(search, result);
158
		assertEquals(1, result.size());
159
		assertTicketEquals(tickets.get(0), result.get(0));
160
		assertEquals("m1", result.get(0).getValue(Key.MILESTONE));
161
		assertEquals("summary1", result.get(0).getValue(Key.SUMMARY));
162
	}
163
164
}
(-)src/org/eclipse/mylar/trac/tests/TracXmlRpcRepositorySearchTest.java (+54 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 - 2006 Mylar eclipse.org project and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Mylar project committers - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.mylar.trac.tests;
13
14
import java.net.URL;
15
import java.util.ArrayList;
16
import java.util.List;
17
18
import org.eclipse.mylar.internal.trac.core.ITracRepository;
19
import org.eclipse.mylar.internal.trac.core.TracXmlRpcRepository;
20
import org.eclipse.mylar.internal.trac.core.ITracRepository.Version;
21
import org.eclipse.mylar.internal.trac.model.TracSearch;
22
import org.eclipse.mylar.internal.trac.model.TracTicket;
23
import org.eclipse.mylar.internal.trac.model.TracTicket.Key;
24
import org.eclipse.mylar.trac.tests.support.AbstractTracRepositoryFactory;
25
26
/**
27
 * @author Steffen Pingel
28
 */
29
public class TracXmlRpcRepositorySearchTest extends AbstractTracRepositorySearchTest {
30
31
	public TracXmlRpcRepositorySearchTest() {
32
		super(new AbstractTracRepositoryFactory() {
33
			protected ITracRepository createRepository(String url, String username, String password) throws Exception {
34
				return new TracXmlRpcRepository(new URL(url), Version.XML_RPC, username, password);
35
			}
36
		});
37
	}
38
39
	public void testSearchValidateTicket() throws Exception {
40
		TracSearch search = new TracSearch();
41
		search.addFilter("summary", "summary1");
42
		List<TracTicket> result = new ArrayList<TracTicket>();
43
		factory.repository.search(search, result);
44
		assertEquals(1, result.size());
45
		assertTicketEquals(tickets.get(0), result.get(0));
46
		assertEquals("component1", result.get(0).getValue(Key.COMPONENT));
47
		assertEquals("description1", result.get(0).getValue(Key.DESCRIPTION));
48
		assertEquals("m1", result.get(0).getValue(Key.MILESTONE));
49
		assertEquals(factory.username, result.get(0).getValue(Key.REPORTER));
50
		assertEquals("summary1", result.get(0).getValue(Key.SUMMARY));
51
		assertEquals("", result.get(0).getValue(Key.VERSION));
52
	}
53
54
}
(-)src/org/eclipse/mylar/trac/tests/support/XmlRpcServer.java (+351 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 - 2006 Mylar eclipse.org project and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Mylar project committers - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.mylar.trac.tests.support;
13
14
import java.io.IOException;
15
import java.net.MalformedURLException;
16
import java.net.URL;
17
import java.util.ArrayList;
18
import java.util.Arrays;
19
import java.util.Hashtable;
20
import java.util.List;
21
import java.util.Vector;
22
23
import org.apache.xmlrpc.XmlRpcClient;
24
import org.apache.xmlrpc.XmlRpcException;
25
import org.eclipse.mylar.internal.trac.core.TracXmlRpcRepository;
26
import org.eclipse.mylar.internal.trac.core.ITracRepository.Version;
27
28
/**
29
 * @author Steffen Pingel
30
 */
31
public class XmlRpcServer {
32
33
	public abstract class AbstractTracItem {
34
35
		public abstract void delete() throws Exception;
36
37
		protected void itemCreated() {
38
			fixture.items.add(this);
39
		}
40
41
		protected void itemDeleted() {
42
			fixture.items.remove(this);
43
		}
44
45
	}
46
47
	/**
48
	 * Represents a Trac type with multiple attributes such as a milestone.
49
	 */
50
	public class ModelEnum extends AbstractTracItem {
51
52
		private String[] attributes;
53
54
		private String id;
55
56
		private String module;
57
58
		public ModelEnum(String module, String id, String... attributes) {
59
			this.module = module;
60
			this.id = id;
61
			this.attributes = attributes;
62
		}
63
64
		public ModelEnum create(Object... params) throws Exception {
65
			call(module + ".create", id, toMap(params));
66
			itemCreated();
67
			return this;
68
		}
69
70
		public void delete() throws Exception {
71
			call(module + ".delete", id);
72
			itemDeleted();
73
		}
74
75
		public void deleteAll() throws Exception {
76
			String[] ids = getAll();
77
			for (String id : ids) {
78
				call(module + ".delete", id);
79
			}
80
		}
81
82
		public ModelEnum deleteAndCreate(Object... params) throws Exception {
83
			try {
84
				if (Arrays.asList(getAll()).contains(id)) {
85
					delete();
86
				}
87
			} catch (Exception e) {
88
				// ignore
89
			}
90
91
			return create(params);
92
		}
93
94
		public Object[] get() throws Exception {
95
			Hashtable values = (Hashtable) call(module + ".get", id);
96
			Object[] result = new Object[values.size()];
97
			for (int i = 0; i < result.length && i < attributes.length; i++) {
98
				result[i] = values.get(attributes[i]);
99
			}
100
			return result;
101
		}
102
103
		@SuppressWarnings("unchecked")
104
		public String[] getAll() throws Exception {
105
			return (String[]) ((Vector) call(module + ".getAll")).toArray(new String[0]);
106
		}
107
108
		private Hashtable<String, Object> toMap(Object... params) {
109
			Hashtable<String, Object> attrs = new Hashtable<String, Object>();
110
			for (int i = 0; i < attributes.length && i < params.length; i++) {
111
				attrs.put((String) attributes[i], params[i]);
112
			}
113
			return attrs;
114
		}
115
116
		public ModelEnum update(Object... params) throws Exception {
117
			call(module + ".update", id, toMap(params));
118
			return this;
119
		}
120
121
	}
122
123
	/**
124
	 * Records changes to the repository.
125
	 */
126
	public class TestFixture {
127
128
		List<AbstractTracItem> items = new ArrayList<AbstractTracItem>();
129
130
		/**
131
		 * Undo all changes.
132
		 */
133
		public void cleanup() throws Exception {
134
			while (!items.isEmpty()) {
135
				items.get(0).delete();
136
			}
137
		}
138
139
	}
140
141
	/**
142
	 * Represents a Trac ticket.
143
	 */
144
	public class Ticket extends AbstractTracItem {
145
146
		private Integer id;
147
148
		public Ticket(Integer id) {
149
			this.id = id;
150
		}
151
152
		public Ticket create(String summary, String description) throws Exception {
153
			this.id = (Integer) call("ticket.create", summary, description, new Hashtable());
154
			if (id == null) {
155
				throw new RuntimeException("Could not create ticket: " + summary);
156
			}
157
			itemCreated();
158
			return this;
159
		}
160
161
		public void delete() throws Exception {
162
			call("ticket.delete", id);
163
			itemDeleted();
164
		}
165
166
		public void deleteAll() throws Exception {
167
			Integer[] ids = getAll();
168
			for (Integer id : ids) {
169
				call("ticket.delete", id);
170
			}
171
		}
172
173
		public Object getValue(String key) throws Exception {
174
			return getValues().get(key);
175
		}
176
177
		public Hashtable getValues() throws Exception {
178
			return (Hashtable) ((Vector) call("ticket.get", id)).get(3);
179
		}
180
181
		@SuppressWarnings("unchecked")
182
		public Integer[] getAll() throws Exception {
183
			return (Integer[]) ((Vector) call("ticket.query", "order=id")).toArray(new Integer[0]);
184
		}
185
186
		public int getId() {
187
			return id;
188
		}
189
190
		public Ticket update(String comment, String key, String value) throws Exception {
191
			Hashtable<String, Object> attrs = new Hashtable<String, Object>();
192
			attrs.put(key, value);
193
			call("ticket.update", id, comment, attrs);
194
			return this;
195
		}
196
197
	}
198
199
	/**
200
	 * Represents a Trac type that has a single attribute such as a priority.
201
	 */
202
	public class TicketEnum extends AbstractTracItem {
203
204
		private String id;
205
206
		private String module;
207
208
		public TicketEnum(String module, String id) {
209
			this.module = module;
210
			this.id = id;
211
		}
212
213
		public TicketEnum create(String param) throws Exception {
214
			call(module + ".create", id, param);
215
			itemCreated();
216
			return this;
217
		}
218
219
		public void delete() throws Exception {
220
			call(module + ".delete", id);
221
			itemDeleted();
222
		}
223
224
		public void deleteAll() throws Exception {
225
			String[] ids = getAll();
226
			for (String id : ids) {
227
				call(module + ".delete", id);
228
			}
229
		}
230
231
		public TicketEnum deleteAndCreate(String param) throws Exception {
232
			try {
233
				if (Arrays.asList(getAll()).contains(id)) {
234
					delete();
235
				}
236
			} catch (Exception e) {
237
				// ignore
238
			}
239
240
			return create(param);
241
		}
242
243
		public String get() throws Exception {
244
			return (String) call(module + ".get", id);
245
		}
246
247
		@SuppressWarnings("unchecked")
248
		public String[] getAll() throws Exception {
249
			return (String[]) ((Vector) call(module + ".getAll")).toArray(new String[0]);
250
		}
251
252
		public TicketEnum update(String param) throws Exception {
253
			call(module + ".update", id, param);
254
			return this;
255
		}
256
257
	}
258
259
	private XmlRpcClient client;
260
261
	private TestFixture fixture;
262
263
	private String password;
264
265
	private TracXmlRpcRepository repository;
266
267
	private String url;
268
269
	private String username;
270
271
	public XmlRpcServer(String url, String username, String password) throws Exception {
272
		this.url = url;
273
		this.username = username;
274
		this.password = password;
275
276
		this.fixture = new TestFixture();
277
278
		this.repository = new TracXmlRpcRepository(new URL(url), Version.XML_RPC, username, password);
279
		this.client = repository.getClient();
280
	}
281
282
	private Object call(String method, Object... parameters) throws XmlRpcException, IOException {
283
		Vector<Object> params = new Vector<Object>(parameters.length);
284
		for (Object parameter : parameters) {
285
			params.add(parameter);
286
		}
287
288
		Object result = client.execute(method, params);
289
		if (result instanceof XmlRpcException) {
290
			throw (XmlRpcException) result;
291
		}
292
		return result;
293
	}
294
295
	public TestFixture getFixture() {
296
		return fixture;
297
	}
298
299
	public String getPassword() {
300
		return password;
301
	}
302
303
	public TracXmlRpcRepository getRepository() throws MalformedURLException {
304
		return repository;
305
	}
306
307
	public String getUrl() {
308
		return url;
309
	}
310
311
	public String getUsername() {
312
		return username;
313
	}
314
315
	public Ticket ticket() throws Exception {
316
		return new Ticket(null);
317
	}
318
319
	public Ticket ticket(int id) throws Exception {
320
		return new Ticket(id);
321
	}
322
323
	public ModelEnum ticketComponent(String id) throws Exception {
324
		return new ModelEnum("ticket.component", id, "owner", "description");
325
	}
326
327
	public ModelEnum ticketMilestone(String id) throws Exception {
328
		return new ModelEnum("ticket.milestone", id, "due", "completed", "description");
329
	}
330
331
	public TicketEnum ticketPriority(String id) throws Exception {
332
		return new TicketEnum("ticket.priority", id);
333
	}
334
335
	public TicketEnum ticketSeverity(String id) throws Exception {
336
		return new TicketEnum("ticket.severity", id);
337
	}
338
339
	public TicketEnum ticketStatus(String id) throws Exception {
340
		return new TicketEnum("ticket.status", id);
341
	}
342
343
	public TicketEnum ticketType(String id) throws Exception {
344
		return new TicketEnum("ticket.type", id);
345
	}
346
347
	public ModelEnum ticketVersion(String id) throws Exception {
348
		return new ModelEnum("ticket.version", id, "time", "description");
349
	}
350
351
}
(-)src/org/eclipse/mylar/trac/tests/support/AbstractTracRepositoryFactory.java (+52 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 - 2006 Mylar eclipse.org project and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Mylar project committers - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.mylar.trac.tests.support;
13
14
import java.net.Authenticator;
15
16
import org.eclipse.mylar.internal.trac.core.ITracRepository;
17
import org.eclipse.mylar.trac.tests.Constants;
18
19
/**
20
 * @author Steffen Pingel
21
 * 
22
 */
23
public abstract class AbstractTracRepositoryFactory {
24
25
	public String repositoryUrl;
26
27
	public ITracRepository repository;
28
29
	public String username;
30
31
	public String password;
32
33
	public ITracRepository connectRepository1() throws Exception {
34
		return connect(Constants.TEST_REPOSITORY1_URL, Constants.TEST_REPOSITORY1_ADMIN_USERNAME,
35
				Constants.TEST_REPOSITORY1_ADMIN_PASSWORD);
36
	}
37
38
	public ITracRepository connect(String url, String username, String password) throws Exception {
39
		this.repositoryUrl = url;
40
		this.username = username;
41
		this.password = password;
42
		this.repository = createRepository(url, username, password);
43
44
		// make sure no dialog pops up to prompt for a password
45
		Authenticator.setDefault(null);
46
47
		return this.repository;
48
	}
49
50
	protected abstract ITracRepository createRepository(String url, String username, String password) throws Exception;
51
52
}
(-)src/org/eclipse/mylar/trac/tests/AbstractTracRepositoryTest.java (+55 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 - 2006 Mylar eclipse.org project and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Mylar project committers - initial API and implementation
10
 *******************************************************************************/
11
12
package org.eclipse.mylar.trac.tests;
13
14
import junit.framework.TestCase;
15
16
import org.eclipse.mylar.internal.trac.core.TracLoginException;
17
import org.eclipse.mylar.trac.tests.support.AbstractTracRepositoryFactory;
18
19
/**
20
 * Test cases for classes that implement {@link ITracRepositor}.
21
 * 
22
 * @author Steffen Pingel
23
 */
24
public abstract class AbstractTracRepositoryTest extends TestCase {
25
26
	protected AbstractTracRepositoryFactory factory;
27
28
	public AbstractTracRepositoryTest(AbstractTracRepositoryFactory factory) {
29
		this.factory = factory;
30
	}
31
32
	public void testValidate() throws Exception {
33
		factory.connectRepository1();
34
		factory.repository.validate();
35
	}
36
37
	public void testValidateFailAuthWrongPassword() throws Exception {
38
		factory.connect(Constants.TEST_REPOSITORY1_URL, Constants.TEST_REPOSITORY1_ADMIN_USERNAME, "wrongpassword");
39
		try {
40
			factory.repository.validate();
41
			fail("Expected TracLoginException");
42
		} catch (TracLoginException e) {
43
		}
44
	}
45
46
	public void testValidateFailAuthWrongUsername() throws Exception {
47
		factory.connect(Constants.TEST_REPOSITORY1_URL, "wrongusername", Constants.TEST_REPOSITORY1_ADMIN_PASSWORD);
48
		try {
49
			factory.repository.validate();
50
			fail("Expected TracLoginException");
51
		} catch (TracLoginException e) {
52
		}
53
	}
54
55
}
(-)META-INF/MANIFEST.MF (-1 / +3 lines)
Lines 8-14 Link Here
8
Bundle-Localization: plugin
8
Bundle-Localization: plugin
9
Require-Bundle: org.eclipse.ui,
9
Require-Bundle: org.eclipse.ui,
10
 org.eclipse.core.runtime,
10
 org.eclipse.core.runtime,
11
 org.eclipse.mylar.core
11
 org.eclipse.mylar.core,
12
 org.eclipse.mylar.tasklist,
13
 org.apache.xmlrpc
12
Eclipse-LazyStart: true
14
Eclipse-LazyStart: true
13
Export-Package: org.eclipse.mylar.internal.trac,
15
Export-Package: org.eclipse.mylar.internal.trac,
14
 org.eclipse.mylar.internal.trac.core,
16
 org.eclipse.mylar.internal.trac.core,
(-)src/org/eclipse/mylar/internal/trac/core/TracXmlRpcRepository.java (+279 lines)
Added Link Here
1
package org.eclipse.mylar.internal.trac.core;
2
3
import java.io.IOException;
4
import java.io.InputStream;
5
import java.io.OutputStream;
6
import java.net.HttpURLConnection;
7
import java.net.URL;
8
import java.util.ArrayList;
9
import java.util.Hashtable;
10
import java.util.Iterator;
11
import java.util.List;
12
import java.util.Vector;
13
14
import org.apache.xmlrpc.XmlRpc;
15
import org.apache.xmlrpc.XmlRpcClient;
16
import org.apache.xmlrpc.XmlRpcClientException;
17
import org.apache.xmlrpc.XmlRpcException;
18
import org.apache.xmlrpc.XmlRpcTransport;
19
import org.apache.xmlrpc.XmlRpcTransportFactory;
20
import org.eclipse.mylar.internal.trac.MylarTracPlugin;
21
import org.eclipse.mylar.internal.trac.model.TracSearch;
22
import org.eclipse.mylar.internal.trac.model.TracTicket;
23
24
/**
25
 * Represents a Trac repository that is accessed through the Trac XmlRpcPlugin.
26
 * 
27
 * @author Steffen Pingel
28
 */
29
public class TracXmlRpcRepository extends AbstractTracRepository {
30
31
	public static final String XMLRPC_URL = "/xmlrpc";
32
33
	private XmlRpcClient xmlrpc;
34
35
	public TracXmlRpcRepository(URL url, Version version, String username, String password) {
36
		super(url, version, username, password);
37
	}
38
39
	public XmlRpcClient getClient() throws TracException {
40
		if (xmlrpc != null) {
41
			return xmlrpc;
42
		}
43
44
		// initialize XML-RPC library
45
		XmlRpc.setDefaultInputEncoding(ITracRepository.CHARSET);
46
47
		try {
48
			String location = repositoryUrl.toString();
49
			if (hasAuthenticationCredentials()) {
50
				location += LOGIN_URL;
51
			}
52
			location += XMLRPC_URL;
53
54
			URL url = new URL(location);
55
			TransportFactory transport = new TransportFactory(url);
56
			xmlrpc = new XmlRpcClient(url, transport);
57
		} catch (Exception e) {
58
			throw new TracException(e);
59
		}
60
61
		return xmlrpc;
62
	}
63
64
	private Object call(String method, Object... parameters) throws TracException {
65
		getClient();
66
67
		Vector<Object> params = new Vector<Object>();
68
		for (Object parameter : parameters) {
69
			params.add(parameter);
70
		}
71
72
		try {
73
			return xmlrpc.execute(method, params);
74
		} catch (HttpException e) {
75
			if (e.responseCode == HttpURLConnection.HTTP_FORBIDDEN
76
					|| e.responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
77
				throw new TracLoginException();
78
			} else {
79
				throw new TracException(e);
80
			}
81
		} catch (XmlRpcException e) {
82
			throw new TracRemoteException(e);
83
		} catch (Exception e) {
84
			throw new TracException(e);
85
		}
86
	}
87
88
	private Vector multicall(Hashtable<String, Object>... calls) throws TracException {
89
		Vector result = (Vector) call("system.multicall", new Object[] { calls });
90
		for (Object item : result) {
91
			try {
92
				checkForException(item);
93
			}
94
			catch (XmlRpcException e) {
95
				throw new TracRemoteException(e);
96
			}
97
			catch (Exception e) {
98
				throw new TracException(e);
99
			}
100
		}
101
		return result;
102
	}
103
104
	private void checkForException(Object result) throws NumberFormatException, XmlRpcException {
105
		if (result instanceof Hashtable) {
106
			Hashtable exceptionData = (Hashtable) result;
107
			if (exceptionData.containsKey("faultCode") && exceptionData.containsKey("faultString")) {
108
				throw new XmlRpcException(
109
						Integer.parseInt(exceptionData.get("faultCode").toString()),
110
						(String) exceptionData.get("faultString"));
111
			}
112
		}
113
	}
114
	
115
	private Hashtable<String, Object> createMultiCall(String methodName, Object... parameters) throws TracException {
116
		Hashtable<String, Object> table = new Hashtable<String, Object>();
117
		table.put("methodName", methodName);
118
		table.put("params", parameters);
119
		return table;
120
	}
121
122
	public void validate() throws TracException {
123
		Vector result = (Vector) call("system.listMethods");
124
		boolean hasGetTicket = false, hasQuery = false;
125
		for (Object methodName : result) {
126
			if ("ticket.get".equals(methodName)) {
127
				hasGetTicket = true;
128
			}
129
			if ("ticket.query".equals(methodName)) {
130
				hasQuery = true;
131
			}
132
133
			if (hasGetTicket && hasQuery) {
134
				return;
135
			}
136
		}
137
138
		throw new TracException("XML-RPC is missing required API calls");
139
	}
140
141
	public TracTicket getTicket(int id) throws TracException {
142
		Vector result = (Vector) call("ticket.get", id);
143
		return parseTicket(result);
144
	}
145
146
	@SuppressWarnings("unchecked")
147
	public List<TracTicket> getTickets(int[] ids) throws TracException {
148
		Hashtable<String, Object>[] calls = new Hashtable[ids.length];
149
		for (int i = 0; i < calls.length; i++) {
150
			calls[i] = createMultiCall("ticket.get", ids[i]);
151
		}
152
153
		Vector result = multicall(calls);
154
		assert result.size() == ids.length; 
155
		
156
		List<TracTicket> tickets = new ArrayList<TracTicket>(result.size());
157
		for (Iterator it = result.iterator(); it.hasNext();) {
158
			Vector ticketResult = (Vector) it.next();
159
			tickets.add(parseTicket(ticketResult));
160
		}
161
		
162
		return tickets;
163
	}
164
165
	@SuppressWarnings("unchecked")
166
	public void search(TracSearch query, List<TracTicket> tickets) throws TracException {
167
		// an empty query string is not valid, therefore prepend order
168
		Vector result = (Vector) call("ticket.query", "order=id" + query.toQuery());
169
170
		Hashtable<String, Object>[] calls = new Hashtable[result.size()];
171
		for (int i = 0; i < calls.length; i++) {
172
			calls[i] = createMultiCall("ticket.get", result.get(i));
173
		}
174
		result = multicall(calls);
175
176
		for (Iterator it = result.iterator(); it.hasNext();) {
177
			Vector ticketResult = (Vector) it.next();
178
			tickets.add(parseTicket(ticketResult));
179
		}
180
	}
181
182
	private TracTicket parseTicket(Vector result) throws InvalidTicketException {
183
		TracTicket ticket = new TracTicket((Integer) result.get(0));
184
		ticket.setCreated((Integer) result.get(1));
185
		ticket.setLastChanged((Integer) result.get(2));
186
		Hashtable attributes = (Hashtable) result.get(3);
187
		for (Object key : attributes.keySet()) {
188
			ticket.putTracValue(key.toString(), attributes.get(key).toString());
189
		}
190
		return ticket;
191
	}
192
193
	/**
194
	 * A custom transport factory used to establish XML-RPC connections. Uses
195
	 * the Eclipse proxy settings.
196
	 * 
197
	 * @author Steffen Pingel
198
	 */
199
	private class TransportFactory implements XmlRpcTransportFactory {
200
201
		private URL url;
202
203
		public TransportFactory(URL url) {
204
			assert url != null;
205
206
			this.url = url;
207
		}
208
209
		public XmlRpcTransport createTransport() throws XmlRpcClientException {
210
			return new XmlRpcTransport() {
211
212
				private HttpURLConnection connection;
213
214
				public void endClientRequest() throws XmlRpcClientException {
215
					assert connection != null;
216
217
					try {
218
						connection.getInputStream().close();
219
					} catch (Exception e) {
220
						throw new XmlRpcClientException("Exception closing connection", e);
221
					}
222
				}
223
224
				public InputStream sendXmlRpc(byte[] request) throws IOException, XmlRpcClientException {
225
					try {
226
						connection = MylarTracPlugin.getHttpConnection(url);
227
					} catch (Exception e) {
228
						throw new IOException(e.toString());
229
					}
230
231
					connection.setDoInput(true);
232
					connection.setDoOutput(true);
233
					connection.setUseCaches(false);
234
					connection.setAllowUserInteraction(false);
235
236
					connection.setRequestProperty("Content-Length", request.length + "");
237
					connection.setRequestProperty("Content-Type", "text/xml");
238
					if (hasAuthenticationCredentials()) {
239
						MylarTracPlugin.setAuthCredentials(connection, username, password);
240
					}
241
242
					OutputStream out = connection.getOutputStream();
243
					out.write(request);
244
					out.flush();
245
					out.close();
246
247
					connection.connect();
248
					int responseCode = connection.getResponseCode();
249
					if (responseCode != HttpURLConnection.HTTP_OK) {
250
						throw new HttpException(responseCode);
251
					}
252
253
					return connection.getInputStream();
254
				}
255
256
			};
257
		}
258
259
		public void setProperty(String key, Object value) {
260
			// ignore, this is never called by the library
261
		}
262
263
	}
264
265
	private class HttpException extends IOException {
266
267
		private static final long serialVersionUID = 7083228933121822248L;
268
269
		final int responseCode;
270
271
		public HttpException(int responseCode) {
272
			super("HTTP Error " + responseCode);
273
274
			this.responseCode = responseCode;
275
		}
276
277
	}
278
279
}

Return to bug 148089