require 'spec_helper' describe "DynportTools::Jenkins" do let(:url) { "http://some.url.com:8098" } let(:jenkins) { DynportTools::Jenkins.new(url) } before(:each) do Typhoeus::Request.stub!(:post).and_return nil end describe "RemoteProject" do let(:remote_project) do xml = File.read(root.join("spec/fixtures/jenkins_job.xml")) remote_project = DynportTools::Jenkins::RemoteProject.new(:xml => xml) remote_project end it "can be initialized" do DynportTools::Jenkins::RemoteProject.new(:url => "some/url", :name => "Some Name", :rgne => "true").should return_values(:url => "some/url", :name => "Some Name" ) end it "returns the correct " do remote_project.commands.should == [%(ssh some.host \"touch /some/path/running.pid\")] end it "returns an empty array when no commands found" do DynportTools::Jenkins::RemoteProject.new(:url => "some/url", :name => "Some Name", :xml => "").commands.should be_empty end it "returns the correct crontab_patterns" do remote_project.crontab_patterns.should == ["0 4 * * *"] end it "returns the correct childProjects" do remote_project.child_projects.should == ["Project 2", "Project 6", "Prohect 9"] end it "returns the correct locks" do remote_project.locks.should == %w(Import) end it "returns the correct md5" do remote_project.stub!(:xml).and_return "some xml" remote_project.md5.should == "53bdfcda073f189a71901011123abf9a" end describe "logrotate" do it "returns the correct amount of days_to_keep" do remote_project.days_to_keep.should == 7 end it "returns nil when days_to_keep == -1" do DynportTools::Jenkins::RemoteProject.new(:xml => "-1").days_to_keep.should be_nil end it "returns nil for num_to_keep when -1" do remote_project.num_to_keep.should be_nil end it "returns the correct value for num_to_keep when set" do DynportTools::Jenkins::RemoteProject.new(:xml => "20").num_to_keep.should == 20 end end it "returns the correct disabled status" do remote_project.should be_disabled end it "returns the correct email_addresses" do remote_project.email_addresses.should == %w(test@test.xx) end it "returns false when not disabled" do DynportTools::Jenkins::RemoteProject.new(:xml => "false").should_not be_disabled end it "extracts the correct node" do remote_project.node.should == "Import" end describe "#with nothing found" do let(:empty_remote_project) { DynportTools::Jenkins::RemoteProject.new(:xml => "") } [:child_projects, :commands, :crontab_patterns, :locks].each do |method| it "returns an empty array for #{method}" do empty_remote_project.send(method).should == [] end end end end describe "Project" do let(:job) { DynportTools::Jenkins::Project.new("Some Name") } let(:doc) { Nokogiri::XML(job.to_xml) } describe "#initialize" do it "sets the commands to an empty array" do job.commands.should == [] end it "sets the commands to an empty array" do job.child_projects.should == [] end it "sets the commands to an empty array" do job.locks.should == [] end it "sets the email addresses to an empty array" do job.email_addresses.should == [] end it "sets the name" do job.name.should == "Some Name" end end describe "#to_xml" do it "returns a string" do job.to_xml.should be_kind_of(String) end it "includes a xml header line" do job.to_xml.should include(%()) end it "includes a project root" do job.to_xml.should include("") job.to_xml.should include("") end %w(actions description properties publishers buildWrappers).each do |key| it "includes an empty node #{key}" do doc.at("/project/#{key}").children.should be_empty end end it "adds a git entry when git is set" do job.git_repository = "git@github.com:dynport/dynport_tools.git" job.to_xml.should include(%(scm class="hudson.plugins.git.GitSCM">)) end it "sets the correct email_addresses when present" do job.email_addresses = %w(test@test.xx test2@test.xx) doc.xpath("/project/publishers/hudson.tasks.Mailer/recipients").map(&:inner_text).should == ["test@test.xx,test2@test.xx"] doc.at("/project/publishers/hudson.tasks.Mailer/dontNotifyEveryUnstableBuild").inner_text.should == "true" doc.at("/project/publishers/hudson.tasks.Mailer/sendToIndividuals").inner_text.should == "false" end { "keepDependencies" => "false", "canRoam" => "true", "disabled" => "false", "blockBuildWhenDownstreamBuilding" => "false", "blockBuildWhenUpstreamBuilding" => "false", "concurrentBuild" => "false" }.each do |key, value| it "sets #{key} to #{value}" do doc.at("/project/#{key}").inner_text.should == value end end it "sets disabled to true when set" do job.disabled = true doc.at("/project/disabled").inner_text.should == "true" end { "scm" => "hudson.scm.NullSCM", "triggers" => "vector" }.each do |key, clazz| it "sets the class of #{key} to #{clazz}" do doc.at("/project/#{key}")["class"].should == clazz end end it "includes all set commands" do job.commands << "hostname" job.commands << "date" shell_tasks = doc.search("project/builders/*") shell_tasks.map(&:name).should == ["hudson.tasks.Shell", "hudson.tasks.Shell"] shell_tasks.map { |node| node.at("command").inner_text }.should == ["hostname", "date"] end it "includes crontab like triggers" do pattern = "0 2 * * *" job.crontab_pattern = pattern triggers = doc.search("project/triggers/*") triggers.map(&:name).should == ["hudson.triggers.TimerTrigger"] triggers.first.at("spec").inner_text.should == "0 2 * * *" end %w(logRotator assignedNode).each do |key| it "does not include a #{key} node by default" do doc.at("/project/#{key}").should be_nil end end it "sets assignedNode when node is set" do job.node = "processor" doc.at("/project/assignedNode").inner_text.should == "processor" doc.at("/project/canRoam").inner_text.should == "false" end it "allows setting a description" do job.description = "some description" doc.at("/project/description").inner_text.should == "some description" end it "returns the correct md5" do job.stub(:to_xml).and_return "some test" job.md5.should == "f1b75ac7689ff88e1ecc40c84b115785" end describe "with days_to_keep set" do before(:each) do job.days_to_keep = 7 end it "sets days_to_keep to 7" do doc.at("/project/logRotator/daysToKeep").inner_text.should == "7" end %w(numToKeep artifactDaysToKeep artifactNumToKeep).each do |key| it "sets #{key} to -1" do doc.at("/project/logRotator/#{key}").inner_text.should == "-1" end end end describe "with num_to_keep set" do before(:each) do job.num_to_keep = 30 end it "sets num_to_keep to 30" do doc.at("/project/logRotator/numToKeep").inner_text.should == "30" end %w(daysToKeep artifactDaysToKeep artifactNumToKeep).each do |key| it "sets #{key} to -1" do doc.at("/project/logRotator/#{key}").inner_text.should == "-1" end end end it "sets numToKeep and daysToKeep when both set" do job.num_to_keep = 10 job.days_to_keep = 2 doc.at("/project/logRotator/numToKeep").inner_text.should == "10" doc.at("/project/logRotator/daysToKeep").inner_text.should == "2" end describe "with child projects" do let(:child1) { DynportTools::Jenkins::Project.new("child 1") } let(:child2) { DynportTools::Jenkins::Project.new("child 2") } let(:triggers) { doc.xpath("/project/publishers/hudson.tasks.BuildTrigger") } before(:each) do job.child_projects << child2 job.child_projects << child1 end it "includes all child projects" do triggers.count.should == 1 triggers.first.at("childProjects").inner_text.should == "child 2,child 1" end { "name" => "SUCCESS", "ordinal" => "0", "color" => "BLUE" }.each do |key, value| it "sets #{key} to #{value} in threshold" do triggers.first.at("threshold/#{key}").inner_text.should == value end end end describe "#with locks" do let(:locks) { doc.xpath("/project/buildWrappers/hudson.plugins.locksandlatches.LockWrapper/locks/hudson.plugins.locksandlatches.LockWrapper_-LockWaitConfig") } before(:each) do job.locks << "exclusive3" job.locks << "exclusive2" end it "sets the correct amount of locks" do locks.count.should == 2 end it "sets the correct locks" do locks.map { |l| l.at("name").inner_text }.should == %w(exclusive3 exclusive2) end end end end describe "#initialize" do it "sets the root url" do DynportTools::Jenkins.new("some/host").url.should == "some/host" end end describe "#post_request" do it "clears the local cache" do jenkins.instance_variable_set("@cache", { :a => 1 }) jenkins.post_request("some/path") jenkins.instance_variable_get("@cache").should == {} end end describe "#projects_hash" do let(:body) do html =<<-HTML NORMAL the master Hudson node 5 Job 2 http://hudson.host:8080/job/Job2/ blue Job 1 http://hudson.host:8080/job/Job1/ blue HTML end let(:response) { double("response", :body => body).as_null_object } before(:each) do Typhoeus::Request.stub(:get).and_return response end it "fetches the correct url" do Typhoeus::Request.should_receive(:get).with("http://some.url.com:8098/api/xml") jenkins.projects_hash end it "returns the correct projects_hash" do jobs = jenkins.projects_hash jobs["http://hudson.host:8080/job/Job1/"].should == { :url => "http://hudson.host:8080/job/Job1/", :name => "Job 1"} jobs["http://hudson.host:8080/job/Job2/"].should == { :url => "http://hudson.host:8080/job/Job2/", :name => "Job 2"} end end it "sends the correct Typhoeus request when creating a project" do xml = "some_xml" Typhoeus::Request.should_receive(:post).with("http://some.url.com:8098/createItem?name=Test%20Job", :headers => { "Content-Type" => "application/xml" }, :body => "some_xml" ) jenkins.create_project("Test Job", xml) end it "sends the correct request when updating a project" do xml = "some_update" Typhoeus::Request.should_receive(:post).with("http://some.url.com:8098/job/Test%20Job/config.xml", :headers => { "Content-Type" => "application/xml" }, :body => "some_update" ) jenkins.update_project("Test Job", xml) end { :delete_project => "doDelete", :build_project => "build", :disable_project => "disable", :enable_project => "enable" }.each do |method, action| it "posts to the correct url when calling #{action}" do Typhoeus::Request.should_receive(:post).with("http://some.url.com:8098/job/Test%20Job/#{action}") jenkins.send(method, "Test Job") end end describe "#project_details" do before(:each) do jenkins.stub!(:projects_hash).and_return( "http://hudson.host:8080/job/Job1/" => { :url => "http://hudson.host:8080/job/Job1/", :name => "Job 1"}, "http://hudson.host:8080/job/Job2/" => { :url => "http://hudson.host:8080/job/Job2/", :name => "Job 2"} ) end it "returns a hash with the correct job details and normalizes with nokogiri" do response1 = Typhoeus::Response.new(:code => 200, :headers => "", :body => "test1") response2 = Typhoeus::Response.new(:code => 200, :headers => "", :body => "test2") jenkins.hydra.stub(:get, "http://hudson.host:8080/job/Job1/config.xml").and_return(response1) jenkins.hydra.stub(:get, "http://hudson.host:8080/job/Job2/config.xml").and_return(response2) details = jenkins.project_details details.should be_an_instance_of(Hash) details["http://hudson.host:8080/job/Job2/"].should == { :body=>"\n\n test2\n \n\n", :md5=>"b52105fcdd28fe6428df019e121f106a", :name=>"Job 2", :url=>"http://hudson.host:8080/job/Job2/" } details["http://hudson.host:8080/job/Job1/"].should == { :body=>"\n\n test1\n \n\n", :md5=>"14fa3890bea86820f7e45ce7f5a3ada4", :name=>"Job 1", :url=>"http://hudson.host:8080/job/Job1/" } end end describe "#remote_projects" do before(:each) do jenkins.stub(:project_details).and_return({}) end it "calls project_details" do jenkins.should_receive(:project_details).and_return({}) jenkins.remote_projects end it "returns a hash" do jenkins.remote_projects.should be_kind_of(Hash) end it "sets RemoteProject as values for hash" do jenkins.should_receive(:project_details).and_return( "url1" => { :name => "Project 1", :body => "some xml", :url => "url1" }, "url2" => { :name => "Project 2", :body => "some other xml", :url => "url2" } ) remote_projects = jenkins.remote_projects remote_projects.values.map(&:class).should == [DynportTools::Jenkins::RemoteProject, DynportTools::Jenkins::RemoteProject] remote_projects["Project 1"].should return_values(:url => "url1", :name => "Project 1", :xml => "some xml") end end end