Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add integration tests for user avatars
Signed-off-by: Daniel Calviño Sánchez <[email protected]>
  • Loading branch information
danxuliu committed Dec 7, 2020
commit 2cc22a06b4d56e1d46d1de45993b3149455c3bb4
25 changes: 25 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,31 @@ trigger:
- pull_request
- push

---
kind: pipeline
name: integration-avatar

steps:
- name: submodules
image: docker:git
commands:
- git submodule update --init
- name: integration-auth
image: nextcloudci/integration-php7.3:integration-php7.3-2
commands:
- bash tests/drone-run-integration-tests.sh || exit 0
- ./occ maintenance:install --admin-pass=admin --data-dir=/dev/shm/nc_int
- cd build/integration
- ./run.sh features/avatar.feature

trigger:
branch:
- master
- stable*
event:
- pull_request
- push

---
kind: pipeline
name: integration-maintenance-mode
Expand Down
Binary file added build/integration/data/coloured-pattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/integration/data/green-square-256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
135 changes: 135 additions & 0 deletions build/integration/features/avatar.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
Feature: avatar

Background:
Given user "user0" exists

Scenario: get default user avatar
When user "user0" gets avatar for user "user0"
Then The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 0 |
And last avatar is a square of size 128
And last avatar is not a single color

Scenario: get default user avatar as an anonymous user
When user "anonymous" gets avatar for user "user0"
Then The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 0 |
And last avatar is a square of size 128
And last avatar is not a single color



Scenario: get temporary user avatar before cropping it
Given Logging in using web as "user0"
And logged in user posts temporary avatar from file "data/green-square-256.png"
When logged in user gets temporary avatar
Then The following headers should be set
| Content-Type | image/png |
# "last avatar" also includes the last temporary avatar
And last avatar is a square of size 256
And last avatar is a single "#00FF00" color

Scenario: get user avatar before cropping it
Given Logging in using web as "user0"
And logged in user posts temporary avatar from file "data/green-square-256.png"
# Avatar needs to be cropped to finish setting it even if it is squared
When user "user0" gets avatar for user "user0"
Then The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 0 |
And last avatar is a square of size 128
And last avatar is not a single color



Scenario: set user avatar from file
Given Logging in using web as "user0"
When logged in user posts temporary avatar from file "data/coloured-pattern.png"
And logged in user crops temporary avatar
| x | 384 |
| y | 256 |
| w | 128 |
| h | 128 |
Then logged in user gets temporary avatar with 404
And user "user0" gets avatar for user "user0"
And The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 1 |
And last avatar is a square of size 128
And last avatar is a single "#FF0000" color
And user "anonymous" gets avatar for user "user0"
And The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 1 |
And last avatar is a square of size 128
And last avatar is a single "#FF0000" color

Scenario: set user avatar from internal path
Given user "user0" uploads file "data/coloured-pattern.png" to "/internal-coloured-pattern.png"
And Logging in using web as "user0"
When logged in user posts temporary avatar from internal path "internal-coloured-pattern.png"
And logged in user crops temporary avatar
| x | 704 |
| y | 320 |
| w | 64 |
| h | 64 |
Then logged in user gets temporary avatar with 404
And user "user0" gets avatar for user "user0" with size "64"
And The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 1 |
And last avatar is a square of size 64
And last avatar is a single "#00FF00" color
And user "anonymous" gets avatar for user "user0" with size "64"
And The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 1 |
And last avatar is a square of size 64
And last avatar is a single "#00FF00" color

Scenario: cropped user avatar needs to be squared
Given Logging in using web as "user0"
And logged in user posts temporary avatar from file "data/coloured-pattern.png"
When logged in user crops temporary avatar with 400
| x | 384 |
| y | 256 |
| w | 192 |
| h | 128 |



Scenario: delete user avatar
Given Logging in using web as "user0"
And logged in user posts temporary avatar from file "data/coloured-pattern.png"
And logged in user crops temporary avatar
| x | 384 |
| y | 256 |
| w | 128 |
| h | 128 |
And user "user0" gets avatar for user "user0"
And The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 1 |
And last avatar is a square of size 128
And last avatar is a single "#FF0000" color
And user "anonymous" gets avatar for user "user0"
And The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 1 |
And last avatar is a square of size 128
And last avatar is a single "#FF0000" color
When logged in user deletes the user avatar
Then user "user0" gets avatar for user "user0"
And The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 0 |
And last avatar is a square of size 128
And last avatar is not a single color
And user "anonymous" gets avatar for user "user0"
And The following headers should be set
| Content-Type | image/png |
| X-NC-IsCustomAvatar | 0 |
And last avatar is a square of size 128
And last avatar is not a single color
208 changes: 208 additions & 0 deletions build/integration/features/bootstrap/Avatar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
<?php
/**
* @copyright Copyright (c) 2020, Daniel Calviño Sánchez ([email protected])
*
* @author Daniel Calviño Sánchez <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

use Behat\Gherkin\Node\TableNode;
use PHPUnit\Framework\Assert;

require __DIR__ . '/../../vendor/autoload.php';

trait Avatar {

/** @var string **/
private $lastAvatar;

