BasicStructure.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. <?php
  2. /**
  3. *
  4. * @author Christoph Wurst <christoph@owncloud.com>
  5. * @author Joas Schilling <coding@schilljs.com>
  6. * @author Lukas Reschke <lukas@statuscode.ch>
  7. * @author Sergio Bertolin <sbertolin@solidgear.es>
  8. * @author Thomas Müller <thomas.mueller@tmit.eu>
  9. *
  10. * @license GNU AGPL version 3 or any later version
  11. *
  12. * This program is free software: you can redistribute it and/or modify
  13. * it under the terms of the GNU Affero General Public License as
  14. * published by the Free Software Foundation, either version 3 of the
  15. * License, or (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Affero General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. *
  25. */
  26. use GuzzleHttp\Client;
  27. use GuzzleHttp\Cookie\CookieJar;
  28. use GuzzleHttp\Exception\ClientException;
  29. use GuzzleHttp\Message\ResponseInterface;
  30. require __DIR__ . '/../../vendor/autoload.php';
  31. trait BasicStructure {
  32. use Auth;
  33. /** @var string */
  34. private $currentUser = '';
  35. /** @var string */
  36. private $currentServer = '';
  37. /** @var string */
  38. private $baseUrl = '';
  39. /** @var int */
  40. private $apiVersion = 1;
  41. /** @var ResponseInterface */
  42. private $response = null;
  43. /** @var CookieJar */
  44. private $cookieJar;
  45. /** @var string */
  46. private $requestToken;
  47. public function __construct($baseUrl, $admin, $regular_user_password) {
  48. // Initialize your context here
  49. $this->baseUrl = $baseUrl;
  50. $this->adminUser = $admin;
  51. $this->regularUser = $regular_user_password;
  52. $this->localBaseUrl = $this->baseUrl;
  53. $this->remoteBaseUrl = $this->baseUrl;
  54. $this->currentServer = 'LOCAL';
  55. $this->cookieJar = new CookieJar();
  56. // in case of ci deployment we take the server url from the environment
  57. $testServerUrl = getenv('TEST_SERVER_URL');
  58. if ($testServerUrl !== false) {
  59. $this->baseUrl = $testServerUrl;
  60. $this->localBaseUrl = $testServerUrl;
  61. }
  62. // federated server url from the environment
  63. $testRemoteServerUrl = getenv('TEST_SERVER_FED_URL');
  64. if ($testRemoteServerUrl !== false) {
  65. $this->remoteBaseUrl = $testRemoteServerUrl;
  66. }
  67. }
  68. /**
  69. * @Given /^using api version "(\d+)"$/
  70. * @param string $version
  71. */
  72. public function usingApiVersion($version) {
  73. $this->apiVersion = (int) $version;
  74. }
  75. /**
  76. * @Given /^As an "([^"]*)"$/
  77. * @param string $user
  78. */
  79. public function asAn($user) {
  80. $this->currentUser = $user;
  81. }
  82. /**
  83. * @Given /^Using server "(LOCAL|REMOTE)"$/
  84. * @param string $server
  85. * @return string Previous used server
  86. */
  87. public function usingServer($server) {
  88. $previousServer = $this->currentServer;
  89. if ($server === 'LOCAL'){
  90. $this->baseUrl = $this->localBaseUrl;
  91. $this->currentServer = 'LOCAL';
  92. return $previousServer;
  93. } else {
  94. $this->baseUrl = $this->remoteBaseUrl;
  95. $this->currentServer = 'REMOTE';
  96. return $previousServer;
  97. }
  98. }
  99. /**
  100. * @When /^sending "([^"]*)" to "([^"]*)"$/
  101. * @param string $verb
  102. * @param string $url
  103. */
  104. public function sendingTo($verb, $url) {
  105. $this->sendingToWith($verb, $url, null);
  106. }
  107. /**
  108. * Parses the xml answer to get ocs response which doesn't match with
  109. * http one in v1 of the api.
  110. * @param ResponseInterface $response
  111. * @return string
  112. */
  113. public function getOCSResponse($response) {
  114. return $response->xml()->meta[0]->statuscode;
  115. }
  116. /**
  117. * This function is needed to use a vertical fashion in the gherkin tables.
  118. * @param array $arrayOfArrays
  119. * @return array
  120. */
  121. public function simplifyArray($arrayOfArrays){
  122. $a = array_map(function($subArray) { return $subArray[0]; }, $arrayOfArrays);
  123. return $a;
  124. }
  125. /**
  126. * @When /^sending "([^"]*)" to "([^"]*)" with$/
  127. * @param string $verb
  128. * @param string $url
  129. * @param \Behat\Gherkin\Node\TableNode $body
  130. */
  131. public function sendingToWith($verb, $url, $body) {
  132. $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php" . $url;
  133. $client = new Client();
  134. $options = [];
  135. if ($this->currentUser === 'admin') {
  136. $options['auth'] = $this->adminUser;
  137. } else {
  138. $options['auth'] = [$this->currentUser, $this->regularUser];
  139. }
  140. $options['headers'] = [
  141. 'OCS_APIREQUEST' => 'true'
  142. ];
  143. if ($body instanceof \Behat\Gherkin\Node\TableNode) {
  144. $fd = $body->getRowsHash();
  145. $options['body'] = $fd;
  146. }
  147. // TODO: Fix this hack!
  148. if ($verb === 'PUT' && $body === null) {
  149. $options['body'] = [
  150. 'foo' => 'bar',
  151. ];
  152. }
  153. try {
  154. $this->response = $client->send($client->createRequest($verb, $fullUrl, $options));
  155. } catch (ClientException $ex) {
  156. $this->response = $ex->getResponse();
  157. }
  158. }
  159. /**
  160. * @When /^sending "([^"]*)" with exact url to "([^"]*)"$/
  161. * @param string $verb
  162. * @param string $url
  163. */
  164. public function sendingToDirectUrl($verb, $url) {
  165. $this->sendingToWithDirectUrl($verb, $url, null);
  166. }
  167. public function sendingToWithDirectUrl($verb, $url, $body) {
  168. $fullUrl = substr($this->baseUrl, 0, -5) . $url;
  169. $client = new Client();
  170. $options = [];
  171. if ($this->currentUser === 'admin') {
  172. $options['auth'] = $this->adminUser;
  173. } else {
  174. $options['auth'] = [$this->currentUser, $this->regularUser];
  175. }
  176. if ($body instanceof \Behat\Gherkin\Node\TableNode) {
  177. $fd = $body->getRowsHash();
  178. $options['body'] = $fd;
  179. }
  180. try {
  181. $this->response = $client->send($client->createRequest($verb, $fullUrl, $options));
  182. } catch (ClientException $ex) {
  183. $this->response = $ex->getResponse();
  184. }
  185. }
  186. public function isExpectedUrl($possibleUrl, $finalPart){
  187. $baseUrlChopped = substr($this->baseUrl, 0, -4);
  188. $endCharacter = strlen($baseUrlChopped) + strlen($finalPart);
  189. return (substr($possibleUrl,0,$endCharacter) == "$baseUrlChopped" . "$finalPart");
  190. }
  191. /**
  192. * @Then /^the OCS status code should be "([^"]*)"$/
  193. * @param int $statusCode
  194. */
  195. public function theOCSStatusCodeShouldBe($statusCode) {
  196. PHPUnit_Framework_Assert::assertEquals($statusCode, $this->getOCSResponse($this->response));
  197. }
  198. /**
  199. * @Then /^the HTTP status code should be "([^"]*)"$/
  200. * @param int $statusCode
  201. */
  202. public function theHTTPStatusCodeShouldBe($statusCode) {
  203. PHPUnit_Framework_Assert::assertEquals($statusCode, $this->response->getStatusCode());
  204. }
  205. /**
  206. * @Then /^the Content-Type should be "([^"]*)"$/
  207. * @param string $contentType
  208. */
  209. public function theContentTypeShouldbe($contentType) {
  210. PHPUnit_Framework_Assert::assertEquals($contentType, $this->response->getHeader('Content-Type'));
  211. }
  212. /**
  213. * @param ResponseInterface $response
  214. */
  215. private function extracRequestTokenFromResponse(ResponseInterface $response) {
  216. $this->requestToken = substr(preg_replace('/(.*)data-requesttoken="(.*)">(.*)/sm', '\2', $response->getBody()->getContents()), 0, 89);
  217. }
  218. /**
  219. * @Given Logging in using web as :user
  220. * @param string $user
  221. */
  222. public function loggingInUsingWebAs($user) {
  223. $loginUrl = substr($this->baseUrl, 0, -5) . '/login';
  224. // Request a new session and extract CSRF token
  225. $client = new Client();
  226. $response = $client->get(
  227. $loginUrl,
  228. [
  229. 'cookies' => $this->cookieJar,
  230. ]
  231. );
  232. $this->extracRequestTokenFromResponse($response);
  233. // Login and extract new token
  234. $password = ($user === 'admin') ? 'admin' : '123456';
  235. $client = new Client();
  236. $response = $client->post(
  237. $loginUrl,
  238. [
  239. 'body' => [
  240. 'user' => $user,
  241. 'password' => $password,
  242. 'requesttoken' => $this->requestToken,
  243. ],
  244. 'cookies' => $this->cookieJar,
  245. ]
  246. );
  247. $this->extracRequestTokenFromResponse($response);
  248. }
  249. /**
  250. * @When Sending a :method to :url with requesttoken
  251. * @param string $method
  252. * @param string $url
  253. */
  254. public function sendingAToWithRequesttoken($method, $url) {
  255. $baseUrl = substr($this->baseUrl, 0, -5);
  256. $client = new Client();
  257. $request = $client->createRequest(
  258. $method,
  259. $baseUrl . $url,
  260. [
  261. 'cookies' => $this->cookieJar,
  262. ]
  263. );
  264. $request->addHeader('requesttoken', $this->requestToken);
  265. try {
  266. $this->response = $client->send($request);
  267. } catch (ClientException $e) {
  268. $this->response = $e->getResponse();
  269. }
  270. }
  271. /**
  272. * @When Sending a :method to :url without requesttoken
  273. * @param string $method
  274. * @param string $url
  275. */
  276. public function sendingAToWithoutRequesttoken($method, $url) {
  277. $baseUrl = substr($this->baseUrl, 0, -5);
  278. $client = new Client();
  279. $request = $client->createRequest(
  280. $method,
  281. $baseUrl . $url,
  282. [
  283. 'cookies' => $this->cookieJar,
  284. ]
  285. );
  286. try {
  287. $this->response = $client->send($request);
  288. } catch (ClientException $e) {
  289. $this->response = $e->getResponse();
  290. }
  291. }
  292. public static function removeFile($path, $filename){
  293. if (file_exists("$path" . "$filename")) {
  294. unlink("$path" . "$filename");
  295. }
  296. }
  297. /**
  298. * @Given User :user modifies text of :filename with text :text
  299. * @param string $user
  300. * @param string $filename
  301. * @param string $text
  302. */
  303. public function modifyTextOfFile($user, $filename, $text) {
  304. self::removeFile("../../data/$user/files", "$filename");
  305. file_put_contents("../../data/$user/files" . "$filename", "$text");
  306. }
  307. public function createFileSpecificSize($name, $size) {
  308. $file = fopen("work/" . "$name", 'w');
  309. fseek($file, $size - 1 ,SEEK_CUR);
  310. fwrite($file,'a'); // write a dummy char at SIZE position
  311. fclose($file);
  312. }
  313. public function createFileWithText($name, $text){
  314. $file = fopen("work/" . "$name", 'w');
  315. fwrite($file, $text);
  316. fclose($file);
  317. }
  318. /**
  319. * @Given file :filename of size :size is created in local storage
  320. * @param string $filename
  321. * @param string $size
  322. */
  323. public function fileIsCreatedInLocalStorageWithSize($filename, $size) {
  324. $this->createFileSpecificSize("local_storage/$filename", $size);
  325. }
  326. /**
  327. * @Given file :filename with text :text is created in local storage
  328. * @param string $filename
  329. * @param string $text
  330. */
  331. public function fileIsCreatedInLocalStorageWithText($filename, $text) {
  332. $this->createFileWithText("local_storage/$filename", $text);
  333. }
  334. /**
  335. * @When User :user empties trashbin
  336. * @param string $user
  337. */
  338. public function emptyTrashbin($user) {
  339. $body = new \Behat\Gherkin\Node\TableNode([['allfiles', 'true'], ['dir', '%2F']]);
  340. $this->sendingToWithDirectUrl('POST', "/index.php/apps/files_trashbin/ajax/delete.php", $body);
  341. $this->theHTTPStatusCodeShouldBe('200');
  342. }
  343. /**
  344. * @When Sleep for :seconds seconds
  345. * @param int $seconds
  346. */
  347. public function sleepForSeconds($seconds) {
  348. sleep((int)$seconds);
  349. }
  350. /**
  351. * @BeforeSuite
  352. */
  353. public static function addFilesToSkeleton(){
  354. for ($i=0; $i<5; $i++){
  355. file_put_contents("../../core/skeleton/" . "textfile" . "$i" . ".txt", "Nextcloud test text file\n");
  356. }
  357. if (!file_exists("../../core/skeleton/FOLDER")) {
  358. mkdir("../../core/skeleton/FOLDER", 0777, true);
  359. }
  360. if (!file_exists("../../core/skeleton/PARENT")) {
  361. mkdir("../../core/skeleton/PARENT", 0777, true);
  362. }
  363. file_put_contents("../../core/skeleton/PARENT/" . "parent.txt", "Nextcloud test text file\n");
  364. if (!file_exists("../../core/skeleton/PARENT/CHILD")) {
  365. mkdir("../../core/skeleton/PARENT/CHILD", 0777, true);
  366. }
  367. file_put_contents("../../core/skeleton/PARENT/CHILD/" . "child.txt", "Nextcloud test text file\n");
  368. }
  369. /**
  370. * @AfterSuite
  371. */
  372. public static function removeFilesFromSkeleton(){
  373. for ($i=0; $i<5; $i++){
  374. self::removeFile("../../core/skeleton/", "textfile" . "$i" . ".txt");
  375. }
  376. if (is_dir("../../core/skeleton/FOLDER")) {
  377. rmdir("../../core/skeleton/FOLDER");
  378. }
  379. self::removeFile("../../core/skeleton/PARENT/CHILD/", "child.txt");
  380. if (is_dir("../../core/skeleton/PARENT/CHILD")) {
  381. rmdir("../../core/skeleton/PARENT/CHILD");
  382. }
  383. self::removeFile("../../core/skeleton/PARENT/", "parent.txt");
  384. if (is_dir("../../core/skeleton/PARENT")) {
  385. rmdir("../../core/skeleton/PARENT");
  386. }
  387. }
  388. /**
  389. * @BeforeScenario @local_storage
  390. */
  391. public static function removeFilesFromLocalStorageBefore(){
  392. $dir = "./work/local_storage/";
  393. $di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
  394. $ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST);
  395. foreach ( $ri as $file ) {
  396. $file->isDir() ? rmdir($file) : unlink($file);
  397. }
  398. }
  399. /**
  400. * @AfterScenario @local_storage
  401. */
  402. public static function removeFilesFromLocalStorageAfter(){
  403. $dir = "./work/local_storage/";
  404. $di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
  405. $ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST);
  406. foreach ( $ri as $file ) {
  407. $file->isDir() ? rmdir($file) : unlink($file);
  408. }
  409. }
  410. }