package org.sugr.gearshift.unit.service; import android.app.Activity; import android.content.SharedPreferences; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.util.Base64; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowPreferenceManager; import org.sugr.gearshift.BuildConfig; import org.sugr.gearshift.G; import org.sugr.gearshift.core.Torrent; import org.sugr.gearshift.core.TransmissionProfile; import org.sugr.gearshift.core.TransmissionSession; import org.sugr.gearshift.datasource.DataSource; import org.sugr.gearshift.datasource.TorrentStatus; import org.sugr.gearshift.service.ConnectionProvider; import org.sugr.gearshift.service.TransmissionSessionManager; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.net.URL; import java.nio.charset.Charset; import java.security.cert.Certificate; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSocketFactory; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class) public class TransmissionSessionManagerTest { private ConnectivityManager connMananager; private SharedPreferences defaultPrefs; private TransmissionProfile profile; private DataSource dataSource; private ConnectionProvider connProvider; private HttpsURLConnectionTest connection; private TransmissionSessionManager manager; @Before public void setUp() throws Exception { defaultPrefs = ShadowPreferenceManager.getDefaultSharedPreferences( RuntimeEnvironment.application.getApplicationContext()); connMananager = mock(ConnectivityManager.class); when(connMananager.getActiveNetworkInfo()).thenReturn(mock(NetworkInfo.class)); profile = mock(TransmissionProfile.class); when(profile.getTimeout()).thenReturn(1); when(profile.getId()).thenReturn("existingId"); Activity activity = Robolectric.buildActivity(Activity.class).create().get(); dataSource = new DataSource(activity); dataSource.open(); connProvider = mock(ConnectionProvider.class); connection = new HttpsURLConnectionTest(new URL("http://example.com")); connection.outputStream = new ByteArrayOutputStream(); when(connProvider.open(profile)).thenReturn(connection); manager = new TransmissionSessionManager(connMananager, defaultPrefs, profile, dataSource, connProvider); } @Test public void connectivity() { assertNotNull(manager); when(connMananager.getActiveNetworkInfo()).thenReturn(null); assertFalse(manager.hasConnectivity()); when(connMananager.getActiveNetworkInfo()).thenReturn(mock(NetworkInfo.class)); assertTrue(manager.hasConnectivity()); } @Test public void network() throws Exception { assertNotNull(manager); setupConnection(HttpURLConnection.HTTP_NOT_FOUND, new HashMap<String, String>(), "", null, "404 not found"); try { manager.updateSession(); } catch (TransmissionSessionManager.ManagerException e) { assertEquals(1000, connection.readTimeout); assertEquals(1000, connection.connectTimeout); assertFalse(connection.isConnected); assertEquals(1, connection.connectCount); assertEquals("application/json", connection.requestProperties.get("Content-Type")); assertEquals("gzip, deflate", connection.requestProperties.get("Accept-Encoding")); assertFalse(connection.useCaches); assertFalse(connection.allowUserInteraction); assertEquals("POST", connection.requestMethod); assertTrue(connection.doInput); assertTrue(connection.doOutput); assertFalse(connection.requestProperties.containsKey("X-Transmission-Session-Id")); assertFalse(connection.requestProperties.containsKey("Authorization")); assertEquals("{\"method\":\"session-get\"}", connection.outputStream.toString()); assertEquals(HttpURLConnection.HTTP_NOT_FOUND, e.getCode()); assertEquals("404 not found", e.getMessage()); } Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "text/html"); setupConnection(HttpURLConnection.HTTP_OK, headers, "<h1>Hello World</h1>", null, ""); try { manager.updateSession(); } catch (TransmissionSessionManager.ManagerException e) { assertEquals(HttpURLConnection.HTTP_OK, e.getCode()); assertEquals("no-json", e.getMessage()); } assertEquals(201, HttpURLConnection.HTTP_CREATED); setupConnection(HttpURLConnection.HTTP_CREATED, headers, "<h1>Hello World</h1>", null, ""); try { manager.updateSession(); } catch (TransmissionSessionManager.ManagerException e) { assertEquals(HttpURLConnection.HTTP_CREATED, e.getCode()); assertEquals("no-json", e.getMessage()); } headers = new HashMap<>(); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\", \"arguments\": {}}", null, ""); manager.updateSession(); headers = new HashMap<>(); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"success\"}", null, ""); manager.updateSession(); final List<Boolean> tries = new ArrayList<>(); connection.setConnectTest(new Runnable() { @Override public void run() { Map<String, String> headers = new HashMap<>(); if ("sessid".equals(connection.requestProperties.get("X-Transmission-Session-Id"))) { headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"success\"}", null, ""); tries.add(true); } else { headers.put("X-Transmission-Session-Id", "sessid"); headers.put("Content-Type", "text/html"); setupConnection(HttpURLConnection.HTTP_CONFLICT, headers, "blabla", null, ""); tries.add(false); } } }); manager.updateSession(); assertEquals(2, tries.size()); assertFalse(tries.get(0)); assertTrue(tries.get(1)); headers = new HashMap<>(); connection.setConnectTest(null); setupConnection(HttpURLConnection.HTTP_OK, headers, "error", null, ""); try { manager.updateSession(); } catch (TransmissionSessionManager.ManagerException e) { assertEquals(-4, e.getCode()); } when(connMananager.getActiveNetworkInfo()).thenReturn(null); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"success\"}", null, ""); try { manager.updateSession(); } catch (TransmissionSessionManager.ManagerException e) { assertEquals("connectivity", e.getMessage()); assertEquals(-1, e.getCode()); } when(connMananager.getActiveNetworkInfo()).thenReturn(mock(NetworkInfo.class)); } @Test public void delayedNetwork() throws Exception { connection = new DelayedHttpsURLConnectionTest(new URL("http://example.com")); ((DelayedHttpsURLConnectionTest) connection).setDelay(2); when(connProvider.open(profile)).thenReturn(connection); Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"success\"}", null, ""); boolean timeout = false; try { manager.updateSession(); } catch (TransmissionSessionManager.ManagerException e) { assertEquals("timeout", e.getMessage()); assertEquals(-1, e.getCode()); timeout = true; } assertTrue(timeout); } @Test public void sslNetwork() throws Exception { when(profile.isUseSSL()).thenReturn(true); Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"success\"}", null, ""); manager.updateSession(); assertTrue(connection.socketFactory instanceof SSLSocketFactory); assertTrue(connection.hostnameVerifier instanceof HostnameVerifier); assertTrue(connection.hostnameVerifier.verify(null, null)); when(profile.getUsername()).thenReturn("foo"); when(profile.getPassword()).thenReturn("bar"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"success\"}", null, ""); manager.updateSession(); assertTrue(connection.requestProperties.containsKey("Authorization")); assertEquals("Basic " + Base64.encodeToString(("foo:bar").getBytes(), Base64.DEFAULT), connection.requestProperties.get("Authorization")); } @Test public void session() throws Exception { Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {\"version\": \"2.52\"}, \"result\": \"success\"}", null, ""); manager.updateSession(); TransmissionSession session = dataSource.getSession(profile.getId()); assertNotNull(session); assertEquals("2.52", session.getVersion()); assertNull(session.getDownloadDir()); session.setDownloadDir("/foo/bar"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setSession(session, TransmissionSession.SetterFields.DOWNLOAD_DIR); ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.readTree(connection.outputStream.toString()); assertEquals("session-set", node.path("method").asText()); assertEquals("/foo/bar", node.path("arguments").path("download-dir").asText()); } @Test public void torrents() throws Exception { Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {\"torrents\": [{\"id\": 10, \"name\": \"fedora 1\", \"status\": 0, \"hashString\": \"foo\"}, {\"id\": 21, \"name\": \"ubuntu 7\", \"status\": 6, \"hashString\": \"bar\"}]}, \"result\": \"success\"}", null, ""); TorrentStatus status = manager.getActiveTorrents(new String[] {"id", "name", "status"}); assertNotNull(status); ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-get", node.path("method").asText()); assertEquals("recently-active", node.path("arguments").path("ids").asText()); assertEquals("id", node.path("arguments").path("fields").path(0).asText()); assertEquals("name", node.path("arguments").path("fields").path(1).asText()); assertEquals("status", node.path("arguments").path("fields").path(2).asText()); Cursor cursor = dataSource.getTorrentCursor(profile.getId(), null, new String[0], null, false); assertEquals(2, cursor.getCount()); cursor.close(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {\"torrents\": [{\"id\": 10, \"name\": \"fedora 1\", \"status\": 0, \"hashString\": \"foo\"}, {\"id\": 21, \"name\": \"ubuntu 7\", \"status\": 6, \"hashString\": \"bar\"}, {\"id\": 37, \"name\": \"mint 14\", \"status\": 4, \"hashString\": \"alpha\"}]}, \"result\": \"success\"}", null, ""); status = manager.getTorrents(new String[] {"id", "name", "status"}, null, false); assertNotNull(status); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-get", node.path("method").asText()); assertNull(node.path("arguments").get("ids")); assertEquals("id", node.path("arguments").path("fields").get(0).asText()); assertEquals("name", node.path("arguments").path("fields").path(1).asText()); assertEquals("status", node.path("arguments").path("fields").path(2).asText()); cursor = dataSource.getTorrentCursor(profile.getId(), null, new String[0], null, false); assertEquals(3, cursor.getCount()); cursor.close(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {\"torrents\": [{\"id\": 10, \"name\": \"fedora 1\", \"status\": 0, \"hashString\": \"foo\"}]}, \"result\": \"success\"}", null, ""); status = manager.getTorrents(new String[] {"id", "name", "status"}, new String[] {"foo"}, false); assertNotNull(status); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-get", node.path("method").asText()); assertEquals("foo", node.path("arguments").path("ids").path(0).asText()); assertNull(node.path("arguments").path("ids").get(1)); assertEquals("id", node.path("arguments").path("fields").get(0).asText()); assertEquals("name", node.path("arguments").path("fields").path(1).asText()); assertEquals("status", node.path("arguments").path("fields").path(2).asText()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"success\"}", null, ""); manager.removeTorrent(new String[] {"foo"}, false); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-remove", node.path("method").asText()); assertEquals("foo", node.path("arguments").path("ids").path(0).asText()); assertNull(node.path("arguments").path("ids").get(1)); assertFalse(node.path("arguments").path("delete-local-data").asBoolean()); cursor = dataSource.getTorrentCursor(profile.getId(), null, new String[0], null, false); assertEquals(2, cursor.getCount()); cursor.close(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"error\"}", null, ""); try { manager.removeTorrent(new String[]{"foo"}, false); } catch (TransmissionSessionManager.ManagerException e) { assertEquals("error", e.getMessage()); } mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); cursor = dataSource.getTorrentCursor(profile.getId(), null, new String[0], null, false); assertEquals(2, cursor.getCount()); cursor.close(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {}, \"result\": \"success\"}", null, ""); manager.removeTorrent(new String[] {"bar"}, true); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-remove", node.path("method").asText()); assertEquals("bar", node.path("arguments").path("ids").path(0).asText()); assertNull(node.path("arguments").path("ids").get(1)); assertTrue(node.path("arguments").path("delete-local-data").asBoolean()); cursor = dataSource.getTorrentCursor(profile.getId(), null, new String[0], null, false); assertEquals(1, cursor.getCount()); cursor.moveToFirst(); assertEquals("mint 14", Torrent.getName(cursor)); cursor.close(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {\"torrent-added\": {\"id\": 57, \"hashString\": \"beta\", \"name\": \"slackware 11\"}}, \"result\": \"success\"}", null, ""); String hash = manager.addTorrent("magnet:somemagnet", null, "/foo", false); assertEquals("beta", hash); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-add", node.path("method").asText()); assertEquals("magnet:somemagnet", node.path("arguments").path("filename").asText()); assertNull(node.path("arguments").get("metainfo")); assertEquals("/foo", node.path("arguments").path("download-dir").asText()); assertFalse(node.path("arguments").path("paused").asBoolean()); cursor = dataSource.getTorrentCursor(profile.getId(), null, new String[0], null, false); assertEquals(2, cursor.getCount()); cursor.moveToLast(); assertEquals("slackware 11", Torrent.getName(cursor)); cursor.close(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {\"torrent-duplicate\": {\"id\": 57, \"hashString\": \"beta\", \"name\": \"slackware 11\"}}, \"result\": \"duplicate torrent\"}", null, ""); try { manager.addTorrent("magnet:somemagnet", null, "/foo", false); } catch (TransmissionSessionManager.ManagerException e) { assertEquals("duplicate torrent", e.getMessage()); assertEquals(-2, e.getCode()); } setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"arguments\": {\"torrent-added\": {\"id\": 59, \"hashString\": \"gamma\", \"name\": \"debian 6\"}}, \"result\": \"success\"}", null, ""); hash = manager.addTorrent(null, "torrentfiledata", "/bar", true); assertEquals("gamma", hash); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-add", node.path("method").asText()); assertNull(node.path("arguments").get("filename")); assertEquals("torrentfiledata", node.path("arguments").path("metainfo").asText()); assertEquals("/bar", node.path("arguments").path("download-dir").asText()); assertTrue(node.path("arguments").path("paused").asBoolean()); cursor = dataSource.getTorrentCursor(profile.getId(), null, new String[0], null, false); assertEquals(3, cursor.getCount()); cursor.moveToLast(); assertEquals("debian 6", Torrent.getName(cursor)); cursor.close(); } @Test public void torrentProperties() throws Exception { Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentAction(new String[] {"foo", "bar"}, "torrent-start"); ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-start", node.path("method").asText()); assertEquals("foo", node.path("arguments").path("ids").path(0).asText()); assertEquals("bar", node.path("arguments").path("ids").path(1).asText()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentLocation(new String[]{"foo", "bar"}, "/test/1", true); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set-location", node.path("method").asText()); assertEquals("foo", node.path("arguments").path("ids").path(0).asText()); assertEquals("bar", node.path("arguments").path("ids").path(1).asText()); assertEquals("/test/1", node.path("arguments").path("location").asText()); assertEquals(true, node.path("arguments").path("move").asBoolean()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentLocation(new String[] {"foo"}, "/test/2", false); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set-location", node.path("method").asText()); assertEquals("foo", node.path("arguments").path("ids").path(0).asText()); assertEquals("/test/2", node.path("arguments").path("location").asText()); assertEquals(false, node.path("arguments").path("move").asBoolean()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); boolean thrown = false; try { manager.setTorrentProperty(new String[]{"foo", "bar"}, "test", null); } catch (IllegalArgumentException ignored) { thrown = true; } assertTrue("Setting an invalid torrent property should throw an error", thrown); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); thrown = false; try { manager.setTorrentProperty(new String[]{"foo", "bar"}, Torrent.SetterFields.DOWNLOAD_LIMIT, "cast error"); } catch (ClassCastException ignored) { thrown = true; } assertTrue("Properties expect certain value types", thrown); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo", "bar"}, Torrent.SetterFields.DOWNLOAD_LIMIT, 10l); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals("foo", node.path("arguments").path("ids").path(0).asText()); assertEquals("bar", node.path("arguments").path("ids").path(1).asText()); assertEquals(10l, node.path("arguments").path(Torrent.SetterFields.DOWNLOAD_LIMIT).asLong()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.DOWNLOAD_LIMITED, true); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals("foo", node.path("arguments").path("ids").path(0).asText()); assertEquals(true, node.path("arguments").path(Torrent.SetterFields.DOWNLOAD_LIMITED).asBoolean()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.PEER_LIMIT, 20); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(20, node.path("arguments").path(Torrent.SetterFields.PEER_LIMIT).asInt()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.QUEUE_POSITION, 30); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(30, node.path("arguments").path(Torrent.SetterFields.QUEUE_POSITION).asInt()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.SEED_RATIO_LIMIT, 1.5f); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(1.5, node.path("arguments").path(Torrent.SetterFields.SEED_RATIO_LIMIT).asDouble(), 0); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.SEED_RATIO_MODE, Torrent.SeedRatioMode.NO_LIMIT); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(Torrent.SeedRatioMode.NO_LIMIT, node.path("arguments").path(Torrent.SetterFields.SEED_RATIO_MODE).asInt()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.SESSION_LIMITS, true); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(true, node.path("arguments").path(Torrent.SetterFields.SESSION_LIMITS).asBoolean()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.TORRENT_PRIORITY, 4); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(4, node.path("arguments").path(Torrent.SetterFields.TORRENT_PRIORITY).asInt()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.UPLOAD_LIMIT, 40l); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(40l, node.path("arguments").path(Torrent.SetterFields.UPLOAD_LIMIT).asLong()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.UPLOAD_LIMITED, true); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(true, node.path("arguments").path(Torrent.SetterFields.UPLOAD_LIMITED).asBoolean()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.FILES_WANTED, 1); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(1, node.path("arguments").path(Torrent.SetterFields.FILES_WANTED).path(0).asInt()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.FILES_WANTED, new Integer[] {2, 3}); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(2, node.path("arguments").path(Torrent.SetterFields.FILES_WANTED).path(0).asInt()); assertEquals(3, node.path("arguments").path(Torrent.SetterFields.FILES_WANTED).path(1).asInt()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.FILES_UNWANTED, 4); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(4, node.path("arguments").path(Torrent.SetterFields.FILES_UNWANTED).path(0).asInt()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.FILES_UNWANTED, new Integer[] {5, 6}); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(5, node.path("arguments").path(Torrent.SetterFields.FILES_UNWANTED).path(0).asInt()); assertEquals(6, node.path("arguments").path(Torrent.SetterFields.FILES_UNWANTED).path(1).asInt()); ArrayList<Integer> list = new ArrayList<>(); list.add(1); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.FILES_LOW, list); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(1, node.path("arguments").path(Torrent.SetterFields.FILES_LOW).path(0).asInt()); list.clear(); list.add(2); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.FILES_NORMAL, list); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(2, node.path("arguments").path(Torrent.SetterFields.FILES_NORMAL).path(0).asInt()); list.clear(); list.add(3); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.FILES_HIGH, list); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(3, node.path("arguments").path(Torrent.SetterFields.FILES_HIGH).path(0).asInt()); assertEquals(1, node.path("arguments").path(Torrent.SetterFields.FILES_HIGH).size()); list.clear(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.TRACKER_ADD, "test"); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals("test", node.path("arguments").path(Torrent.SetterFields.TRACKER_ADD).asText()); list.add(5); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.TRACKER_REMOVE, list); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(5, node.path("arguments").path(Torrent.SetterFields.TRACKER_REMOVE).path(0).asInt()); assertEquals(1, node.path("arguments").path(Torrent.SetterFields.TRACKER_REMOVE).size()); ArrayList<String> tuple = new ArrayList<>(); tuple.add("1"); tuple.add("bar"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\"}", null, ""); manager.setTorrentProperty(new String[]{"foo"}, Torrent.SetterFields.TRACKER_REPLACE, tuple); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("torrent-set", node.path("method").asText()); assertEquals(1, node.path("arguments").path(Torrent.SetterFields.TRACKER_REPLACE).path(0).asInt()); assertEquals("bar", node.path("arguments").path(Torrent.SetterFields.TRACKER_REPLACE).path(1).asText()); assertEquals(2, node.path("arguments").path(Torrent.SetterFields.TRACKER_REPLACE).size()); } @Test public void misc() throws Exception { Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\", \"arguments\": {\"port-is-open\": true}}", null, ""); boolean isPortOpen = manager.testPort(); assertTrue(isPortOpen); ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.readTree(connection.outputStream.toString()); assertEquals("port-test", node.path("method").asText()); assertNull(node.get("arguments")); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\", \"arguments\": {\"blocklist-size\": 1234567890}}", null, ""); long blocklistSize = manager.updateBlocklist(); assertEquals(1234567890l, blocklistSize); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("blocklist-update", node.path("method").asText()); assertNull(node.get("arguments")); defaultPrefs.edit().putString(G.PREF_LIST_DIRECTORY, "/test").commit(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\", \"arguments\": {\"path\": \"/test\", \"size-bytes\": 123123123}}", null, ""); long freeSpace = manager.getFreeSpace(null); assertEquals(123123123l, freeSpace); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("free-space", node.path("method").asText()); assertEquals("/test", node.path("arguments").path("path").asText()); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\", \"arguments\": {\"path\": \"/test\", \"size-bytes\": 123123123}}", null, ""); freeSpace = manager.getFreeSpace("/default/path"); assertEquals(123123123l, freeSpace); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("free-space", node.path("method").asText()); assertEquals("/test", node.path("arguments").path("path").asText()); defaultPrefs.edit().putString(G.PREF_LIST_DIRECTORY, null).commit(); setupConnection(HttpURLConnection.HTTP_OK, headers, "{\"result\": \"success\", \"arguments\": {\"path\": \"/test2\", \"size-bytes\": 123123123123}}", null, ""); freeSpace = manager.getFreeSpace("/test2"); assertEquals(123123123123l, freeSpace); mapper = new ObjectMapper(); node = mapper.readTree(connection.outputStream.toString()); assertEquals("free-space", node.path("method").asText()); assertEquals("/test2", node.path("arguments").path("path").asText()); } private void setupConnection(int responseCode, Map<String, String> headerFields, String response, String contentEncoding, String responseMessage) { connection.responseCode = responseCode; connection.contentEncoding = contentEncoding; connection.responseMessage = responseMessage; InputStream is = new ByteArrayInputStream(Charset.forName("UTF-16").encode(response).array()); connection.inputStream = is; if (headerFields != null) { connection.headerFields.putAll(headerFields); } connection.outputStream = new ByteArrayOutputStream(); } private static class HttpsURLConnectionTest extends HttpsURLConnection { public int connectCount = 0; public boolean isConnected; public int readTimeout; public int connectTimeout; public Map<String, String> requestProperties = new HashMap<>(); public boolean useCaches; public boolean allowUserInteraction; public String requestMethod = "GET"; public boolean doInput; public boolean doOutput; public SSLSocketFactory socketFactory; public HostnameVerifier hostnameVerifier; public OutputStream outputStream; public InputStream inputStream; public int responseCode; public Map<String, String> headerFields = new HashMap<>(); public String contentEncoding; public String responseMessage; public Runnable connectRunnable; public HttpsURLConnectionTest(URL url) { super(url); } public void setConnectTest(Runnable connectTest) { this.connectRunnable = connectTest; } @Override public String getCipherSuite() { return null; } @Override public Certificate[] getLocalCertificates() { return new Certificate[0]; } @Override public Certificate[] getServerCertificates() throws SSLPeerUnverifiedException { return new Certificate[0]; } @Override public void disconnect() { isConnected = false; } @Override public boolean usingProxy() { return false; } @Override public void connect() throws IOException { if (connectRunnable != null) { connectRunnable.run(); } isConnected = true; connectCount++; } @Override public void setReadTimeout(int timeout) { readTimeout = timeout; } @Override public void setConnectTimeout(int connectTimeout) { this.connectTimeout = connectTimeout; } @Override public void setRequestProperty(String key, String value) { requestProperties.put(key, value); } @Override public void setUseCaches(boolean useCaches) { this.useCaches = useCaches; } @Override public void setAllowUserInteraction(boolean allowUserInteraction) { this.allowUserInteraction = allowUserInteraction; } @Override public void setRequestMethod(String requestMethod) { this.requestMethod = requestMethod; } @Override public void setDoInput(boolean doInput) { this.doInput = doInput; } @Override public void setDoOutput(boolean doOutput) { this.doOutput = doOutput; } @Override public void setSSLSocketFactory(SSLSocketFactory sf) { socketFactory = sf; } @Override public void setHostnameVerifier(HostnameVerifier hv) { hostnameVerifier = hv; } @Override public OutputStream getOutputStream() { return outputStream; } @Override public int getResponseCode() { return responseCode; } @Override public InputStream getInputStream() { return inputStream; } @Override public String getHeaderField(String key) { return headerFields.get(key); } @Override public String getContentEncoding() { return contentEncoding; } @Override public String getResponseMessage() { return responseMessage; } } private static class DelayedHttpsURLConnectionTest extends HttpsURLConnectionTest { private int delay; public DelayedHttpsURLConnectionTest(URL url) { super(url); } public void setDelay(int delay) { this.delay = delay; } @Override public void connect() throws IOException { if (delay * 1000 > connectTimeout) { throw new SocketTimeoutException(); } super.connect(); } } }