[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#861668: unblock pre-approval: python-jenkins/0.4.11-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock


Dear release team,

Antoine Musso reported #861656, and claims it is RC. To adress it, he
suggested upgrading to upstream release 0.4.12. I checked the diff,
which I attached to this mail. If removing the tests, then the change
are very small. I have therefore attached 2 diff: one with only the
change to the library code, and one diff containing all the changes
between 0.4.11 and 0.4.12.

At this point, would the release team accept an upgrade to upstream
version 0.4.12? Do you agree than #861656 should be considered RC?

Cheers,

Thomas Goirand (zigo)
diff --git a/.gitreview b/.gitreview
index fbfb964..1630945 100644
--- a/.gitreview
+++ b/.gitreview
@@ -1,4 +1,4 @@
 [gerrit]
 host=review.openstack.org
 port=29418
-project=stackforge/python-jenkins.git
+project=openstack/python-jenkins.git
diff --git a/README.rst b/README.rst
index 6a37401..f87ff22 100644
--- a/README.rst
+++ b/README.rst
@@ -44,11 +44,11 @@ Bug report:
 
 Repository:
 
-* https://git.openstack.org/cgit/stackforge/python-jenkins
+* https://git.openstack.org/cgit/openstack/python-jenkins
 
 Cloning:
 
-* git clone https://git.openstack.org/stackforge/python-jenkins
+* git clone https://git.openstack.org/openstack/python-jenkins
 
 Patches are submitted via Gerrit at:
 
diff --git a/doc/source/examples.rst b/doc/source/examples.rst
index d20dbb8..812343e 100644
--- a/doc/source/examples.rst
+++ b/doc/source/examples.rst
@@ -104,6 +104,21 @@ This is an example showing how to add, configure, enable and delete Jenkins node
     server.disable_node('slave1')
     server.enable_node('slave1')
 
+    # create node with parameters
+    params = {
+        'port': '22',
+        'username': 'juser',
+        'credentialsId': '10f3a3c8-be35-327e-b60b-a3e5edb0e45f',
+        'host': 'my.jenkins.slave1'
+    }
+    server.create_node(
+        'slave1',
+        nodeDescription='my test slave',
+        remoteFS='/home/juser',
+        labels='precise',
+        exclusive=True,
+        launcher=jenkins.LAUNCHER_SSH,
+        launcher_params=params)
 
 Example 6: Working with Jenkins Build Queue
 -------------------------------------------
diff --git a/jenkins/__init__.py b/jenkins/__init__.py
index 65f8b6a..34cae71 100644
--- a/jenkins/__init__.py
+++ b/jenkins/__init__.py
@@ -240,7 +240,10 @@ class Jenkins(object):
     def _build_url(self, format_spec, variables=None):
 
         if variables:
-            url_path = format_spec % self._get_encoded_params(variables)
+            if format_spec == CREATE_NODE:
+                url_path = format_spec % urlencode(self._get_encoded_params(variables))
+            else:
+                url_path = format_spec % self._get_encoded_params(variables)
         else:
             url_path = format_spec
 
@@ -453,7 +456,7 @@ class Jenkins(object):
             u'name': u'my_job'}
 
         """
-        url = "/".join((item, INFO))
+        url = '/'.join((item, INFO)).lstrip('/')
         if query:
             url += query
         try:
diff --git a/setup.cfg b/setup.cfg
index 7abf945..0294a71 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -7,7 +7,7 @@ maintainer = OpenStack Infrastructure Team
 maintainer_email = openstack@lists.launchpad.net
 description-file = README.rst
 license = BSD
-home-page = http://git.openstack.org/cgit/stackforge/python-jenkins
+home-page = http://git.openstack.org/cgit/openstack/python-jenkins
 classifier =
     Topic :: Utilities
     Intended Audience :: Developers
diff --git a/tests/base.py b/tests/base.py
index b5583ca..86a8180 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -1,6 +1,7 @@
 import sys
 
 from six.moves.urllib.request import build_opener
+from testscenarios import TestWithScenarios
 
 import jenkins
 
@@ -10,18 +11,26 @@ else:
     import unittest
 
 
-class JenkinsTestBase(unittest.TestCase):
+class JenkinsTestBase(TestWithScenarios, unittest.TestCase):
 
     crumb_data = {
         "crumb": "dab177f483b3dd93483ef6716d8e792d",
         "crumbRequestField": ".crumb",
     }
 
+    scenarios = [
+        ('base_url1', dict(base_url='http://example.com')),
+        ('base_url2', dict(base_url='http://example.com/jenkins'))
+    ]
+
     def setUp(self):
         super(JenkinsTestBase, self).setUp()
         self.opener = build_opener()
 
-        self.j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        self.j = jenkins.Jenkins(self.base_url, 'test', 'test')
+
+    def make_url(self, path):
+        return u'{0}/{1}'.format(self.base_url, path)
 
     def _check_requests(self, requests):
 
diff --git a/tests/jobs/test_build.py b/tests/jobs/test_build.py
index 83eb664..b437fd7 100644
--- a/tests/jobs/test_build.py
+++ b/tests/jobs/test_build.py
@@ -15,7 +15,7 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
         build_info = self.j.build_job(u'Test Job')
 
         self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(),
-                         u'http://example.com/job/Test%20Job/build')
+                         self.make_url('job/Test%20Job/build'))
         self.assertEqual(build_info, {'foo': 'bar'})
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -28,7 +28,7 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
         build_info = self.j.build_job(u'a Folder/Test Job')
 
         self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(),
-                         u'http://example.com/job/a%20Folder/job/Test%20Job/build')
+                         self.make_url('job/a%20Folder/job/Test%20Job/build'))
         self.assertEqual(build_info, {'foo': 'bar'})
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -41,7 +41,7 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
         build_info = self.j.build_job(u'TestJob', token='some_token')
 
         self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(),
-                         u'http://example.com/job/TestJob/build?token=some_token')
+                         self.make_url('job/TestJob/build?token=some_token'))
         self.assertEqual(build_info, {'foo': 'bar'})
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -54,7 +54,7 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
         build_info = self.j.build_job(u'a Folder/TestJob', token='some_token')
 
         self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(),
-                         u'http://example.com/job/a%20Folder/job/TestJob/build?token=some_token')
+                         self.make_url('job/a%20Folder/job/TestJob/build?token=some_token'))
         self.assertEqual(build_info, {'foo': 'bar'})
         self._check_requests(jenkins_mock.call_args_list)
 
diff --git a/tests/jobs/test_config.py b/tests/jobs/test_config.py
index f880de7..692d6b6 100644
--- a/tests/jobs/test_config.py
+++ b/tests/jobs/test_config.py
@@ -12,7 +12,7 @@ class JenkinsGetJobConfigTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/Test%20Job/config.xml')
+            self.make_url('job/Test%20Job/config.xml'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -21,5 +21,5 @@ class JenkinsGetJobConfigTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20folder/job/Test%20Job/config.xml')
+            self.make_url('job/a%20folder/job/Test%20Job/config.xml'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/jobs/test_copy.py b/tests/jobs/test_copy.py
index bded76e..766339e 100644
--- a/tests/jobs/test_copy.py
+++ b/tests/jobs/test_copy.py
@@ -19,8 +19,7 @@ class JenkinsCopyJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/createItem'
-            '?name=Test%20Job_2&mode=copy&from=Test%20Job')
+            self.make_url('createItem?name=Test%20Job_2&mode=copy&from=Test%20Job'))
         self.assertTrue(self.j.job_exists('Test Job_2'))
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -36,8 +35,8 @@ class JenkinsCopyJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/createItem'
-            '?name=Test%20Job_2&mode=copy&from=Test%20Job')
+            self.make_url('job/a%20Folder/createItem?name=Test%20Job_2'
+                          '&mode=copy&from=Test%20Job'))
         self.assertTrue(self.j.job_exists('a Folder/Test Job_2'))
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -52,8 +51,7 @@ class JenkinsCopyJobTest(JenkinsJobsTestBase):
             self.j.copy_job(u'TestJob', u'TestJob_2')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/createItem'
-            '?name=TestJob_2&mode=copy&from=TestJob')
+            self.make_url('createItem?name=TestJob_2&mode=copy&from=TestJob'))
         self.assertEqual(
             str(context_manager.exception),
             'create[TestJob_2] failed')
@@ -70,8 +68,8 @@ class JenkinsCopyJobTest(JenkinsJobsTestBase):
             self.j.copy_job(u'a Folder/TestJob', u'a Folder/TestJob_2')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/createItem'
-            '?name=TestJob_2&mode=copy&from=TestJob')
+            self.make_url('job/a%20Folder/createItem?name=TestJob_2&mode=copy'
+                          '&from=TestJob'))
         self.assertEqual(
             str(context_manager.exception),
             'create[a Folder/TestJob_2] failed')
diff --git a/tests/jobs/test_create.py b/tests/jobs/test_create.py
index 828df51..ea8c2e4 100644
--- a/tests/jobs/test_create.py
+++ b/tests/jobs/test_create.py
@@ -19,7 +19,7 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            'http://example.com/createItem?name=Test%20Job')
+            self.make_url('createItem?name=Test%20Job'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -34,7 +34,7 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/createItem?name=Test%20Job')
+            self.make_url('job/a%20Folder/createItem?name=Test%20Job'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -48,7 +48,7 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
             self.j.create_job(u'TestJob', self.config_xml)
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/TestJob/api/json?tree=name')
+            self.make_url('job/TestJob/api/json?tree=name'))
         self.assertEqual(
             str(context_manager.exception),
             'job[TestJob] already exists')
@@ -65,7 +65,7 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
             self.j.create_job(u'a Folder/TestJob', self.config_xml)
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/TestJob/api/json?tree=name')
+            self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name'))
         self.assertEqual(
             str(context_manager.exception),
             'job[a Folder/TestJob] already exists')
@@ -83,10 +83,10 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
             self.j.create_job(u'TestJob', self.config_xml)
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/TestJob/api/json?tree=name')
+            self.make_url('job/TestJob/api/json?tree=name'))
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            'http://example.com/createItem?name=TestJob')
+            self.make_url('createItem?name=TestJob'))
         self.assertEqual(
             str(context_manager.exception),
             'create[TestJob] failed')
@@ -104,10 +104,10 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
             self.j.create_job(u'a Folder/TestJob', self.config_xml)
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/TestJob/api/json?tree=name')
+            self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name'))
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/createItem?name=TestJob')
+            self.make_url('job/a%20Folder/createItem?name=TestJob'))
         self.assertEqual(
             str(context_manager.exception),
             'create[a Folder/TestJob] failed')
diff --git a/tests/jobs/test_debug.py b/tests/jobs/test_debug.py
index ac54773..397c38b 100644
--- a/tests/jobs/test_debug.py
+++ b/tests/jobs/test_debug.py
@@ -21,7 +21,7 @@ class JenkinsDebugJobInfoTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/Test%20Job/api/json?depth=0')
+            self.make_url('job/Test%20Job/api/json?depth=0'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -38,5 +38,5 @@ class JenkinsDebugJobInfoTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/Test%20Job/api/json?depth=0')
+            self.make_url('job/a%20Folder/job/Test%20Job/api/json?depth=0'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/jobs/test_delete.py b/tests/jobs/test_delete.py
index e168e14..a8a2421 100644
--- a/tests/jobs/test_delete.py
+++ b/tests/jobs/test_delete.py
@@ -18,7 +18,7 @@ class JenkinsDeleteJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/Test%20Job/doDelete')
+            self.make_url('job/Test%20Job/doDelete'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -32,7 +32,7 @@ class JenkinsDeleteJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/Test%20Job/doDelete')
+            self.make_url('job/a%20Folder/job/Test%20Job/doDelete'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -47,7 +47,7 @@ class JenkinsDeleteJobTest(JenkinsJobsTestBase):
             self.j.delete_job(u'TestJob')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/TestJob/doDelete')
+            self.make_url('job/TestJob/doDelete'))
         self.assertEqual(
             str(context_manager.exception),
             'delete[TestJob] failed')
@@ -65,7 +65,7 @@ class JenkinsDeleteJobTest(JenkinsJobsTestBase):
             self.j.delete_job(u'a Folder/TestJob')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/TestJob/doDelete')
+            self.make_url('job/a%20Folder/job/TestJob/doDelete'))
         self.assertEqual(
             str(context_manager.exception),
             'delete[a Folder/TestJob] failed')
diff --git a/tests/jobs/test_disable.py b/tests/jobs/test_disable.py
index 8e1fb7d..c309d39 100644
--- a/tests/jobs/test_disable.py
+++ b/tests/jobs/test_disable.py
@@ -18,7 +18,7 @@ class JenkinsDisableJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/Test%20Job/disable')
+            self.make_url('job/Test%20Job/disable'))
         self.assertTrue(self.j.job_exists('Test Job'))
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -33,6 +33,6 @@ class JenkinsDisableJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/Test%20Job/disable')
+            self.make_url('job/a%20Folder/job/Test%20Job/disable'))
         self.assertTrue(self.j.job_exists('a Folder/Test Job'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/jobs/test_enable.py b/tests/jobs/test_enable.py
index e6354c9..b04b3cb 100644
--- a/tests/jobs/test_enable.py
+++ b/tests/jobs/test_enable.py
@@ -18,7 +18,7 @@ class JenkinsEnableJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/TestJob/enable')
+            self.make_url('job/TestJob/enable'))
         self.assertTrue(self.j.job_exists('TestJob'))
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -33,6 +33,6 @@ class JenkinsEnableJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/TestJob/enable')
+            self.make_url('job/a%20Folder/job/TestJob/enable'))
         self.assertTrue(self.j.job_exists('a Folder/TestJob'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/jobs/test_get.py b/tests/jobs/test_get.py
index d93f2d5..c6ba22b 100644
--- a/tests/jobs/test_get.py
+++ b/tests/jobs/test_get.py
@@ -24,13 +24,13 @@ class JenkinsGetJobsTest(JenkinsGetJobsTestBase):
         self.assertEqual(job_info, [jobs])
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/api/json?tree=jobs[url,color,name,jobs]')
+            self.make_url('api/json?tree=jobs[url,color,name,jobs]'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_folders_simple(self, jenkins_mock):
         response = build_jobs_list_responses(
-            self.jobs_in_folder, 'http://example.com/')
+            self.jobs_in_folder, self.make_url(''))
         jenkins_mock.side_effect = iter(response)
 
         jobs_info = self.j.get_jobs()
@@ -45,7 +45,7 @@ class JenkinsGetJobsTest(JenkinsGetJobsTestBase):
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_folders_additional_level(self, jenkins_mock):
         response = build_jobs_list_responses(
-            self.jobs_in_folder, 'http://example.com/')
+            self.jobs_in_folder, self.make_url(''))
         jenkins_mock.side_effect = iter(response)
 
         jobs_info = self.j.get_jobs(folder_depth=1)
diff --git a/tests/jobs/test_info.py b/tests/jobs/test_info.py
index 923974e..180ac07 100644
--- a/tests/jobs/test_info.py
+++ b/tests/jobs/test_info.py
@@ -22,7 +22,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
         self.assertEqual(job_info, job_info_to_return)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/Test%20Job/api/json?depth=0')
+            self.make_url('job/Test%20Job/api/json?depth=0'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -40,7 +40,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
         self.assertEqual(job_info, job_info_to_return)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/Test%20Job/api/json?depth=0')
+            self.make_url('job/a%20Folder/job/Test%20Job/api/json?depth=0'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -71,7 +71,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
             self.j.get_job_info(u'TestJob')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/TestJob/api/json?depth=0')
+            self.make_url('job/TestJob/api/json?depth=0'))
         self.assertEqual(
             str(context_manager.exception),
             'job[TestJob] does not exist')
@@ -85,7 +85,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
             self.j.get_job_info(u'TestJob')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/TestJob/api/json?depth=0')
+            self.make_url('job/TestJob/api/json?depth=0'))
         self.assertEqual(
             str(context_manager.exception),
             'Could not parse JSON info for job[TestJob]')
@@ -94,7 +94,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob/api/json?depth=0',
+            self.make_url('job/TestJob/api/json?depth=0'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -104,7 +104,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
             self.j.get_job_info(u'TestJob')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/TestJob/api/json?depth=0')
+            self.make_url('job/TestJob/api/json?depth=0'))
         self.assertEqual(
             str(context_manager.exception),
             'job[TestJob] does not exist')
@@ -113,7 +113,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_in_folder_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/a%20Folder/job/TestJob/api/json?depth=0',
+            self.make_url('job/a%20Folder/job/TestJob/api/json?depth=0'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -123,7 +123,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
             self.j.get_job_info(u'a Folder/TestJob')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/TestJob/api/json?depth=0')
+            self.make_url('job/a%20Folder/job/TestJob/api/json?depth=0'))
         self.assertEqual(
             str(context_manager.exception),
             'job[a Folder/TestJob] does not exist')
diff --git a/tests/jobs/test_name.py b/tests/jobs/test_name.py
index 47d44ce..39f5263 100644
--- a/tests/jobs/test_name.py
+++ b/tests/jobs/test_name.py
@@ -17,7 +17,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
         self.assertEqual(job_name, 'Test Job')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/Test%20Job/api/json?tree=name')
+            self.make_url('job/Test%20Job/api/json?tree=name'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -30,7 +30,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
         self.assertEqual(job_name, 'Test Job')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/Test%20Job/api/json?tree=name')
+            self.make_url('job/a%20Folder/job/Test%20Job/api/json?tree=name'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -42,7 +42,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
         self.assertEqual(job_name, None)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/TestJob/api/json?tree=name')
+            self.make_url('job/TestJob/api/json?tree=name'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -54,7 +54,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
         self.assertEqual(job_name, None)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/TestJob/api/json?tree=name')
+            self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -66,7 +66,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
             self.j.get_job_name(u'TestJob')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/TestJob/api/json?tree=name')
+            self.make_url('job/TestJob/api/json?tree=name'))
         self.assertEqual(
             str(context_manager.exception),
             'Jenkins returned an unexpected job name {0} '
@@ -82,7 +82,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
             self.j.get_job_name(u'a Folder/TestJob')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/TestJob/api/json?tree=name')
+            self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name'))
         self.assertEqual(
             str(context_manager.exception),
             'Jenkins returned an unexpected job name {0} (expected: '
diff --git a/tests/jobs/test_reconfig.py b/tests/jobs/test_reconfig.py
index 007be15..1bef54f 100644
--- a/tests/jobs/test_reconfig.py
+++ b/tests/jobs/test_reconfig.py
@@ -17,7 +17,7 @@ class JenkinsReconfigJobTest(JenkinsJobsTestBase):
         self.j.reconfig_job(u'Test Job', self.config_xml)
 
         self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(),
-                         u'http://example.com/job/Test%20Job/config.xml')
+                         self.make_url('job/Test%20Job/config.xml'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -30,5 +30,5 @@ class JenkinsReconfigJobTest(JenkinsJobsTestBase):
         self.j.reconfig_job(u'a Folder/Test Job', self.config_xml)
 
         self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(),
-                         u'http://example.com/job/a%20Folder/job/Test%20Job/config.xml')
+                         self.make_url('job/a%20Folder/job/Test%20Job/config.xml'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/jobs/test_rename.py b/tests/jobs/test_rename.py
index 24f2e44..15ac9ae 100644
--- a/tests/jobs/test_rename.py
+++ b/tests/jobs/test_rename.py
@@ -19,7 +19,7 @@ class JenkinsRenameJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/Test%20Job/doRename?newName=Test%20Job_2')
+            self.make_url('job/Test%20Job/doRename?newName=Test%20Job_2'))
         self.assertTrue(self.j.job_exists('Test Job_2'))
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -35,7 +35,7 @@ class JenkinsRenameJobTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/Test%20Job/doRename?newName=Test%20Job_2')
+            self.make_url('job/a%20Folder/job/Test%20Job/doRename?newName=Test%20Job_2'))
         self.assertTrue(self.j.job_exists('Test Job_2'))
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -50,7 +50,7 @@ class JenkinsRenameJobTest(JenkinsJobsTestBase):
             self.j.rename_job(u'TestJob', u'TestJob_2')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/TestJob/doRename?newName=TestJob_2')
+            self.make_url('job/TestJob/doRename?newName=TestJob_2'))
         self.assertEqual(
             str(context_manager.exception),
             'rename[TestJob_2] failed')
@@ -67,7 +67,7 @@ class JenkinsRenameJobTest(JenkinsJobsTestBase):
             self.j.rename_job(u'a Folder/TestJob', u'a Folder/TestJob_2')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/job/a%20Folder/job/TestJob/doRename?newName=TestJob_2')
+            self.make_url('job/a%20Folder/job/TestJob/doRename?newName=TestJob_2'))
         self.assertEqual(
             str(context_manager.exception),
             'rename[a Folder/TestJob_2] failed')
diff --git a/tests/jobs/test_set_next_build_number.py b/tests/jobs/test_set_next_build_number.py
index 94e176e..c87ff86 100644
--- a/tests/jobs/test_set_next_build_number.py
+++ b/tests/jobs/test_set_next_build_number.py
@@ -12,7 +12,7 @@ class JenkinsSetNextBuildNumberTest(JenkinsJobsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/TestJob/nextbuildnumber/submit')
+            self.make_url('job/TestJob/nextbuildnumber/submit'))
         self.assertEqual(
             jenkins_mock.call_args[0][0].data,
             b'nextBuildNumber=1234')
diff --git a/tests/test_build.py b/tests/test_build.py
index 9320560..c5ce49f 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -16,7 +16,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
         self.assertEqual(build_info, jenkins_mock.return_value)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/Test%20Job/52/consoleText')
+            self.make_url('job/Test%20Job/52/consoleText'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -28,7 +28,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
         self.assertEqual(build_info, jenkins_mock.return_value)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/Test%20Job/52/consoleText')
+            self.make_url('job/a%20Folder/job/Test%20Job/52/consoleText'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -64,7 +64,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob/52/consoleText',
+            self.make_url('job/TestJob/52/consoleText'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -74,7 +74,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
             self.j.get_build_console_output(u'TestJob', number=52)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/TestJob/52/consoleText')
+            self.make_url('job/TestJob/52/consoleText'))
         self.assertEqual(
             str(context_manager.exception),
             'job[TestJob] number[52] does not exist')
@@ -83,7 +83,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_in_folder_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/a%20Folder/job/TestJob/52/consoleText',
+            self.make_url('job/a%20Folder/job/TestJob/52/consoleText'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -93,7 +93,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
             self.j.get_build_console_output(u'a Folder/TestJob', number=52)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/TestJob/52/consoleText')
+            self.make_url('job/a%20Folder/job/TestJob/52/consoleText'))
         self.assertEqual(
             str(context_manager.exception),
             'job[a Folder/TestJob] number[52] does not exist')
@@ -117,7 +117,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase):
         self.assertEqual(build_info, build_info_to_return)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/Test%20Job/52/api/json?depth=0')
+            self.make_url('job/Test%20Job/52/api/json?depth=0'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -135,7 +135,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase):
         self.assertEqual(build_info, build_info_to_return)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/Test%20Job/52/api/json?depth=0')
+            self.make_url('job/a%20Folder/job/Test%20Job/52/api/json?depth=0'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -163,7 +163,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase):
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob/api/json?depth=0',
+            self.make_url('job/TestJob/api/json?depth=0'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -179,7 +179,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase):
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_in_folder_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/a%20Folder/job/TestJob/api/json?depth=0',
+            self.make_url('job/a%20Folder/job/TestJob/api/json?depth=0'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -201,7 +201,7 @@ class JenkinsStopBuildTest(JenkinsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/Test%20Job/52/stop')
+            self.make_url('job/Test%20Job/52/stop'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -211,7 +211,7 @@ class JenkinsStopBuildTest(JenkinsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/job/a%20Folder/job/Test%20Job/52/stop')
+            self.make_url('job/a%20Folder/job/Test%20Job/52/stop'))
         self._check_requests(jenkins_mock.call_args_list)
 
 
diff --git a/tests/test_info.py b/tests/test_info.py
index b519be9..5bab926 100644
--- a/tests/test_info.py
+++ b/tests/test_info.py
@@ -23,13 +23,13 @@ class JenkinsInfoTest(JenkinsTestBase):
         self.assertEqual(job_info, job_info_to_return)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/api/json')
+            self.make_url('api/json'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob/api/json?depth=0',
+            self.make_url('job/TestJob/api/json?depth=0'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -39,10 +39,10 @@ class JenkinsInfoTest(JenkinsTestBase):
             self.j.get_info()
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/api/json')
+            self.make_url('api/json'))
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -53,10 +53,10 @@ class JenkinsInfoTest(JenkinsTestBase):
             self.j.get_info()
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/api/json')
+            self.make_url('api/json'))
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -67,25 +67,25 @@ class JenkinsInfoTest(JenkinsTestBase):
             self.j.get_info()
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/api/json')
+            self.make_url('api/json'))
         self.assertEqual(
             str(context_manager.exception),
-            'Could not parse JSON info for server[http://example.com/]')
+            'Could not parse JSON info for server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_return_empty_response(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.JenkinsException(
-            "Error communicating with server[http://example.com/]: "
-            "empty response")
+            "Error communicating with server[{0}/]: empty response".
+            format(self.base_url))
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
             self.j.get_info()
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/api/json')
+            self.make_url('api/json'))
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]: '
-            'empty response')
+            'Error communicating with server[{0}/]: '
+            'empty response'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/test_jenkins.py b/tests/test_jenkins.py
index 5d3de72..154f99b 100644
--- a/tests/test_jenkins.py
+++ b/tests/test_jenkins.py
@@ -18,27 +18,27 @@ def get_mock_urlopen_return_value(a_dict=None):
 class JenkinsConstructorTest(JenkinsTestBase):
 
     def test_url_with_trailing_slash(self):
-        self.assertEqual(self.j.server, 'http://example.com/')
+        self.assertEqual(self.j.server, self.make_url(''))
         self.assertEqual(self.j.auth, b'Basic dGVzdDp0ZXN0')
         self.assertEqual(self.j.crumb, None)
 
     def test_url_without_trailing_slash(self):
-        j = jenkins.Jenkins('http://example.com', 'test', 'test')
-        self.assertEqual(j.server, 'http://example.com/')
+        j = jenkins.Jenkins(self.base_url, 'test', 'test')
+        self.assertEqual(j.server, self.make_url(''))
         self.assertEqual(j.auth, b'Basic dGVzdDp0ZXN0')
         self.assertEqual(j.crumb, None)
 
     def test_without_user_or_password(self):
-        j = jenkins.Jenkins('http://example.com')
-        self.assertEqual(j.server, 'http://example.com/')
+        j = jenkins.Jenkins('{0}'.format(self.base_url))
+        self.assertEqual(j.server, self.make_url(''))
         self.assertEqual(j.auth, None)
         self.assertEqual(j.crumb, None)
 
     def test_unicode_password(self):
-        j = jenkins.Jenkins('http://example.com',
+        j = jenkins.Jenkins('{0}'.format(self.base_url),
                             six.u('nonascii'),
                             six.u('\xe9\u20ac'))
-        self.assertEqual(j.server, 'http://example.com/')
+        self.assertEqual(j.server, self.make_url(''))
         self.assertEqual(j.auth, b'Basic bm9uYXNjaWk6w6nigqw=')
         self.assertEqual(j.crumb, None)
 
@@ -46,18 +46,18 @@ class JenkinsConstructorTest(JenkinsTestBase):
         long_str = 'a' * 60
         long_str_b64 = 'YWFh' * 20
 
-        j = jenkins.Jenkins('http://example.com', long_str, long_str)
+        j = jenkins.Jenkins('{0}'.format(self.base_url), long_str, long_str)
 
         self.assertNotIn(b"\n", j.auth)
         self.assertEqual(j.auth.decode('utf-8'), 'Basic %s' % (
             long_str_b64 + 'Om' + long_str_b64[2:] + 'YQ=='))
 
     def test_default_timeout(self):
-        j = jenkins.Jenkins('http://example.com')
+        j = jenkins.Jenkins('{0}'.format(self.base_url))
         self.assertEqual(j.timeout, socket._GLOBAL_DEFAULT_TIMEOUT)
 
     def test_custom_timeout(self):
-        j = jenkins.Jenkins('http://example.com', timeout=300)
+        j = jenkins.Jenkins('{0}'.format(self.base_url), timeout=300)
         self.assertEqual(j.timeout, 300)
 
 
@@ -66,13 +66,13 @@ class JenkinsMaybeAddCrumbTest(JenkinsTestBase):
     @patch('jenkins.urlopen')
     def test_simple(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.NotFoundException()
-        request = jenkins.Request('http://example.com/job/TestJob')
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         self.j.maybe_add_crumb(request)
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/crumbIssuer/api/json')
+            self.make_url('crumbIssuer/api/json'))
         self.assertFalse(self.j.crumb)
         self.assertFalse('.crumb' in request.headers)
         self._check_requests(jenkins_mock.call_args_list)
@@ -80,13 +80,13 @@ class JenkinsMaybeAddCrumbTest(JenkinsTestBase):
     @patch('jenkins.urlopen')
     def test_with_data(self, jenkins_mock):
         jenkins_mock.return_value = get_mock_urlopen_return_value(self.crumb_data)
-        request = jenkins.Request('http://example.com/job/TestJob')
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         self.j.maybe_add_crumb(request)
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/crumbIssuer/api/json')
+            self.make_url('crumbIssuer/api/json'))
         self.assertEqual(self.j.crumb, self.crumb_data)
         self.assertEqual(request.headers['.crumb'], self.crumb_data['crumb'])
         self._check_requests(jenkins_mock.call_args_list)
@@ -95,13 +95,13 @@ class JenkinsMaybeAddCrumbTest(JenkinsTestBase):
     def test_return_empty_response(self, jenkins_mock):
         "Don't try to create crumb header from an empty response"
         jenkins_mock.side_effect = jenkins.EmptyResponseException("empty response")
-        request = jenkins.Request('http://example.com/job/TestJob')
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         self.j.maybe_add_crumb(request)
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/crumbIssuer/api/json')
+            self.make_url('crumbIssuer/api/json'))
         self.assertFalse(self.j.crumb)
         self.assertFalse('.crumb' in request.headers)
         self._check_requests(jenkins_mock.call_args_list)
@@ -116,13 +116,13 @@ class JenkinsOpenTest(JenkinsTestBase):
             get_mock_urlopen_return_value(self.crumb_data),
             get_mock_urlopen_return_value(data),
         ]
-        request = jenkins.Request('http://example.com/job/TestJob')
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         response = self.j.jenkins_open(request)
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/job/TestJob')
+            self.make_url('job/TestJob'))
         self.assertEqual(response, json.dumps(data))
         self.assertEqual(self.j.crumb, self.crumb_data)
         self.assertEqual(request.headers['.crumb'], self.crumb_data['crumb'])
@@ -131,12 +131,12 @@ class JenkinsOpenTest(JenkinsTestBase):
     @patch('jenkins.urlopen')
     def test_response_403(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob',
+            self.make_url('job/TestJob'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
             fp=None)
-        request = jenkins.Request('http://example.com/job/TestJob')
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
             self.j.jenkins_open(request, add_crumb=False)
@@ -146,18 +146,18 @@ class JenkinsOpenTest(JenkinsTestBase):
             'basic auth failed')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/job/TestJob')
+            self.make_url('job/TestJob'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch('jenkins.urlopen')
     def test_response_404(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob',
+            self.make_url('job/TestJob'),
             code=404,
             msg="basic auth failed",
             hdrs=[],
             fp=None)
-        request = jenkins.Request('http://example.com/job/TestJob')
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         with self.assertRaises(jenkins.NotFoundException) as context_manager:
             self.j.jenkins_open(request, add_crumb=False)
@@ -166,35 +166,35 @@ class JenkinsOpenTest(JenkinsTestBase):
             'Requested item could not be found')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/job/TestJob')
+            self.make_url('job/TestJob'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch('jenkins.urlopen')
     def test_empty_response(self, jenkins_mock):
         jenkins_mock.return_value = Mock(**{'read.return_value': None})
 
-        request = jenkins.Request('http://example.com/job/TestJob')
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
             self.j.jenkins_open(request, False)
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]: '
-            'empty response')
+            'Error communicating with server[{0}/]: '
+            'empty response'.format(self.base_url))
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/job/TestJob')
+            self.make_url('job/TestJob'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch('jenkins.urlopen')
     def test_response_501(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob',
+            self.make_url('job/TestJob'),
             code=501,
             msg="Not implemented",
             hdrs=[],
             fp=None)
-        request = jenkins.Request('http://example.com/job/TestJob')
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         with self.assertRaises(HTTPError) as context_manager:
             self.j.jenkins_open(request, add_crumb=False)
@@ -203,15 +203,15 @@ class JenkinsOpenTest(JenkinsTestBase):
             'HTTP Error 501: Not implemented')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/job/TestJob')
+            self.make_url('job/TestJob'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch('jenkins.urlopen')
     def test_timeout(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.URLError(
             reason="timed out")
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test', timeout=1)
-        request = jenkins.Request('http://example.com/job/TestJob')
+        j = jenkins.Jenkins(self.make_url(''), 'test', 'test', timeout=1)
+        request = jenkins.Request(self.make_url('job/TestJob'))
 
         with self.assertRaises(jenkins.JenkinsException) as context_manager:
             j.jenkins_open(request, add_crumb=False)
@@ -220,5 +220,5 @@ class JenkinsOpenTest(JenkinsTestBase):
             'Error in request: timed out')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/job/TestJob')
+            self.make_url('job/TestJob'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/test_node.py b/tests/test_node.py
index 854349e..4d28241 100644
--- a/tests/test_node.py
+++ b/tests/test_node.py
@@ -43,10 +43,10 @@ class JenkinsGetNodesTest(JenkinsNodesTestBase):
             self.j.get_nodes()
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/api/json')
+            self.make_url('computer/api/json'))
         self.assertEqual(
             str(context_manager.exception),
-            'Could not parse JSON info for server[http://example.com/]')
+            'Could not parse JSON info for server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch('jenkins.urlopen')
@@ -56,13 +56,13 @@ class JenkinsGetNodesTest(JenkinsNodesTestBase):
             self.j.get_nodes()
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(urlopen_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob',
+            self.make_url('job/TestJob'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -72,10 +72,10 @@ class JenkinsGetNodesTest(JenkinsNodesTestBase):
             self.j.get_nodes()
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/api/json')
+            self.make_url('computer/api/json'))
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
 
@@ -90,7 +90,7 @@ class JenkinsGetNodeInfoTest(JenkinsNodesTestBase):
         self.assertEqual(self.j.get_node_info('test node'), self.node_info)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/test%20node/api/json?depth=0')
+            self.make_url('computer/test%20node/api/json?depth=0'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -103,7 +103,7 @@ class JenkinsGetNodeInfoTest(JenkinsNodesTestBase):
             self.j.get_node_info('test_node')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/test_node/api/json?depth=0')
+            self.make_url('computer/test_node/api/json?depth=0'))
         self.assertEqual(
             str(context_manager.exception),
             'Could not parse JSON info for node[test_node]')
@@ -112,7 +112,7 @@ class JenkinsGetNodeInfoTest(JenkinsNodesTestBase):
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/TestJob',
+            self.make_url('job/TestJob'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -122,7 +122,7 @@ class JenkinsGetNodeInfoTest(JenkinsNodesTestBase):
             self.j.get_node_info('test_node')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/test_node/api/json?depth=0')
+            self.make_url('computer/test_node/api/json?depth=0'))
         self.assertEqual(
             str(context_manager.exception),
             'node[test_node] does not exist')
@@ -166,7 +166,7 @@ class JenkinsDeleteNodeTest(JenkinsNodesTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            'http://example.com/computer/test%20node/doDelete')
+            self.make_url('computer/test%20node/doDelete'))
         self.assertFalse(self.j.node_exists('test node'))
         self._check_requests(jenkins_mock.call_args_list)
 
@@ -182,7 +182,7 @@ class JenkinsDeleteNodeTest(JenkinsNodesTestBase):
             self.j.delete_node('test_node')
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            'http://example.com/computer/test_node/doDelete')
+            self.make_url('computer/test_node/doDelete'))
         self.assertEqual(
             str(context_manager.exception),
             'delete[test_node] failed')
@@ -204,11 +204,56 @@ class JenkinsCreateNodeTest(JenkinsNodesTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url().split('?')[0],
-            'http://example.com/computer/doCreateItem')
+            self.make_url('computer/doCreateItem'))
         self.assertTrue(self.j.node_exists('test node'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_urlencode(self, jenkins_mock):
+        jenkins_mock.side_effect = [
+            None,
+            None,
+            json.dumps(self.node_info),
+            json.dumps(self.node_info),
+        ]
+        params = {
+            'port': '22',
+            'username': 'juser',
+            'credentialsId': '10f3a3c8-be35-327e-b60b-a3e5edb0e45f',
+            'host': 'my.jenkins.slave1'
+        }
+        self.j.create_node(
+            'slave1',
+            nodeDescription='my test slave',
+            remoteFS='/home/juser',
+            labels='precise',
+            exclusive=True,
+            launcher=jenkins.LAUNCHER_SSH,
+            launcher_params=params)
+
+        actual = jenkins_mock.call_args_list[1][0][0].get_full_url()
+        # As python dicts do not guarantee order so the parameters get
+        # re-ordered when it gets processed by _get_encoded_params(),
+        # verify sections of the URL with self.assertIn() instead of
+        # the entire URL
+        self.assertIn(u'username%22%3A+%22juser', actual)
+        self.assertIn(
+            u'stapler-class%22%3A+%22hudson.plugins.sshslaves.SSHLauncher',
+            actual)
+        self.assertIn(u'host%22%3A+%22my.jenkins.slave1', actual)
+        self.assertIn(
+            u'credentialsId%22%3A+%2210f3a3c8-be35-327e-b60b-a3e5edb0e45f',
+            actual)
+        self.assertIn(u'port%22%3A+%2222', actual)
+        self.assertIn(u'remoteFS%22%3A+%22%2Fhome%2Fjuser', actual)
+        self.assertIn(u'labelString%22%3A+%22precise', actual)
+        self.assertIn(u'name%22%3A+%22slave1', actual)
+        self.assertIn(
+            u'type%22%3A+%22hudson.slaves.DumbSlave%24DescriptorImpl',
+            actual)
+        self._check_requests(jenkins_mock.call_args_list)
+
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_already_exists(self, jenkins_mock):
         jenkins_mock.side_effect = [
             json.dumps(self.node_info),
@@ -234,7 +279,7 @@ class JenkinsCreateNodeTest(JenkinsNodesTestBase):
             self.j.create_node('test_node')
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url().split('?')[0],
-            'http://example.com/computer/doCreateItem')
+            self.make_url('computer/doCreateItem'))
         self.assertEqual(
             str(context_manager.exception),
             'create[test_node] failed')
@@ -254,8 +299,8 @@ class JenkinsEnableNodeTest(JenkinsNodesTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/test%20node/' +
-            'toggleOffline?offlineMessage=')
+            '{0}/computer/test%20node/'
+            'toggleOffline?offlineMessage='.format(self.base_url))
 
         jenkins_mock.side_effect = [json.dumps(self.online_node_info)]
         node_info = self.j.get_node_info('test node')
@@ -275,7 +320,7 @@ class JenkinsEnableNodeTest(JenkinsNodesTestBase):
         # Last call to jenkins was to check status
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/test_node/api/json?depth=0')
+            self.make_url('computer/test_node/api/json?depth=0'))
 
         jenkins_mock.side_effect = [json.dumps(self.online_node_info)]
         node_info = self.j.get_node_info('test_node')
@@ -296,8 +341,8 @@ class JenkinsDisableNodeTest(JenkinsNodesTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/test%20node/' +
-            'toggleOffline?offlineMessage=')
+            '{0}/computer/test%20node/'
+            'toggleOffline?offlineMessage='.format(self.base_url))
 
         jenkins_mock.side_effect = [json.dumps(self.offline_node_info)]
         node_info = self.j.get_node_info('test node')
@@ -317,7 +362,7 @@ class JenkinsDisableNodeTest(JenkinsNodesTestBase):
         # Last call to jenkins was to check status
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            'http://example.com/computer/test_node/api/json?depth=0')
+            self.make_url('computer/test_node/api/json?depth=0'))
 
         jenkins_mock.side_effect = [json.dumps(self.offline_node_info)]
         node_info = self.j.get_node_info('test_node')
diff --git a/tests/test_plugins.py b/tests/test_plugins.py
index 698a7a6..de2ae7d 100644
--- a/tests/test_plugins.py
+++ b/tests/test_plugins.py
@@ -33,7 +33,7 @@
 
 import json
 from mock import patch
-from testscenarios.testcase import TestWithScenarios
+from testscenarios.scenarios import multiply_scenarios
 
 import jenkins
 from jenkins import plugins
@@ -84,7 +84,7 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
         self.assertEqual(plugins_info, self.plugin_info_json['plugins'])
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/pluginManager/api/json?depth=2')
+            self.make_url('pluginManager/api/json?depth=2'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -104,7 +104,7 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
         self.j.get_plugins_info(depth=1)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/pluginManager/api/json?depth=1')
+            self.make_url('pluginManager/api/json?depth=1'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -115,10 +115,10 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
             self.j.get_plugins_info()
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/pluginManager/api/json?depth=2')
+            self.make_url('pluginManager/api/json?depth=2'))
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -129,16 +129,16 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
             self.j.get_plugins_info()
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/pluginManager/api/json?depth=2')
+            self.make_url('pluginManager/api/json?depth=2'))
         self.assertEqual(
             str(context_manager.exception),
-            'Could not parse JSON info for server[http://example.com/]')
+            'Could not parse JSON info for server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/pluginManager/api/json?depth=2',
+            self.make_url('job/pluginManager/api/json?depth=2'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -148,7 +148,7 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
             self.j.get_plugins_info(depth=52)
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
 
@@ -179,7 +179,7 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
             json.dumps(self.plugin_info_json),
             json.dumps(self.updated_plugin_info_json)
         ]
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        j = jenkins.Jenkins(self.make_url(''), 'test', 'test')
 
         plugins_info = j.get_plugins()
         self.assertEqual(plugins_info["mailer"]["version"],
@@ -210,7 +210,7 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
         self.j.get_plugin_info('test', depth=1)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/pluginManager/api/json?depth=1')
+            self.make_url('pluginManager/api/json?depth=1'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -221,10 +221,10 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
             self.j.get_plugin_info('test')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/pluginManager/api/json?depth=2')
+            self.make_url('pluginManager/api/json?depth=2'))
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -235,16 +235,16 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
             self.j.get_plugin_info('test')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/pluginManager/api/json?depth=2')
+            self.make_url('pluginManager/api/json?depth=2'))
         self.assertEqual(
             str(context_manager.exception),
-            'Could not parse JSON info for server[http://example.com/]')
+            'Could not parse JSON info for server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_raise_HTTPError(self, jenkins_mock):
         jenkins_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/job/pluginManager/api/json?depth=2',
+            self.make_url('job/pluginManager/api/json?depth=2'),
             code=401,
             msg="basic auth failed",
             hdrs=[],
@@ -254,26 +254,29 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
             self.j.get_plugin_info(u'TestPlugin', depth=52)
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(jenkins_mock.call_args_list)
 
 
-class PluginsTestScenarios(TestWithScenarios, JenkinsPluginsBase):
-    scenarios = [
-        ('s1', dict(v1='1.0.0', op='__gt__', v2='0.8.0')),
-        ('s2', dict(v1='1.0.1alpha', op='__gt__', v2='1.0.0')),
-        ('s3', dict(v1='1.0', op='__eq__', v2='1.0.0')),
-        ('s4', dict(v1='1.0', op='__eq__', v2='1.0')),
-        ('s5', dict(v1='1.0', op='__lt__', v2='1.8.0')),
-        ('s6', dict(v1='1.0.1alpha', op='__lt__', v2='1.0.1')),
-        ('s7', dict(v1='1.0alpha', op='__lt__', v2='1.0.0')),
-        ('s8', dict(v1='1.0-alpha', op='__lt__', v2='1.0.0')),
-        ('s9', dict(v1='1.1-alpha', op='__gt__', v2='1.0')),
-        ('s10', dict(v1='1.0-SNAPSHOT', op='__lt__', v2='1.0')),
-        ('s11', dict(v1='1.0.preview', op='__lt__', v2='1.0')),
-        ('s12', dict(v1='1.1-SNAPSHOT', op='__gt__', v2='1.0')),
-        ('s13', dict(v1='1.0a-SNAPSHOT', op='__lt__', v2='1.0a')),
-    ]
+class PluginsTestScenarios(JenkinsPluginsBase):
+
+    scenarios = multiply_scenarios(
+        JenkinsPluginsBase.scenarios,
+        [
+            ('s1', dict(v1='1.0.0', op='__gt__', v2='0.8.0')),
+            ('s2', dict(v1='1.0.1alpha', op='__gt__', v2='1.0.0')),
+            ('s3', dict(v1='1.0', op='__eq__', v2='1.0.0')),
+            ('s4', dict(v1='1.0', op='__eq__', v2='1.0')),
+            ('s5', dict(v1='1.0', op='__lt__', v2='1.8.0')),
+            ('s6', dict(v1='1.0.1alpha', op='__lt__', v2='1.0.1')),
+            ('s7', dict(v1='1.0alpha', op='__lt__', v2='1.0.0')),
+            ('s8', dict(v1='1.0-alpha', op='__lt__', v2='1.0.0')),
+            ('s9', dict(v1='1.1-alpha', op='__gt__', v2='1.0')),
+            ('s10', dict(v1='1.0-SNAPSHOT', op='__lt__', v2='1.0')),
+            ('s11', dict(v1='1.0.preview', op='__lt__', v2='1.0')),
+            ('s12', dict(v1='1.1-SNAPSHOT', op='__gt__', v2='1.0')),
+            ('s13', dict(v1='1.0a-SNAPSHOT', op='__lt__', v2='1.0a')),
+        ])
 
     def setUp(self):
         super(PluginsTestScenarios, self).setUp()
@@ -293,7 +296,7 @@ class PluginsTestScenarios(TestWithScenarios, JenkinsPluginsBase):
         equality operator defined for the scenario.
         """
         plugin_name = "Jenkins Mailer Plugin"
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        j = jenkins.Jenkins(self.base_url, 'test', 'test')
         plugin_info = j.get_plugins()[plugin_name]
         v1 = plugin_info.get("version")
 
