Skip to content

Commit

Permalink
More fixes to parameterized builds - still broken.
Browse files Browse the repository at this point in the history
  • Loading branch information
salimfadhley committed Aug 3, 2014
1 parent a7543ee commit e89569f
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 111 deletions.
55 changes: 55 additions & 0 deletions examples/low_level/post_watcher.py
Original file line number Diff line number Diff line change
@@ -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()
34 changes: 22 additions & 12 deletions jenkinsapi/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ def _get_config_element_tree(self):
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

Expand All @@ -148,21 +151,28 @@ def _mk_json_from_build_parameters(build_params, file_params=None):
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)
Expand All @@ -178,12 +188,15 @@ def invoke(self, securitytoken=None, block=False, build_params=None, cause=None,
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,
Expand All @@ -194,9 +207,6 @@ def invoke(self, securitytoken=None, block=False, build_params=None, cause=None,

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)

Expand Down
158 changes: 78 additions & 80 deletions jenkinsapi_tests/systests/test_parameterized_builds.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,86 +37,84 @@ def test_invoke_job_with_file(self):
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__':
Expand Down
65 changes: 46 additions & 19 deletions jenkinsapi_tests/unittests/test_job.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import mock
import json
# To run unittests on python 2.6 please use unittest2 library
try:
import unittest2 as unittest
Expand Down Expand Up @@ -131,24 +132,6 @@ def test_wrong__mk_json_from_build_parameters(self):
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):
Expand Down Expand Up @@ -280,7 +263,7 @@ def test_get_params_list(self, get_data):
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:
Expand All @@ -299,5 +282,49 @@ def test_get_build_metadata(self):
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()

0 comments on commit e89569f

Please sign in to comment.