AmazonS3Spec.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. <?php
  2. namespace spec\Gaufrette\Adapter;
  3. use AmazonS3;
  4. use PhpSpec\ObjectBehavior;
  5. use Prophecy\Argument;
  6. class AmazonS3Spec extends ObjectBehavior
  7. {
  8. /**
  9. * @param \AmazonS3 $service
  10. */
  11. function let(AmazonS3 $service)
  12. {
  13. $this->beConstructedWith($service, 'bucketName');
  14. }
  15. function it_is_adapter()
  16. {
  17. $this->shouldHaveType('Gaufrette\Adapter');
  18. }
  19. function it_supports_metadata()
  20. {
  21. $this->shouldHaveType('Gaufrette\Adapter\MetadataSupporter');
  22. }
  23. /**
  24. * @param \AmazonS3 $service
  25. */
  26. function it_reads_file(AmazonS3 $service)
  27. {
  28. $options = array(
  29. 'range' => 12,
  30. 'response' => array(
  31. 'content-language' => 'pl-pl'
  32. )
  33. );
  34. $service
  35. ->if_bucket_exists('bucketName')
  36. ->shouldBeCalled()
  37. ->willReturn(true)
  38. ;
  39. $service
  40. ->get_object(
  41. 'bucketName',
  42. 'filename',
  43. $options
  44. )
  45. ->shouldBeCalled()
  46. ->willReturn(new \CFResponse('header', 'some content', 200))
  47. ;
  48. $this->setMetadata('filename', $options);
  49. $this->read('filename')->shouldReturn('some content');
  50. }
  51. /**
  52. * @param \AmazonS3 $service
  53. */
  54. function it_returns_false_when_cannot_read(AmazonS3 $service)
  55. {
  56. $service
  57. ->if_bucket_exists('bucketName')
  58. ->shouldBeCalled()
  59. ->willReturn(true)
  60. ;
  61. $service
  62. ->get_object(
  63. 'bucketName',
  64. 'filename',
  65. array()
  66. )
  67. ->shouldBeCalled()
  68. ->willReturn(new \CFResponse('header', 'some content', 500))
  69. ;
  70. $this->read('filename')->shouldReturn(false);
  71. }
  72. /**
  73. * @param \AmazonS3 $service
  74. */
  75. function it_is_verbose_and_throws_exceptions_when_read(AmazonS3 $service)
  76. {
  77. $service
  78. ->if_bucket_exists('bucketName')
  79. ->shouldBeCalled()
  80. ->willReturn(true)
  81. ;
  82. $service
  83. ->get_object(
  84. 'bucketName',
  85. 'filename',
  86. array()
  87. )
  88. ->willThrow(new \RuntimeException('read'))
  89. ;
  90. $this->shouldThrow(new \RuntimeException('read'))->duringRead('filename');
  91. }
  92. /**
  93. * @param \AmazonS3 $service
  94. */
  95. function it_rename_file(AmazonS3 $service)
  96. {
  97. $service
  98. ->if_bucket_exists('bucketName')
  99. ->shouldBeCalled()
  100. ->willReturn(true)
  101. ;
  102. $service
  103. ->copy_object(
  104. array(
  105. 'bucket' => 'bucketName',
  106. 'filename' => 'filename1',
  107. ),
  108. array(
  109. 'bucket' => 'bucketName',
  110. 'filename' => 'filename2'
  111. ),
  112. array('acl' => \AmazonS3::ACL_OWNER_READ)
  113. )
  114. ->shouldBeCalled()
  115. ->willReturn(new \CFResponse('header', 'some content', 200))
  116. ;
  117. $service
  118. ->delete_object(
  119. 'bucketName',
  120. 'filename1',
  121. Argument::any()
  122. )
  123. ->shouldBeCalled()
  124. ->willReturn(new \CFResponse(array(), 'some', 200))
  125. ;
  126. $this->setMetadata('filename1', array('acl' => \AmazonS3::ACL_OWNER_READ));
  127. $this->rename('filename1', 'filename2')->shouldReturn(true);
  128. }
  129. /**
  130. * @param \AmazonS3 $service
  131. */
  132. function it_is_verbose_and_throws_exceptions_when_rename(AmazonS3 $service)
  133. {
  134. $service
  135. ->if_bucket_exists('bucketName')
  136. ->shouldBeCalled()
  137. ->willReturn(true)
  138. ;
  139. $service
  140. ->copy_object(Argument::cetera())
  141. ->willThrow(new \RuntimeException('rename'))
  142. ;
  143. $this->shouldThrow(new \RuntimeException('rename'))->duringRename('filename', 'filename1');
  144. }
  145. /**
  146. * @param \AmazonS3 $service
  147. */
  148. function it_returns_false_when_cannot_rename(AmazonS3 $service)
  149. {
  150. $service
  151. ->if_bucket_exists('bucketName')
  152. ->shouldBeCalled()
  153. ->willReturn(true)
  154. ;
  155. $service
  156. ->copy_object(
  157. array(
  158. 'bucket' => 'bucketName',
  159. 'filename' => 'filename1',
  160. ),
  161. array(
  162. 'bucket' => 'bucketName',
  163. 'filename' => 'filename2'
  164. ),
  165. array()
  166. )
  167. ->shouldBeCalled()
  168. ->willReturn(new \CFResponse('header', 'some content', 500))
  169. ;
  170. $this->rename('filename1', 'filename2')->shouldReturn(false);
  171. }
  172. /**
  173. * @param \AmazonS3 $service
  174. */
  175. function it_should_write_file(AmazonS3 $service)
  176. {
  177. $service
  178. ->if_bucket_exists('bucketName')
  179. ->shouldBeCalled()
  180. ->willReturn(true)
  181. ;
  182. $service
  183. ->create_object(
  184. 'bucketName',
  185. 'filename',
  186. array(
  187. 'acl' => \AmazonS3::ACL_PRIVATE,
  188. 'body' => 'some content'
  189. )
  190. )
  191. ->shouldBeCalled()
  192. ->willReturn(new \CFResponse(array('x-aws-requestheaders' => array('Content-Length' => 12)), 'some content', 200))
  193. ;
  194. $this->setMetadata('filename', array('acl' => \AmazonS3::ACL_PRIVATE, 'body' => 'other content'));
  195. $this->write('filename', 'some content')->shouldReturn(12);
  196. }
  197. /**
  198. * @param \AmazonS3 $service
  199. */
  200. function it_returns_false_when_cannot_write(AmazonS3 $service)
  201. {
  202. $service
  203. ->if_bucket_exists('bucketName')
  204. ->shouldBeCalled()
  205. ->willReturn(true)
  206. ;
  207. $service
  208. ->create_object(
  209. 'bucketName',
  210. 'filename',
  211. array(
  212. 'acl' => \AmazonS3::ACL_PUBLIC,
  213. 'body' => 'some content'
  214. )
  215. )
  216. ->shouldBeCalled()
  217. ->willReturn(new \CFResponse(array('x-aws-requestheaders' => array('Content-Length' => 12)), 'some content', 500))
  218. ;
  219. $this->write('filename', 'some content')->shouldReturn(false);
  220. }
  221. /**
  222. * @param \AmazonS3 $service
  223. */
  224. function it_is_verbose_and_throws_exceptions_when_write(AmazonS3 $service)
  225. {
  226. $service
  227. ->if_bucket_exists('bucketName')
  228. ->shouldBeCalled()
  229. ->willReturn(true)
  230. ;
  231. $service
  232. ->create_object(Argument::cetera())
  233. ->willThrow(new \RuntimeException('write'))
  234. ;
  235. $this->shouldThrow(new \RuntimeException('write'))->duringWrite('filename', 'some content');
  236. }
  237. /**
  238. * @param \AmazonS3 $service
  239. */
  240. function it_should_check_if_file_exists(AmazonS3 $service)
  241. {
  242. $service
  243. ->if_bucket_exists('bucketName')
  244. ->shouldBeCalled()
  245. ->willReturn(true)
  246. ;
  247. $service->if_object_exists('bucketName', 'filename')->willReturn(true);
  248. $this->exists('filename')->shouldReturn(true);
  249. $service->if_object_exists('bucketName', 'filename')->willReturn(false);
  250. $this->exists('filename')->shouldReturn(false);
  251. }
  252. /**
  253. * @param \AmazonS3 $service
  254. */
  255. function it_is_verbose_and_throws_exceptions_when_file_exists(AmazonS3 $service)
  256. {
  257. $service
  258. ->if_bucket_exists('bucketName')
  259. ->shouldBeCalled()
  260. ->willReturn(true)
  261. ;
  262. $service
  263. ->if_object_exists('bucketName', 'filename')
  264. ->willThrow(new \RuntimeException('exists'))
  265. ;
  266. $this->shouldThrow(new \RuntimeException('exists'))->duringExists('filename');
  267. }
  268. /**
  269. * @param \AmazonS3 $service
  270. */
  271. function it_should_get_file_mtime(AmazonS3 $service)
  272. {
  273. $metadata = array('acl' => \AmazonS3::ACL_PUBLIC);
  274. $service
  275. ->if_bucket_exists('bucketName')
  276. ->shouldBeCalled()
  277. ->willReturn(true)
  278. ;
  279. $service
  280. ->get_object_metadata(
  281. 'bucketName',
  282. 'filename',
  283. $metadata
  284. )
  285. ->shouldBeCalled()
  286. ->willReturn(array('Headers' => array('last-modified' => '2012-01-01 23:10:10')))
  287. ;
  288. $this->setMetadata('filename', $metadata);
  289. $this->mtime('filename')->shouldReturn(strtotime('2012-01-01 23:10:10'));
  290. }
  291. /**
  292. * @param \AmazonS3 $service
  293. */
  294. function it_returns_false_when_cannot_fetch_mtime(AmazonS3 $service)
  295. {
  296. $service
  297. ->if_bucket_exists('bucketName')
  298. ->shouldBeCalled()
  299. ->willReturn(true)
  300. ;
  301. $service
  302. ->get_object_metadata(
  303. 'bucketName',
  304. 'filename',
  305. array()
  306. )
  307. ->shouldBeCalled()
  308. ->willReturn(array('Headers' => array()))
  309. ;
  310. $this->mtime('filename')->shouldReturn(false);
  311. }
  312. /**
  313. * @param \AmazonS3 $service
  314. */
  315. function it_is_verbose_and_throws_exceptions_when_fetch_mtime(AmazonS3 $service)
  316. {
  317. $service
  318. ->if_bucket_exists('bucketName')
  319. ->shouldBeCalled()
  320. ->willReturn(true)
  321. ;
  322. $service
  323. ->get_object_metadata('bucketName', 'filename', Argument::any())
  324. ->willThrow(new \RuntimeException('mtime'))
  325. ;
  326. $this->shouldThrow(new \RuntimeException('mtime'))->duringMtime('filename');
  327. }
  328. /**
  329. * @param \AmazonS3 $service
  330. */
  331. function it_should_delete_file(AmazonS3 $service)
  332. {
  333. $metadata = array('acl' => \AmazonS3::ACL_PRIVATE);
  334. $service
  335. ->if_bucket_exists('bucketName')
  336. ->shouldBeCalled()
  337. ->willReturn(true)
  338. ;
  339. $service
  340. ->delete_object(
  341. 'bucketName',
  342. 'filename',
  343. $metadata
  344. )
  345. ->willReturn(new \CFResponse(array(), 'some', 200))
  346. ;
  347. $this->setMetadata('filename', $metadata);
  348. $this->delete('filename')->shouldReturn(true);
  349. }
  350. /**
  351. * @param \AmazonS3 $service
  352. */
  353. function it_is_verbose_and_throws_exceptions_when_fetch_delete(AmazonS3 $service)
  354. {
  355. $service
  356. ->if_bucket_exists('bucketName')
  357. ->willReturn(true)
  358. ;
  359. $service
  360. ->delete_object(
  361. 'bucketName',
  362. 'filename',
  363. Argument::any()
  364. )
  365. ->willThrow(new \RuntimeException('delete'))
  366. ;
  367. $this->shouldThrow(new \RuntimeException('delete'))->duringDelete('filename');
  368. }
  369. /**
  370. * @param \AmazonS3 $service
  371. */
  372. function it_returns_false_when_cannot_delete(AmazonS3 $service)
  373. {
  374. $service
  375. ->if_bucket_exists('bucketName')
  376. ->shouldBeCalled()
  377. ->willReturn(true)
  378. ;
  379. $service
  380. ->delete_object(
  381. 'bucketName',
  382. 'filename',
  383. array()
  384. )
  385. ->willReturn(new \CFResponse(array(), 'some', 500))
  386. ;
  387. $this->delete('filename')->shouldReturn(false);
  388. }
  389. /**
  390. * @param \AmazonS3 $service
  391. */
  392. function it_should_get_keys(AmazonS3 $service)
  393. {
  394. $service
  395. ->if_bucket_exists('bucketName')
  396. ->shouldBeCalled()
  397. ->willReturn(true)
  398. ;
  399. $service
  400. ->get_object_list('bucketName')
  401. ->shouldBeCalled()
  402. ->willReturn(array('filename2', 'aaa/filename', 'filename1'))
  403. ;
  404. $this->keys()->shouldReturn(array('aaa', 'aaa/filename', 'filename1', 'filename2'));
  405. }
  406. /**
  407. * @param \AmazonS3 $service
  408. */
  409. function it_is_verbose_and_throws_exceptions_when_fetch_keys(AmazonS3 $service)
  410. {
  411. $service
  412. ->if_bucket_exists('bucketName')
  413. ->willReturn(true)
  414. ;
  415. $service
  416. ->get_object_list('bucketName')
  417. ->willThrow(new \RuntimeException('keys'))
  418. ;
  419. $this->shouldThrow(new \RuntimeException('keys'))->duringKeys();
  420. }
  421. /**
  422. * @param \AmazonS3 $service
  423. */
  424. function it_should_handle_dirs(AmazonS3 $service)
  425. {
  426. $service
  427. ->if_bucket_exists('bucketName')
  428. ->willReturn(true)
  429. ;
  430. $service
  431. ->if_object_exists('bucketName', 'filename')
  432. ->shouldNotBeCalled()
  433. ;
  434. $service
  435. ->if_object_exists('bucketName', 'filename/')
  436. ->shouldBeCalled()
  437. ->willReturn(false)
  438. ;
  439. $service
  440. ->if_object_exists('bucketName', 'dirname/')
  441. ->willReturn(true)
  442. ;
  443. $this->isDirectory('filename')->shouldReturn(false);
  444. $this->isDirectory('dirname')->shouldReturn(true);
  445. }
  446. /**
  447. * @param \AmazonS3 $service
  448. */
  449. function it_should_fail_when_bucket_does_not_exist(AmazonS3 $service)
  450. {
  451. $service
  452. ->if_bucket_exists('bucketName')
  453. ->willReturn(false)
  454. ;
  455. $this
  456. ->shouldThrow(new \RuntimeException('The configured bucket "bucketName" does not exist.'))
  457. ->duringRead('filename')
  458. ;
  459. $this
  460. ->shouldThrow(new \RuntimeException('The configured bucket "bucketName" does not exist.'))
  461. ->duringWrite('filename', 'content')
  462. ;
  463. $this
  464. ->shouldThrow(new \RuntimeException('The configured bucket "bucketName" does not exist.'))
  465. ->duringDelete('filename')
  466. ;
  467. $this
  468. ->shouldThrow(new \RuntimeException('The configured bucket "bucketName" does not exist.'))
  469. ->duringExists('filename')
  470. ;
  471. $this
  472. ->shouldThrow(new \RuntimeException('The configured bucket "bucketName" does not exist.'))
  473. ->duringMtime('filename')
  474. ;
  475. $this
  476. ->shouldThrow(new \RuntimeException('The configured bucket "bucketName" does not exist.'))
  477. ->duringRename('filename', 'filename2')
  478. ;
  479. $this
  480. ->shouldThrow(new \RuntimeException('The configured bucket "bucketName" does not exist.'))
  481. ->duringKeys()
  482. ;
  483. }
  484. /**
  485. * @param \AmazonS3 $service
  486. */
  487. function it_creates_bucket_if_create_mode_is_enabled(AmazonS3 $service)
  488. {
  489. $service->set_region(Argument::any())->shouldBeCalled();
  490. $service
  491. ->if_bucket_exists('bucketName')
  492. ->willReturn(false)
  493. ;
  494. $service->hostname = \AmazonS3::REGION_US_E1;
  495. $service
  496. ->create_bucket('bucketName', \AmazonS3::REGION_US_E1)
  497. ->shouldBeCalled()
  498. ->willReturn(new \CFResponse(array(), 'created', 201))
  499. ;
  500. $service
  501. ->if_object_exists('bucketName', 'filename')
  502. ->willReturn(false)
  503. ;
  504. $this->beConstructedWith($service, 'bucketName', array('create' => true));
  505. $this->exists('filename');
  506. }
  507. /**
  508. * @param \AmazonS3 $service
  509. */
  510. function it_fails_when_cannot_create_bucket(AmazonS3 $service)
  511. {
  512. $service
  513. ->if_bucket_exists('bucketName')
  514. ->willReturn(false)
  515. ;
  516. $service
  517. ->create_bucket('bucketName', Argument::any())
  518. ->shouldBeCalled()
  519. ->willReturn(new \CFResponse(array(), 'created', 500))
  520. ;
  521. $this->beConstructedWith($service, 'bucketName', array('create' => true));
  522. $this
  523. ->shouldThrow(new \RuntimeException('Failed to create the configured bucket "bucketName".'))
  524. ->duringExists('filename')
  525. ;
  526. }
  527. /**
  528. * @param \AmazonS3 $service
  529. */
  530. function it_allows_to_configure_reqion(AmazonS3 $service)
  531. {
  532. $service
  533. ->if_bucket_exists('bucketName')
  534. ->willReturn(true)
  535. ;
  536. $service
  537. ->set_region(\AmazonS3::REGION_EU_W1)
  538. ->shouldBeCalled()
  539. ;
  540. $service
  541. ->if_object_exists('bucketName', 'filename')
  542. ->willReturn(true)
  543. ;
  544. $this->beConstructedWith($service, 'bucketName', array('region' => \AmazonS3::REGION_EU_W1));
  545. $this->exists('filename');
  546. }
  547. /**
  548. * @param \AmazonS3 $service
  549. */
  550. function it_allows_to_configure_region_for_bucket(AmazonS3 $service)
  551. {
  552. $service->set_region(Argument::any())->shouldBeCalled();
  553. $service
  554. ->if_bucket_exists('bucketName')
  555. ->willReturn(false)
  556. ;
  557. $service
  558. ->create_bucket('bucketName', \AmazonS3::REGION_EU_W1)
  559. ->shouldBeCalled()
  560. ->willReturn(new \CFResponse(array(), 'created', 201))
  561. ;
  562. $service
  563. ->if_object_exists('bucketName', 'filename')
  564. ->willReturn(false)
  565. ;
  566. $this->beConstructedWith($service, 'bucketName', array('create' => true, 'region' => \AmazonS3::REGION_EU_W1));
  567. $this->exists('filename');
  568. }
  569. /**
  570. * @param \AmazonS3 $service
  571. */
  572. function it_allows_to_configure_acl(AmazonS3 $service)
  573. {
  574. $this->setAcl('123abc');
  575. $service
  576. ->if_bucket_exists('bucketName')
  577. ->shouldBeCalled()
  578. ->willReturn(true)
  579. ;
  580. $service
  581. ->create_object(
  582. 'bucketName',
  583. 'filename',
  584. array(
  585. 'acl' => '123abc',
  586. 'body' => 'some content'
  587. )
  588. )
  589. ->shouldBeCalled()
  590. ->willReturn(new \CFResponse(array('x-aws-requestheaders' => array('Content-Length' => 12)), 'some content', 200))
  591. ;
  592. $this->write('filename', 'some content')->shouldReturn(12);
  593. $this->getAcl()->shouldBe('123abc');
  594. }
  595. /**
  596. * @param \AmazonS3 $service
  597. */
  598. function its_file_metadata_acl_are_more_important_than_global_acl_config(AmazonS3 $service)
  599. {
  600. $this->setAcl('123abc');
  601. $service
  602. ->if_bucket_exists('bucketName')
  603. ->shouldBeCalled()
  604. ->willReturn(true)
  605. ;
  606. $service
  607. ->create_object(
  608. 'bucketName',
  609. 'filename',
  610. array(
  611. 'acl' => 'more important acl',
  612. 'body' => 'some content'
  613. )
  614. )
  615. ->shouldBeCalled()
  616. ->willReturn(new \CFResponse(array('x-aws-requestheaders' => array('Content-Length' => 12)), 'some content', 200))
  617. ;
  618. $this->setMetadata('filename', array('acl' => 'more important acl'));
  619. $this->write('filename', 'some content')->shouldReturn(12);
  620. }
  621. }