More fixes to parameterized builds - still broken.
authorSalim Fadhley <sal@stodge.org>
Sun, 3 Aug 2014 21:53:33 +0000 (22:53 +0100)
committerSalim Fadhley <sal@stodge.org>
Sun, 3 Aug 2014 21:53:33 +0000 (22:53 +0100)
examples/low_level/post_watcher.py [new file with mode: 0644]
jenkinsapi/job.py
jenkinsapi_tests/systests/test_parameterized_builds.py
jenkinsapi_tests/unittests/test_job.py

diff --git a/examples/low_level/post_watcher.py b/examples/low_level/post_watcher.py
new file mode 100644 (file)
index 0000000..c6921fd
--- /dev/null
@@ -0,0 +1,55 @@
+"""
+Save this file as server.py
+>>> python server.py 0.0.0.0 8001
+serving on 0.0.0.0:8001
+
+or simply
+
+>>> python server.py
+Serving on localhost:8000
+
+You can use this to test GET and POST methods.
+
+"""
+
+import SimpleHTTPServer
+import SocketServer
+import logging
+import cgi
+
+import sys
+
+
+
+PORT = 8080
+I = "localhost"
+
+
+class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+
+    def do_GET(self):
+        logging.warning("======= GET STARTED =======")
+        logging.warning(self.headers)
+        SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
+
+    def do_POST(self):
+        logging.warning("======= POST STARTED =======")
+        logging.warning(self.headers)
+        form = cgi.FieldStorage(
+            fp=self.rfile,
+            headers=self.headers,
+            environ={'REQUEST_METHOD':'POST',
+                     'CONTENT_TYPE':self.headers['Content-Type'],
+                     })
+        logging.warning("======= POST VALUES =======")
+        for item in form.list:
+            logging.warning(item)
+        logging.warning("\n")
+        SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
+
+Handler = ServerHandler
+
+httpd = SocketServer.TCPServer(("", PORT), Handler)
+
+print "Serving at: http://%(interface)s:%(port)s" % dict(interface=I or "localhost", port=PORT)
+httpd.serve_forever()
\ No newline at end of file
index 3f3056cb42e6bff15309c017032ed2505ebd7a1a..eada1fc5f434faca6c380df3c148c621c1ffd76c 100644 (file)
@@ -133,8 +133,11 @@ class Job(JenkinsBase, MutableJenkinsThing):
             self._element_tree = ET.fromstring(self._config)
         return self._element_tree
 
-    def get_build_triggerurl(self):
-        if not self.has_params():
+    def get_build_triggerurl(self, files):
+        if files or (not self.has_params()):
+            # If job has file parameters - it must be triggered
+            # using "/build", not by "/buildWithParameters"
+            # "/buildWithParameters" will ignore non-file parameters
             return "%s/build" % self.baseurl
         return "%s/buildWithParameters" % self.baseurl
 
@@ -148,21 +151,28 @@ class Job(JenkinsBase, MutableJenkinsThing):
         assert isinstance(
             build_params, dict), 'Build parameters must be a dict'
 
-        build_p = [{'name': k, 'value': v}
-                   for k, v in build_params.items()]
+        build_p = [{'name': k, 'value': str(v)}
+                   for k, v in sorted(build_params.items())]
         out = {'parameter': build_p}
         if file_params:
             file_p = [{'name': k, 'file': k}
                       for k in file_params.keys()]
             out['parameter'].extend(file_p)
 
+        if len(out['parameter']) == 1:
+            out['parameter'] = out['parameter'][0]
+
         return out
 
     @staticmethod
     def mk_json_from_build_parameters(build_params, file_params=None):
