appDataFactory = $this->createMock(Factory::class); $this->appData = $this->createMock(AppData::class); $this->appDataFactory->expects($this->once()) ->method('get') ->with('appstore') ->willReturn($this->appData); $this->clientService = $this->createMock(IClientService::class); $this->timeFactory = $this->createMock(ITimeFactory::class); $this->config = $this->createMock(IConfig::class); $this->logger = $this->createMock(LoggerInterface::class); $this->registry = $this->createMock(IRegistry::class); } public function testGetWithAlreadyExistingFileAndUpToDateTimestampAndVersion(): void { $this->config ->method('getSystemValueString') ->willReturnCallback(function ($var, $default) { if ($var === 'version') { return '11.0.0.2'; } return $default; }); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willReturn($file); $file ->expects($this->once()) ->method('getContent') ->willReturn('{"timestamp":1200,"data":[{"id":"MyApp"}],"ncversion":"11.0.0.2"}'); $this->timeFactory ->expects($this->once()) ->method('getTime') ->willReturn(1499); $expected = [ [ 'id' => 'MyApp', ], ]; $this->assertSame($expected, $this->fetcher->get()); } public function testGetWithNotExistingFileAndUpToDateTimestampAndVersion(): void { $this->config ->method('getSystemValueString') ->willReturnCallback(function ($var, $default) { if ($var === 'appstoreurl') { return 'https://apps.nextcloud.com/api/v1'; } elseif ($var === 'version') { return '11.0.0.2'; } return $default; }); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willThrowException(new NotFoundException()); $folder ->expects($this->once()) ->method('newFile') ->with($this->fileName) ->willReturn($file); $client = $this->createMock(IClient::class); $this->clientService ->expects($this->once()) ->method('newClient') ->willReturn($client); $response = $this->createMock(IResponse::class); $client ->expects($this->once()) ->method('get') ->with($this->endpoint) ->willReturn($response); $response ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); $response->method('getHeader') ->with($this->equalTo('ETag')) ->willReturn('"myETag"'); $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->once()) ->method('putContent') ->with($fileData); $file ->expects($this->once()) ->method('getContent') ->willReturn($fileData); $this->timeFactory ->expects($this->once()) ->method('getTime') ->willReturn(1502); $expected = [ [ 'id' => 'MyNewApp', 'foo' => 'foo', ], [ 'id' => 'bar', ], ]; $this->assertSame($expected, $this->fetcher->get()); } public function testGetWithAlreadyExistingFileAndOutdatedTimestamp(): void { $this->config->method('getSystemValueString') ->willReturnCallback(function ($key, $default) { if ($key === 'version') { return '11.0.0.2'; } else { return $default; } }); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willReturn($file); $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1502,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->once()) ->method('putContent') ->with($fileData); $file ->expects($this->exactly(2)) ->method('getContent') ->willReturnOnConsecutiveCalls( '{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}},"ncversion":"11.0.0.2"}', $fileData ); $this->timeFactory ->expects($this->exactly(2)) ->method('getTime') ->willReturnOnConsecutiveCalls( 4801, 1502 ); $client = $this->createMock(IClient::class); $this->clientService ->expects($this->once()) ->method('newClient') ->willReturn($client); $response = $this->createMock(IResponse::class); $client ->expects($this->once()) ->method('get') ->with($this->endpoint) ->willReturn($response); $response ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); $response->method('getHeader') ->with($this->equalTo('ETag')) ->willReturn('"myETag"'); $expected = [ [ 'id' => 'MyNewApp', 'foo' => 'foo', ], [ 'id' => 'bar', ], ]; $this->assertSame($expected, $this->fetcher->get()); } public function testGetWithAlreadyExistingFileAndNoVersion(): void { $this->config ->method('getSystemValueString') ->willReturnCallback(function ($var, $default) { if ($var === 'appstoreurl') { return 'https://apps.nextcloud.com/api/v1'; } elseif ($var === 'version') { return '11.0.0.2'; } return $default; }); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willReturn($file); $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1201,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->once()) ->method('putContent') ->with($fileData); $file ->expects($this->exactly(2)) ->method('getContent') ->willReturnOnConsecutiveCalls( '{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}}', $fileData ); $this->timeFactory ->expects($this->once()) ->method('getTime') ->willReturn(1201); $client = $this->createMock(IClient::class); $this->clientService ->expects($this->once()) ->method('newClient') ->willReturn($client); $response = $this->createMock(IResponse::class); $client ->expects($this->once()) ->method('get') ->with($this->endpoint) ->willReturn($response); $response ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); $response->method('getHeader') ->with($this->equalTo('ETag')) ->willReturn('"myETag"'); $expected = [ [ 'id' => 'MyNewApp', 'foo' => 'foo', ], [ 'id' => 'bar', ], ]; $this->assertSame($expected, $this->fetcher->get()); } public function testGetWithAlreadyExistingFileAndOutdatedVersion(): void { $this->config ->method('getSystemValueString') ->willReturnCallback(function ($var, $default) { if ($var === 'appstoreurl') { return 'https://apps.nextcloud.com/api/v1'; } elseif ($var === 'version') { return '11.0.0.2'; } return $default; }); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willReturn($file); $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1201,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->once()) ->method('putContent') ->with($fileData); $file ->expects($this->exactly(2)) ->method('getContent') ->willReturnOnConsecutiveCalls( '{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}},"ncversion":"11.0.0.1"', $fileData ); $this->timeFactory ->method('getTime') ->willReturn(1201); $client = $this->createMock(IClient::class); $this->clientService ->expects($this->once()) ->method('newClient') ->willReturn($client); $response = $this->createMock(IResponse::class); $client ->expects($this->once()) ->method('get') ->with($this->endpoint) ->willReturn($response); $response ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp", "foo": "foo"}, {"id":"bar"}]'); $response->method('getHeader') ->with($this->equalTo('ETag')) ->willReturn('"myETag"'); $expected = [ [ 'id' => 'MyNewApp', 'foo' => 'foo', ], [ 'id' => 'bar', ], ]; $this->assertSame($expected, $this->fetcher->get()); } public function testGetWithExceptionInClient(): void { $this->config->method('getSystemValueString') ->willReturnArgument(1); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willReturn($file); $file ->expects($this->once()) ->method('getContent') ->willReturn('{"timestamp":1200,"data":{"MyApp":{"id":"MyApp"}}}'); $client = $this->createMock(IClient::class); $this->clientService ->expects($this->once()) ->method('newClient') ->willReturn($client); $client ->expects($this->once()) ->method('get') ->with($this->endpoint) ->willThrowException(new \Exception()); $this->assertSame([], $this->fetcher->get()); } public function testGetMatchingETag(): void { $this->config->method('getSystemValueString') ->willReturnCallback(function ($key, $default) { if ($key === 'version') { return '11.0.0.2'; } else { return $default; } }); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willReturn($file); $origData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1200,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $newData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":4802,"ncversion":"11.0.0.2","ETag":"\"myETag\""}'; $file ->expects($this->once()) ->method('putContent') ->with($newData); $file ->expects($this->exactly(2)) ->method('getContent') ->willReturnOnConsecutiveCalls( $origData, $newData, ); $this->timeFactory ->expects($this->exactly(2)) ->method('getTime') ->willReturnOnConsecutiveCalls( 4801, 4802 ); $client = $this->createMock(IClient::class); $this->clientService ->expects($this->once()) ->method('newClient') ->willReturn($client); $response = $this->createMock(IResponse::class); $client ->expects($this->once()) ->method('get') ->with( $this->equalTo($this->endpoint), $this->equalTo([ 'timeout' => 60, 'headers' => [ 'If-None-Match' => '"myETag"' ] ]) )->willReturn($response); $response->method('getStatusCode') ->willReturn(304); $expected = [ [ 'id' => 'MyNewApp', 'foo' => 'foo', ], [ 'id' => 'bar', ], ]; $this->assertSame($expected, $this->fetcher->get()); } public function testGetNoMatchingETag(): void { $this->config->method('getSystemValueString') ->willReturnCallback(function ($key, $default) { if ($key === 'version') { return '11.0.0.2'; } else { return $default; } }); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willReturn($file); $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":4802,"ncversion":"11.0.0.2","ETag":"\"newETag\""}'; $file ->expects($this->once()) ->method('putContent') ->with($fileData); $file ->expects($this->exactly(2)) ->method('getContent') ->willReturnOnConsecutiveCalls( '{"data":[{"id":"MyOldApp","abc":"def"}],"timestamp":1200,"ncversion":"11.0.0.2","ETag":"\"myETag\""}', $fileData, ); $this->timeFactory ->expects($this->exactly(2)) ->method('getTime') ->willReturnOnConsecutiveCalls( 4801, 4802, ); $client = $this->createMock(IClient::class); $this->clientService ->expects($this->once()) ->method('newClient') ->willReturn($client); $response = $this->createMock(IResponse::class); $client ->expects($this->once()) ->method('get') ->with( $this->equalTo($this->endpoint), $this->equalTo([ 'timeout' => 60, 'headers' => [ 'If-None-Match' => '"myETag"', ] ]) ) ->willReturn($response); $response->method('getStatusCode') ->willReturn(200); $response ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}]'); $response->method('getHeader') ->with($this->equalTo('ETag')) ->willReturn('"newETag"'); $expected = [ [ 'id' => 'MyNewApp', 'foo' => 'foo', ], [ 'id' => 'bar', ], ]; $this->assertSame($expected, $this->fetcher->get()); } public function testFetchAfterUpgradeNoETag(): void { $this->config->method('getSystemValueString') ->willReturnCallback(function ($key, $default) { if ($key === 'version') { return '11.0.0.3'; } else { return $default; } }); $this->config->method('getSystemValueBool') ->willReturnArgument(1); $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $this->appData ->expects($this->once()) ->method('getFolder') ->with('/') ->willReturn($folder); $folder ->expects($this->once()) ->method('getFile') ->with($this->fileName) ->willReturn($file); $fileData = '{"data":[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}],"timestamp":1501,"ncversion":"11.0.0.3","ETag":"\"newETag\""}'; $file ->expects($this->once()) ->method('putContent') ->with($fileData); $file ->expects($this->exactly(2)) ->method('getContent') ->willReturnOnConsecutiveCalls( '{"data":[{"id":"MyOldApp","abc":"def"}],"timestamp":1200,"ncversion":"11.0.0.2","ETag":"\"myETag\""}', $fileData ); $client = $this->createMock(IClient::class); $this->clientService ->expects($this->once()) ->method('newClient') ->willReturn($client); $response = $this->createMock(IResponse::class); $client ->expects($this->once()) ->method('get') ->with( $this->equalTo($this->endpoint), $this->equalTo([ 'timeout' => 60, ]) ) ->willReturn($response); $response->method('getStatusCode') ->willReturn(200); $response ->expects($this->once()) ->method('getBody') ->willReturn('[{"id":"MyNewApp","foo":"foo"},{"id":"bar"}]'); $response->method('getHeader') ->with($this->equalTo('ETag')) ->willReturn('"newETag"'); $this->timeFactory ->expects($this->once()) ->method('getTime') ->willReturn(1501); $expected = [ [ 'id' => 'MyNewApp', 'foo' => 'foo', ], [ 'id' => 'bar', ], ]; $this->assertSame($expected, $this->fetcher->get()); } }