commit afb0cc024dc40a872ec59f69b734257aa0611c77
Author: vastja <vastja@students.zcu.cz>
Date:   Tue May 26 19:27:22 2020 +0000

    + Re #8081
    + tests environmnet prepared
    + fast fix in build script

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..3a6ede0
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,44 @@
+// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
+// https://github.com/microsoft/vscode-dev-containers/tree/v0.117.0/containers/docker-existing-docker-compose
+// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
+{
+	"name": "Existing Docker Compose (Extend)",
+
+	// Update the 'dockerComposeFile' list if you have more compose files or use different names.
+	// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
+	"dockerComposeFile": [
+		"..\\docker-compose-dev.yml",
+		"docker-compose.yml"
+	],
+
+	// The 'service' property is the name of the service for the container that VS Code should
+	// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
+	"service": "php-fpm",
+
+	// The optional 'workspaceFolder' property is the path VS Code should open by default when
+	// connected. This is typically a file mount in .devcontainer/docker-compose.yml
+	"workspaceFolder": "/workspace",
+
+	// Set *default* container specific settings.json values on container create.
+	"settings": { 
+		"terminal.integrated.shell.linux": null
+	},
+
+	// Add the IDs of extensions you want installed when the container is created.
+	"extensions": []
+
+	// Use 'forwardPorts' to make a list of ports inside the container available locally.
+	// "forwardPorts": [],
+
+	// Uncomment the next line if you want start specific services in your Docker Compose config.
+	// "runServices": [],
+
+	// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
+	// "shutdownAction": "none",
+
+	// Uncomment the next line to run commands after the container is created - for example installing git.
+	// "postCreateCommand": "apt-get update && apt-get install -y git",
+
+	// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
+	// "remoteUser": "vscode"
+}
diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml
new file mode 100644
index 0000000..af4a65b
--- /dev/null
+++ b/.devcontainer/docker-compose.yml
@@ -0,0 +1,43 @@
+#-------------------------------------------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
+#-------------------------------------------------------------------------------------------------------------
+
+version: '3.2'
+services:
+  # Update this to the name of the service you want to work with in your docker-compose.yml file
+  php-fpm:
+    # If you want add a non-root user to your Dockerfile, you can use the "remoteUser"
+    # property in devcontainer.json to cause VS Code its sub-processes (terminals, tasks, 
+    # debugging) to execute as the user. Uncomment the next line if you want the entire 
+    # container to run as this user instead. Note that, on Linux, you may need to 
+    # ensure the UID and GID of the container user you create matches your local user. 
+    # See https://aka.ms/vscode-remote/containers/non-root for details.
+    #
+    # user: vscode
+
+    # Uncomment if you want to override the service's Dockerfile to one in the .devcontainer 
+    # folder. Note that the path of the Dockerfile and context is relative to the *primary* 
+    # docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile"
+    # array). The sample below assumes your primary file is in the root of your project.
+    #
+    # build:
+    #   context: .
+    #   dockerfile: .devcontainer/Dockerfile
+    
+    volumes:
+      # Update this to wherever you want VS Code to mount the folder of your project
+      - .:/workspace:cached
+
+      # Uncomment the next line to use Docker from inside the container. See https://aka.ms/vscode-remote/samples/docker-in-docker-compose for details.
+      # - /var/run/docker.sock:/var/run/docker.sock 
+
+    # Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
+    # cap_add:
+    #   - SYS_PTRACE
+    # security_opt:
+    #   - seccomp:unconfined
+
+    # Overrides default command so things don't shut down after the process ends.
+    command: /bin/sh -c "while sleep 1000; do :; done"
+ 
diff --git a/website/.env.test b/website/.env.test
new file mode 100644
index 0000000..7c76a65
--- /dev/null
+++ b/website/.env.test
@@ -0,0 +1,3 @@
+APP_ENV=test
+APP_SECRET=ca5751564bbb9a0d75d412e020790283
+DATABASE_CONNECTION_STRING=mongodb://root:root@database
diff --git a/website/src/Controller/HeatmapController.php b/website/src/Controller/HeatmapController.php
index 59a81b1..0ae3ce3 100644
--- a/website/src/Controller/HeatmapController.php
+++ b/website/src/Controller/HeatmapController.php
@@ -51,7 +51,7 @@ class HeatmapController extends AbstractController {
     /**
      * @Route("heatmap/available/{date}", name="available")
      */
-    public function availableDatasets(IOpenDataManager $manager, $date = '01012020') {
+    public function availableDatasets(IOpenDataManager $manager, $date = '2020-01-01') {
         return $this->json($manager->getAvailableCollectionsByDay($date));
     }
 
diff --git a/website/src/Repository/OpenDataManager.php b/website/src/Repository/OpenDataManager.php
index 2a4522b..b4f346d 100644
--- a/website/src/Repository/OpenDataManager.php
+++ b/website/src/Repository/OpenDataManager.php
@@ -16,6 +16,10 @@ class OpenDataManager implements IOpenDataManager {
     }
 
     public function getCollectionDataByName($name, $date, $hour) {
+        if (null == $name || null == $date || null == $hour) {
+            return [];
+        }
+
         $valh = $hour < 10 ? '0'.$hour : $hour;
         $openData = $this->manager->executeQuery('open-data-db.'.$name.$date, new Query(['date' => $date.'-'.$valh], []));
 
@@ -54,6 +58,10 @@ class OpenDataManager implements IOpenDataManager {
     }
 
     public function isCollectionAvailable($name, $date) {
+        if (null == $name || null == $date) {
+            return false;
+        }
+
         $result = $this->manager->executeQuery('open-data-db.'.$name, new Query(['date' => $date], []));
 
         return !empty($result->toArray());
@@ -90,6 +98,10 @@ class OpenDataManager implements IOpenDataManager {
     }
 
     public function getMaxCollectionNumberAtDay($name, $date) {
+        if (null == $name || null == $date) {
+            return 0;
+        }
+
         $max = $this->manager->executeQuery('open-data-db.'.$name.$date, new Query([], ['sort' => ['number' => -1], 'limit' => 1]));
 
         $max->setTypeMap([
@@ -100,10 +112,14 @@ class OpenDataManager implements IOpenDataManager {
 
         $result = $max->toArray();
 
-        return empty($result) ? 1 : $result[0]['number'];
+        return empty($result) ? 0 : $result[0]['number'];
     }
 
     public function getDataSourcePositions($name = 'NONE') {
+        if (null == $name) {
+            return [];
+        }
+
         $positions = $this->manager->executeQuery('open-data-db.'.$name.'DEVICES', new Query([], []));
 
         $positions->setTypeMap([
diff --git a/website/tests/Controller/HeatmapControllerTest.php b/website/tests/Controller/HeatmapControllerTest.php
index 1d4abd2..40df004 100644
--- a/website/tests/Controller/HeatmapControllerTest.php
+++ b/website/tests/Controller/HeatmapControllerTest.php
@@ -6,9 +6,97 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
 
 class HatmapControllerTest extends WebTestCase {
 
-    public function testMainPage() {
+    public function testPageLoad() {
         $client = static::createClient();
         $client->request('GET', '/heatmap');
-        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+        $this->assertTrue($client->getResponse()->isSuccessful());
     }
+
+    public function testPageLoadWithData() {
+        $client = static::createClient();
+        $client->request('GET', '/heatmap?data_set[date]=2019-04-11&data_set[time]=12&data_set[type]=JIS');
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
+    public function testPageLoadWithInvalidData() {
+        $client = static::createClient();
+        $client->request('GET', '/heatmap?data_set[date]=2019-04-11&data_set[time]=12&data_set[type]=NIC');
+        $this->assertTrue($client->getResponse()->isSuccessful());
+
+        $client->request('GET', '/heatmap?data_set[date]=2019-04-11&data_set[time]=25&data_set[type]=KOLOBEZKY');
+        $this->assertTrue($client->getResponse()->isSuccessful());
+
+        $client->request('GET', '/heatmap?data_set[date]=11-04-2019&data_set[time]=12&data_set[type]=KOLOBEZKY');
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
+    public function testFormSubmit() {
+        $client = static::createClient();
+        $client->request('GET', '/heatmap');
+
+        $crawler = $client->submitForm('Potvrdit výběr');
+        $this->assertTrue($client->getResponse()->isSuccessful());
+
+        $crawler = $client->submitForm('Potvrdit výběr', 
+        [
+            'data_set[date]' => '2019-04-11',
+            'data_set[time]' => '0',
+            'data_set[type]' => 'JIS'
+        ]);
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
+    public function testFormSubmitInvalid() {
+        $client = static::createClient();
+        $client->request('GET', '/heatmap');
+
+        $crawler = $client->submitForm('Potvrdit výběr', 
+        [
+            'data_set[date]' => '11-04-2019',
+            'data_set[time]' => '0',
+            'data_set[type]' => 'JIS'
+        ]);
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
+    public function testOpenDataAjax() {
+        $client = static::createClient();
+        $client->xmlHttpRequest('POST', '/heatmap/opendata', [
+            'name' => 'KOLOBEZKY',
+            'date' => '2019-04-11',
+            'time' => '9'
+        ]);
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
+    public function testAvailableDatasetsAjax() {
+        $client = static::createClient();
+        $client->xmlHttpRequest('POST', '/heatmap/available', 
+        [
+            'date' => '2019-04-11'
+        ]);
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
+    public function testDatesWithAvailableDatasetsAjax() {
+        $client = static::createClient();
+        $client->xmlHttpRequest('POST', '/heatmap/dates');
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
+    public function testDataSourcePoistionsAjax() {
+        $client = static::createClient();
+        $client->xmlHttpRequest('POST', '/heatmap/positions', 
+        [
+            'name' => 'KOLOBEZKY'
+        ]);
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
+    public function testLastAvailableCollectionsAjax() {
+        $client = static::createClient();
+        $client->xmlHttpRequest('POST', '/heatmap/last');
+        $this->assertTrue($client->getResponse()->isSuccessful());
+    }
+
 }
\ No newline at end of file
diff --git a/website/tests/Controller/HomeControllerTest.php b/website/tests/Controller/HomeControllerTest.php
index 6fecd6b..1c24a44 100644
--- a/website/tests/Controller/HomeControllerTest.php
+++ b/website/tests/Controller/HomeControllerTest.php
@@ -5,10 +5,31 @@ namespace App\Tests\Controller;
 use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
 
 class HomeControllerTest extends WebTestCase {
-
     public function testMainPage() {
         $client = static::createClient();
         $client->request('GET', '/');
-        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+        $this->assertTrue($client->getResponse()->isSuccessful());
     }
-}
\ No newline at end of file
+
+    // public function provideLinks() {
+    //     return [
+    //         ['Logo Západočeské univerzity v Plzni'],
+    //         ['Heatmap.ZČU'],
+    //         ['Život na ZČU během dne'],
+    //         ['Hledání anomálií'],
+    //         ['O projektu'],
+    //         ['Zobrazit heatmapu'],
+    //         ['Vyzkoušet heatmapu'],
+    //     ];
+    // }
+
+    // /**
+    //  * @dataProvider provideLinks
+    //  */
+    // public function testLinks($link) {
+    //     $client = static::createClient();
+    //     $crawler = $client->request('GET', '/');
+    //     $client->clickLink($link);
+    //     $this->assertTrue($client->getResponse()->isSuccessful());
+    // }
+}
diff --git a/website/tests/Repository/OpenDataManagerTest.php b/website/tests/Repository/OpenDataManagerTest.php
index 87a9ce1..ae9dd9d 100644
--- a/website/tests/Repository/OpenDataManagerTest.php
+++ b/website/tests/Repository/OpenDataManagerTest.php
@@ -6,15 +6,81 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
 use App\Repository\OpenDataManager;
 
 class OpenDataManagerTest extends KernelTestCase {
-
     private $manager;
 
-    protected function setUp() : void {
-       $kernel = self::bootKernel();
-       $this->manager = $kernel->getContainer()->get('App\Repository\IOpenDataManager');
+    protected function setUp(): void {
+        $kernel = self::bootKernel();
+        $this->manager = $kernel->getContainer()->get('App\Repository\IOpenDataManager');
+    }
+
+    public function testGetCollectionDataByName() {
+        $this->assertFalse(empty($this->manager->getCollectionDataByName('KOLOBEZKY', '2019-04-11', '9')));
+        $this->assertTrue(array_key_exists('number', $this->manager->getCollectionDataByName('KOLOBEZKY', '2019-04-11', '9')[0]));
+        $this->assertTrue(array_key_exists('place', $this->manager->getCollectionDataByName('KOLOBEZKY', '2019-04-11', '9')[0]));
+        $this->assertTrue(array_key_exists('x', $this->manager->getCollectionDataByName('KOLOBEZKY', '2019-04-11', '9')[0]));
+        $this->assertTrue(array_key_exists('y', $this->manager->getCollectionDataByName('KOLOBEZKY', '2019-04-11', '9')[0]));
+        $this->assertTrue(array_key_exists('date', $this->manager->getCollectionDataByName('KOLOBEZKY', '2019-04-11', '9')[0]));
     }
-    
+
+    public function testGetCollectionDataByNameInvalid() {
+        $this->assertTrue(empty($this->manager->getCollectionDataByName(null, null, null)));
+        $this->assertTrue(empty($this->manager->getCollectionDataByName('NIC', '2019-04-11', '9')));
+        $this->assertTrue(empty($this->manager->getCollectionDataByName('NIC', '11-04-2020', '9')));
+        $this->assertTrue(empty($this->manager->getCollectionDataByName('NIC', '2019-04-11', '25')));
+    }
+
     public function testAvailableCollections() {
-        $this->assertCount(3, $this->manager->getAvailableCollections());
+        $this->assertFalse(empty($this->manager->getAvailableCollections()));
+    }
+
+    public function testGetAvailableCollectionsByDay() {
+        $this->assertFalse(empty($this->manager->getAvailableCollectionsByDay('2019-04-11')));
+    }
+
+    public function testGetAvailableCollectionsByDayInvalid() {
+        $this->assertTrue(empty($this->manager->getAvailableCollectionsByDay(null)));
+        $this->assertTrue(empty($this->manager->getAvailableCollectionsByDay('11-04-2020')));
+    }
+
+    public function testIsCollectionAvailable() {
+        $this->assertTrue($this->manager->isCollectionAvailable('KOLOBEZKY', '2019-04-11'));
+        $this->assertFalse($this->manager->isCollectionAvailable('KOLOBEZKY', '2000-04-11'));
+    }
+
+    public function testIsCollectionAvailableInvalid() {
+        $this->assertFalse($this->manager->isCollectionAvailable(null, null));
+        $this->assertFalse($this->manager->isCollectionAvailable('NIC', '2019-04-11'));
+        $this->assertFalse($this->manager->isCollectionAvailable('KOLOBEZKY', '11-04-2019'));
+    }
+
+    public function testGetDatesWithAvailableCollection() {
+        $this->assertFalse(empty($this->manager->getDatesWithAvailableCollection()));
+        $this->assertRegExp('/^(\d{4})-(\d{2})-(\d{2})/', $this->manager->getDatesWithAvailableCollection()[0]);
+    }
+
+    public function testGetLastAvailableCollections() {
+        $this->assertFalse(empty($this->manager->getLastAvailableCollections()));
+        $this->assertRegExp('/^(\d{4})-(\d{2})-(\d{2})/', $this->manager->getLastAvailableCollections()['KOLOBEZKY']);
+    }
+
+    public function testGetMaxCollectionNumberAtDay() {
+        $this->assertGreaterThan(0, $this->manager->getMaxCollectionNumberAtDay('KOLOBEZKY', '2019-04-11'));
+    }
+
+    public function testGetMaxCollectionNumberAtDayInvalid() {
+        $this->assertEquals(0, $this->manager->getMaxCollectionNumberAtDay(null, null));
+        $this->assertEquals(0, $this->manager->getMaxCollectionNumberAtDay('NIC', '2019-04-11'));
+        $this->assertEquals(0, $this->manager->getMaxCollectionNumberAtDay('KOLOBEZKY', '11-04-2019'));
+    }
+
+    public function testGetDataSourcePositions() {
+        $this->assertFalse(empty($this->manager->getDataSourcePositions('KOLOBEZKY')));
+        $this->assertTrue(array_key_exists('x', $this->manager->getDataSourcePositions('KOLOBEZKY')[0]));
+        $this->assertTrue(array_key_exists('y', $this->manager->getDataSourcePositions('KOLOBEZKY')[0]));
+    }
+
+    public function testGetDataSourcePositionsInvalid() {
+        $this->assertTrue(empty($this->manager->getDataSourcePositions(null)));
+        $this->assertTrue(empty($this->manager->getDataSourcePositions('NIC')));
     }
-}
+}
\ No newline at end of file