-        to_json_structure = Job._mk_json_from_build_parameters(build_params,
-                                                               file_params)
-        return json.dumps(to_json_structure)
+        json_structure = Job._mk_json_from_build_parameters(
+            build_params,
+            file_params
+        )
+        json_structure['statusCode'] = "303"
+        json_structure['redirectTo'] = "."
+        return json.dumps(json_structure)
 
     def invoke(self, securitytoken=None, block=False, build_params=None, cause=None, files=None, delay=5):
         assert isinstance(block, bool)
@@ -178,12 +188,15 @@ class Job(JenkinsBase, MutableJenkinsThing):
         build_params = build_params and dict(
             build_params.items()) or {}  # Via POSTed JSON
 
-        url = self.get_build_triggerurl()
+        url = self.get_build_triggerurl(files)
         if cause:
             build_params['cause'] = cause
-
+        
+        # Build require params as form fields
+        # and as Json.
         data = {'json': self.mk_json_from_build_parameters(
             build_params, files)}
+        data.update(build_params)
 
         response = self.jenkins.requester.post_url(
             url,
@@ -194,9 +207,6 @@ class Job(JenkinsBase, MutableJenkinsThing):
 
         redirect_url = response.headers['location']
 
-        # It's possible that an error triggering the build will cause Jenkins
-        # not build, the signal is that we will be redirected to something
-        # other than a QueueItem URL.
         if not redirect_url.startswith("%s/queue/item" % self.jenkins.baseurl):
             raise ValueError("Not a Queue URL: %s" % redirect_url)
 
index cc25539412853b13d09f2ed0ba6fa1370bdeff50..43e7edee9e48cff1492d7e82f0531b224ce3120b 100644 (file)
@@ -37,86 +37,84 @@ class TestParameterizedBuilds(BaseSystemTest):
         art_file = artifacts['file.txt']
         self.assertTrue(art_file.get_data().strip(), file_data)
 
-#     def test_invoke_job_parameterized(self):
-#         param_B = random_string()
-#  
-#         job_name = 'create2_%s' % random_string()
-#         job = self.jenkins.create_job(job_name, JOB_WITH_PARAMETERS)
-#         job.invoke(block=True, build_params={'B': param_B})
-#  
-#         build = job.get_last_build()
-#         while build.is_running():
-#             time.sleep(0.25)
-#  
-#         artifacts = build.get_artifact_dict()
-#         self.assertIsInstance(artifacts, dict)
-#         artB = artifacts['b.txt']
-#         self.assertTrue(artB.get_data().strip(), param_B)
-#  
-#         self.assertIn(param_B, build.get_console())
-# 
-#     def test_parameterized_job_build_queuing(self):
-#         """Accept multiple builds of parameterized jobs with unique
-#            parameters."""
-#         job_name = 'create_%s' % random_string()
-#         job = self.jenkins.create_job(job_name, JOB_WITH_PARAMETERS)
-# 
-#         for i in range(3):
-#             param_B = random_string()
-#             params = {'B': param_B}
-#             job.invoke(build_params=params)
-#             time.sleep(0.25)
-# 
-#         self.assertTrue(job.has_queued_build(params))
-# 
-#         while job.has_queued_build(params):
-#             time.sleep(0.25)
-# 
-#         build = job.get_last_build()
-#         while build.is_running():
-#             time.sleep(0.25)
-# 
-#         artifacts = build.get_artifact_dict()
-#         self.assertIsInstance(artifacts, dict)
-#         artB = artifacts['b.txt']
-#         self.assertTrue(artB.get_data().strip(), param_B)
-# 
-#         self.assertIn(param_B, build.get_console())
-# 
-#     def test_parameterized_multiple_builds_get_the_same_queue_item(self):
-#         """Multiple attempts to run the same parameteized
-#         build will get the same queue item."""
-#         job_name = 'create_%s' % random_string()
-#         job = self.jenkins.create_job(job_name, JOB_WITH_PARAMETERS)
-# 
-#         for i in range(3):
-#             params = {'B': random_string()}
-#             qq0 = job.invoke(build_params=params)
-# 
-#         
-#         qq1 = job.invoke(build_params=params)
-#         self.assertEqual(qq0, qq1)
-# 
-#     def test_invoke_job_with_file_and_params(self):
-#         file_data = random_string()
-#         param_data = random_string()
-#         param_file = StringIO(file_data)
-# 
-#         job_name = 'create_%s' % random_string()
-#         job = self.jenkins.create_job(job_name, JOB_WITH_FILE_AND_PARAMS)
-#         job.invoke(block=True, files={'file.txt': param_file},
-#                    build_params={'B': param_data})
-# 
-#         build = job.get_last_build()
-#         while build.is_running():
-#             time.sleep(0.25)
-# 
-#         artifacts = build.get_artifact_dict()
-#         self.assertIsInstance(artifacts, dict)
-#         art_file = artifacts['file.txt']
-#         self.assertTrue(art_file.get_data().strip(), file_data)
-#         art_param = artifacts['file1.txt']
-#         self.assertTrue(art_param.get_data().strip(), param_data)
+    def test_invoke_job_parameterized(self):
+        param_B = random_string()
+  
+        job_name = 'create2_%s' % random_string()
+        job = self.jenkins.create_job(job_name, JOB_WITH_PARAMETERS)
+        job.invoke(block=True, build_params={'B': param_B})
+        build = job.get_last_build()
+
+        artifacts = build.get_artifact_dict()
+        artB = artifacts['b.txt']
+        self.assertEqual(
+            artB.get_data().strip(),
+            param_B,
+        )
+  
+        self.assertIn(param_B, build.get_console())
+    def test_parameterized_job_build_queuing(self):
+        """Accept multiple builds of parameterized jobs with unique
+           parameters."""
+        job_name = 'create_%s' % random_string()
+        job = self.jenkins.create_job(job_name, JOB_WITH_PARAMETERS)
+  
+        for i in range(3):
+            param_B = random_string()
+            params = {'B': param_B}
+            job.invoke(build_params=params)
+            time.sleep(0.25)
+  
+        self.assertTrue(job.has_queued_build(params))
+  
+        while job.has_queued_build(params):
+            time.sleep(0.25)
+  
+        build = job.get_last_build()
+        while build.is_running():
+            time.sleep(0.25)
+  
+        artifacts = build.get_artifact_dict()
+        self.assertIsInstance(artifacts, dict)
+        artB = artifacts['b.txt']
+        self.assertTrue(artB.get_data().strip(), param_B)
+  
+        self.assertIn(param_B, build.get_console())
+  
+    def test_parameterized_multiple_builds_get_the_same_queue_item(self):
+        """Multiple attempts to run the same parameteized
+        build will get the same queue item."""
+        job_name = 'create_%s' % random_string()
+        job = self.jenkins.create_job(job_name, JOB_WITH_PARAMETERS)
+  
+        for i in range(3):
+            params = {'B': random_string()}
+            qq0 = job.invoke(build_params=params)
+  
+          
+        qq1 = job.invoke(build_params=params)
+        self.assertEqual(qq0, qq1)
+  
+    def test_invoke_job_with_file_and_params(self):
+        file_data = random_string()
+        param_data = random_string()
+        param_file = StringIO(file_data)
+  
+        job_name = 'create_%s' % random_string()
+        job = self.jenkins.create_job(job_name, JOB_WITH_FILE_AND_PARAMS)
+        job.invoke(
+            block=True,
+            files={'file.txt': param_file},
+            build_params={'B': param_data}
+        )
+        build = job.get_last_build()
+        artifacts = build.get_artifact_dict()
+        self.assertIsInstance(artifacts, dict)
+        art_file = artifacts['file.txt']
+        self.assertTrue(art_file.get_data().strip(), file_data)
+        art_param = artifacts['file1.txt']
+        self.assertTrue(art_param.get_data().strip(), param_data)
 
 
 if __name__ == '__main__':
index 7d30ca9f11be6b8641dea192c2bf1a862e5891a4..ab0a41100bde046fc71841f5c155e9433595f9cb 100644 (file)
@@ -1,4 +1,5 @@
 import mock
+import json
 # To run unittests on python 2.6 please use unittest2 library
 try:
     import unittest2 as unittest
@@ -131,24 +132,6 @@ class TestJob(unittest.TestCase):
         self.assertEquals(
             str(ar.exception), 'Build parameters must be a dict')
 
-    def test__mk_json_from_build_parameters(self):
-        params = {'param1': 'value1', 'param2': 'value2'}
-        ret = self.j.mk_json_from_build_parameters(build_params=params)
-        self.assertTrue(isinstance(ret, str))
-        try:
-            self.assertItemsEqual(ret,
-                              '{"parameter": [{"name": "param2", "value": "value2"}, {"name": "param1", "value": "value1"}]}')
-        except AttributeError:
-            self.assertCountEqual(ret,
-                              '{"parameter": [{"name": "param2", "value": "value2"}, {"name": "param1", "value": "value1"}]}')
-
-    def test_wrong_mk_json_from_build_parameters(self):
-        with self.assertRaises(AssertionError) as ar:
-            self.j.mk_json_from_build_parameters(build_params='bad parameter')
-
-        self.assertEquals(
-            str(ar.exception), 'Build parameters must be a dict')
-
     @mock.patch.object(JenkinsBase, 'get_data', fakeGetData)
     def test_wrong_field__build_id_for_type(self):
         with self.assertRaises(AssertionError):
@@ -280,7 +263,7 @@ class TestJob(unittest.TestCase):
         self.assertIsInstance(params, list)
         self.assertEquals(len(params), 2)
         self.assertEquals(params, ['param1', 'param2'])
-    
+
     def test_get_build(self):
         buildnumber = 1
         with mock.patch('jenkinsapi.job.Build') as build_mock:
@@ -299,5 +282,49 @@ class TestJob(unittest.TestCase):
             build_mock.assert_called_with('http://halob:8080/job/foo/1/',
                                           buildnumber, job=self.j, depth=0)
 
+    def assertJsonEqual(self, jsonA, jsonB, msg=None):
+        A = json.loads(jsonA)
+        B = json.loads(jsonB)
+        self.assertEqual(
+            A,
+            B,
+            msg
+        )
+
+    def test_get_json_for_single_param(self):
+        params = {"B": "one two three"}
+        expected = '{"parameter": {"name": "B", "value": "one two three"}, "statusCode": "303", "redirectTo": "."}'
+        self.assertJsonEqual(
+            Job.mk_json_from_build_parameters(params),
+            expected
+        )
+
+    def test_get_json_for_many_params(self):
+        params = {"B": "Honey", "A": "Boo", "C": 2}
+        expected = '{"parameter": [{"name": "A", "value": "Boo"}, {"name": "B", "value": "Honey"}, {"name": "C", "value": "2"}], "statusCode": "303", "redirectTo": "."}'
+
+        self.assertJsonEqual(
+            Job.mk_json_from_build_parameters(params),
+            expected
+        )
+
+    def test__mk_json_from_build_parameters(self):
+        params = {'param1': 'value1', 'param2': 'value2'}
+        result = self.j._mk_json_from_build_parameters(build_params=params)
+        self.assertTrue(isinstance(result, dict))
+
+        self.assertEquals(
+            result,
+            {"parameter": [{"name": "param1", "value": "value1"}, {
+                "name": "param2", "value": "value2"}]}
+        )
+
+    def test_wrong_mk_json_from_build_parameters(self):
+        with self.assertRaises(AssertionError) as ar:
+            self.j.mk_json_from_build_parameters(build_params='bad parameter')
+
+        self.assertEquals(
+            str(ar.exception), 'Build parameters must be a dict')
+
 if __name__ == '__main__':
     unittest.main()