/** @AfterScenario **/
public function cleanupLastAvatar() {
$this->lastAvatar = null;
}

private function getLastAvatar() {
$this->lastAvatar = '';

$body = $this->response->getBody();
while (!$body->eof()) {
$this->lastAvatar .= $body->read(8192);
}
$body->close();
}

/**
* @When user :user gets avatar for user :userAvatar
*
* @param string $user
* @param string $userAvatar
*/
public function userGetsAvatarForUser(string $user, string $userAvatar) {
$this->userGetsAvatarForUserWithSize($user, $userAvatar, '128');
}

/**
* @When user :user gets avatar for user :userAvatar with size :size
*
* @param string $user
* @param string $userAvatar
* @param string $size
*/
public function userGetsAvatarForUserWithSize(string $user, string $userAvatar, string $size) {
$this->asAn($user);
$this->sendingToDirectUrl('GET', '/index.php/avatar/' . $userAvatar . '/' . $size);
$this->theHTTPStatusCodeShouldBe('200');

$this->getLastAvatar();
}

/**
* @When logged in user gets temporary avatar
*/
public function loggedInUserGetsTemporaryAvatar() {
$this->loggedInUserGetsTemporaryAvatarWith('200');
}

/**
* @When logged in user gets temporary avatar with :statusCode
*
* @param string $statusCode
*/
public function loggedInUserGetsTemporaryAvatarWith(string $statusCode) {
$this->sendingAToWithRequesttoken('GET', '/index.php/avatar/tmp');
$this->theHTTPStatusCodeShouldBe($statusCode);

$this->getLastAvatar();
}

/**
* @When logged in user posts temporary avatar from file :source
*
* @param string $source
*/
public function loggedInUserPostsTemporaryAvatarFromFile(string $source) {
$file = \GuzzleHttp\Psr7\stream_for(fopen($source, 'r'));

$this->sendingAToWithRequesttoken('POST', '/index.php/avatar',
[
'multipart' => [
[
'name' => 'files[]',
'contents' => $file
]
]
]);
$this->theHTTPStatusCodeShouldBe('200');
}

/**
* @When logged in user posts temporary avatar from internal path :path
*
* @param string $path
*/
public function loggedInUserPostsTemporaryAvatarFromInternalPath(string $path) {
$this->sendingAToWithRequesttoken('POST', '/index.php/avatar?path=' . $path);
$this->theHTTPStatusCodeShouldBe('200');
}

/**
* @When logged in user crops temporary avatar
*
* @param TableNode $crop
*/
public function loggedInUserCropsTemporaryAvatar(TableNode $crop) {
$this->loggedInUserCropsTemporaryAvatarWith('200', $crop);
}

/**
* @When logged in user crops temporary avatar with :statusCode
*
* @param string $statusCode
* @param TableNode $crop
*/
public function loggedInUserCropsTemporaryAvatarWith(string $statusCode, TableNode $crop) {
$parameters = [];
foreach ($crop->getRowsHash() as $key => $value) {
$parameters[] = 'crop[' . $key . ']=' . $value;
}

$this->sendingAToWithRequesttoken('POST', '/index.php/avatar/cropped?' . implode('&', $parameters));
$this->theHTTPStatusCodeShouldBe($statusCode);
}

/**
* @When logged in user deletes the user avatar
*/
public function loggedInUserDeletesTheUserAvatar() {
$this->sendingAToWithRequesttoken('DELETE', '/index.php/avatar');
$this->theHTTPStatusCodeShouldBe('200');
}

/**
* @Then last avatar is a square of size :size
*
* @param string size
*/
public function lastAvatarIsASquareOfSize(string $size) {
list($width, $height) = getimagesizefromstring($this->lastAvatar);

Assert::assertEquals($width, $height, 'Avatar is not a square');
Assert::assertEquals($size, $width);
}

/**
* @Then last avatar is not a single color
*/
public function lastAvatarIsNotASingleColor() {
Assert::assertEquals(null, $this->getColorFromLastAvatar());
}

/**
* @Then last avatar is a single :color color
*
* @param string $color
* @param string $size
*/
public function lastAvatarIsASingleColor(string $color) {
Assert::assertEquals($color, $this->getColorFromLastAvatar());
}

private function getColorFromLastAvatar() {
$image = imagecreatefromstring($this->lastAvatar);

$firstPixelColor = imagecolorat($image, 0, 0);

for ($i = 0; $i < imagesx($image); $i++) {
for ($j = 0; $j < imagesx($image); $j++) {
$currentPixelColor = imagecolorat($image, $i, $j);

if ($firstPixelColor !== $currentPixelColor) {
imagedestroy($image);

return null;
}
}
}

imagedestroy($image);

// Assume that the image is a truecolor image and thus the index is the
// RGB value of the pixel as an integer.
return '#' . str_pad(strtoupper(dechex($firstPixelColor)), 6, '0', STR_PAD_LEFT);
}
}
1 change: 1 addition & 0 deletions build/integration/features/bootstrap/BasicStructure.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

trait BasicStructure {
use Auth;
use Avatar;
use Download;
use Mail;
use Trashbin;
Expand Down