"Fossies" - the Fresh Open Source Software Archive

Member "dav-4.0.3/tests/Sabre/DAV/Locks/PluginTest.php" (10 Jan 2020, 32037 Bytes) of package /linux/www/dav-4.0.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "PluginTest.php": 4.0.2_vs_4.0.3.

    1 <?php
    2 
    3 declare(strict_types=1);
    4 
    5 namespace Sabre\DAV\Locks;
    6 
    7 use Sabre\DAV;
    8 use Sabre\HTTP;
    9 
   10 require_once 'Sabre/DAV/AbstractServer.php';
   11 
   12 class PluginTest extends DAV\AbstractServer
   13 {
   14     /**
   15      * @var Plugin
   16      */
   17     protected $locksPlugin;
   18 
   19     public function setUp()
   20     {
   21         parent::setUp();
   22         $locksBackend = new Backend\File(SABRE_TEMPDIR.'/locksdb');
   23         $locksPlugin = new Plugin($locksBackend);
   24         $this->server->addPlugin($locksPlugin);
   25         $this->locksPlugin = $locksPlugin;
   26     }
   27 
   28     public function testGetInfo()
   29     {
   30         $this->assertArrayHasKey(
   31             'name',
   32             $this->locksPlugin->getPluginInfo()
   33         );
   34     }
   35 
   36     public function testGetFeatures()
   37     {
   38         $this->assertEquals([2], $this->locksPlugin->getFeatures());
   39     }
   40 
   41     public function testGetHTTPMethods()
   42     {
   43         $this->assertEquals(['LOCK', 'UNLOCK'], $this->locksPlugin->getHTTPMethods(''));
   44     }
   45 
   46     public function testLockNoBody()
   47     {
   48         $request = new HTTP\Request('LOCK', '/test.txt');
   49         $this->server->httpRequest = $request;
   50         $this->server->exec();
   51 
   52         $this->assertEquals([
   53             'X-Sabre-Version' => [DAV\Version::VERSION],
   54             'Content-Type' => ['application/xml; charset=utf-8'],
   55             ],
   56             $this->response->getHeaders()
   57          );
   58 
   59         $this->assertEquals(400, $this->response->status);
   60     }
   61 
   62     public function testLock()
   63     {
   64         $request = new HTTP\Request('LOCK', '/test.txt');
   65         $request->setBody('<?xml version="1.0"?>
   66 <D:lockinfo xmlns:D="DAV:">
   67     <D:lockscope><D:exclusive/></D:lockscope>
   68     <D:locktype><D:write/></D:locktype>
   69     <D:owner>
   70         <D:href>http://example.org/~ejw/contact.html</D:href>
   71     </D:owner>
   72 </D:lockinfo>');
   73 
   74         $this->server->httpRequest = $request;
   75         $this->server->exec();
   76 
   77         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
   78         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
   79 
   80         $this->assertEquals(200, $this->response->status, 'Got an incorrect status back. Response body: '.$this->response->getBodyAsString());
   81 
   82         $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", 'xmlns\\1="urn:DAV"', $this->response->getBodyAsString());
   83         $xml = simplexml_load_string($body);
   84         $xml->registerXPathNamespace('d', 'urn:DAV');
   85 
   86         $elements = [
   87             '/d:prop',
   88             '/d:prop/d:lockdiscovery',
   89             '/d:prop/d:lockdiscovery/d:activelock',
   90             '/d:prop/d:lockdiscovery/d:activelock/d:locktype',
   91             '/d:prop/d:lockdiscovery/d:activelock/d:lockroot',
   92             '/d:prop/d:lockdiscovery/d:activelock/d:lockroot/d:href',
   93             '/d:prop/d:lockdiscovery/d:activelock/d:locktype/d:write',
   94             '/d:prop/d:lockdiscovery/d:activelock/d:lockscope',
   95             '/d:prop/d:lockdiscovery/d:activelock/d:lockscope/d:exclusive',
   96             '/d:prop/d:lockdiscovery/d:activelock/d:depth',
   97             '/d:prop/d:lockdiscovery/d:activelock/d:owner',
   98             '/d:prop/d:lockdiscovery/d:activelock/d:timeout',
   99             '/d:prop/d:lockdiscovery/d:activelock/d:locktoken',
  100             '/d:prop/d:lockdiscovery/d:activelock/d:locktoken/d:href',
  101         ];
  102 
  103         foreach ($elements as $elem) {
  104             $data = $xml->xpath($elem);
  105             $this->assertEquals(1, count($data), 'We expected 1 match for the xpath expression "'.$elem.'". '.count($data).' were found. Full response body: '.$this->response->getBodyAsString());
  106         }
  107 
  108         $depth = $xml->xpath('/d:prop/d:lockdiscovery/d:activelock/d:depth');
  109         $this->assertEquals('infinity', (string) $depth[0]);
  110 
  111         $token = $xml->xpath('/d:prop/d:lockdiscovery/d:activelock/d:locktoken/d:href');
  112         $this->assertEquals($this->response->getHeader('Lock-Token'), '<'.(string) $token[0].'>', 'Token in response body didn\'t match token in response header.');
  113     }
  114 
  115     /**
  116      * @depends testLock
  117      */
  118     public function testDoubleLock()
  119     {
  120         $request = new HTTP\Request('LOCK', '/test.txt');
  121         $request->setBody('<?xml version="1.0"?>
  122 <D:lockinfo xmlns:D="DAV:">
  123     <D:lockscope><D:exclusive/></D:lockscope>
  124     <D:locktype><D:write/></D:locktype>
  125     <D:owner>
  126         <D:href>http://example.org/~ejw/contact.html</D:href>
  127     </D:owner>
  128 </D:lockinfo>');
  129 
  130         $this->server->httpRequest = $request;
  131         $this->server->exec();
  132 
  133         $this->response = new HTTP\ResponseMock();
  134         $this->server->httpResponse = $this->response;
  135 
  136         $this->server->exec();
  137 
  138         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  139 
  140         $this->assertEquals(423, $this->response->status, 'Full response: '.$this->response->getBodyAsString());
  141     }
  142 
  143     /**
  144      * @depends testLock
  145      */
  146     public function testLockRefresh()
  147     {
  148         $request = new HTTP\Request('LOCK', '/test.txt');
  149         $request->setBody('<?xml version="1.0"?>
  150 <D:lockinfo xmlns:D="DAV:">
  151     <D:lockscope><D:exclusive/></D:lockscope>
  152     <D:locktype><D:write/></D:locktype>
  153     <D:owner>
  154         <D:href>http://example.org/~ejw/contact.html</D:href>
  155     </D:owner>
  156 </D:lockinfo>');
  157 
  158         $this->server->httpRequest = $request;
  159         $this->server->exec();
  160 
  161         $lockToken = $this->response->getHeader('Lock-Token');
  162 
  163         $this->response = new HTTP\ResponseMock();
  164         $this->server->httpResponse = $this->response;
  165 
  166         $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '('.$lockToken.')']);
  167         $request->setBody('');
  168 
  169         $this->server->httpRequest = $request;
  170         $this->server->exec();
  171 
  172         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  173 
  174         $this->assertEquals(200, $this->response->status, 'We received an incorrect status code. Full response body: '.$this->response->getBody());
  175     }
  176 
  177     /**
  178      * @depends testLock
  179      */
  180     public function testLockRefreshBadToken()
  181     {
  182         $request = new HTTP\Request('LOCK', '/test.txt');
  183         $request->setBody('<?xml version="1.0"?>
  184 <D:lockinfo xmlns:D="DAV:">
  185     <D:lockscope><D:exclusive/></D:lockscope>
  186     <D:locktype><D:write/></D:locktype>
  187     <D:owner>
  188         <D:href>http://example.org/~ejw/contact.html</D:href>
  189     </D:owner>
  190 </D:lockinfo>');
  191 
  192         $this->server->httpRequest = $request;
  193         $this->server->exec();
  194 
  195         $lockToken = $this->response->getHeader('Lock-Token');
  196 
  197         $this->response = new HTTP\ResponseMock();
  198         $this->server->httpResponse = $this->response;
  199 
  200         $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '('.$lockToken.'foobar) (<opaquelocktoken:anotherbadtoken>)']);
  201         $request->setBody('');
  202 
  203         $this->server->httpRequest = $request;
  204         $this->server->exec();
  205 
  206         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  207 
  208         $this->assertEquals(423, $this->response->getStatus(), 'We received an incorrect status code. Full response body: '.$this->response->getBody());
  209     }
  210 
  211     /**
  212      * @depends testLock
  213      */
  214     public function testLockNoFile()
  215     {
  216         $request = new HTTP\Request('LOCK', '/notfound.txt');
  217         $request->setBody('<?xml version="1.0"?>
  218 <D:lockinfo xmlns:D="DAV:">
  219     <D:lockscope><D:exclusive/></D:lockscope>
  220     <D:locktype><D:write/></D:locktype>
  221     <D:owner>
  222         <D:href>http://example.org/~ejw/contact.html</D:href>
  223     </D:owner>
  224 </D:lockinfo>');
  225 
  226         $this->server->httpRequest = $request;
  227         $this->server->exec();
  228 
  229         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  230         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  231 
  232         $this->assertEquals(201, $this->response->status);
  233     }
  234 
  235     /**
  236      * @depends testLock
  237      */
  238     public function testUnlockNoToken()
  239     {
  240         $request = new HTTP\Request('UNLOCK', '/test.txt');
  241         $this->server->httpRequest = $request;
  242         $this->server->exec();
  243 
  244         $this->assertEquals([
  245             'X-Sabre-Version' => [DAV\Version::VERSION],
  246             'Content-Type' => ['application/xml; charset=utf-8'],
  247             ],
  248             $this->response->getHeaders()
  249          );
  250 
  251         $this->assertEquals(400, $this->response->status);
  252     }
  253 
  254     /**
  255      * @depends testLock
  256      */
  257     public function testUnlockBadToken()
  258     {
  259         $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => '<opaquelocktoken:blablabla>']);
  260         $this->server->httpRequest = $request;
  261         $this->server->exec();
  262 
  263         $this->assertEquals([
  264             'X-Sabre-Version' => [DAV\Version::VERSION],
  265             'Content-Type' => ['application/xml; charset=utf-8'],
  266             ],
  267             $this->response->getHeaders()
  268          );
  269 
  270         $this->assertEquals(409, $this->response->status, 'Got an incorrect status code. Full response body: '.$this->response->getBodyAsString());
  271     }
  272 
  273     /**
  274      * @depends testLock
  275      */
  276     public function testLockPutNoToken()
  277     {
  278         $request = new HTTP\Request('LOCK', '/test.txt');
  279         $request->setBody('<?xml version="1.0"?>
  280 <D:lockinfo xmlns:D="DAV:">
  281     <D:lockscope><D:exclusive/></D:lockscope>
  282     <D:locktype><D:write/></D:locktype>
  283     <D:owner>
  284         <D:href>http://example.org/~ejw/contact.html</D:href>
  285     </D:owner>
  286 </D:lockinfo>');
  287 
  288         $this->server->httpRequest = $request;
  289         $this->server->exec();
  290 
  291         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  292         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  293 
  294         $this->assertEquals(200, $this->response->status);
  295 
  296         $request = new HTTP\Request('PUT', '/test.txt');
  297         $request->setBody('newbody');
  298         $this->server->httpRequest = $request;
  299         $this->server->exec();
  300 
  301         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  302         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  303 
  304         $this->assertEquals(423, $this->response->status);
  305     }
  306 
  307     /**
  308      * @depends testLock
  309      */
  310     public function testUnlock()
  311     {
  312         $request = new HTTP\Request('LOCK', '/test.txt');
  313         $this->server->httpRequest = $request;
  314 
  315         $request->setBody('<?xml version="1.0"?>
  316 <D:lockinfo xmlns:D="DAV:">
  317     <D:lockscope><D:exclusive/></D:lockscope>
  318     <D:locktype><D:write/></D:locktype>
  319     <D:owner>
  320         <D:href>http://example.org/~ejw/contact.html</D:href>
  321     </D:owner>
  322 </D:lockinfo>');
  323 
  324         $this->server->invokeMethod($request, $this->server->httpResponse);
  325         $lockToken = $this->server->httpResponse->getHeader('Lock-Token');
  326 
  327         $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => $lockToken]);
  328         $this->server->httpRequest = $request;
  329         $this->server->httpResponse = new HTTP\ResponseMock();
  330         $this->server->invokeMethod($request, $this->server->httpResponse);
  331 
  332         $this->assertEquals(204, $this->server->httpResponse->status, 'Got an incorrect status code. Full response body: '.$this->response->getBodyAsString());
  333         $this->assertEquals([
  334             'X-Sabre-Version' => [DAV\Version::VERSION],
  335             'Content-Length' => ['0'],
  336             ],
  337             $this->server->httpResponse->getHeaders()
  338          );
  339     }
  340 
  341     /**
  342      * @depends testLock
  343      */
  344     public function testUnlockWindowsBug()
  345     {
  346         $request = new HTTP\Request('LOCK', '/test.txt');
  347         $this->server->httpRequest = $request;
  348 
  349         $request->setBody('<?xml version="1.0"?>
  350 <D:lockinfo xmlns:D="DAV:">
  351     <D:lockscope><D:exclusive/></D:lockscope>
  352     <D:locktype><D:write/></D:locktype>
  353     <D:owner>
  354         <D:href>http://example.org/~ejw/contact.html</D:href>
  355     </D:owner>
  356 </D:lockinfo>');
  357 
  358         $this->server->invokeMethod($request, $this->server->httpResponse);
  359         $lockToken = $this->server->httpResponse->getHeader('Lock-Token');
  360 
  361         // See Issue 123
  362         $lockToken = trim($lockToken, '<>');
  363 
  364         $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => $lockToken]);
  365         $this->server->httpRequest = $request;
  366         $this->server->httpResponse = new HTTP\ResponseMock();
  367         $this->server->invokeMethod($request, $this->server->httpResponse);
  368 
  369         $this->assertEquals(204, $this->server->httpResponse->status, 'Got an incorrect status code. Full response body: '.$this->response->getBodyAsString());
  370         $this->assertEquals([
  371             'X-Sabre-Version' => [DAV\Version::VERSION],
  372             'Content-Length' => ['0'],
  373             ],
  374             $this->server->httpResponse->getHeaders()
  375          );
  376     }
  377 
  378     /**
  379      * @depends testLock
  380      */
  381     public function testLockRetainOwner()
  382     {
  383         $request = new HTTP\Request('LOCK', '/test.txt');
  384         $this->server->httpRequest = $request;
  385 
  386         $request->setBody('<?xml version="1.0"?>
  387 <D:lockinfo xmlns:D="DAV:">
  388     <D:lockscope><D:exclusive/></D:lockscope>
  389     <D:locktype><D:write/></D:locktype>
  390     <D:owner>Evert</D:owner>
  391 </D:lockinfo>');
  392 
  393         $this->server->invokeMethod($request, $this->server->httpResponse);
  394         $lockToken = $this->server->httpResponse->getHeader('Lock-Token');
  395 
  396         $locks = $this->locksPlugin->getLocks('test.txt');
  397         $this->assertEquals(1, count($locks));
  398         $this->assertEquals('Evert', $locks[0]->owner);
  399     }
  400 
  401     /**
  402      * @depends testLock
  403      */
  404     public function testLockPutBadToken()
  405     {
  406         $request = new HTTP\Request('LOCK', '/test.txt');
  407         $request->setBody('<?xml version="1.0"?>
  408 <D:lockinfo xmlns:D="DAV:">
  409     <D:lockscope><D:exclusive/></D:lockscope>
  410     <D:locktype><D:write/></D:locktype>
  411     <D:owner>
  412         <D:href>http://example.org/~ejw/contact.html</D:href>
  413     </D:owner>
  414 </D:lockinfo>');
  415 
  416         $this->server->httpRequest = $request;
  417         $this->server->exec();
  418 
  419         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  420         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  421 
  422         $this->assertEquals(200, $this->response->status);
  423 
  424         $request = new HTTP\Request('PUT', '/test.txt', [
  425             'If' => '(<opaquelocktoken:token1>)',
  426         ]);
  427         $request->setBody('newbody');
  428         $this->server->httpRequest = $request;
  429         $this->server->exec();
  430 
  431         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  432         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  433 
  434         // $this->assertEquals('412 Precondition failed',$this->response->status);
  435         $this->assertEquals(423, $this->response->status);
  436     }
  437 
  438     /**
  439      * @depends testLock
  440      */
  441     public function testLockDeleteParent()
  442     {
  443         $request = new HTTP\Request('LOCK', '/dir/child.txt');
  444         $request->setBody('<?xml version="1.0"?>
  445 <D:lockinfo xmlns:D="DAV:">
  446     <D:lockscope><D:exclusive/></D:lockscope>
  447     <D:locktype><D:write/></D:locktype>
  448     <D:owner>
  449         <D:href>http://example.org/~ejw/contact.html</D:href>
  450     </D:owner>
  451 </D:lockinfo>');
  452 
  453         $this->server->httpRequest = $request;
  454         $this->server->exec();
  455 
  456         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  457         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  458 
  459         $this->assertEquals(200, $this->response->status);
  460 
  461         $request = new HTTP\Request('DELETE', '/dir');
  462         $this->server->httpRequest = $request;
  463         $this->server->exec();
  464 
  465         $this->assertEquals(423, $this->response->status);
  466         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  467     }
  468 
  469     /**
  470      * @depends testLock
  471      */
  472     public function testLockDeleteSucceed()
  473     {
  474         $request = new HTTP\Request('LOCK', '/dir/child.txt');
  475         $request->setBody('<?xml version="1.0"?>
  476 <D:lockinfo xmlns:D="DAV:">
  477     <D:lockscope><D:exclusive/></D:lockscope>
  478     <D:locktype><D:write/></D:locktype>
  479     <D:owner>
  480         <D:href>http://example.org/~ejw/contact.html</D:href>
  481     </D:owner>
  482 </D:lockinfo>');
  483 
  484         $this->server->httpRequest = $request;
  485         $this->server->exec();
  486 
  487         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  488         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  489 
  490         $this->assertEquals(200, $this->response->status);
  491 
  492         $request = new HTTP\Request('DELETE', '/dir/child.txt', [
  493             'If' => '('.$this->response->getHeader('Lock-Token').')',
  494         ]);
  495         $this->server->httpRequest = $request;
  496         $this->server->exec();
  497 
  498         $this->assertEquals(204, $this->response->status);
  499         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  500     }
  501 
  502     /**
  503      * @depends testLock
  504      */
  505     public function testLockCopyLockSource()
  506     {
  507         $request = new HTTP\Request('LOCK', '/dir/child.txt');
  508         $request->setBody('<?xml version="1.0"?>
  509 <D:lockinfo xmlns:D="DAV:">
  510     <D:lockscope><D:exclusive/></D:lockscope>
  511     <D:locktype><D:write/></D:locktype>
  512     <D:owner>
  513         <D:href>http://example.org/~ejw/contact.html</D:href>
  514     </D:owner>
  515 </D:lockinfo>');
  516 
  517         $this->server->httpRequest = $request;
  518         $this->server->exec();
  519 
  520         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  521         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  522 
  523         $this->assertEquals(200, $this->response->status);
  524 
  525         $request = new HTTP\Request('COPY', '/dir/child.txt', [
  526             'Destination' => '/dir/child2.txt',
  527         ]);
  528 
  529         $this->server->httpRequest = $request;
  530         $this->server->exec();
  531 
  532         $this->assertEquals(201, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination');
  533         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  534     }
  535 
  536     /**
  537      * @depends testLock
  538      */
  539     public function testLockCopyLockDestination()
  540     {
  541         $request = new HTTP\Request('LOCK', '/dir/child2.txt');
  542         $request->setBody('<?xml version="1.0"?>
  543 <D:lockinfo xmlns:D="DAV:">
  544     <D:lockscope><D:exclusive/></D:lockscope>
  545     <D:locktype><D:write/></D:locktype>
  546     <D:owner>
  547         <D:href>http://example.org/~ejw/contact.html</D:href>
  548     </D:owner>
  549 </D:lockinfo>');
  550 
  551         $this->server->httpRequest = $request;
  552         $this->server->exec();
  553 
  554         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  555         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  556 
  557         $this->assertEquals(201, $this->response->status);
  558 
  559         $request = new HTTP\Request('COPY', '/dir/child.txt', [
  560             'Destination' => '/dir/child2.txt',
  561         ]);
  562         $this->server->httpRequest = $request;
  563         $this->server->exec();
  564 
  565         $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination');
  566         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  567     }
  568 
  569     /**
  570      * @depends testLock
  571      */
  572     public function testLockMoveLockSourceLocked()
  573     {
  574         $request = new HTTP\Request('LOCK', '/dir/child.txt');
  575         $request->setBody('<?xml version="1.0"?>
  576 <D:lockinfo xmlns:D="DAV:">
  577     <D:lockscope><D:exclusive/></D:lockscope>
  578     <D:locktype><D:write/></D:locktype>
  579     <D:owner>
  580         <D:href>http://example.org/~ejw/contact.html</D:href>
  581     </D:owner>
  582 </D:lockinfo>');
  583 
  584         $this->server->httpRequest = $request;
  585         $this->server->exec();
  586 
  587         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  588         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  589 
  590         $this->assertEquals(200, $this->response->status);
  591 
  592         $request = new HTTP\Request('MOVE', '/dir/child.txt', [
  593             'Destination' => '/dir/child2.txt',
  594         ]);
  595         $this->server->httpRequest = $request;
  596         $this->server->exec();
  597 
  598         $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination');
  599         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  600     }
  601 
  602     /**
  603      * @depends testLock
  604      */
  605     public function testLockMoveLockSourceSucceed()
  606     {
  607         $request = new HTTP\Request('LOCK', '/dir/child.txt');
  608         $request->setBody('<?xml version="1.0"?>
  609 <D:lockinfo xmlns:D="DAV:">
  610     <D:lockscope><D:exclusive/></D:lockscope>
  611     <D:locktype><D:write/></D:locktype>
  612     <D:owner>
  613         <D:href>http://example.org/~ejw/contact.html</D:href>
  614     </D:owner>
  615 </D:lockinfo>');
  616 
  617         $this->server->httpRequest = $request;
  618         $this->server->exec();
  619 
  620         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  621         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  622 
  623         $this->assertEquals(200, $this->response->status);
  624 
  625         $request = new HTTP\Request('MOVE', '/dir/child.txt', [
  626             'Destination' => '/dir/child2.txt',
  627             'If' => '('.$this->response->getHeader('Lock-Token').')',
  628         ]);
  629         $this->server->httpRequest = $request;
  630         $this->server->exec();
  631 
  632         $this->assertEquals(201, $this->response->status, 'A valid lock-token was provided for the source, so this MOVE operation must succeed. Full response body: '.$this->response->getBodyAsString());
  633     }
  634 
  635     /**
  636      * @depends testLock
  637      */
  638     public function testLockMoveLockDestination()
  639     {
  640         $request = new HTTP\Request('LOCK', '/dir/child2.txt');
  641         $request->setBody('<?xml version="1.0"?>
  642 <D:lockinfo xmlns:D="DAV:">
  643     <D:lockscope><D:exclusive/></D:lockscope>
  644     <D:locktype><D:write/></D:locktype>
  645     <D:owner>
  646         <D:href>http://example.org/~ejw/contact.html</D:href>
  647     </D:owner>
  648 </D:lockinfo>');
  649 
  650         $this->server->httpRequest = $request;
  651         $this->server->exec();
  652 
  653         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  654         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  655 
  656         $this->assertEquals(201, $this->response->status);
  657 
  658         $request = new HTTP\Request('MOVE', '/dir/child.txt', [
  659             'Destination' => '/dir/child2.txt',
  660         ]);
  661         $this->server->httpRequest = $request;
  662         $this->server->exec();
  663 
  664         $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination');
  665         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  666     }
  667 
  668     /**
  669      * @depends testLock
  670      */
  671     public function testLockMoveLockParent()
  672     {
  673         $request = new HTTP\Request('LOCK', '/dir', [
  674             'Depth' => 'infinite',
  675         ]);
  676         $request->setBody('<?xml version="1.0"?>
  677 <D:lockinfo xmlns:D="DAV:">
  678     <D:lockscope><D:exclusive/></D:lockscope>
  679     <D:locktype><D:write/></D:locktype>
  680     <D:owner>
  681         <D:href>http://example.org/~ejw/contact.html</D:href>
  682     </D:owner>
  683 </D:lockinfo>');
  684 
  685         $this->server->httpRequest = $request;
  686         $this->server->exec();
  687 
  688         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  689         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  690 
  691         $this->assertEquals(200, $this->response->status);
  692 
  693         $request = new HTTP\Request('MOVE', '/dir/child.txt', [
  694             'Destination' => '/dir/child2.txt',
  695             'If' => '</dir> ('.$this->response->getHeader('Lock-Token').')',
  696         ]);
  697         $this->server->httpRequest = $request;
  698         $this->server->exec();
  699 
  700         $this->assertEquals(201, $this->response->status, 'We locked the parent of both the source and destination, but the move didn\'t succeed.');
  701         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  702     }
  703 
  704     /**
  705      * @depends testLock
  706      */
  707     public function testLockPutGoodToken()
  708     {
  709         $request = new HTTP\Request('LOCK', '/test.txt');
  710         $request->setBody('<?xml version="1.0"?>
  711 <D:lockinfo xmlns:D="DAV:">
  712     <D:lockscope><D:exclusive/></D:lockscope>
  713     <D:locktype><D:write/></D:locktype>
  714     <D:owner>
  715         <D:href>http://example.org/~ejw/contact.html</D:href>
  716     </D:owner>
  717 </D:lockinfo>');
  718 
  719         $this->server->httpRequest = $request;
  720         $this->server->exec();
  721 
  722         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  723         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  724 
  725         $this->assertEquals(200, $this->response->status);
  726 
  727         $request = new HTTP\Request('PUT', '/test.txt', [
  728             'If' => '('.$this->response->getHeader('Lock-Token').')',
  729         ]);
  730         $request->setBody('newbody');
  731         $this->server->httpRequest = $request;
  732         $this->server->exec();
  733 
  734         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  735         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  736 
  737         $this->assertEquals(204, $this->response->status);
  738     }
  739 
  740     /**
  741      * @depends testLock
  742      */
  743     public function testLockPutUnrelatedToken()
  744     {
  745         $request = new HTTP\Request('LOCK', '/unrelated.txt');
  746         $request->setBody('<?xml version="1.0"?>
  747 <D:lockinfo xmlns:D="DAV:">
  748     <D:lockscope><D:exclusive/></D:lockscope>
  749     <D:locktype><D:write/></D:locktype>
  750     <D:owner>
  751         <D:href>http://example.org/~ejw/contact.html</D:href>
  752     </D:owner>
  753 </D:lockinfo>');
  754 
  755         $this->server->httpRequest = $request;
  756         $this->server->exec();
  757 
  758         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  759         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  760 
  761         $this->assertEquals(201, $this->response->getStatus());
  762 
  763         $request = new HTTP\Request(
  764             'PUT',
  765             '/test.txt',
  766             ['If' => '</unrelated.txt> ('.$this->response->getHeader('Lock-Token').')']
  767         );
  768         $request->setBody('newbody');
  769         $this->server->httpRequest = $request;
  770         $this->server->exec();
  771 
  772         $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type'));
  773         $this->assertTrue(1 === preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')), 'We did not get a valid Locktoken back ('.$this->response->getHeader('Lock-Token').')');
  774 
  775         $this->assertEquals(204, $this->response->status);
  776     }
  777 
  778     public function testPutWithIncorrectETag()
  779     {
  780         $request = new HTTP\Request('PUT', '/test.txt', [
  781             'If' => '(["etag1"])',
  782         ]);
  783         $request->setBody('newbody');
  784         $this->server->httpRequest = $request;
  785         $this->server->exec();
  786         $this->assertEquals(412, $this->response->status);
  787     }
  788 
  789     /**
  790      * @depends testPutWithIncorrectETag
  791      */
  792     public function testPutWithCorrectETag()
  793     {
  794         // We need an ETag-enabled file node.
  795         $tree = new DAV\Tree(new DAV\FSExt\Directory(SABRE_TEMPDIR));
  796         $this->server->tree = $tree;
  797 
  798         $filename = SABRE_TEMPDIR.'/test.txt';
  799         $etag = sha1(
  800             fileinode($filename).
  801             filesize($filename).
  802             filemtime($filename)
  803         );
  804 
  805         $request = new HTTP\Request('PUT', '/test.txt', [
  806             'If' => '(["'.$etag.'"])',
  807         ]);
  808         $request->setBody('newbody');
  809 
  810         $this->server->httpRequest = $request;
  811         $this->server->exec();
  812         $this->assertEquals(204, $this->response->status, 'Incorrect status received. Full response body:'.$this->response->getBodyAsString());
  813     }
  814 
  815     public function testDeleteWithETagOnCollection()
  816     {
  817         $request = new HTTP\Request('DELETE', '/dir', [
  818             'If' => '(["etag1"])',
  819         ]);
  820 
  821         $this->server->httpRequest = $request;
  822         $this->server->exec();
  823         $this->assertEquals(412, $this->response->status);
  824     }
  825 
  826     public function testGetTimeoutHeader()
  827     {
  828         $request = new HTTP\Request('LOCK', '/foo/bar', [
  829             'Timeout' => 'second-100',
  830         ]);
  831 
  832         $this->server->httpRequest = $request;
  833         $this->assertEquals(100, $this->locksPlugin->getTimeoutHeader());
  834     }
  835 
  836     public function testGetTimeoutHeaderTwoItems()
  837     {
  838         $request = new HTTP\Request('LOCK', '/foo/bar', [
  839             'Timeout' => 'second-5, infinite',
  840         ]);
  841         $this->server->httpRequest = $request;
  842         $this->assertEquals(5, $this->locksPlugin->getTimeoutHeader());
  843     }
  844 
  845     public function testGetTimeoutHeaderInfinite()
  846     {
  847         $request = new HTTP\Request('LOCK', '/foo/bar', [
  848             'Timeout' => 'infinite, second-5',
  849         ]);
  850         $this->server->httpRequest = $request;
  851         $this->assertEquals(LockInfo::TIMEOUT_INFINITE, $this->locksPlugin->getTimeoutHeader());
  852     }
  853 
  854     /**
  855      * @expectedException \Sabre\DAV\Exception\BadRequest
  856      */
  857     public function testGetTimeoutHeaderInvalid()
  858     {
  859         $request = new HTTP\Request('GET', '/', ['Timeout' => 'yourmom']);
  860 
  861         $this->server->httpRequest = $request;
  862         $this->locksPlugin->getTimeoutHeader();
  863     }
  864 }