mirror of
https://github.com/ChristianLight/tutor.git
synced 2024-12-12 14:17:46 +00:00
2a47100d6a
This fix is for a rather serious issue that affects users who upgrade from Olive to Palm. The client mysql charset and collation was incorrectly set to utf8mb4, while the server stil runs utf8mb3. Only users who run the mysql container are affected. To resolve this issue, we explicitely configure the client to use the utf8mb3 charset/collation. Important note: users who have somehow managed to upgrade from olive to Palm before may find themselves in an undefined state. They might have to fix their mysql data manually. Same thing for users who launched Palm from scratch; although, according to my preliinary tests, they should be able to downgrade their connection from utf8mb4 to utf8mb3 without issue. In addition, we upgrade to mysql 8.1.0. Among many other fixes, this avoids a server restart after the upgrade: > An in-place upgrade from MySQL 5.7 to MySQL 8.0, without a server > restart, could result in unexpected errors when executing queries on > tables. This fix eliminates the need to restart the server between the > upgrade and queries. (Bug #35410528) https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-34.html See also the 8.1.0 release notes: https://dev.mysql.com/doc/relnotes/mysql/8.1/en/news-8-1-0.html Close #887.
158 lines
5.5 KiB
Python
158 lines
5.5 KiB
Python
from unittest.mock import Mock, patch
|
|
|
|
from tests.helpers import PluginsTestCase, temporary_root
|
|
from tutor import images, plugins, utils
|
|
from tutor.__about__ import __version__
|
|
from tutor.commands.images import ImageNotFoundError
|
|
|
|
from .base import TestCommandMixin
|
|
|
|
|
|
class ImagesTests(PluginsTestCase, TestCommandMixin):
|
|
def test_images_help(self) -> None:
|
|
result = self.invoke(["images", "--help"])
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code)
|
|
|
|
def test_images_pull_image(self) -> None:
|
|
result = self.invoke(["images", "pull"])
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code)
|
|
|
|
def test_images_pull_plugin_invalid_plugin_should_throw_error(self) -> None:
|
|
result = self.invoke(["images", "pull", "plugin"])
|
|
self.assertEqual(1, result.exit_code)
|
|
self.assertEqual(ImageNotFoundError, type(result.exception))
|
|
|
|
@patch.object(images, "pull", return_value=None)
|
|
def test_images_pull_plugin(self, image_pull: Mock) -> None:
|
|
plugins.v0.DictPlugin(
|
|
{
|
|
"name": "plugin1",
|
|
"hooks": {
|
|
"remote-image": {
|
|
"service1": "service1:1.0.0",
|
|
"service2": "service2:2.0.0",
|
|
}
|
|
},
|
|
}
|
|
)
|
|
plugins.load("plugin1")
|
|
result = self.invoke(["images", "pull", "service1"])
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code)
|
|
image_pull.assert_called_once_with("service1:1.0.0")
|
|
|
|
@patch.object(images, "pull", return_value=None)
|
|
def test_images_pull_all_vendor_images(self, image_pull: Mock) -> None:
|
|
result = self.invoke(["images", "pull", "mysql"])
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code)
|
|
# Note: we should update this tag whenever the mysql image is updated
|
|
image_pull.assert_called_once_with("docker.io/mysql:8.1.0")
|
|
|
|
def test_images_printtag_image(self) -> None:
|
|
result = self.invoke(["images", "printtag", "openedx"])
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code)
|
|
self.assertRegex(
|
|
result.output, rf"docker.io/overhangio/openedx:{__version__}\n"
|
|
)
|
|
|
|
def test_images_printtag_plugin(self) -> None:
|
|
plugins.v0.DictPlugin(
|
|
{
|
|
"name": "plugin1",
|
|
"hooks": {
|
|
"build-image": {
|
|
"service1": "service1:1.0.0",
|
|
"service2": "service2:2.0.0",
|
|
}
|
|
},
|
|
}
|
|
)
|
|
plugins.load("plugin1")
|
|
result = self.invoke(["images", "printtag", "service1"])
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code, result)
|
|
self.assertEqual(result.output, "service1:1.0.0\n")
|
|
|
|
@patch.object(images, "build", return_value=None)
|
|
def test_images_build_plugin(self, mock_image_build: Mock) -> None:
|
|
plugins.v0.DictPlugin(
|
|
{
|
|
"name": "plugin1",
|
|
"hooks": {
|
|
"build-image": {
|
|
"service1": "service1:1.0.0",
|
|
"service2": "service2:2.0.0",
|
|
}
|
|
},
|
|
}
|
|
)
|
|
plugins.load("plugin1")
|
|
with temporary_root() as root:
|
|
self.invoke_in_root(root, ["config", "save"])
|
|
result = self.invoke_in_root(root, ["images", "build", "service1"])
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code)
|
|
mock_image_build.assert_called()
|
|
self.assertIn("service1:1.0.0", mock_image_build.call_args[0])
|
|
|
|
@patch.object(images, "build", return_value=None)
|
|
def test_images_build_plugin_with_args(self, image_build: Mock) -> None:
|
|
plugins.v0.DictPlugin(
|
|
{
|
|
"name": "plugin1",
|
|
"hooks": {
|
|
"build-image": {
|
|
"service1": "service1:1.0.0",
|
|
"service2": "service2:2.0.0",
|
|
}
|
|
},
|
|
}
|
|
)
|
|
plugins.load("plugin1")
|
|
build_args = [
|
|
"images",
|
|
"build",
|
|
"--no-cache",
|
|
"-a",
|
|
"myarg=value",
|
|
"--add-host",
|
|
"host",
|
|
"--target",
|
|
"target",
|
|
"-d",
|
|
"docker_args",
|
|
"service1",
|
|
]
|
|
with temporary_root() as root:
|
|
utils.is_buildkit_enabled.cache_clear()
|
|
with patch.object(utils, "is_buildkit_enabled", return_value=False):
|
|
self.invoke_in_root(root, ["config", "save"])
|
|
result = self.invoke_in_root(root, build_args)
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code)
|
|
image_build.assert_called()
|
|
self.assertIn("service1:1.0.0", image_build.call_args[0])
|
|
self.assertEqual(
|
|
[
|
|
"service1:1.0.0",
|
|
"--no-cache",
|
|
"--build-arg",
|
|
"myarg=value",
|
|
"--add-host",
|
|
"host",
|
|
"--target",
|
|
"target",
|
|
"docker_args",
|
|
],
|
|
list(image_build.call_args[0][1:]),
|
|
)
|
|
|
|
def test_images_push(self) -> None:
|
|
result = self.invoke(["images", "push"])
|
|
self.assertIsNone(result.exception)
|
|
self.assertEqual(0, result.exit_code)
|