More service layer functionality, builds now. Also some extra tests for projects and build models.

This commit is contained in:
Dan Cryer 2014-07-14 16:02:36 +01:00
parent 9a51a1458e
commit 3fd1bc2a36
9 changed files with 602 additions and 42 deletions

View file

@ -13,6 +13,7 @@ use b8;
use b8\Exception\HttpException\NotFoundException;
use PHPCI\BuildFactory;
use PHPCI\Model\Build;
use PHPCI\Service\BuildService;
/**
* Build Controller - Allows users to run and view builds.
@ -26,10 +27,16 @@ class BuildController extends \PHPCI\Controller
* @var \PHPCI\Store\BuildStore
*/
protected $buildStore;
/**
* @var \PHPCI\Service\BuildService
*/
protected $buildService;
public function init()
{
$this->buildStore = b8\Store\Factory::getStore('Build');
$this->buildStore = b8\Store\Factory::getStore('Build');
$this->buildService = new BuildService($this->buildStore);
}
/**
@ -123,17 +130,7 @@ class BuildController extends \PHPCI\Controller
throw new NotFoundException('Build with ID: ' . $buildId . ' does not exist.');
}
$build = new Build();
$build->setProjectId($copy->getProjectId());
$build->setCommitId($copy->getCommitId());
$build->setStatus(Build::STATUS_NEW);
$build->setBranch($copy->getBranch());
$build->setCreated(new \DateTime());
$build->setCommitterEmail($copy->getCommitterEmail());
$build->setCommitMessage($copy->getCommitMessage());
$build->setExtra(json_encode($copy->getExtra()));
$build = $this->buildStore->save($build);
$build = $this->buildService->createDuplicateBuild($copy);
header('Location: '.PHPCI_URL.'build/view/' . $build->getId());
exit;
@ -154,7 +151,7 @@ class BuildController extends \PHPCI\Controller
throw new NotFoundException('Build with ID: ' . $buildId . ' does not exist.');
}
$this->buildStore->delete($build);
$this->buildService->delete($build);
header('Location: '.PHPCI_URL.'project/view/' . $build->getProjectId());
exit;

View file

@ -20,6 +20,7 @@ use PHPCI\Helper\Github;
use PHPCI\Helper\SshKey;
use PHPCI\Model\Build;
use PHPCI\Model\Project;
use PHPCI\Service\BuildService;
use PHPCI\Service\ProjectService;
/**
@ -30,11 +31,6 @@ use PHPCI\Service\ProjectService;
*/
class ProjectController extends \PHPCI\Controller
{
/**
* @var \PHPCI\Store\BuildStore
*/
protected $buildStore;
/**
* @var \PHPCI\Store\ProjectStore
*/
@ -45,11 +41,22 @@ class ProjectController extends \PHPCI\Controller
*/
protected $projectService;
/**
* @var \PHPCI\Store\BuildStore
*/
protected $buildStore;
/**
* @var \PHPCI\Service\BuildService
*/
protected $buildService;
public function init()
{
$this->buildStore = Store\Factory::getStore('Build');
$this->projectStore = Store\Factory::getStore('Project');
$this->projectService = new ProjectService($this->projectStore);
$this->buildService = new BuildService($this->buildStore);
}
/**
@ -95,15 +102,7 @@ class ProjectController extends \PHPCI\Controller
throw new NotFoundException('Project with id: ' . $projectId . ' not found');
}
$build = new Build();
$build->setProjectId($projectId);
$build->setCommitId('Manual');
$build->setStatus(Build::STATUS_NEW);
$build->setBranch($project->getBranch());
$build->setCreated(new \DateTime());
$build->setCommitterEmail($_SESSION['user']->getEmail());
$build = $this->buildStore->save($build);
$build = $this->buildService->createBuild($project, null, null, $_SESSION['user']->getEmail());
header('Location: '.PHPCI_URL.'build/view/' . $build->getId());
exit;

View file

@ -45,6 +45,8 @@ class BuildBase extends Model
'committer_email' => null,
'commit_message' => null,
'extra' => null,
'parent_id' => null,
'engine' => null,
);
/**
@ -64,9 +66,12 @@ class BuildBase extends Model
'committer_email' => 'getCommitterEmail',
'commit_message' => 'getCommitMessage',
'extra' => 'getExtra',
'parent_id' => 'getParentId',
'engine' => 'getEngine',
// Foreign key getters:
'Project' => 'getProject',
'Parent' => 'getParent',
);
/**
@ -86,9 +91,12 @@ class BuildBase extends Model
'committer_email' => 'setCommitterEmail',
'commit_message' => 'setCommitMessage',
'extra' => 'setExtra',
'parent_id' => 'setParentId',
'engine' => 'setEngine',
// Foreign key setters:
'Project' => 'setProject',
'Parent' => 'setParent',
);
/**
@ -159,6 +167,18 @@ class BuildBase extends Model
'nullable' => true,
'default' => null,
),
'parent_id' => array(
'type' => 'int',
'length' => 11,
'nullable' => true,
'default' => null,
),
'engine' => array(
'type' => 'varchar',
'length' => 50,
'nullable' => true,
'default' => null,
),
);
/**
@ -168,6 +188,7 @@ class BuildBase extends Model
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'project_id' => array('columns' => 'project_id'),
'idx_status' => array('columns' => 'status'),
'parent_id' => array('columns' => 'parent_id'),
);
/**
@ -181,6 +202,13 @@ class BuildBase extends Model
'table' => 'project',
'col' => 'id'
),
'build_ibfk_2' => array(
'local_col' => 'parent_id',
'update' => 'CASCADE',
'delete' => 'CASCADE',
'table' => 'build',
'col' => 'id'
),
);
/**
@ -339,6 +367,30 @@ class BuildBase extends Model
return $rtn;
}
/**
* Get the value of ParentId / parent_id.
*
* @return int
*/
public function getParentId()
{
$rtn = $this->data['parent_id'];
return $rtn;
}
/**
* Get the value of Engine / engine.
*
* @return string
*/
public function getEngine()
{
$rtn = $this->data['engine'];
return $rtn;
}
/**
* Set the value of Id / id.
*
@ -563,6 +615,42 @@ class BuildBase extends Model
$this->_setModified('extra');
}
/**
* Set the value of ParentId / parent_id.
*
* @param $value int
*/
public function setParentId($value)
{
$this->_validateInt('ParentId', $value);
if ($this->data['parent_id'] === $value) {
return;
}
$this->data['parent_id'] = $value;
$this->_setModified('parent_id');
}
/**
* Set the value of Engine / engine.
*
* @param $value string
*/
public function setEngine($value)
{
$this->_validateString('Engine', $value);
if ($this->data['engine'] === $value) {
return;
}
$this->data['engine'] = $value;
$this->_setModified('engine');
}
/**
* Get the Project model for this Build by Id.
*
@ -620,6 +708,75 @@ class BuildBase extends Model
return $this->setProjectId($value->getId());
}
/**
* Get the Build model for this Build by Id.
*
* @uses \PHPCI\Store\BuildStore::getById()
* @uses \PHPCI\Model\Build
* @return \PHPCI\Model\Build
*/
public function getParent()
{
$key = $this->getParentId();
if (empty($key)) {
return null;
}
$cacheKey = 'Cache.Build.' . $key;
$rtn = $this->cache->get($cacheKey, null);
if (empty($rtn)) {
$rtn = Factory::getStore('Build', 'PHPCI')->getById($key);
$this->cache->set($cacheKey, $rtn);
}
return $rtn;
}
/**
* Set Parent - Accepts an ID, an array representing a Build or a Build model.
*
* @param $value mixed
*/
public function setParent($value)
{
// Is this an instance of Build?
if ($value instanceof \PHPCI\Model\Build) {
return $this->setParentObject($value);
}
// Is this an array representing a Build item?
if (is_array($value) && !empty($value['id'])) {
return $this->setParentId($value['id']);
}
// Is this a scalar value representing the ID of this foreign key?
return $this->setParentId($value);
}
/**
* Set Parent - Accepts a Build model.
*
* @param $value \PHPCI\Model\Build
*/
public function setParentObject(\PHPCI\Model\Build $value)
{
return $this->setParentId($value->getId());
}
/**
* Get Build models by ParentId for this Build.
*
* @uses \PHPCI\Store\BuildStore::getByParentId()
* @uses \PHPCI\Model\Build
* @return \PHPCI\Model\Build[]
*/
public function getParentBuilds()
{
return Factory::getStore('Build', 'PHPCI')->getByParentId($this->getId());
}
/**
* Get BuildMeta models by BuildId for this Build.
*

View file

@ -38,15 +38,6 @@ class Build extends BuildBase
return '#';
}
/**
* @return string
*/
public function getProjectTitle()
{
$project = $this->getProject();
return $project ? $project->getTitle() : "";
}
/**
* Get link to branch from another source (i.e. Github)
*/
@ -55,6 +46,11 @@ class Build extends BuildBase
return '#';
}
public function getFileLinkTemplate()
{
return null;
}
/**
* Send status updates to any relevant third parties (i.e. Github)
*/
@ -63,6 +59,15 @@ class Build extends BuildBase
return;
}
/**
* @return string
*/
public function getProjectTitle()
{
$project = $this->getProject();
return $project ? $project->getTitle() : "";
}
/**
* Store build metadata
*/
@ -160,11 +165,6 @@ class Build extends BuildBase
return $config;
}
public function getFileLinkTemplate()
{
return null;
}
public function getExtra($key = null)
{
$data = json_decode($this->data['extra'], true);

View file

@ -0,0 +1,112 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Service;
use PHPCI\Model\Build;
use PHPCI\Model\Project;
use PHPCI\Store\BuildStore;
class BuildService
{
/**
* @var \PHPCI\Store\BuildStore
*/
protected $buildStore;
/**
* @param BuildStore $buildStore
*/
public function __construct(BuildStore $buildStore)
{
$this->buildStore = $buildStore;
}
/**
* @param Project $project
* @param string|null $commitId
* @param string|null $branch
* @param string|null $committerEmail
* @param string|null $commitMessage
* @param string|null $extra
* @return \PHPCI\Model\Build
*/
public function createBuild(
Project $project,
$commitId = null,
$branch = null,
$committerEmail = null,
$commitMessage = null,
$extra = null
)
{
$build = new Build();
$build->setCreated(new \DateTime());
$build->setProject($project);
$build->setStatus(0);
if (!is_null($commitId)) {
$build->setCommitId($commitId);
} else {
$build->setCommitId('Manual');
}
if (!is_null($branch)) {
$build->setBranch($branch);
} else {
$build->setBranch($project->getBranch());
}
if (!is_null($committerEmail)) {
$build->setCommitterEmail($committerEmail);
}
if (!is_null($commitMessage)) {
$build->setCommitMessage($commitMessage);
}
if (!is_null($extra)) {
$build->setExtra(json_encode($extra));
}
return $this->buildStore->save($build);
}
/**
* @param Build $copyFrom
* @return \PHPCI\Model\Build
*/
public function createDuplicateBuild(Build $copyFrom)
{
$data = $copyFrom->getDataArray();
// Clean up unwanted properties from the original build:
unset($data['id']);
unset($data['status']);
unset($data['log']);
unset($data['started']);
unset($data['finished']);
$build = new Build();
$build->setValues($data);
$build->setCreated(new \DateTime());
return $this->buildStore->save($build);
}
/**
* Delete a given build.
* @param Build $build
* @return bool
*/
public function deleteBuild(Build $build)
{
return $this->buildStore->delete($build);
}
}

View file

@ -107,4 +107,36 @@ class BuildStoreBase extends Store
return array('items' => array(), 'count' => 0);
}
}
public function getByParentId($value, $limit = null, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$add = '';
if ($limit) {
$add .= ' LIMIT ' . $limit;
}
$count = null;
$query = 'SELECT * FROM `build` WHERE `parent_id` = :parent_id' . $add;
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':parent_id', $value);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new Build($item);
};
$rtn = array_map($map, $res);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);
}
}
}

