use Test2::V0; #use Test2::Require::EnvVar 'LIVE_TEST_JENKINS_URL'; # Set LIVE_TEST_JENKINS_URL if you want to run these tests against a live jenkins server. # Set LIVE_TEST_JENKINS_API_KEY and LIVE_TEST_JENKINS_API_PASS if your server requires authentication. use Test2::Plugin::BailOnFail; use Test2::Tools::Explain; use Jenkins::API; use HTTP::Response; use REST::Client; my $url = $ENV{LIVE_TEST_JENKINS_URL}; my $apiKey = $ENV{LIVE_TEST_JENKINS_API_KEY}; my $apiPass = $ENV{LIVE_TEST_JENKINS_API_PASS}; my $mock_client; unless ( $ENV{LIVE_TEST_JENKINS_URL} ) { setup_fake_responses(); } my $api = Jenkins::API->new( base_url => $url, api_key => $apiKey, api_pass => $apiPass ); my $v = $api->check_jenkins_url; ok $v, 'Jenkins running on ' . $url; note explain $v; my $status = $api->current_status; ok( ( grep { $_ eq 'Test-Project' } map { $_->{name} } @{ $status->{jobs} } ), 'Ensure we found the Test-Project' ); note 'This is the current status returned by the API'; note explain($status); note 'This is a more refined query of the API'; $status = $api->current_status( { extra_params => { tree => 'jobs[name,color]' } } ); note explain $status; ok grep { $_ eq 'Test-Project' } map { $_->{name} } @{ $status->{jobs} }; $status = $api->current_status( { path_parts => [qw/job Test-Project/], extra_params => { depth => 1 } } ); note 'Querying job Test-Project with depth => 1'; note explain $status; my $build_status = $api->build_queue; note 'Build queue'; note explain $build_status; $build_status = $api->build_queue( { extra_params => { depth => 1 } } ); note 'With depth => 1'; note explain $build_status; my $statistics = $api->load_statistics; is $api->response_code, '200'; ok $api->response_content; note explain $api->project_config('Test-Project'); my $job_info = $api->get_job_details('Test-Project'); note 'get_job_details'; note explain $job_info; my $job_info2 = $api->get_job_details( 'Test-Project', { extra_params => { tree => 'healthReport' } } ); note explain $job_info2; note 'Load statistics'; note explain $statistics; my $view = $api->view_status('Test'); note explain $view; my $view_list = $api->current_status( { extra_params => { tree => 'views[name]' } } ); note explain $view_list; my @views = grep { $_ ne 'All' } map { $_->{name} } @{ $view_list->{views} }; for my $view (@views) { my $view_jobs = $api->view_status( $view, { extra_params => { tree => 'jobs[name,color]' } } ); note explain $view_jobs; } my $response = $api->general_call( [ 'job', 'Test', 'api', 'json' ], { method => 'GET', extra_params => { tree => 'color,description' }, decode_json => 1, expected_response_code => 200, } ); note 'General call'; note explain $response; done_testing; sub setup_fake_responses { $url = 'http://jenkins:8080'; my $fake_responses = [ { 'req' => { 'url' => 'http://172.17.0.2:8080/', 'content' => '', 'method' => 'GET' }, 'res' => { 'msg' => 'OK', 'code' => '200', 'content' => " Dashboard [Jenkins]Skip to content
\"title\"\"title\"
\x{a0}Colin | log out
\x{a0}
\"collapse\"Build Queue
No builds in the queue.
   S   WNameLast SuccessLast FailureLast Duration\x{a0}\x{a0}
