New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Adds machine token commands for 1.0 #1182
Changes from 4 commits
a264d57
8d10b09
dcd8f6b
18f73eb
005e173
db59595
1df3b87
f93a411
609f3ed
f76a18e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
namespace Pantheon\Terminus\Commands\MachineToken; | ||
|
||
use Pantheon\Terminus\Commands\TerminusCommand; | ||
use Terminus\Exceptions\TerminusException; | ||
|
||
class DeleteCommand extends TerminusCommand | ||
{ | ||
|
@@ -15,14 +16,27 @@ class DeleteCommand extends TerminusCommand | |
* Removes a machine token from the logged-in user's account | ||
* | ||
* @name machine-token:delete | ||
* @param string $machine_token_id The ID of the machine token to be deleted | ||
* @throws \Terminus\Exceptions\TerminusException | ||
* @aliases mt:delete | ||
* | ||
* @param machine_token_id The ID of the machine token to be deleted | ||
* @usage terminus machine-token:delete <machine_token_id> | ||
* Removes the given machine token from the user's account | ||
*/ | ||
public function delete($machine_token_id) { | ||
$user = $this->session()->getUser(); | ||
|
||
// Find the token. Will throw an exception if it doesn't exist. | ||
$machine_token = $user->machine_tokens->get($machine_token_id); | ||
$name = $machine_token->get('device_name'); | ||
|
||
$this->log()->notice('Deleting {token} ...', ['token' => $name]); | ||
$response = $machine_token->delete(); | ||
if ($response['status_code'] == 200) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should be leaking the response status code out of the model here. I'd rather have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By "break the old stuff" I mean "require a change to the old stuff" I woudn't leave the existing code in a broken state obviously There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This status-code check must've persisted for some time because it's not necessary anymore. We can just remove it. |
||
$this->log()->notice('Deleted {token}!', ['token' => $name]); | ||
} else { | ||
throw new TerminusException('There was an problem deleting the machine token.'); | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ | |
namespace Pantheon\Terminus\Commands\MachineToken; | ||
|
||
use Pantheon\Terminus\Commands\TerminusCommand; | ||
use Consolidation\OutputFormatters\StructuredData\RowsOfFields; | ||
|
||
|
||
class ListCommand extends TerminusCommand | ||
{ | ||
|
@@ -19,9 +21,27 @@ class ListCommand extends TerminusCommand | |
* | ||
* @usage terminus machine-token:list | ||
* Lists your user's machine tokens | ||
* | ||
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields | ||
*/ | ||
public function listTokens() { | ||
public function listTokens($options = ['format' => 'table', 'fields' => '']) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
$user = $this->session()->getUser(); | ||
|
||
$machine_tokens = $user->machine_tokens->all(); | ||
$data = array(); | ||
foreach ($machine_tokens as $id => $machine_token) { | ||
$data[] = array( | ||
'id' => $machine_token->id, | ||
'device_name' => $machine_token->get('device_name'), | ||
); | ||
} | ||
|
||
if (count($data) == 0) { | ||
$this->log()->warning('You have no machine tokens.'); | ||
} | ||
|
||
// Return the output data. | ||
return new RowsOfFields($data); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yay! |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
Feature: Machine tokens command | ||
In order to manage my devices | ||
As a user | ||
I need to be able to view and delete my machine tokens. | ||
|
||
Background: I am logged in | ||
Given I am authenticated | ||
|
||
@vcr machine-tokens_list | ||
Scenario: List the machine tokens | ||
When I run "terminus machine-token:list" | ||
Then I should get: | ||
""" | ||
[[machine_token_id]] | ||
""" | ||
|
||
@vcr machine-tokens_delete | ||
Scenario: Delete machine token | ||
When I run "terminus machine-token:delete [[machine_token_id]]" | ||
Then I should get: | ||
""" | ||
Deleted [[machine_token_device]]! | ||
""" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
/** | ||
* @file | ||
* Contains Pantheon\Terminus\UnitTests\Commands\Auth\MachineTokenCommandTest | ||
*/ | ||
|
||
|
||
namespace Pantheon\Terminus\UnitTests\Commands\Auth; | ||
|
||
|
||
use Pantheon\Terminus\Session\Session; | ||
use Psr\Log\NullLogger; | ||
use Terminus\Collections\MachineTokens; | ||
use Terminus\Models\User; | ||
|
||
abstract class MachineTokenCommandTest extends \PHPUnit_Framework_TestCase { | ||
protected $session; | ||
protected $machine_tokens; | ||
protected $user; | ||
protected $logger; | ||
protected $command; | ||
|
||
/** | ||
* Sets up the fixture, for example, open a network connection. | ||
* This method is called before a test is executed. | ||
*/ | ||
protected function setUp() | ||
{ | ||
$this->machine_tokens = $this->getMockBuilder(MachineTokens::class) | ||
->disableOriginalConstructor() | ||
->getMock(); | ||
|
||
$this->user = $this->getMockBuilder(User::class) | ||
->disableOriginalConstructor() | ||
->getMock(); | ||
$this->user->machine_tokens = $this->machine_tokens; | ||
|
||
$this->session = $this->getMockBuilder(Session::class) | ||
->disableOriginalConstructor() | ||
->getMock(); | ||
|
||
$this->session->method('getUser') | ||
->willReturn($this->user); | ||
|
||
$this->logger = $this->getMockBuilder(NullLogger::class) | ||
->setMethods(array('log')) | ||
->getMock(); | ||
|
||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<?php | ||
namespace Pantheon\Terminus\UnitTests\Commands\Auth; | ||
use Pantheon\Terminus\Commands\MachineToken\DeleteCommand; | ||
use Pantheon\Terminus\Config; | ||
use Terminus\Exceptions\TerminusException; | ||
use Terminus\Models\MachineToken; | ||
|
||
/** | ||
* Testing class for Pantheon\Terminus\Commands\Auth\LoginCommand | ||
*/ | ||
class MachineTokenDeleteCommandTest extends MachineTokenCommandTest | ||
{ | ||
|
||
/** | ||
* Sets up the fixture, for example, open a network connection. | ||
* This method is called before a test is executed. | ||
*/ | ||
protected function setUp() | ||
{ | ||
parent::setUp(); | ||
|
||
$this->command = new DeleteCommand(new Config()); | ||
$this->command->setSession($this->session); | ||
$this->command->setLogger($this->logger); | ||
} | ||
|
||
|
||
/** | ||
* Tests the machine-token:delete command. | ||
* | ||
* @return void | ||
*/ | ||
public function testMachineTokenDelete() | ||
{ | ||
$token = $this->getMockBuilder(MachineToken::class) | ||
->disableOriginalConstructor() | ||
->getMock(); | ||
|
||
$token->expects($this->once()) | ||
->method('delete') | ||
->willReturn( | ||
['status_code' => 200] | ||
); | ||
|
||
|
||
$this->machine_tokens->expects($this->once()) | ||
->method('get') | ||
->with($this->equalTo('123')) | ||
->willReturn( | ||
$token | ||
); | ||
|
||
|
||
$this->command->delete('123'); | ||
} | ||
|
||
/** | ||
* Tests the machine-token:delete command when there are no tokens. | ||
* | ||
* @return void | ||
*/ | ||
public function testMachineTokenDeleteNonExistant() | ||
{ | ||
$token = $this->getMockBuilder(MachineToken::class) | ||
->disableOriginalConstructor() | ||
->getMock(); | ||
|
||
$token->expects($this->never()) | ||
->method('delete'); | ||
|
||
$this->machine_tokens->expects($this->once()) | ||
->method('get') | ||
->with($this->equalTo('123')) | ||
->will($this->throwException(new TerminusException)); | ||
|
||
|
||
$this->setExpectedException(TerminusException::class); | ||
|
||
$this->command->delete('123'); | ||
} | ||
|
||
/** | ||
* Tests the machine-token:delete command when the API fails. | ||
* | ||
* @return void | ||
*/ | ||
public function testMachineTokenDeleteAPIFailure() | ||
{ | ||
$token = $this->getMockBuilder(MachineToken::class) | ||
->disableOriginalConstructor() | ||
->getMock(); | ||
|
||
$token->expects($this->once()) | ||
->method('delete') | ||
->willReturn( | ||
['status_code' => 500] | ||
); | ||
|
||
$this->machine_tokens->expects($this->once()) | ||
->method('get') | ||
->with($this->equalTo('123')) | ||
->willReturn( | ||
$token | ||
); | ||
|
||
|
||
$this->setExpectedException(\Exception::class, 'There was an problem deleting the machine token.'); | ||
|
||
$this->command->delete('123'); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
namespace Pantheon\Terminus\UnitTests\Commands\Auth; | ||
use Pantheon\Terminus\Commands\MachineToken\ListCommand; | ||
use Pantheon\Terminus\Config; | ||
use Terminus\Collections\MachineTokens; | ||
use Terminus\Models\MachineToken; | ||
|
||
/** | ||
* Testing class for Pantheon\Terminus\Commands\Auth\LoginCommand | ||
*/ | ||
class MachineTokensListCommandTest extends MachineTokenCommandTest | ||
{ | ||
/** | ||
* Sets up the fixture, for example, open a network connection. | ||
* This method is called before a test is executed. | ||
*/ | ||
protected function setUp() | ||
{ | ||
parent::setUp(); | ||
|
||
$this->command = new ListCommand(new Config()); | ||
$this->command->setSession($this->session); | ||
$this->command->setLogger($this->logger); | ||
} | ||
|
||
/** | ||
* Tests the machine-token:list command when there are no tokens. | ||
* | ||
* @return void | ||
*/ | ||
public function testMachineTokenListEmpty() | ||
{ | ||
$this->machine_tokens->method('all') | ||
->willReturn([]); | ||
|
||
$this->logger->expects($this->once()) | ||
->method('log') | ||
->with($this->equalTo('warning'), $this->equalTo('You have no machine tokens.')); | ||
|
||
$out = $this->command->listTokens(); | ||
$this->assertInstanceOf('Consolidation\OutputFormatters\StructuredData\RowsOfFields', $out); | ||
$this->assertEquals([], $out->getArrayCopy()); | ||
} | ||
|
||
/** | ||
* Tests the machine-token:list command when there are tokens. | ||
* | ||
* @return void | ||
*/ | ||
public function testMachineTokenListNotEmpty() | ||
{ | ||
$tokens = [ | ||
['id' => '1', 'device_name' => 'Foo'], | ||
['id' => '2', 'device_name' => 'Bar'] | ||
]; | ||
$collection = new MachineTokens(['user' => $this->user]); | ||
$this->machine_tokens->method('all') | ||
->willReturn([ | ||
new MachineToken((object)$tokens[0], ['collection' => $collection]), | ||
new MachineToken((object)$tokens[1], ['collection' => $collection]) | ||
]); | ||
|
||
$this->logger->expects($this->never()) | ||
->method($this->anything()); | ||
|
||
$out = $this->command->listTokens(); | ||
$this->assertInstanceOf('Consolidation\OutputFormatters\StructuredData\RowsOfFields', $out); | ||
$this->assertEquals($tokens, $out->getArrayCopy()); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I'm letting the exception thrown by
get()
fall through and get caught by the runner. This works fine (and saves a few lines of code) but the Robo runner isn't familiar with our translatable exceptions. That means the output when there is an error here is:[error] Could not find {model} "{id}"
We have 3 options:
getMessage()
always returns a valid error messageI favor #3. We'll have to revisit it a bit when we actually start looking at translating error messages, but it should be backwards compatible with the old Terminus runner and forwards compatible with the new one (while not prematurely interpolating error strings).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TeslaDethray ^^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also favor approach approach 3.