View file

@ -0,0 +1,84 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
namespace PHPCI\Model\Tests;
use PHPCI\Model\Build;
use PHPCI\Model;
/**
* Unit tests for the Build model class.
* @author Dan Cryer <dan@block8.co.uk>
*/
class BuildTest extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_TestIsAValidModel()
{
$build = new Build();
$this->assertTrue($build instanceof \b8\Model);
$this->assertTrue($build instanceof Model);
$this->assertTrue($build instanceof Model\Base\BuildBase);
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_TestBaseBuildDefaults()
{
$build = new Build();
$this->assertEquals('#', $build->getCommitLink());
$this->assertEquals('#', $build->getBranchLink());
$this->assertEquals(null, $build->getFileLinkTemplate());
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_TestIsSuccessful()
{
$build = new Build();
$build->setStatus(Build::STATUS_NEW);
$this->assertFalse($build->isSuccessful());
$build->setStatus(Build::STATUS_RUNNING);
$this->assertFalse($build->isSuccessful());
$build->setStatus(Build::STATUS_FAILED);
$this->assertFalse($build->isSuccessful());
$build->setStatus(Build::STATUS_SUCCESS);
$this->assertTrue($build->isSuccessful());
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_TestBuildExtra()
{
$info = array(
'item1' => 'Item One',
'item2' => 2,
);
$build = new Build();
$build->setExtra(json_encode($info));
$this->assertEquals('Item One', $build->getExtra('item1'));
$this->assertEquals(2, $build->getExtra('item2'));
$this->assertNull($build->getExtra('item3'));
$this->assertEquals($info, $build->getExtra());
}
}

View file

@ -10,9 +10,10 @@
namespace PHPCI\Model\Tests;
use PHPCI\Model\Project;
use PHPCI\Model;
/**
* Unit tests for the ProjectService class.
* Unit tests for the Project model class.
* @author Dan Cryer <dan@block8.co.uk>
*/
class ProjectTest extends \PHPUnit_Framework_TestCase
@ -21,6 +22,17 @@ class ProjectTest extends \PHPUnit_Framework_TestCase
{
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_TestIsAValidModel()
{
$project = new Project();
$this->assertTrue($project instanceof \b8\Model);
$this->assertTrue($project instanceof Model);
$this->assertTrue($project instanceof Model\Base\ProjectBase);
}
/**
* @covers PHPUnit::execute
*/
@ -75,4 +87,23 @@ class ProjectTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('default', $project->getBranch());
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_TestProjectAccessInformation()
{
$info = array(
'item1' => 'Item One',
'item2' => 2,
);
$project = new Project();
$project->setAccessInformation(serialize($info));
$this->assertEquals('Item One', $project->getAccessInformation('item1'));
$this->assertEquals(2, $project->getAccessInformation('item2'));
$this->assertNull($project->getAccessInformation('item3'));
$this->assertEquals($info, $project->getAccessInformation());
}
}

View file

@ -0,0 +1,148 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
namespace PHPCI\Service\Tests;
use PHPCI\Model\Build;
use PHPCI\Model\Project;
use PHPCI\Service\BuildService;
/**
* Unit tests for the ProjectService class.
* @author Dan Cryer <dan@block8.co.uk>
*/
class BuildServiceTest extends \PHPUnit_Framework_TestCase
{
/**
* @var BuildService $testedService
*/
protected $testedService;
/**
* @var \ $mockBuildStore
*/
protected $mockBuildStore;
public function setUp()
{
$this->mockBuildStore = $this->getMock('PHPCI\Store\BuildStore');
$this->mockBuildStore->expects($this->any())
->method('save')
->will($this->returnArgument(0));
$this->testedService = new BuildService($this->mockBuildStore);
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_CreateBasicBuild()
{
$project = new Project();
$project->setType('github');
$project->setId(101);
$returnValue = $this->testedService->createBuild($project);
$this->assertEquals(101, $returnValue->getProjectId());
$this->assertEquals(Build::STATUS_NEW, $returnValue->getStatus());
$this->assertNull($returnValue->getStarted());
$this->assertNull($returnValue->getFinished());
$this->assertNull($returnValue->getLog());
$this->assertNull($returnValue->getCommitMessage());
$this->assertNull($returnValue->getCommitterEmail());
$this->assertNull($returnValue->getExtra());
$this->assertEquals('master', $returnValue->getBranch());
$this->assertInstanceOf('DateTime', $returnValue->getCreated());
$this->assertEquals('Manual', $returnValue->getCommitId());
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_CreateBuildWithOptions()
{
$project = new Project();
$project->setType('hg');
$project->setId(101);
$returnValue = $this->testedService->createBuild($project, '123', 'testbranch', 'test@example.com', 'test');
$this->assertEquals('testbranch', $returnValue->getBranch());
$this->assertEquals('123', $returnValue->getCommitId());
$this->assertEquals('test', $returnValue->getCommitMessage());
$this->assertEquals('test@example.com', $returnValue->getCommitterEmail());
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_CreateBuildWithExtra()
{
$project = new Project();
$project->setType('bitbucket');
$project->setId(101);
$returnValue = $this->testedService->createBuild($project, null, null, null, null, array('item1' => 1001));
$this->assertEquals(1001, $returnValue->getExtra('item1'));
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_CreateDuplicateBuild()
{
$build = new Build();
$build->setId(1);
$build->setProjectId(101);
$build->setCommitId('abcde');
$build->setStatus(Build::STATUS_FAILED);
$build->setLog('Test');
$build->setBranch('example_branch');
$build->setStarted(new \DateTime());
$build->setFinished(new \DateTime());
$build->setCommitMessage('test');
$build->setCommitterEmail('test@example.com');
$build->setExtra(json_encode(array('item1' => 1001)));
$returnValue = $this->testedService->createDuplicateBuild($build);
$this->assertNotEquals($build->getId(), $returnValue->getId());
$this->assertEquals($build->getProjectId(), $returnValue->getProjectId());
$this->assertEquals($build->getCommitId(), $returnValue->getCommitId());
$this->assertNotEquals($build->getStatus(), $returnValue->getStatus());
$this->assertEquals(Build::STATUS_NEW, $returnValue->getStatus());
$this->assertNull($returnValue->getLog());
$this->assertEquals($build->getBranch(), $returnValue->getBranch());
$this->assertNotEquals($build->getCreated(), $returnValue->getCreated());
$this->assertNull($returnValue->getStarted());
$this->assertNull($returnValue->getFinished());
$this->assertEquals('test', $returnValue->getCommitMessage());
$this->assertEquals('test@example.com', $returnValue->getCommitterEmail());
$this->assertEquals($build->getExtra('item1'), $returnValue->getExtra('item1'));
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_DeleteBuild()
{
$store = $this->getMock('PHPCI\Store\BuildStore');
$store->expects($this->once())
->method('delete')
->will($this->returnValue(true));
$service = new BuildService($store);
$build = new Build();
$this->assertEquals(true, $service->deleteBuild($build));
}
}