@@ -311,7 +314,7 @@ class PluginsTestScenarios(TestWithScenarios, JenkinsPluginsBase):
         type of PluginVersion before comparing provides the same result.
         """
         plugin_name = "Jenkins Mailer Plugin"
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        j = jenkins.Jenkins(self.base_url, 'test', 'test')
         plugin_info = j.get_plugins()[plugin_name]
         v1 = plugin_info.get("version")
 
diff --git a/tests/test_queue.py b/tests/test_queue.py
index adda62f..cd7157f 100644
--- a/tests/test_queue.py
+++ b/tests/test_queue.py
@@ -16,7 +16,7 @@ class JenkinsCancelQueueTest(JenkinsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/queue/cancelItem?id=52')
+            self.make_url('queue/cancelItem?id=52'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open',
@@ -29,7 +29,7 @@ class JenkinsCancelQueueTest(JenkinsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/queue/cancelItem?id=52')
+            self.make_url('queue/cancelItem?id=52'))
         self._check_requests(jenkins_mock.call_args_list)
 
 
@@ -68,5 +68,5 @@ class JenkinsQueueInfoTest(JenkinsTestBase):
         self.assertEqual(queue_info, queue_info_to_return['items'])
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/queue/api/json?depth=0')
+            self.make_url('queue/api/json?depth=0'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/test_quiet_down.py b/tests/test_quiet_down.py
index 415e6b3..f4e2818 100644
--- a/tests/test_quiet_down.py
+++ b/tests/test_quiet_down.py
@@ -17,10 +17,10 @@ class JenkinsQuietDownTest(JenkinsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            u'http://example.com/quietDown')
+            self.make_url('quietDown'))
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            u'http://example.com/api/json')
+            self.make_url('api/json'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -35,10 +35,10 @@ class JenkinsQuietDownTest(JenkinsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            u'http://example.com/quietDown')
+            self.make_url('quietDown'))
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            u'http://example.com/api/json')
+            self.make_url('api/json'))
         self.assertEqual(
             str(context_manager.exception),
             'quiet down failed')
@@ -55,5 +55,5 @@ class JenkinsQuietDownTest(JenkinsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/quietDown')
+            self.make_url('quietDown'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tests/test_script.py b/tests/test_script.py
index 8829def..cc0c521 100644
--- a/tests/test_script.py
+++ b/tests/test_script.py
@@ -12,18 +12,18 @@ class JenkinsScriptTest(JenkinsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/scriptText')
+            self.make_url('scriptText'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_install_plugin(self, jenkins_mock):
         '''Installation of plugins is done with the run_script method
         '''
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        j = jenkins.Jenkins(self.make_url(''), 'test', 'test')
         j.install_plugin("jabber")
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/scriptText')
+            self.make_url('scriptText'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -31,7 +31,7 @@ class JenkinsScriptTest(JenkinsTestBase):
     def test_install_plugin_with_dependencies(self, run_script_mock, jenkins_mock):
         '''Verify install plugins with dependencies
         '''
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        j = jenkins.Jenkins(self.make_url(''), 'test', 'test')
         j.install_plugin("jabber")
         self.assertEqual(len(run_script_mock.call_args_list), 2)
         self.assertEqual(run_script_mock.call_args_list[0][0][0],
@@ -47,7 +47,7 @@ class JenkinsScriptTest(JenkinsTestBase):
     def test_install_plugin_without_dependencies(self, run_script_mock, jenkins_mock):
         '''Verify install plugins without dependencies
         '''
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        j = jenkins.Jenkins(self.make_url(''), 'test', 'test')
         j.install_plugin("jabber", include_dependencies=False)
         self.assertEqual(len(run_script_mock.call_args_list), 2)
         self.assertEqual(run_script_mock.call_args_list[0][0][0],
@@ -63,7 +63,7 @@ class JenkinsScriptTest(JenkinsTestBase):
         '''Verify install plugin does not need a restart
         '''
         run_script_mock.return_value = u'Result: false\n'
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        j = jenkins.Jenkins(self.make_url(''), 'test', 'test')
         self.assertFalse(j.install_plugin("jabber"))
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -72,5 +72,5 @@ class JenkinsScriptTest(JenkinsTestBase):
         '''Verify install plugin needs a restart
         '''
         run_script_mock.return_value = u'Result: true\n'
-        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        j = jenkins.Jenkins(self.make_url(''), 'test', 'test')
         self.assertTrue(j.install_plugin("jabber"))
diff --git a/tests/test_version.py b/tests/test_version.py
index fa152cb..13e35ee 100644
--- a/tests/test_version.py
+++ b/tests/test_version.py
@@ -24,7 +24,7 @@ class JenkinsVersionTest(JenkinsTestBase):
     @patch('jenkins.urlopen')
     def test_raise_HTTPError(self, urlopen_mock):
         urlopen_mock.side_effect = jenkins.HTTPError(
-            'http://example.com/',
+            self.make_url(''),
             code=503,
             msg="internal server error",
             hdrs=[],
@@ -33,7 +33,7 @@ class JenkinsVersionTest(JenkinsTestBase):
             self.j.get_version()
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(urlopen_mock.call_args_list)
 
     @patch('jenkins.urlopen')
@@ -43,7 +43,7 @@ class JenkinsVersionTest(JenkinsTestBase):
             self.j.get_version()
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]')
+            'Error communicating with server[{0}/]'.format(self.base_url))
         self._check_requests(urlopen_mock.call_args_list)
 
     @patch('jenkins.urlopen', return_value=None)
@@ -52,6 +52,6 @@ class JenkinsVersionTest(JenkinsTestBase):
             self.j.get_version()
         self.assertEqual(
             str(context_manager.exception),
-            'Error communicating with server[http://example.com/]:'
-            ' empty response')
+            'Error communicating with server[{0}/]:'
+            ' empty response'.format(self.base_url))
         self._check_requests(urlopen_mock.call_args_list)
diff --git a/tests/test_view.py b/tests/test_view.py
index e7117bf..45b2587 100644
--- a/tests/test_view.py
+++ b/tests/test_view.py
@@ -25,7 +25,7 @@ class JenkinsGetViewNameTest(JenkinsViewsTestBase):
         self.assertEqual(view_name, 'Test View')
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/view/Test%20View/api/json?tree=name')
+            self.make_url('view/Test%20View/api/json?tree=name'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -37,7 +37,7 @@ class JenkinsGetViewNameTest(JenkinsViewsTestBase):
         self.assertEqual(view_name, None)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/view/TestView/api/json?tree=name')
+            self.make_url('view/TestView/api/json?tree=name'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -49,7 +49,7 @@ class JenkinsGetViewNameTest(JenkinsViewsTestBase):
             self.j.get_view_name(u'TestView')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/view/TestView/api/json?tree=name')
+            self.make_url('view/TestView/api/json?tree=name'))
         self.assertEqual(
             str(context_manager.exception),
             'Jenkins returned an unexpected view name {0} '
@@ -95,7 +95,7 @@ class JenkinsGetViewsTest(JenkinsViewsTestBase):
         self.assertEqual(view_info, views)
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/api/json')
+            self.make_url('api/json'))
         self._check_requests(jenkins_mock.call_args_list)
 
 
@@ -112,7 +112,7 @@ class JenkinsDeleteViewTest(JenkinsViewsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/view/Test%20View/doDelete')
+            self.make_url('view/Test%20View/doDelete'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -127,7 +127,7 @@ class JenkinsDeleteViewTest(JenkinsViewsTestBase):
             self.j.delete_view(u'TestView')
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/view/TestView/doDelete')
+            self.make_url('view/TestView/doDelete'))
         self.assertEqual(
             str(context_manager.exception),
             'delete[TestView] failed')
@@ -148,7 +148,7 @@ class JenkinsCreateViewTest(JenkinsViewsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            'http://example.com/createView?name=Test%20View')
+            self.make_url('createView?name=Test%20View'))
         self._check_requests(jenkins_mock.call_args_list)
 
     @patch.object(jenkins.Jenkins, 'jenkins_open')
@@ -162,7 +162,7 @@ class JenkinsCreateViewTest(JenkinsViewsTestBase):
             self.j.create_view(u'TestView', self.config_xml)
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/view/TestView/api/json?tree=name')
+            self.make_url('view/TestView/api/json?tree=name'))
         self.assertEqual(
             str(context_manager.exception),
             'view[TestView] already exists')
@@ -180,10 +180,10 @@ class JenkinsCreateViewTest(JenkinsViewsTestBase):
             self.j.create_view(u'TestView', self.config_xml)
         self.assertEqual(
             jenkins_mock.call_args_list[0][0][0].get_full_url(),
-            'http://example.com/view/TestView/api/json?tree=name')
+            self.make_url('view/TestView/api/json?tree=name'))
         self.assertEqual(
             jenkins_mock.call_args_list[1][0][0].get_full_url(),
-            'http://example.com/createView?name=TestView')
+            self.make_url('createView?name=TestView'))
         self.assertEqual(
             str(context_manager.exception),
             'create[TestView] failed')
@@ -202,7 +202,7 @@ class JenkinsReconfigViewTest(JenkinsViewsTestBase):
         self.j.reconfig_view(u'Test View', self.config_xml)
 
         self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(),
-                         u'http://example.com/view/Test%20View/config.xml')
+                         self.make_url('view/Test%20View/config.xml'))
         self._check_requests(jenkins_mock.call_args_list)
 
 
@@ -214,5 +214,5 @@ class JenkinsGetViewConfigTest(JenkinsViewsTestBase):
 
         self.assertEqual(
             jenkins_mock.call_args[0][0].get_full_url(),
-            u'http://example.com/view/Test%20View/config.xml')
+            self.make_url('view/Test%20View/config.xml'))
         self._check_requests(jenkins_mock.call_args_list)
diff --git a/tox.ini b/tox.ini
index 4cf6cd3..e8b9ce4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,7 @@
 [tox]
 minversion = 1.6
 skipsdist = True
-envlist = py33, py34, pep8, py27, pypy
+envlist = py34, pep8, py27, pypy
 
 [testenv]
 setenv VIRTUAL_ENV={envdir}
@@ -16,9 +16,6 @@ commands =
     coverage report --omit="tests/*" --show-missing
     coverage html --omit="tests/*" -d cover
 
-[tox:jenkins]
-downloadcache = ~/cache/pip
-
 [testenv:pep8]
 commands = flake8
 
diff --git a/jenkins/__init__.py b/jenkins/__init__.py
index 65f8b6a..34cae71 100644
--- a/jenkins/__init__.py
+++ b/jenkins/__init__.py
@@ -240,7 +240,10 @@ class Jenkins(object):
     def _build_url(self, format_spec, variables=None):
 
         if variables:
-            url_path = format_spec % self._get_encoded_params(variables)
+            if format_spec == CREATE_NODE:
+                url_path = format_spec % urlencode(self._get_encoded_params(variables))
+            else:
+                url_path = format_spec % self._get_encoded_params(variables)
         else:
             url_path = format_spec
 
@@ -453,7 +456,7 @@ class Jenkins(object):
             u'name': u'my_job'}
 
         """
-        url = "/".join((item, INFO))
+        url = '/'.join((item, INFO)).lstrip('/')
         if query:
             url += query
         try:

Reply to: