WebDav.php 17.3 KB
Newer Older
1
2
<?php

3
use GuzzleHttp\Client as GClient;
4
use GuzzleHttp\Message\ResponseInterface;
5
use Sabre\DAV\Client as SClient;
6
7
8
9

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


10
trait WebDav {
Joas Schilling's avatar
Joas Schilling committed
11
12
	use Sharing;

13
14
	/** @var string*/
	private $davPath = "remote.php/webdav";
15
16
	/** @var boolean*/
	private $usingOldDavPath = true;
17
18
	/** @var ResponseInterface */
	private $response;
19
20
21
22
23
24

	/**
	 * @Given /^using dav path "([^"]*)"$/
	 */
	public function usingDavPath($davPath) {
		$this->davPath = $davPath;
Vincent Petry's avatar
Vincent Petry committed
25
	}
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
	/**
	 * @Given /^using old dav path$/
	 */
	public function usingOldDavPath() {
		$this->davPath = "remote.php/webdav";
		$this->usingOldDavPath = true;
	}

	/**
	 * @Given /^using new dav path$/
	 */
	public function usingNewDavPath() {
		$this->davPath = "remote.php/dav";
		$this->usingOldDavPath = false;
	}

	/*public function getDavFilesPath($user){
		if ($this->usingOldDavPath === true){
			return $this->davPath . '/';
		} else {
			return $this->davPath . '/files/' . $user . '/';
		}
	}*/

	public function getDavFilesPath($user){
		if ($this->usingOldDavPath === true){
			return $this->davPath;
		} else {
			return $this->davPath . '/files/' . $user;
		}
	}

Sergio Bertolin's avatar
Sergio Bertolin committed
59
	public function getFilesPath($user){
60
61
		$basePath = '';
		if ($this->davPath === "remote.php/dav"){
Sergio Bertolin's avatar
Sergio Bertolin committed
62
			$basePath = '/files/' . $user . '/';
63
64
65
66
67
68
		} else {
			$basePath = '/';
		}
		return $basePath;
	}

69
	public function makeDavRequest($user, $method, $path, $headers, $body = null){
70
		$fullUrl = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user) . "$path";
71
		$client = new GClient();
72
73
74
75
76
77
78
		$options = [];
		if ($user === 'admin') {
			$options['auth'] = $this->adminUser;
		} else {
			$options['auth'] = [$user, $this->regularUser];
		}
		$request = $client->createRequest($method, $fullUrl, $options);
79
80
		if (!is_null($headers)){
			foreach ($headers as $key => $value) {
Vincent Petry's avatar
Vincent Petry committed
81
				$request->addHeader($key, $value);
82
			}
83
		}
84
85
86
87
88

		if (!is_null($body)) {
			$request->setBody($body);
		}

89
90
91
92
		return $client->send($request);
	}

	/**
93
	 * @Given /^User "([^"]*)" moved (file|folder|entry) "([^"]*)" to "([^"]*)"$/
Joas Schilling's avatar
Joas Schilling committed
94
95
96
	 * @param string $user
	 * @param string $fileSource
	 * @param string $fileDestination
97
	 */
98
	public function userMovedFile($user, $entry, $fileSource, $fileDestination){
99
		$fullUrl = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user);
100
101
102
103
104
105
		$headers['Destination'] = $fullUrl . $fileDestination;
		$this->response = $this->makeDavRequest($user, "MOVE", $fileSource, $headers);
		PHPUnit_Framework_Assert::assertEquals(201, $this->response->getStatusCode());
	}

	/**
106
	 * @When /^User "([^"]*)" moves (file|folder|entry) "([^"]*)" to "([^"]*)"$/
Joas Schilling's avatar
Joas Schilling committed
107
108
109
	 * @param string $user
	 * @param string $fileSource
	 * @param string $fileDestination
110
	 */
111
	public function userMovesFile($user, $entry, $fileSource, $fileDestination){
112
		$fullUrl = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user);
113
		$headers['Destination'] = $fullUrl . $fileDestination;
114
115
116
117
118
119
120
121
122
123
124
125
126
127
		try {
			$this->response = $this->makeDavRequest($user, "MOVE", $fileSource, $headers);
		} catch (\GuzzleHttp\Exception\ClientException $e) {
			$this->response = $e->getResponse();
		}
	}

	/**
	 * @When /^User "([^"]*)" copies file "([^"]*)" to "([^"]*)"$/
	 * @param string $user
	 * @param string $fileSource
	 * @param string $fileDestination
	 */
	public function userCopiesFile($user, $fileSource, $fileDestination){
128
		$fullUrl = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user);
129
130
131
132
133
134
		$headers['Destination'] = $fullUrl . $fileDestination;
		try {
			$this->response = $this->makeDavRequest($user, "COPY", $fileSource, $headers);
		} catch (\GuzzleHttp\Exception\ClientException $e) {
			$this->response = $e->getResponse();
		}
135
136
	}

137
138
	/**
	 * @When /^Downloading file "([^"]*)" with range "([^"]*)"$/
Joas Schilling's avatar
Joas Schilling committed
139
140
	 * @param string $fileSource
	 * @param string $range
141
142
143
144
145
146
	 */
	public function downloadFileWithRange($fileSource, $range){
		$headers['Range'] = $range;
		$this->response = $this->makeDavRequest($this->currentUser, "GET", $fileSource, $headers);
	}

147
148
	/**
	 * @When /^Downloading last public shared file with range "([^"]*)"$/
Joas Schilling's avatar
Joas Schilling committed
149
	 * @param string $range
150
151
152
153
154
155
156
157
158
	 */
	public function downloadPublicFileWithRange($range){
		$token = $this->lastShareData->data->token;
		$fullUrl = substr($this->baseUrl, 0, -4) . "public.php/webdav";
		$headers['Range'] = $range;

		$client = new GClient();
		$options = [];
		$options['auth'] = [$token, ""];
Vincent Petry's avatar
Vincent Petry committed
159

160
		$request = $client->createRequest("GET", $fullUrl, $options);
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
		$request->addHeader('Range', $range);

		$this->response = $client->send($request);
	}

	/**
	 * @When /^Downloading last public shared file inside a folder "([^"]*)" with range "([^"]*)"$/
	 * @param string $range
	 */
	public function downloadPublicFileInsideAFolderWithRange($path, $range){
		$token = $this->lastShareData->data->token;
		$fullUrl = substr($this->baseUrl, 0, -4) . "public.php/webdav" . "$path";
		$headers['Range'] = $range;

		$client = new GClient();
		$options = [];
		$options['auth'] = [$token, ""];
Vincent Petry's avatar
Vincent Petry committed
178

179
180
181
182
183
184
		$request = $client->createRequest("GET", $fullUrl, $options);
		$request->addHeader('Range', $range);

		$this->response = $client->send($request);
	}

185
186
	/**
	 * @Then /^Downloaded content should be "([^"]*)"$/
Joas Schilling's avatar
Joas Schilling committed
187
	 * @param string $content
188
189
190
191
192
	 */
	public function downloadedContentShouldBe($content){
		PHPUnit_Framework_Assert::assertEquals($content, (string)$this->response->getBody());
	}

193
194
	/**
	 * @Then /^Downloaded content when downloading file "([^"]*)" with range "([^"]*)" should be "([^"]*)"$/
Joas Schilling's avatar
Joas Schilling committed
195
196
197
	 * @param string $fileSource
	 * @param string $range
	 * @param string $content
198
199
200
201
202
203
	 */
	public function downloadedContentWhenDownloadindShouldBe($fileSource, $range, $content){
		$this->downloadFileWithRange($fileSource, $range);
		$this->downloadedContentShouldBe($content);
	}

204
205
	/**
	 * @When Downloading file :fileName
Joas Schilling's avatar
Joas Schilling committed
206
	 * @param string $fileName
207
208
	 */
	public function downloadingFile($fileName) {
209
210
211
212
213
		try {
			$this->response = $this->makeDavRequest($this->currentUser, 'GET', $fileName, []);
		} catch (\GuzzleHttp\Exception\ClientException $e) {
			$this->response = $e->getResponse();
		}
214
215
216
217
	}

	/**
	 * @Then The following headers should be set
Joas Schilling's avatar
Joas Schilling committed
218
219
	 * @param \Behat\Gherkin\Node\TableNode $table
	 * @throws \Exception
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
	 */
	public function theFollowingHeadersShouldBeSet(\Behat\Gherkin\Node\TableNode $table) {
		foreach($table->getTable() as $header) {
			$headerName = $header[0];
			$expectedHeaderValue = $header[1];
			$returnedHeader = $this->response->getHeader($headerName);
			if($returnedHeader !== $expectedHeaderValue) {
				throw new \Exception(
					sprintf(
						"Expected value '%s' for header '%s', got '%s'",
						$expectedHeaderValue,
						$headerName,
						$returnedHeader
					)
				);
			}
		}
	}

	/**
	 * @Then Downloaded content should start with :start
Joas Schilling's avatar
Joas Schilling committed
241
242
	 * @param int $start
	 * @throws \Exception
243
244
245
246
247
248
249
250
251
252
253
254
	 */
	public function downloadedContentShouldStartWith($start) {
		if(strpos($this->response->getBody()->getContents(), $start) !== 0) {
			throw new \Exception(
				sprintf(
					"Expected '%s', got '%s'",
					$start,
					$this->response->getBody()->getContents()
				)
			);
		}
	}
255

Vincent Petry's avatar
Vincent Petry committed
256
	/**
257
	 * @Then /^as "([^"]*)" gets properties of (file|folder|entry) "([^"]*)" with$/
Joas Schilling's avatar
Joas Schilling committed
258
259
	 * @param string $user
	 * @param string $path
Vincent Petry's avatar
Vincent Petry committed
260
261
	 * @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
	 */
262
	public function asGetsPropertiesOfFolderWith($user, $elementType, $path, $propertiesTable) {
Vincent Petry's avatar
Vincent Petry committed
263
264
265
266
267
268
269
270
271
		$properties = null;
		if ($propertiesTable instanceof \Behat\Gherkin\Node\TableNode) {
			foreach ($propertiesTable->getRows() as $row) {
				$properties[] = $row[0];
			}
		}
		$this->response = $this->listFolder($user, $path, 0, $properties);
	}

272
273
274
275
276
277
278
279
	/**
	 * @Then /^as "([^"]*)" the (file|folder|entry) "([^"]*)" does not exist$/
	 * @param string $user
	 * @param string $path
	 * @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
	 */
	public function asTheFileOrFolderDoesNotExist($user, $entry, $path) {
		$client = $this->getSabreClient($user);
Sergio Bertolin's avatar
Sergio Bertolin committed
280
		$response = $client->request('HEAD', $this->makeSabrePath($user, $path));
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
		if ($response['statusCode'] !== 404) {
			throw new \Exception($entry . ' "' . $path . '" expected to not exist (status code ' . $response['statusCode'] . ', expected 404)');
		}

		return $response;
	}

	/**
	 * @Then /^as "([^"]*)" the (file|folder|entry) "([^"]*)" exists$/
	 * @param string $user
	 * @param string $path
	 * @param \Behat\Gherkin\Node\TableNode|null $propertiesTable
	 */
	public function asTheFileOrFolderExists($user, $entry, $path) {
		$this->response = $this->listFolder($user, $path, 0);
	}

Vincent Petry's avatar
Vincent Petry committed
298
299
	/**
	 * @Then the single response should contain a property :key with value :value
Joas Schilling's avatar
Joas Schilling committed
300
301
302
	 * @param string $key
	 * @param string $expectedValue
	 * @throws \Exception
Vincent Petry's avatar
Vincent Petry committed
303
304
305
	 */
	public function theSingleResponseShouldContainAPropertyWithValue($key, $expectedValue) {
		$keys = $this->response;
Roeland Jago Douma's avatar
Roeland Jago Douma committed
306
		if (!array_key_exists($key, $keys)) {
Joas Schilling's avatar
Joas Schilling committed
307
			throw new \Exception("Cannot find property \"$key\" with \"$expectedValue\"");
Vincent Petry's avatar
Vincent Petry committed
308
309
310
		}

		$value = $keys[$key];
311
		if ($value != $expectedValue) {
Vincent Petry's avatar
Vincent Petry committed
312
313
314
315
			throw new \Exception("Property \"$key\" found with value \"$value\", expected \"$expectedValue\"");
		}
	}

Roeland Jago Douma's avatar
Roeland Jago Douma committed
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
	/**
	 * @Then the response should contain a share-types property with
	 */
	public function theResponseShouldContainAShareTypesPropertyWith($table)
	{
		$keys = $this->response;
		if (!array_key_exists('{http://owncloud.org/ns}share-types', $keys)) {
			throw new \Exception("Cannot find property \"{http://owncloud.org/ns}share-types\"");
		}

		$foundTypes = [];
		$data = $keys['{http://owncloud.org/ns}share-types'];
		foreach ($data as $item) {
			if ($item['name'] !== '{http://owncloud.org/ns}share-type') {
				throw new \Exception('Invalid property found: "' . $item['name'] . '"');
			}

			$foundTypes[] = $item['value'];
		}

		foreach ($table->getRows() as $row) {
			$key = array_search($row[0], $foundTypes);
			if ($key === false) {
				throw new \Exception('Expected type ' . $row[0] . ' not found');
			}

			unset($foundTypes[$key]);
		}

		if ($foundTypes !== []) {
			throw new \Exception('Found more share types then specified: ' . $foundTypes);
		}
	}

	/**
	 * @Then the response should contain an empty property :property
	 * @param string $property
	 * @throws \Exception
	 */
	public function theResponseShouldContainAnEmptyProperty($property) {
		$properties = $this->response;
		if (!array_key_exists($property, $properties)) {
			throw new \Exception("Cannot find property \"$property\"");
		}

		if ($properties[$property] !== null) {
			throw new \Exception("Property \"$property\" is not empty");
		}
	}

366
	/*Returns the elements of a propfind, $folderDepth requires 1 to see elements without children*/
Vincent Petry's avatar
Vincent Petry committed
367
	public function listFolder($user, $path, $folderDepth, $properties = null){
368
369
370
371
372
373
374
		$client = $this->getSabreClient($user);
		if (!$properties) {
			$properties = [
				'{DAV:}getetag'
			];
		}

Sergio Bertolin's avatar
Sergio Bertolin committed
375
		$response = $client->propfind($this->makeSabrePath($user, $path), $properties, $folderDepth);
376
377
378
379

		return $response;
	}

Sergio Bertolin's avatar
Sergio Bertolin committed
380
	public function makeSabrePath($user, $path) {
381
		return $this->encodePath($this->getDavFilesPath($user) . $path);
382
383
384
	}

	public function getSabreClient($user) {
385
386
		$fullUrl = substr($this->baseUrl, 0, -4);

Thomas Müller's avatar
Thomas Müller committed
387
		$settings = [
388
389
			'baseUri' => $fullUrl,
			'userName' => $user,
Thomas Müller's avatar
Thomas Müller committed
390
		];
391
392
393
394
395
396
397

		if ($user === 'admin') {
			$settings['password'] = $this->adminUser[1];
		} else {
			$settings['password'] = $this->regularUser;
		}

398
		return new SClient($settings);
399
400
401
	}

	/**
402
	 * @Then /^user "([^"]*)" should see following elements$/
Joas Schilling's avatar
Joas Schilling committed
403
	 * @param string $user
404
	 * @param \Behat\Gherkin\Node\TableNode|null $expectedElements
405
	 */
406
	public function checkElementList($user, $expectedElements){
407
		$elementList = $this->listFolder($user, '/', 3);
408
409
410
411
		if ($expectedElements instanceof \Behat\Gherkin\Node\TableNode) {
			$elementRows = $expectedElements->getRows();
			$elementsSimplified = $this->simplifyArray($elementRows);
			foreach($elementsSimplified as $expectedElement) {
412
				$webdavPath = "/" . $this->getDavFilesPath($user) . $expectedElement;
413
414
415
416
417
				if (!array_key_exists($webdavPath,$elementList)){
					PHPUnit_Framework_Assert::fail("$webdavPath" . " is not in propfind answer");
				}
			}
		}
418
	}
419
420
421

	/**
	 * @When User :user uploads file :source to :destination
Joas Schilling's avatar
Joas Schilling committed
422
423
424
	 * @param string $user
	 * @param string $source
	 * @param string $destination
425
426
427
428
429
430
431
432
433
434
435
	 */
	public function userUploadsAFileTo($user, $source, $destination)
	{
		$file = \GuzzleHttp\Stream\Stream::factory(fopen($source, 'r'));
		try {
			$this->response = $this->makeDavRequest($user, "PUT", $destination, [], $file);
		} catch (\GuzzleHttp\Exception\ServerException $e) {
			// 4xx and 5xx responses cause an exception
			$this->response = $e->getResponse();
		}
	}
436

437
438
439
440
441
442
443
444
	/**
	 * @When User :user adds a file of :bytes bytes to :destination
	 * @param string $user
	 * @param string $bytes
	 * @param string $destination
	 */
	public function userAddsAFileTo($user, $bytes, $destination){
		$filename = "filespecificSize.txt";
445
		$this->createFileSpecificSize($filename, $bytes);
446
447
448
		PHPUnit_Framework_Assert::assertEquals(1, file_exists("data/$filename"));
		$this->userUploadsAFileTo($user, "data/$filename", $destination);
		$this->removeFile("data/", $filename);
449
		PHPUnit_Framework_Assert::assertEquals(1, file_exists("../../data/$user/files$destination"));
450
451
	}

452
453
454
455
456
457
458
459
460
461
462
463
464
465
	/**
	 * @When User :user uploads file with content :content to :destination
	 */
	public function userUploadsAFileWithContentTo($user, $content, $destination)
	{
		$file = \GuzzleHttp\Stream\Stream::factory($content);
		try {
			$this->response = $this->makeDavRequest($user, "PUT", $destination, [], $file);
		} catch (\GuzzleHttp\Exception\ServerException $e) {
			// 4xx and 5xx responses cause an exception
			$this->response = $e->getResponse();
		}
	}

466
	/**
467
	 * @When /^User "([^"]*)" deletes (file|folder) "([^"]*)"$/
Joas Schilling's avatar
Joas Schilling committed
468
	 * @param string $user
469
	 * @param string $type
Joas Schilling's avatar
Joas Schilling committed
470
	 * @param string $file
471
	 */
472
	public function userDeletesFile($user, $type, $file)  {
473
474
475
476
477
478
479
480
		try {
			$this->response = $this->makeDavRequest($user, 'DELETE', $file, []);
		} catch (\GuzzleHttp\Exception\ServerException $e) {
			// 4xx and 5xx responses cause an exception
			$this->response = $e->getResponse();
		}
	}

481
482
	/**
	 * @Given User :user created a folder :destination
Joas Schilling's avatar
Joas Schilling committed
483
484
	 * @param string $user
	 * @param string $destination
485
486
487
	 */
	public function userCreatedAFolder($user, $destination){
		try {
488
			$this->response = $this->makeDavRequest($user, "MKCOL", $destination, []);
489
490
491
492
493
494
		} catch (\GuzzleHttp\Exception\ServerException $e) {
			// 4xx and 5xx responses cause an exception
			$this->response = $e->getResponse();
		}
	}

Roeland Jago Douma's avatar
Roeland Jago Douma committed
495
496
	/**
	 * @Given user :user uploads chunk file :num of :total with :data to :destination
Joas Schilling's avatar
Joas Schilling committed
497
498
499
500
501
	 * @param string $user
	 * @param int $num
	 * @param int $total
	 * @param string $data
	 * @param string $destination
Roeland Jago Douma's avatar
Roeland Jago Douma committed
502
503
504
505
506
507
508
509
510
	 */
	public function userUploadsChunkFileOfWithToWithChecksum($user, $num, $total, $data, $destination)
	{
		$num -= 1;
		$data = \GuzzleHttp\Stream\Stream::factory($data);
		$file = $destination . '-chunking-42-'.$total.'-'.$num;
		$this->makeDavRequest($user, 'PUT', $file, ['OC-Chunked' => '1'], $data);
	}