\"Not\"100%\"TestN/AN/AN/A\"Schedule\x{a0}
\"Not\"100%\"Test-ProjectN/AN/AN/A\"Schedule\x{a0}
Icon: \x{a0}S\x{a0}M\x{a0}L
", 'headers' => [ 'Cache-Control', 'no-cache,no-store,must-revalidate', 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'text/html;charset=UTF-8', 'Expires', 'Thu, 01 Jan 1970 00:00:00 GMT', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="shortcut icon"; type="image/vnd.microsoft.icon"', 'Link', '; color="black"; rel="mask-icon"', 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="stylesheet"; type="text/css"', 'Link', '; rel="search"; title="Jenkins"; type="application/opensearchdescription+xml"', 'Link', '; rel="alternate"; title="Jenkins:all (all builds)"; type="application/rss+xml"', 'Link', '; rel="alternate"; title="Jenkins:all (all builds) (RSS 2.0)"; type="application/rss+xml"', 'Link', '; rel="alternate"; title="Jenkins:all (failed builds)"; type="application/rss+xml"', 'Link', '; rel="alternate"; title="Jenkins:all (failed builds) (RSS 2.0)"; type="application/rss+xml"', 'Set-Cookie', 'JSESSIONID.c629e2b1=rwi44fgcsgop1phy3o0yl76pz;Path=/;HttpOnly', 'Title', 'Dashboard [Jenkins]', 'X-Content-Type-Options', 'nosniff', 'X-Frame-Options', 'sameorigin', 'X-Hudson', '1.395', 'X-Hudson-CLI-Port', '50000', 'X-Hudson-Theme', 'default', 'X-Instance-Identity', 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhY8RerN8MW+X8D9b4FMQfw3t9M0WAcE2cLagkhJ+EmX3F972ReiMWWdY8l/1BEq2fHvRYuB/WzwdXvGpeWEbj/fXpUU5ny8ezchkdlx0WaP330c7d04FJbTHlVNXhRuPjk+ywvcfcZlXfEiybjglvVH/s0ks1C2YWfG7heYq40ip/qvdev7cT4mVW3IFaz8E2Kx1jhnE6nWa3XtZhO6he1U5iT1jkFqplk/DZ8bYNqOSSvD+AAU2SJKlwKanx2VFY/6QfiyYriqgEzype5tSZn6XXVonhMP/LsT5DbF98Vy0vmKxeDzSvuAp9jOTZyEYQtltjV0tauURNTDtfP/61wIDAQAB', 'X-Jenkins', '2.60.3', 'X-Jenkins-CLI-Port', '50000', 'X-Jenkins-CLI2-Port', '50000', 'X-Jenkins-Session', 'c70f6e5a', 'X-Meta-ROBOTS', 'INDEX,NOFOLLOW', 'X-Meta-Viewport', 'width=device-width, initial-scale=1' ] } }, { 'res' => { 'code' => '200', 'msg' => 'OK', 'content' => '{"_class":"hudson.model.Hudson","assignedLabels":[{}],"mode":"NORMAL","nodeDescription":"the master Jenkins node","nodeName":"","numExecutors":2,"description":null,"jobs":[{"_class":"hudson.model.FreeStyleProject","name":"Test","url":"http://172.17.0.2:8080/job/Test/","color":"notbuilt"},{"_class":"hudson.model.FreeStyleProject","name":"Test-Project","url":"http://172.17.0.2:8080/job/Test-Project/","color":"notbuilt"}],"overallLoad":{},"primaryView":{"_class":"hudson.model.AllView","name":"all","url":"http://172.17.0.2:8080/"},"quietingDown":false,"slaveAgentPort":50000,"unlabeledLoad":{"_class":"jenkins.model.UnlabeledLoadStatistics"},"useCrumbs":true,"useSecurity":true,"views":[{"_class":"hudson.model.ListView","name":"Test","url":"http://172.17.0.2:8080/view/Test/"},{"_class":"hudson.model.AllView","name":"all","url":"http://172.17.0.2:8080/"}]}', 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ] }, 'req' => { 'url' => 'http://172.17.0.2:8080/api/json', 'method' => 'GET', 'content' => '' } }, { 'res' => { 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ], 'content' => '{"_class":"hudson.model.Hudson","jobs":[{"_class":"hudson.model.FreeStyleProject","name":"Test","color":"notbuilt"},{"_class":"hudson.model.FreeStyleProject","name":"Test-Project","color":"notbuilt"}]}', 'msg' => 'OK', 'code' => '200' }, 'req' => { 'content' => '', 'method' => 'GET', 'url' => 'http://172.17.0.2:8080/api/json?tree=jobs%5Bname%2Ccolor%5D' } }, { 'req' => { 'url' => 'http://172.17.0.2:8080/job/Test-Project/api/json?depth=1', 'method' => 'GET', 'content' => '' }, 'res' => { 'content' => '{"_class":"hudson.model.FreeStyleProject","actions":[{},{},{"_class":"com.cloudbees.plugins.credentials.ViewCredentialsAction","stores":{}}],"description":"","displayName":"Test-Project","displayNameOrNull":null,"fullDisplayName":"Test-Project","fullName":"Test-Project","name":"Test-Project","url":"http://172.17.0.2:8080/job/Test-Project/","buildable":true,"builds":[],"color":"notbuilt","firstBuild":null,"healthReport":[],"inQueue":false,"keepDependencies":false,"lastBuild":null,"lastCompletedBuild":null,"lastFailedBuild":null,"lastStableBuild":null,"lastSuccessfulBuild":null,"lastUnstableBuild":null,"lastUnsuccessfulBuild":null,"nextBuildNumber":1,"property":[],"queueItem":null,"concurrentBuild":false,"downstreamProjects":[],"scm":{"_class":"hudson.scm.NullSCM","browser":null,"type":"hudson.scm.NullSCM"},"upstreamProjects":[]}', 'code' => '200', 'msg' => 'OK', 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ] } }, { 'req' => { 'method' => 'GET', 'content' => '', 'url' => 'http://172.17.0.2:8080/queue/api/json' }, 'res' => { 'content' => '{"_class":"hudson.model.Queue","discoverableItems":[],"items":[]}', 'msg' => 'OK', 'code' => '200', 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ] } }, { 'res' => { 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ], 'code' => '200', 'msg' => 'OK', 'content' => '{"_class":"hudson.model.Queue","discoverableItems":[],"items":[]}' }, 'req' => { 'url' => 'http://172.17.0.2:8080/queue/api/json?depth=1', 'content' => '', 'method' => 'GET' } }, { 'req' => { 'url' => 'http://172.17.0.2:8080/overallLoad/api/json', 'content' => '', 'method' => 'GET' }, 'res' => { 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ], 'content' => '{"_class":"hudson.model.OverallLoadStatistics","availableExecutors":{},"busyExecutors":{},"connectingExecutors":{},"definedExecutors":{},"idleExecutors":{},"onlineExecutors":{},"queueLength":{},"totalExecutors":{},"totalQueueLength":{}}', 'msg' => 'OK', 'code' => '200' } }, { 'res' => { 'msg' => 'OK', 'code' => '200', 'content' => ' false true false false false false ', 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/xml', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff' ] }, 'req' => { 'content' => '', 'method' => 'GET', 'url' => 'http://172.17.0.2:8080/job/Test-Project/config.xml' } }, { 'req' => { 'method' => 'GET', 'content' => '', 'url' => 'http://172.17.0.2:8080/job/Test-Project/api/json' }, 'res' => { 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ], 'content' => '{"_class":"hudson.model.FreeStyleProject","actions":[{},{},{"_class":"com.cloudbees.plugins.credentials.ViewCredentialsAction"}],"description":"","displayName":"Test-Project","displayNameOrNull":null,"fullDisplayName":"Test-Project","fullName":"Test-Project","name":"Test-Project","url":"http://172.17.0.2:8080/job/Test-Project/","buildable":true,"builds":[],"color":"notbuilt","firstBuild":null,"healthReport":[],"inQueue":false,"keepDependencies":false,"lastBuild":null,"lastCompletedBuild":null,"lastFailedBuild":null,"lastStableBuild":null,"lastSuccessfulBuild":null,"lastUnstableBuild":null,"lastUnsuccessfulBuild":null,"nextBuildNumber":1,"property":[],"queueItem":null,"concurrentBuild":false,"downstreamProjects":[],"scm":{"_class":"hudson.scm.NullSCM"},"upstreamProjects":[]}', 'msg' => 'OK', 'code' => '200' } }, { 'res' => { 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ], 'msg' => 'OK', 'code' => '200', 'content' => '{"_class":"hudson.model.FreeStyleProject","healthReport":[]}' }, 'req' => { 'url' => 'http://172.17.0.2:8080/job/Test-Project/api/json?tree=healthReport', 'content' => '', 'method' => 'GET' } }, { 'res' => { 'content' => '{"_class":"hudson.model.ListView","description":null,"jobs":[],"name":"Test","property":[],"url":"http://172.17.0.2:8080/view/Test/"}', 'code' => '200', 'msg' => 'OK', 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ] }, 'req' => { 'url' => 'http://172.17.0.2:8080/view/Test/api/json', 'method' => 'GET', 'content' => '' } }, { 'req' => { 'url' => 'http://172.17.0.2:8080/api/json?tree=views%5Bname%5D', 'method' => 'GET', 'content' => '' }, 'res' => { 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ], 'content' => '{"_class":"hudson.model.Hudson","views":[{"_class":"hudson.model.ListView","name":"Test"},{"_class":"hudson.model.AllView","name":"all"}]}', 'code' => '200', 'msg' => 'OK' } }, { 'res' => { 'content' => '{"_class":"hudson.model.ListView","jobs":[]}', 'msg' => 'OK', 'code' => '200', 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ] }, 'req' => { 'content' => '', 'method' => 'GET', 'url' => 'http://172.17.0.2:8080/view/Test/api/json?tree=jobs%5Bname%2Ccolor%5D' } }, { 'res' => { 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ], 'content' => '{"_class":"hudson.model.AllView","jobs":[{"_class":"hudson.model.FreeStyleProject","name":"Test","color":"notbuilt"},{"_class":"hudson.model.FreeStyleProject","name":"Test-Project","color":"notbuilt"}]}', 'code' => '200', 'msg' => 'OK' }, 'req' => { 'url' => 'http://172.17.0.2:8080/view/all/api/json?tree=jobs%5Bname%2Ccolor%5D', 'content' => '', 'method' => 'GET' } }, { 'req' => { 'url' => 'http://172.17.0.2:8080/job/Test/api/json?tree=color%2Cdescription', 'method' => 'GET', 'content' => '' }, 'res' => { 'headers' => [ 'Connection', 'close', 'Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Server', 'Jetty(9.2.z-SNAPSHOT)', 'Content-Type', 'application/json;charset=UTF-8', 'Client-Date', 'Tue, 26 Sep 2017 18:02:40 GMT', 'Client-Peer', '172.17.0.2:8080', 'Client-Response-Num', 1, 'X-Content-Type-Options', 'nosniff', 'X-Jenkins', '2.60.3', 'X-Jenkins-Session', 'c70f6e5a' ], 'msg' => 'OK', 'code' => '200', 'content' => '{"_class":"hudson.model.FreeStyleProject","description":null,"color":"notbuilt"}' } } ]; $mock_client = mock 'REST::Client' => ( override => [ request => sub { my $self = shift; my $req = shift @$fake_responses; my $res = $req->{res}; # FIXME: check request looks sane $self->{_res} = HTTP::Response->new( $res->{code}, $res->{msg}, $res->{headers}, $res->{content} ); return $self; } ] ); }