commit ea92a5e5858f6cc361018ddf841fc17860db49eb
Author: vastja <vastja@students.zcu.cz>
Date:   Tue May 26 14:08:09 2020 +0000

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

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index caf6594..83533d8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,19 +2,11 @@
 #     IMAGE_NAME: zcu-campus-life-app:$CI_COMMIT_REF_NAME
 
 stages:
-    - test
     - linter
     - build
+    - test
     - deploy
-
-unit_tests:
-    stage: test
-    tags:
-        - test
-    script:
-        - cd website
-        - composer require --dev symfony/phpunit-bridge
-        - php bin/phpunit
+    
 php_linter: 
     stage: linter
     tags:
@@ -23,14 +15,27 @@ php_linter:
         - cd website
         - composer require --dev squizlabs/php_codesniffer
         - ./vendor/bin/php-cs-fixer fix --dry-run --config .php_cs --stop-on-violation --using-cache=no
+
 build:
     stage: build
     tags:
         - build
     script:
         # Test whether container can be build or not
-        - docker-compose build
+        - ./scripts/build.sh
+        - docker-compose stop crawler nginx
         # We could also push docker image to some registry or docker hub
+
+tests:
+    stage: test
+    tags:
+        - test
+    script:
+        - cd website
+        - composer require --dev symfony/phpunit-bridge
+        - composer require --dev symfony/browser-kit symfony/css-selector 
+        - docker-compose exec -T php-fpm /bin/sh -c "export APP_ENV=test && cd ../symfony && php bin/phpunit"
+        - docker stop $(docker ps -q)
         
 deploy_prod:
     stage: deploy
diff --git a/scripts/dev/build.bat b/scripts/dev/build.bat
index f3e253c..a2533c2 100644
--- a/scripts/dev/build.bat
+++ b/scripts/dev/build.bat
@@ -2,5 +2,5 @@ docker-compose -f docker-compose.yml -f docker-compose-dev.yml up --build -d
 docker-compose exec php-fpm composer config extra.symfony.allow-contrib true --no-interaction --working-dir=/var/www/symfony
 docker-compose exec php-fpm composer install --no-interaction --working-dir=/var/www/symfony
 docker-compose exec php-fpm composer update --no-interaction --working-dir=/var/www/symfony
-docker-compose exec php-fpm /bin/sh -c 'cd /var/www/symfony && npm install'
+docker-compose exec php-fpm /bin/sh -c "cd /var/www/symfony && npm install"
 docker-compose exec crawler /bin/sh -c "cd /src && python docker_prepare_structure.py && echo '-all' | python force_update_datasets.py"
\ No newline at end of file
diff --git a/website/.gitignore b/website/.gitignore
index 85b60cf..4401a4d 100644
--- a/website/.gitignore
+++ b/website/.gitignore
@@ -22,4 +22,9 @@ cache
 
 
 /.php_cs.dist