511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
	/**
	 * @Given user :user creates a new chunking upload with id :id
	 */
	public function userCreatesANewChunkingUploadWithId($user, $id)
	{
		$destination = '/uploads/'.$user.'/'.$id;
		$this->makeDavRequest($user, 'MKCOL', $destination, []);
	}

	/**
	 * @Given user :user uploads new chunk file :num with :data to id :id
	 */
	public function userUploadsNewChunkFileOfWithToId($user, $num, $data, $id)
	{
		$data = \GuzzleHttp\Stream\Stream::factory($data);
		$destination = '/uploads/'.$user.'/'.$id.'/'.$num;
		$this->makeDavRequest($user, 'PUT', $destination, [], $data);
	}

	/**
	 * @Given user :user moves new chunk file with id :id to :dest
	 */
	public function userMovesNewChunkFileWithIdToMychunkedfile($user, $id, $dest)
	{
		$source = '/uploads/'.$user.'/'.$id.'/.file';
536
		$destination = substr($this->baseUrl, 0, -4) . $this->getDavFilesPath($user) . $dest;
537
538
539
540
541
542
		$this->makeDavRequest($user, 'MOVE', $source, [
			'Destination' => $destination
		]);
	}


543
544
545
546
547
548
549
550
551
552
	/**
	 * @Given /^Downloading file "([^"]*)" as "([^"]*)"$/
	 */
	public function downloadingFileAs($fileName, $user) {
		try {
			$this->response = $this->makeDavRequest($user, 'GET', $fileName, []);
		} catch (\GuzzleHttp\Exception\ServerException $ex) {
			$this->response = $ex->getResponse();
		}
	}
553

554
555
556
557
558
559
560
561
562
563
564
	/**
	 * URL encodes the given path but keeps the slashes
	 *
	 * @param string $path to encode
	 * @return string encoded path
	 */
	private function encodePath($path) {
		// slashes need to stay
		return str_replace('%2F', '/', rawurlencode($path));
	}

Sergio Bertolín's avatar
Sergio Bertolín committed
565
566
	/**
	 * @When user :user favorites element :path
567
	 */
568
569
570
571
572
573
574
575
576
	public function userFavoritesElement($user, $path){
		$this->response = $this->changeFavStateOfAnElement($user, $path, 1, 0, null);
	}

	/**
	 * @When user :user unfavorites element :path
	 */
	public function userUnfavoritesElement($user, $path){
		$this->response = $this->changeFavStateOfAnElement($user, $path, 0, 0, null);
577
578
579
	}

	/*Set the elements of a proppatch, $folderDepth requires 1 to see elements without children*/
580
	public function changeFavStateOfAnElement($user, $path, $favOrUnfav, $folderDepth, $properties = null){
581
		$fullUrl = substr($this->baseUrl, 0, -4);
Thomas Müller's avatar
Thomas Müller committed
582
		$settings = [
583
584
			'baseUri' => $fullUrl,
			'userName' => $user,
Thomas Müller's avatar
Thomas Müller committed
585
		];
586
587
588
589
590
591
592
593
		if ($user === 'admin') {
			$settings['password'] = $this->adminUser[1];
		} else {
			$settings['password'] = $this->regularUser;
		}
		$client = new SClient($settings);
		if (!$properties) {
			$properties = [
594
				'{http://owncloud.org/ns}favorite' => $favOrUnfav
595
596
			];
		}
Sergio Bertolín's avatar
Sergio Bertolín committed
597

598
		$response = $client->proppatch($this->getDavFilesPath($user), $properties, $folderDepth);
599
600
		return $response;
	}
Sergio Bertolín's avatar
Sergio Bertolín committed
601

602
}