-node_modules
\ No newline at end of file
+node_modules
+###> symfony/phpunit-bridge ###
+.phpunit
+.phpunit.result.cache
+/phpunit.xml
+###< symfony/phpunit-bridge ###
diff --git a/website/bin/phpunit b/website/bin/phpunit
new file mode 100644
index 0000000..4d1ed05
--- /dev/null
+++ b/website/bin/phpunit
@@ -0,0 +1,13 @@
+#!/usr/bin/env php
+<?php
+
+if (!file_exists(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
+    echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
+    exit(1);
+}
+
+if (false === getenv('SYMFONY_PHPUNIT_DIR')) {
+    putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit');
+}
+
+require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';
diff --git a/website/composer.json b/website/composer.json
index 4696e3b..637b00e 100644
--- a/website/composer.json
+++ b/website/composer.json
@@ -20,7 +20,10 @@
     },
     "require-dev": {
         "friendsofphp/php-cs-fixer": "^2.16",
-        "squizlabs/php_codesniffer": "^3.5"
+        "squizlabs/php_codesniffer": "^3.5",
+        "symfony/browser-kit": "5.0.*",
+        "symfony/css-selector": "5.0.*",
+        "symfony/phpunit-bridge": "^5.0"
     },
     "config": {
         "preferred-install": {
diff --git a/website/config/services.yaml b/website/config/services.yaml
index d9387bb..c6ceef1 100644
--- a/website/config/services.yaml
+++ b/website/config/services.yaml
@@ -29,6 +29,10 @@ services:
     # add more service definitions when explicit configuration is needed
     # please note that last definitions always *replace* previous ones
 
-    App\OpenData\OpenDataManager: ~
-    App\OpenData\IOpenDataManager: '@App\OpenData\OpenDataManager'
+    App\Repository\OpenDataManager:
+        arguments:
+            $connectionString: '%env(resolve:DATABASE_CONNECTION_STRING)%'
+    App\Repository\IOpenDataManager: 
+        alias: 'App\Repository\OpenDataManager'
+        public: true
     App\Form\Type\DataSetType: ~
diff --git a/website/phpunit.xml.dist b/website/phpunit.xml.dist
new file mode 100644
index 0000000..00a0f68
--- /dev/null
+++ b/website/phpunit.xml.dist
@@ -0,0 +1,12 @@
+<phpunit bootstrap="vendor/autoload.php">
+    <testsuites>
+            <testsuite name="Project Test Suite">
+                <directory>tests</directory>
+            </testsuite>
+    </testsuites>
+    <php>
+        <env name="APP_ENV" value="test" />
+        <env name="KERNEL_CLASS" value="App\Kernel" />
+        <env name="DATABASE_CONNECTION_STRING" value="mongodb://root:root@database" />
+    </php>
+</phpunit>
\ No newline at end of file
diff --git a/website/src/Calculator.php b/website/src/Calculator.php
deleted file mode 100644
index 098067c..0000000
--- a/website/src/Calculator.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-namespace App;
-
-class Calculator {
-    public function add($a, $b) {
-        return $a + $b;
-    }
-}
diff --git a/website/src/Controller/HeatmapController.php b/website/src/Controller/HeatmapController.php
index de207cc..59a81b1 100644
--- a/website/src/Controller/HeatmapController.php
+++ b/website/src/Controller/HeatmapController.php
@@ -4,7 +4,7 @@ namespace App\Controller;
 
 use App\Entity\DataSet;
 use App\Form\Type\DataSetType;
-use App\OpenData\IOpenDataManager;
+use App\Repository\IOpenDataManager;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Annotation\Route;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
diff --git a/website/src/Form/DataSetType.php b/website/src/Form/DataSetType.php
index b4bb2b0..4903f94 100644
--- a/website/src/Form/DataSetType.php
+++ b/website/src/Form/DataSetType.php
@@ -4,7 +4,7 @@ namespace App\Form\Type;
 
 use App\Utils\Utils;
 use App\Entity\DataSet;
-use App\OpenData\IOpenDataManager;
+use App\Repository\IOpenDataManager;
 use Symfony\Component\Form\FormView;
 use Symfony\Component\Form\AbstractType;
 use Symfony\Component\Form\FormInterface;
diff --git a/website/src/IOpenDataManager.php b/website/src/IOpenDataManager.php
deleted file mode 100644
index a9d89e9..0000000
--- a/website/src/IOpenDataManager.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-namespace App\OpenData;
-
-interface IOpenDataManager {
-    public function getCollectionDataByName($name, $date, $hour);
-
-    public function getAvailableCollections();
-
-    public function getAvailableCollectionsByDay($date);
-
-    public function isCollectionAvailable($name, $date);
-
-    public function getDatesWithAvailableCollection();
-
-    public function getMaxCollectionNumberAtDay($name, $date);
-
-    public function getDataSourcePositions($name);
-
-    public function getLastAvailableCollections();
-}
diff --git a/website/src/OpenDataManager.php b/website/src/OpenDataManager.php
deleted file mode 100644
index ef33d98..0000000
--- a/website/src/OpenDataManager.php
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-
-namespace App\OpenData;
-
-use MongoDB\Driver\Query;
-use MongoDB\Driver\Manager;
-
-class OpenDataManager implements IOpenDataManager {
-    private $manager;
-
-    public function __construct() {
-        $this->manager = new Manager(
-            $_ENV['DATABASE_CONNECTION_STRING']
-        );
-    }
-
-    public function getCollectionDataByName($name, $date, $hour) {
-        $valh = $hour < 10 ? '0'.$hour : $hour;
-        $openData = $this->manager->executeQuery('open-data-db.'.$name.$date, new Query(['date' => $date.'-'.$valh], []));
-
-        $openData->setTypeMap([
-            'array' => 'array',
-            'document' => 'array',
-            'root' => 'array',
-        ]);
-
-        return $openData->toArray();
-    }
-
-    public function getAvailableCollections() {
-        $openData = $this->manager->executeQuery('open-data-db.DATASETS', new Query([], ['projection' => ['key-name' => 1, 'display-name' => 1, '_id' => 0]]));
-
-        $openData->setTypeMap([
-            'array' => 'array',
-            'document' => 'array',
-            'root' => 'array',
-        ]);
-
-        return $openData->toArray();
-    }
-
-    public function getAvailableCollectionsByDay($date) {
-        $availableInDate = [];
-        $available = $this->getAvailableCollections();
-        $index = 0;
-        foreach ($available as $key => $value) {
-            if ($this->isCollectionAvailable($value['key-name'], $date) && false == array_key_exists($value['key-name'], $availableInDate)) {
-                $availableInDate[$value['key-name']] = $value['display-name'];
-            }
-        }
-
-        return $availableInDate;
-    }
-
-    public function isCollectionAvailable($name, $date) {
-        $result = $this->manager->executeQuery('open-data-db.'.$name, new Query(['date' => $date], []));
-
-        return !empty($result->toArray());
-    }
-
-    public function getDatesWithAvailableCollection() {
-        $available = $this->getAvailableCollections();
-        $result = [];
-
-        foreach ($available as $key => $value) {
-            $dates = $this->manager->executeQuery('open-data-db.'.$value['key-name'], new Query([], ['projection' => ['date' => true, '_id' => false]]));
-            $dates->setTypeMap(['root' => 'array']);
-            $result = array_merge($result, array_map(function ($item) {return $item['date']; }, $dates->toArray()));
-        }
-
-        return array_values(array_unique($result));
-    }
-
-    public function getLastAvailableCollections() {
-        $available = $this->getAvailableCollections();
-        $result = [];
-
-        foreach ($available as $key => $value) {
-            $date = $this->manager->executeQuery('open-data-db.'.$value['key-name'], new Query([], ['sort' => ['date' => -1], 'limit' => 1, 'projection' => ['date' => true, '_id' => false]]));
-            $date->setTypeMap(['root' => 'array']);
-
-            $date_array = $date->toArray();
-            if (!empty($date_array)) {
-                $result[$value['key-name']] = $date_array[0]['date'];
-            }
-        }
-
-        return $result;
-    }
-
-    public function getMaxCollectionNumberAtDay($name, $date) {
-        $max = $this->manager->executeQuery('open-data-db.'.$name.$date, new Query([], ['sort' => ['number' => -1], 'limit' => 1]));
-
-        $max->setTypeMap([
-            'array' => 'array',
-            'document' => 'array',
-            'root' => 'array',
-        ]);
-
-        $result = $max->toArray();
-
-        return empty($result) ? 1 : $result[0]['number'];
-    }
-
-    public function getDataSourcePositions($name = 'NONE') {
-        $positions = $this->manager->executeQuery('open-data-db.'.$name.'DEVICES', new Query([], []));
-
-        $positions->setTypeMap([
-            'array' => 'array',
-            'document' => 'array',
-            'root' => 'array',
-        ]);
-
-        return $positions->toArray();
-    }
-}
diff --git a/website/src/Repository/IOpenDataManager.php b/website/src/Repository/IOpenDataManager.php
new file mode 100644
index 0000000..589a326
--- /dev/null
+++ b/website/src/Repository/IOpenDataManager.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace App\Repository;
+
+interface IOpenDataManager {
+    public function getCollectionDataByName($name, $date, $hour);
+
+    public function getAvailableCollections();
+
+    public function getAvailableCollectionsByDay($date);
+
+    public function isCollectionAvailable($name, $date);
+
+    public function getDatesWithAvailableCollection();
+
+    public function getMaxCollectionNumberAtDay($name, $date);
+
+    public function getDataSourcePositions($name);
+
+    public function getLastAvailableCollections();
+}
diff --git a/website/src/Repository/OpenDataManager.php b/website/src/Repository/OpenDataManager.php
new file mode 100644
index 0000000..2a4522b
--- /dev/null
+++ b/website/src/Repository/OpenDataManager.php
@@ -0,0 +1,117 @@
+<?php
+
+namespace App\Repository;
+
+use MongoDB\Driver\Query;
+use MongoDB\Driver\Manager;
+
+class OpenDataManager implements IOpenDataManager {
+    private $manager;
+
+    public function __construct($connectionString) {
+        $this->manager = new Manager(
+            $connectionString
+            // $_ENV['DATABASE_CONNECTION_STRING']
+        );
+    }
+
+    public function getCollectionDataByName($name, $date, $hour) {
+        $valh = $hour < 10 ? '0'.$hour : $hour;
+        $openData = $this->manager->executeQuery('open-data-db.'.$name.$date, new Query(['date' => $date.'-'.$valh], []));
+
+        $openData->setTypeMap([
+            'array' => 'array',
+            'document' => 'array',
+            'root' => 'array',
+        ]);
+
+        return $openData->toArray();
+    }
+
+    public function getAvailableCollections() {
+        $openData = $this->manager->executeQuery('open-data-db.DATASETS', new Query([], ['projection' => ['key-name' => 1, 'display-name' => 1, '_id' => 0]]));
+
+        $openData->setTypeMap([
+            'array' => 'array',
+            'document' => 'array',
+            'root' => 'array',
+        ]);
+
+        return $openData->toArray();
+    }
+
+    public function getAvailableCollectionsByDay($date) {
+        $availableInDate = [];
+        $available = $this->getAvailableCollections();
+        $index = 0;
+        foreach ($available as $key => $value) {
+            if ($this->isCollectionAvailable($value['key-name'], $date) && false == array_key_exists($value['key-name'], $availableInDate)) {
+                $availableInDate[$value['key-name']] = $value['display-name'];
+            }
+        }
+
+        return $availableInDate;
+    }
+
+    public function isCollectionAvailable($name, $date) {
+        $result = $this->manager->executeQuery('open-data-db.'.$name, new Query(['date' => $date], []));
+
+        return !empty($result->toArray());
+    }
+
+    public function getDatesWithAvailableCollection() {
+        $available = $this->getAvailableCollections();
+        $result = [];
+
+        foreach ($available as $key => $value) {
+            $dates = $this->manager->executeQuery('open-data-db.'.$value['key-name'], new Query([], ['projection' => ['date' => true, '_id' => false]]));
+            $dates->setTypeMap(['root' => 'array']);
+            $result = array_merge($result, array_map(function ($item) {return $item['date']; }, $dates->toArray()));
+        }
+
+        return array_values(array_unique($result));
+    }
+
+    public function getLastAvailableCollections() {
+        $available = $this->getAvailableCollections();
+        $result = [];
+
+        foreach ($available as $key => $value) {
+            $date = $this->manager->executeQuery('open-data-db.'.$value['key-name'], new Query([], ['sort' => ['date' => -1], 'limit' => 1, 'projection' => ['date' => true, '_id' => false]]));
+            $date->setTypeMap(['root' => 'array']);
+
+            $date_array = $date->toArray();
+            if (!empty($date_array)) {
+                $result[$value['key-name']] = $date_array[0]['date'];
+            }
+        }
+
+        return $result;
+    }
+
+    public function getMaxCollectionNumberAtDay($name, $date) {
+        $max = $this->manager->executeQuery('open-data-db.'.$name.$date, new Query([], ['sort' => ['number' => -1], 'limit' => 1]));
+
+        $max->setTypeMap([
+            'array' => 'array',
+            'document' => 'array',
+            'root' => 'array',
+        ]);
+
+        $result = $max->toArray();
+
+        return empty($result) ? 1 : $result[0]['number'];
+    }
+
+    public function getDataSourcePositions($name = 'NONE') {
+        $positions = $this->manager->executeQuery('open-data-db.'.$name.'DEVICES', new Query([], []));
+
+        $positions->setTypeMap([
+            'array' => 'array',
+            'document' => 'array',
+            'root' => 'array',
+        ]);
+
+        return $positions->toArray();
+    }
+}
diff --git a/website/tests/CalculatorTest.php b/website/tests/CalculatorTest.php
deleted file mode 100644
index 86ef6f8..0000000
--- a/website/tests/CalculatorTest.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-namespace App\tests;
-
-use App\Calculator;
-use PHPUnit\Framework\TestCase;
-
-class CalculatorTest extends TestCase
-{
-    public function testAdd()
-    {
-        $calculator = new Calculator();
-        $result = $calculator->add(30, 12);
-
-        // assert that your calculator added the numbers correctly!
-        $this->assertEquals(42, $result);
-    }
-}
\ No newline at end of file
diff --git a/website/tests/Controller/HeatmapControllerTest.php b/website/tests/Controller/HeatmapControllerTest.php
new file mode 100644
index 0000000..1d4abd2
--- /dev/null
+++ b/website/tests/Controller/HeatmapControllerTest.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Tests\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+
+class HatmapControllerTest extends WebTestCase {
+
+    public function testMainPage() {
+        $client = static::createClient();
+        $client->request('GET', '/heatmap');
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+    }
+}
\ No newline at end of file
diff --git a/website/tests/Controller/HomeControllerTest.php b/website/tests/Controller/HomeControllerTest.php
new file mode 100644
index 0000000..6fecd6b
--- /dev/null
+++ b/website/tests/Controller/HomeControllerTest.php
@@ -0,0 +1,14 @@
+<?php
+
+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());
+    }
+}
\ No newline at end of file
diff --git a/website/tests/Repository/OpenDataManagerTest.php b/website/tests/Repository/OpenDataManagerTest.php
new file mode 100644
index 0000000..87a9ce1
--- /dev/null
+++ b/website/tests/Repository/OpenDataManagerTest.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Test\Repository;
+
+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');
+    }
+    
+    public function testAvailableCollections() {
+        $this->assertCount(3, $this->manager->getAvailableCollections());
+    }
+}
diff --git a/website/tests/bootstrap.php b/website/tests/bootstrap.php
new file mode 100644
index 0000000..469dcce
--- /dev/null
+++ b/website/tests/bootstrap.php
@@ -0,0 +1,11 @@
+<?php
+
+use Symfony\Component\Dotenv\Dotenv;
+
+require dirname(__DIR__).'/vendor/autoload.php';
+
+if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
+    require dirname(__DIR__).'/config/bootstrap.php';
+} elseif (method_exists(Dotenv::class, 'bootEnv')) {
+    (new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
+}
