update charts
diff --git a/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/conftest.py b/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/conftest.py
new file mode 100644
index 0000000..8cd3443
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/conftest.py
@@ -0,0 +1,92 @@
+# pylint: disable=W0613
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import random
+import string
+import time
+
+import pytest
+
+
+class GitBackendContainer:
+    def __init__(self, docker_client, image, port, credentials_dir):
+        self.docker_client = docker_client
+        self.image = image
+        self.port = port
+        self.apache_credentials_dir = credentials_dir
+
+        self.container = None
+
+    def start(self):
+        self.container = self.docker_client.containers.run(
+            image=self.image.id,
+            ports={"80": self.port},
+            volumes={
+                self.apache_credentials_dir: {
+                    "bind": "/var/apache/credentials",
+                    "mode": "ro",
+                }
+            },
+            detach=True,
+            auto_remove=True,
+            platform="linux/amd64",
+        )
+
+    def stop(self):
+        self.container.stop(timeout=1)
+
+
+@pytest.fixture(scope="module")
+def container_run_factory(
+    docker_client, apache_git_http_backend_image, htpasswd, credentials_dir
+):
+    def run_container(port):
+        return GitBackendContainer(
+            docker_client,
+            apache_git_http_backend_image,
+            port,
+            str(credentials_dir),
+        )
+
+    return run_container
+
+
+@pytest.fixture(scope="module")
+def container_run(container_run_factory, free_port):
+    test_setup = container_run_factory(free_port)
+    test_setup.start()
+    time.sleep(3)
+
+    yield test_setup
+
+    test_setup.stop()
+
+
+@pytest.fixture(scope="module")
+def base_url(container_run):
+    return f"http://localhost:{container_run.port}"
+
+
+@pytest.fixture(scope="function")
+def random_repo_name():
+    return "".join(
+        [random.choice(string.ascii_letters + string.digits) for n in range(8)]
+    )
+
+
+@pytest.fixture(scope="function")
+def repo_creation_url(base_url, random_repo_name):
+    return f"{base_url}/a/projects/{random_repo_name}"
diff --git a/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_build_apache_git_http_backend.py b/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_build_apache_git_http_backend.py
new file mode 100644
index 0000000..984d6be
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_build_apache_git_http_backend.py
@@ -0,0 +1,24 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+
+@pytest.mark.structure
+def test_build_apache_git_http_backend_image(
+    apache_git_http_backend_image, tag_of_cached_container
+):
+    if tag_of_cached_container:
+        pytest.skip("Cached image used for testing. Build will not be tested.")
+    assert apache_git_http_backend_image.id is not None
diff --git a/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_integration_apache_git_http_backend.py b/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_integration_apache_git_http_backend.py
new file mode 100755
index 0000000..0d5ef65
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_integration_apache_git_http_backend.py
@@ -0,0 +1,96 @@
+# pylint: disable=W0613
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from pathlib import Path
+
+import os.path
+
+import pygit2 as git
+import pytest
+import requests
+
+
+@pytest.fixture(scope="function")
+def repo_dir(tmp_path_factory, random_repo_name):
+    return tmp_path_factory.mktemp(random_repo_name)
+
+
+@pytest.fixture(scope="function")
+def mock_repo(repo_dir):
+    repo = git.init_repository(repo_dir, False)
+    file_name = os.path.join(repo_dir, "test.txt")
+    Path(file_name).touch()
+    repo.index.add("test.txt")
+    repo.index.write()
+    # pylint: disable=E1101
+    author = git.Signature("Gerrit Review", "gerrit@review.com")
+    committer = git.Signature("Gerrit Review", "gerrit@review.com")
+    message = "Initial commit"
+    tree = repo.index.write_tree()
+    repo.create_commit("HEAD", author, committer, message, tree, [])
+    return repo
+
+
+@pytest.mark.docker
+@pytest.mark.integration
+def test_apache_git_http_backend_repo_creation(
+    container_run, htpasswd, repo_creation_url
+):
+    request = requests.put(
+        repo_creation_url,
+        auth=requests.auth.HTTPBasicAuth(htpasswd["user"], htpasswd["password"]),
+    )
+    assert request.status_code == 201
+
+
+@pytest.mark.docker
+@pytest.mark.integration
+def test_apache_git_http_backend_repo_creation_fails_without_credentials(
+    container_run, repo_creation_url
+):
+    request = requests.put(repo_creation_url)
+    assert request.status_code == 401
+
+
+@pytest.mark.docker
+@pytest.mark.integration
+def test_apache_git_http_backend_repo_creation_fails_wrong_fs_permissions(
+    container_run, htpasswd, repo_creation_url
+):
+    container_run.container.exec_run("chown -R root:root /var/gerrit/git")
+    request = requests.put(
+        repo_creation_url,
+        auth=requests.auth.HTTPBasicAuth(htpasswd["user"], htpasswd["password"]),
+    )
+    container_run.container.exec_run("chown -R gerrit:users /var/gerrit/git")
+    assert request.status_code == 500
+
+
+@pytest.mark.docker
+@pytest.mark.integration
+def test_apache_git_http_backend_repo_creation_push_repo(
+    container_run, base_url, htpasswd, mock_repo, random_repo_name
+):
+    container_run.container.exec_run(
+        f"su -c 'git init --bare /var/gerrit/git/{random_repo_name}.git' gerrit"
+    )
+    url = f"{base_url}/{random_repo_name}.git"
+    url = url.replace("//", f"//{htpasswd['user']}:{htpasswd['password']}@")
+    origin = mock_repo.remotes.create("origin", url)
+    origin.push(["refs/heads/master:refs/heads/master"])
+
+    remote_refs = origin.ls_remotes()
+    assert str(remote_refs[0]["oid"]) == mock_repo.revparse_single("HEAD").hex
diff --git a/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_structure_apache_git_http_backend.py b/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_structure_apache_git_http_backend.py
new file mode 100755
index 0000000..a138ef5
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/apache-git-http-backend/test_container_structure_apache_git_http_backend.py
@@ -0,0 +1,61 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+import utils
+
+
+# pylint: disable=E1101
+@pytest.mark.structure
+def test_apache_git_http_backend_inherits_from_base(apache_git_http_backend_image):
+    assert utils.check_if_ancestor_image_is_inherited(
+        apache_git_http_backend_image, "base:latest"
+    )
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_apache_git_http_backend_contains_apache2(container_run):
+    exit_code, _ = container_run.container.exec_run("which httpd")
+    assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_apache_git_http_backend_http_site_configured(container_run):
+    exit_code, _ = container_run.container.exec_run(
+        "test -f /etc/apache2/conf.d/git-http-backend.conf"
+    )
+    assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_apache_git_http_backend_contains_start_script(container_run):
+    exit_code, _ = container_run.container.exec_run("test -f /var/tools/start")
+    assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_apache_git_http_backend_contains_repo_creation_cgi_script(container_run):
+    exit_code, _ = container_run.container.exec_run("test -f /var/cgi/project_admin.sh")
+    assert exit_code == 0
+
+
+@pytest.mark.structure
+def test_apache_git_http_backend_has_entrypoint(apache_git_http_backend_image):
+    entrypoint = apache_git_http_backend_image.attrs["ContainerConfig"]["Entrypoint"]
+    assert len(entrypoint) == 2
+    assert entrypoint[1] == "/var/tools/start"
diff --git a/charts/k8s-gerrit/tests/container-images/base/test_container_build_base.py b/charts/k8s-gerrit/tests/container-images/base/test_container_build_base.py
new file mode 100644
index 0000000..2a3afa5
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/base/test_container_build_base.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+
+@pytest.mark.structure
+def test_build_base(base_image, tag_of_cached_container):
+    if tag_of_cached_container:
+        pytest.skip("Cached image used for testing. Build will not be tested.")
+    assert base_image.id is not None
diff --git a/charts/k8s-gerrit/tests/container-images/base/test_container_structure_base.py b/charts/k8s-gerrit/tests/container-images/base/test_container_structure_base.py
new file mode 100755
index 0000000..528d2b4
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/base/test_container_structure_base.py
@@ -0,0 +1,45 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+
+@pytest.fixture(scope="module")
+def container_run(docker_client, container_endless_run_factory, base_image):
+    container_run = container_endless_run_factory(docker_client, base_image)
+    yield container_run
+    container_run.stop(timeout=1)
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_base_contains_git(container_run):
+    exit_code, _ = container_run.exec_run("which git")
+    assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_base_has_non_root_user_gerrit(container_run):
+    exit_code, output = container_run.exec_run("id -u gerrit")
+    assert exit_code == 0
+    uid = int(output.strip().decode("utf-8"))
+    assert uid != 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_base_gerrit_no_root_permissions(container_run):
+    exit_code, _ = container_run.exec_run("su -c 'rm -rf /bin' gerrit")
+    assert exit_code > 0
diff --git a/charts/k8s-gerrit/tests/container-images/conftest.py b/charts/k8s-gerrit/tests/container-images/conftest.py
new file mode 100644
index 0000000..8a4b8f2
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/conftest.py
@@ -0,0 +1,105 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os.path
+import socket
+
+import pytest
+
+
+class GerritContainer:
+    def __init__(self, docker_client, docker_network, tmp_dir, image, configs, port):
+        self.docker_client = docker_client
+        self.docker_network = docker_network
+        self.tmp_dir = tmp_dir
+        self.image = image
+        self.configs = configs
+        self.port = port
+
+        self.container = None
+
+    def _create_config_files(self):
+        tmp_config_dir = os.path.join(self.tmp_dir, "configs")
+        if not os.path.isdir(tmp_config_dir):
+            os.mkdir(tmp_config_dir)
+        config_paths = {}
+        for filename, content in self.configs.items():
+            gerrit_config_file = os.path.join(tmp_config_dir, filename)
+            with open(gerrit_config_file, "w", encoding="utf-8") as config_file:
+                config_file.write(content)
+            config_paths[filename] = gerrit_config_file
+        return config_paths
+
+    def _define_volume_mounts(self):
+        volumes = {
+            v: {"bind": f"/var/gerrit/etc/{k}", "mode": "rw"}
+            for (k, v) in self._create_config_files().items()
+        }
+        volumes[os.path.join(self.tmp_dir, "lib")] = {
+            "bind": "/var/gerrit/lib",
+            "mode": "rw",
+        }
+        return volumes
+
+    def start(self):
+        self.container = self.docker_client.containers.run(
+            image=self.image.id,
+            user="gerrit",
+            volumes=self._define_volume_mounts(),
+            ports={8080: str(self.port)},
+            network=self.docker_network.name,
+            detach=True,
+            auto_remove=True,
+            platform="linux/amd64",
+        )
+
+    def stop(self):
+        self.container.stop(timeout=1)
+
+
+@pytest.fixture(scope="session")
+def gerrit_container_factory():
+    def get_gerrit_container(
+        docker_client, docker_network, tmp_dir, image, gerrit_config, port
+    ):
+        return GerritContainer(
+            docker_client, docker_network, tmp_dir, image, gerrit_config, port
+        )
+
+    return get_gerrit_container
+
+
+@pytest.fixture(scope="session")
+def container_endless_run_factory():
+    def get_container(docker_client, image):
+        return docker_client.containers.run(
+            image=image.id,
+            entrypoint="/bin/ash",
+            command=["-c", "tail -f /dev/null"],
+            user="gerrit",
+            detach=True,
+            auto_remove=True,
+            platform="linux/amd64",
+        )
+
+    return get_container
+
+
+@pytest.fixture(scope="session")
+def free_port():
+    skt = socket.socket()
+    skt.bind(("", 0))
+    port = skt.getsockname()[1]
+    skt.close()
+    return port
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit-base/test_container_build_gerrit_base.py b/charts/k8s-gerrit/tests/container-images/gerrit-base/test_container_build_gerrit_base.py
new file mode 100644
index 0000000..93954d8
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit-base/test_container_build_gerrit_base.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+
+@pytest.mark.structure
+def test_build_gerrit_base(gerrit_base_image, tag_of_cached_container):
+    if tag_of_cached_container:
+        pytest.skip("Cached image used for testing. Build will not be tested.")
+    assert gerrit_base_image.id is not None
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit-base/test_container_structure_gerrit_base.py b/charts/k8s-gerrit/tests/container-images/gerrit-base/test_container_structure_gerrit_base.py
new file mode 100755
index 0000000..05161b2
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit-base/test_container_structure_gerrit_base.py
@@ -0,0 +1,100 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+
+import pytest
+
+import utils
+
+
+JAVA_VER = 11
+
+
+@pytest.fixture(scope="module")
+def container_run(docker_client, container_endless_run_factory, gerrit_base_image):
+    container_run = container_endless_run_factory(docker_client, gerrit_base_image)
+    yield container_run
+    container_run.stop(timeout=1)
+
+
+# pylint: disable=E1101
+@pytest.mark.structure
+def test_gerrit_base_inherits_from_base(gerrit_base_image):
+    assert utils.check_if_ancestor_image_is_inherited(gerrit_base_image, "base:latest")
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_base_contains_java(container_run):
+    _, output = container_run.exec_run("java -version")
+    output = output.strip().decode("utf-8")
+    assert re.search(re.compile(f'openjdk version "{JAVA_VER}.[0-9.]+"'), output)
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_base_java_path(container_run):
+    exit_code, output = container_run.exec_run(
+        '/bin/ash -c "readlink -f $(which java)"'
+    )
+    output = output.strip().decode("utf-8")
+    assert exit_code == 0
+    assert output == f"/usr/lib/jvm/java-{JAVA_VER}-openjdk/bin/java"
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_base_contains_gerrit_war(container_run):
+    exit_code, _ = container_run.exec_run("test -f /var/war/gerrit.war")
+    assert exit_code == 0
+
+    exit_code, _ = container_run.exec_run("test -f /var/gerrit/bin/gerrit.war")
+    assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_base_war_contains_gerrit(container_run):
+    exit_code, output = container_run.exec_run("java -jar /var/war/gerrit.war version")
+    assert exit_code == 0
+    output = output.strip().decode("utf-8")
+    assert re.search(re.compile("gerrit version.*"), output)
+
+    exit_code, output = container_run.exec_run(
+        "java -jar /var/gerrit/bin/gerrit.war version"
+    )
+    assert exit_code == 0
+    output = output.strip().decode("utf-8")
+    assert re.search(re.compile("gerrit version.*"), output)
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_base_site_permissions(container_run):
+    exit_code, _ = container_run.exec_run("test -O /var/gerrit")
+    assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_base_war_dir_permissions(container_run):
+    exit_code, _ = container_run.exec_run("test -O /var/war")
+    assert exit_code == 0
+
+
+@pytest.mark.structure
+def test_gerrit_base_has_entrypoint(gerrit_base_image):
+    entrypoint = gerrit_base_image.attrs["ContainerConfig"]["Entrypoint"]
+    assert "/var/tools/start" in entrypoint
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_build_gerrit_init.py b/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_build_gerrit_init.py
new file mode 100644
index 0000000..dc16d74
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_build_gerrit_init.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+
+@pytest.mark.structure
+def test_build_gerrit_init(gerrit_init_image, tag_of_cached_container):
+    if tag_of_cached_container:
+        pytest.skip("Cached image used for testing. Build will not be tested.")
+    assert gerrit_init_image.id is not None
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py b/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py
new file mode 100644
index 0000000..4dac6e0
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py
@@ -0,0 +1,190 @@
+# pylint: disable=E1101
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os.path
+import re
+
+from docker.errors import NotFound
+
+import pytest
+import yaml
+
+
+@pytest.fixture(scope="class")
+def container_run_default(request, docker_client, gerrit_init_image, tmp_path_factory):
+    tmp_site_dir = tmp_path_factory.mktemp("gerrit_site")
+    container_run = docker_client.containers.run(
+        image=gerrit_init_image.id,
+        user="gerrit",
+        volumes={tmp_site_dir: {"bind": "/var/gerrit", "mode": "rw"}},
+        detach=True,
+        auto_remove=True,
+        platform="linux/amd64",
+    )
+
+    def stop_container():
+        try:
+            container_run.stop(timeout=1)
+        except NotFound:
+            print("Container already stopped.")
+
+    request.addfinalizer(stop_container)
+
+    return container_run
+
+
+@pytest.fixture(scope="class")
+def init_config_dir(tmp_path_factory):
+    return tmp_path_factory.mktemp("init_config")
+
+
+@pytest.fixture(scope="class")
+def tmp_site_dir(tmp_path_factory):
+    return tmp_path_factory.mktemp("gerrit_site")
+
+
+@pytest.fixture(scope="class")
+def container_run_endless(
+    docker_client, gerrit_init_image, init_config_dir, tmp_site_dir
+):
+    container_run = docker_client.containers.run(
+        image=gerrit_init_image.id,
+        entrypoint="/bin/ash",
+        command=["-c", "tail -f /dev/null"],
+        user="gerrit",
+        volumes={
+            tmp_site_dir: {"bind": "/var/gerrit", "mode": "rw"},
+            init_config_dir: {"bind": "/var/config", "mode": "rw"},
+        },
+        detach=True,
+        auto_remove=True,
+        platform="linux/amd64",
+    )
+
+    yield container_run
+    container_run.stop(timeout=1)
+
+
+@pytest.mark.docker
+@pytest.mark.incremental
+@pytest.mark.integration
+class TestGerritInitEmptySite:
+    @pytest.mark.timeout(60)
+    def test_gerrit_init_gerrit_is_initialized(self, container_run_default):
+        def wait_for_init_success_message():
+            log = container_run_default.logs().decode("utf-8")
+            return log, re.search(r"Initialized /var/gerrit", log)
+
+        while not wait_for_init_success_message():
+            continue
+
+    @pytest.mark.timeout(60)
+    def test_gerrit_init_exits_after_init(self, container_run_default):
+        assert container_run_default.wait()["StatusCode"] == 0
+
+
+@pytest.fixture(
+    scope="function",
+    params=[
+        ["replication", "reviewnotes"],
+        ["replication", "reviewnotes", "hooks"],
+        ["download-commands"],
+        [],
+    ],
+)
+def plugins_to_install(request):
+    return request.param
+
+
+@pytest.mark.docker
+@pytest.mark.incremental
+@pytest.mark.integration
+class TestGerritInitPluginInstallation:
+    def _configure_packaged_plugins(self, file_path, plugins):
+        with open(file_path, "w", encoding="utf-8") as f:
+            yaml.dump(
+                {"plugins": [{"name": p} for p in plugins]}, f, default_flow_style=False
+            )
+
+    def test_gerrit_init_plugins_are_installed(
+        self,
+        container_run_endless,
+        init_config_dir,
+        plugins_to_install,
+        tmp_site_dir,
+        required_plugins,
+    ):
+        self._configure_packaged_plugins(
+            os.path.join(init_config_dir, "init.yaml"), plugins_to_install
+        )
+
+        exit_code, _ = container_run_endless.exec_run(
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/init.yaml init"
+        )
+        assert exit_code == 0
+
+        plugins_path = os.path.join(tmp_site_dir, "plugins")
+
+        for plugin in plugins_to_install:
+            assert os.path.exists(os.path.join(plugins_path, f"{plugin}.jar"))
+
+        installed_plugins = os.listdir(plugins_path)
+        expected_plugins = plugins_to_install + required_plugins
+        for plugin in installed_plugins:
+            assert os.path.splitext(plugin)[0] in expected_plugins
+
+    def test_required_plugins_are_installed(
+        self, container_run_endless, init_config_dir, tmp_site_dir, required_plugins
+    ):
+        self._configure_packaged_plugins(
+            os.path.join(init_config_dir, "init.yaml"), ["hooks"]
+        )
+
+        exit_code, _ = container_run_endless.exec_run(
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/init.yaml init"
+        )
+        assert exit_code == 0
+
+        for plugin in required_plugins:
+            assert os.path.exists(
+                os.path.join(tmp_site_dir, "plugins", f"{plugin}.jar")
+            )
+
+    def test_libraries_are_symlinked(
+        self, container_run_endless, init_config_dir, tmp_site_dir
+    ):
+        with open(
+            os.path.join(init_config_dir, "init.yaml"), "w", encoding="utf-8"
+        ) as f:
+            yaml.dump(
+                {"plugins": [{"name": "hooks", "installAsLibrary": True}]},
+                f,
+                default_flow_style=False,
+            )
+
+        exit_code, _ = container_run_endless.exec_run(
+            "python3 /var/tools/gerrit-initializer -s /var/gerrit -c /var/config/init.yaml init"
+        )
+        assert exit_code == 0
+
+        assert os.path.exists(os.path.join(tmp_site_dir, "plugins", "hooks.jar"))
+        assert os.path.islink(os.path.join(tmp_site_dir, "lib", "hooks.jar"))
+
+        exit_code, output = container_run_endless.exec_run(
+            "readlink -f /var/gerrit/lib/hooks.jar"
+        )
+        assert exit_code == 0
+        assert output.decode("utf-8").strip() == "/var/gerrit/plugins/hooks.jar"
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_integration_gerrit_init_reindexing.py b/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_integration_gerrit_init_reindexing.py
new file mode 100644
index 0000000..c8a5b49
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_integration_gerrit_init_reindexing.py
@@ -0,0 +1,160 @@
+# pylint: disable=E1101
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+import pytest
+
+
+@pytest.fixture(scope="function")
+def temp_site(tmp_path_factory):
+    return tmp_path_factory.mktemp("gerrit-index-test")
+
+
+@pytest.fixture(scope="function")
+def container_run_endless(request, docker_client, gerrit_init_image, temp_site):
+    container_run = docker_client.containers.run(
+        image=gerrit_init_image.id,
+        entrypoint="/bin/ash",
+        command=["-c", "tail -f /dev/null"],
+        volumes={str(temp_site): {"bind": "/var/gerrit", "mode": "rw"}},
+        user="gerrit",
+        detach=True,
+        auto_remove=True,
+        platform="linux/amd64",
+    )
+
+    def stop_container():
+        container_run.stop(timeout=1)
+
+    request.addfinalizer(stop_container)
+
+    return container_run
+
+
+@pytest.mark.incremental
+class TestGerritReindex:
+    def _get_indices(self, container):
+        _, indices = container.exec_run(
+            "git config -f /var/gerrit/index/gerrit_index.config "
+            + "--name-only "
+            + "--get-regexp index"
+        )
+        indices = indices.decode().strip().splitlines()
+        return [index.split(".")[1] for index in indices]
+
+    def test_gerrit_init_skips_reindexing_on_fresh_site(
+        self, temp_site, container_run_endless
+    ):
+        assert not os.path.exists(
+            os.path.join(temp_site, "index", "gerrit_index.config")
+        )
+        exit_code, _ = container_run_endless.exec_run(
+            (
+                "python3 /var/tools/gerrit-initializer "
+                "-s /var/gerrit -c /var/config/gerrit-init.yaml init"
+            )
+        )
+        assert exit_code == 0
+        expected_files = ["gerrit_index.config"] + self._get_indices(
+            container_run_endless
+        )
+        for expected_file in expected_files:
+            assert os.path.exists(os.path.join(temp_site, "index", expected_file))
+
+        timestamp_index_dir = os.path.getctime(os.path.join(temp_site, "index"))
+
+        exit_code, _ = container_run_endless.exec_run(
+            (
+                "python3 /var/tools/gerrit-initializer "
+                "-s /var/gerrit -c /var/config/gerrit-init.yaml reindex"
+            )
+        )
+        assert exit_code == 0
+        assert timestamp_index_dir == os.path.getctime(os.path.join(temp_site, "index"))
+
+    def test_gerrit_init_fixes_missing_index_config(
+        self, container_run_endless, temp_site
+    ):
+        container_run_endless.exec_run(
+            (
+                "python3 /var/tools/gerrit-initializer "
+                "-s /var/gerrit -c /var/config/gerrit-init.yaml init"
+            )
+        )
+        os.remove(os.path.join(temp_site, "index", "gerrit_index.config"))
+
+        exit_code, _ = container_run_endless.exec_run(
+            (
+                "python3 /var/tools/gerrit-initializer "
+                "-s /var/gerrit -c /var/config/gerrit-init.yaml reindex"
+            )
+        )
+        assert exit_code == 0
+
+        exit_code, _ = container_run_endless.exec_run("/var/gerrit/bin/gerrit.sh start")
+        assert exit_code == 0
+
+    def test_gerrit_init_fixes_not_ready_indices(self, container_run_endless):
+        container_run_endless.exec_run(
+            (
+                "python3 /var/tools/gerrit-initializer "
+                "-s /var/gerrit -c /var/config/gerrit-init.yaml init"
+            )
+        )
+
+        indices = self._get_indices(container_run_endless)
+        assert indices
+        container_run_endless.exec_run(
+            f"git config -f /var/gerrit/index/gerrit_index.config {indices[0]} false"
+        )
+
+        exit_code, _ = container_run_endless.exec_run(
+            (
+                "python3 /var/tools/gerrit-initializer "
+                "-s /var/gerrit -c /var/config/gerrit-init.yaml reindex"
+            )
+        )
+        assert exit_code == 0
+
+        exit_code, _ = container_run_endless.exec_run("/var/gerrit/bin/gerrit.sh start")
+        assert exit_code == 0
+
+    def test_gerrit_init_fixes_outdated_indices(self, container_run_endless, temp_site):
+        container_run_endless.exec_run(
+            (
+                "python3 /var/tools/gerrit-initializer "
+                "-s /var/gerrit -c /var/config/gerrit-init.yaml init"
+            )
+        )
+
+        index = self._get_indices(container_run_endless)[0]
+        (name, version) = index.split("_")
+        os.rename(
+            os.path.join(temp_site, "index", index),
+            os.path.join(temp_site, "index", f"{name}_{int(version) - 1:04d}"),
+        )
+
+        exit_code, _ = container_run_endless.exec_run(
+            (
+                "python3 /var/tools/gerrit-initializer "
+                "-s /var/gerrit -c /var/config/gerrit-init.yaml reindex"
+            )
+        )
+        assert exit_code == 0
+
+        exit_code, _ = container_run_endless.exec_run("/var/gerrit/bin/gerrit.sh start")
+        assert exit_code == 0
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_structure_gerrit_init.py b/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_structure_gerrit_init.py
new file mode 100755
index 0000000..5861a5e
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit-init/test_container_structure_gerrit_init.py
@@ -0,0 +1,74 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+import utils
+
+
+@pytest.fixture(scope="module")
+def container_run(docker_client, container_endless_run_factory, gerrit_init_image):
+    container_run = container_endless_run_factory(docker_client, gerrit_init_image)
+    yield container_run
+    container_run.stop(timeout=1)
+
+
+@pytest.fixture(
+    scope="function",
+    params=[
+        "/var/tools/gerrit-initializer/__main__.py",
+        "/var/tools/gerrit-initializer/main.py",
+    ],
+)
+def expected_script(request):
+    return request.param
+
+
+@pytest.fixture(scope="function", params=["python3"])
+def expected_tool(request):
+    return request.param
+
+
+@pytest.fixture(scope="function", params=["pyyaml", "requests"])
+def expected_pip_package(request):
+    return request.param
+
+
+# pylint: disable=E1101
+@pytest.mark.structure
+def test_gerrit_init_inherits_from_gerrit_base(gerrit_init_image):
+    assert utils.check_if_ancestor_image_is_inherited(
+        gerrit_init_image, "gerrit-base:latest"
+    )
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_init_contains_expected_scripts(container_run, expected_script):
+    exit_code, _ = container_run.exec_run(f"test -f {expected_script}")
+    assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_init_contains_expected_tools(container_run, expected_tool):
+    exit_code, _ = container_run.exec_run(f"which {expected_tool}")
+    assert exit_code == 0
+
+
+@pytest.mark.structure
+def test_gerrit_init_has_entrypoint(gerrit_init_image):
+    entrypoint = gerrit_init_image.attrs["ContainerConfig"]["Entrypoint"]
+    assert len(entrypoint) >= 1
+    assert entrypoint == ["python3", "/var/tools/gerrit-initializer"]
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit/test_container_build_gerrit.py b/charts/k8s-gerrit/tests/container-images/gerrit/test_container_build_gerrit.py
new file mode 100644
index 0000000..a2c3dd5
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit/test_container_build_gerrit.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+
+@pytest.mark.structure
+def test_build_gerrit(gerrit_image, tag_of_cached_container):
+    if tag_of_cached_container:
+        pytest.skip("Cached image used for testing. Build will not be tested.")
+    assert gerrit_image.id is not None
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit/test_container_integration_gerrit.py b/charts/k8s-gerrit/tests/container-images/gerrit/test_container_integration_gerrit.py
new file mode 100644
index 0000000..9376a4a
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit/test_container_integration_gerrit.py
@@ -0,0 +1,108 @@
+# pylint: disable=W0613, E1101
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import time
+
+import pytest
+import requests
+
+
+@pytest.fixture(scope="module")
+def tmp_dir(tmp_path_factory):
+    return tmp_path_factory.mktemp("gerrit-test")
+
+
+@pytest.fixture(scope="class")
+def container_run(
+    docker_client,
+    docker_network,
+    tmp_dir,
+    gerrit_image,
+    gerrit_container_factory,
+    free_port,
+):
+    configs = {
+        "gerrit.config": """
+      [gerrit]
+        basePath = git
+
+      [httpd]
+        listenUrl = http://*:8080
+
+      [test]
+        success = True
+      """,
+        "secure.config": """
+      [test]
+        success = True
+      """,
+        "replication.config": """
+      [test]
+        success = True
+      """,
+    }
+    test_setup = gerrit_container_factory(
+        docker_client, docker_network, tmp_dir, gerrit_image, configs, free_port
+    )
+    test_setup.start()
+
+    yield test_setup
+
+    test_setup.stop()
+
+
+@pytest.fixture(params=["gerrit.config", "secure.config", "replication.config"])
+def config_file_to_test(request):
+    return request.param
+
+
+@pytest.mark.docker
+@pytest.mark.incremental
+@pytest.mark.integration
+@pytest.mark.slow
+class TestGerritStartScript:
+    @pytest.mark.timeout(60)
+    def test_gerrit_gerrit_starts_up(self, container_run):
+        def wait_for_gerrit_start():
+            log = container_run.container.logs().decode("utf-8")
+            return re.search(r"Gerrit Code Review .+ ready", log)
+
+        while not wait_for_gerrit_start:
+            continue
+
+    def test_gerrit_custom_gerrit_config_available(
+        self, container_run, config_file_to_test
+    ):
+        exit_code, output = container_run.container.exec_run(
+            f"git config --file=/var/gerrit/etc/{config_file_to_test} --get test.success"
+        )
+        output = output.decode("utf-8").strip()
+        assert exit_code == 0
+        assert output == "True"
+
+    @pytest.mark.timeout(60)
+    def test_gerrit_httpd_is_responding(self, container_run):
+        status = None
+        while not status == 200:
+            try:
+                response = requests.get(f"http://localhost:{container_run.port}")
+                status = response.status_code
+            except requests.exceptions.ConnectionError:
+                time.sleep(1)
+
+        assert response.status_code == 200
+        assert re.search(r'content="Gerrit Code Review"', response.text)
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit/test_container_integration_gerrit_replica.py b/charts/k8s-gerrit/tests/container-images/gerrit/test_container_integration_gerrit_replica.py
new file mode 100644
index 0000000..3673eab
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit/test_container_integration_gerrit_replica.py
@@ -0,0 +1,122 @@
+# pylint: disable=W0613, E1101
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import os.path
+import re
+
+import pygit2 as git
+import pytest
+import requests
+
+CONFIG_FILES = ["gerrit.config", "secure.config"]
+
+
+@pytest.fixture(scope="module")
+def tmp_dir(tmp_path_factory):
+    return tmp_path_factory.mktemp("gerrit-replica-test")
+
+
+@pytest.fixture(scope="class")
+def container_run(
+    request,
+    docker_client,
+    docker_network,
+    tmp_dir,
+    gerrit_image,
+    gerrit_container_factory,
+    free_port,
+):
+    configs = {
+        "gerrit.config": """
+      [gerrit]
+        basePath = git
+
+      [httpd]
+        listenUrl = http://*:8080
+
+      [container]
+        replica = true
+
+      [test]
+        success = True
+      """,
+        "secure.config": """
+      [test]
+          success = True
+      """,
+    }
+
+    test_setup = gerrit_container_factory(
+        docker_client, docker_network, tmp_dir, gerrit_image, configs, free_port
+    )
+    test_setup.start()
+
+    request.addfinalizer(test_setup.stop)
+
+    return test_setup
+
+
+@pytest.mark.docker
+@pytest.mark.incremental
+@pytest.mark.integration
+@pytest.mark.slow
+class TestGerritReplica:
+    @pytest.fixture(params=CONFIG_FILES)
+    def config_file_to_test(self, request):
+        return request.param
+
+    @pytest.fixture(params=["All-Users.git", "All-Projects.git"])
+    def expected_repository(self, request):
+        return request.param
+
+    @pytest.mark.timeout(60)
+    def test_gerrit_replica_gerrit_starts_up(self, container_run):
+        def wait_for_gerrit_start():
+            log = container_run.container.logs().decode("utf-8")
+            return re.search(r"Gerrit Code Review .+ ready", log)
+
+        while not wait_for_gerrit_start():
+            continue
+
+    def test_gerrit_replica_custom_gerrit_config_available(
+        self, container_run, config_file_to_test
+    ):
+        exit_code, output = container_run.container.exec_run(
+            f"git config --file=/var/gerrit/etc/{config_file_to_test} --get test.success"
+        )
+        output = output.decode("utf-8").strip()
+        assert exit_code == 0
+        assert output == "True"
+
+    def test_gerrit_replica_repository_exists(self, container_run, expected_repository):
+        exit_code, _ = container_run.container.exec_run(
+            f"test -d /var/gerrit/git/{expected_repository}"
+        )
+        assert exit_code == 0
+
+    def test_gerrit_replica_clone_repo_works(self, container_run, tmp_path_factory):
+        container_run.container.exec_run("git init --bare /var/gerrit/git/test.git")
+        clone_dest = tmp_path_factory.mktemp("gerrit_replica_clone_test")
+        repo = git.clone_repository(
+            f"http://localhost:{container_run.port}/test.git", clone_dest
+        )
+        assert repo.path == os.path.join(clone_dest, ".git/")
+
+    def test_gerrit_replica_webui_not_accessible(self, container_run):
+        response = requests.get(f"http://localhost:{container_run.port}")
+        assert response.status_code == 404
+        assert response.text == "Not Found"
diff --git a/charts/k8s-gerrit/tests/container-images/gerrit/test_container_structure_gerrit.py b/charts/k8s-gerrit/tests/container-images/gerrit/test_container_structure_gerrit.py
new file mode 100755
index 0000000..7ece25e
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/gerrit/test_container_structure_gerrit.py
@@ -0,0 +1,39 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+import utils
+
+
+@pytest.fixture(scope="module")
+def container_run(docker_client, container_endless_run_factory, gerrit_image):
+    container_run = container_endless_run_factory(docker_client, gerrit_image)
+    yield container_run
+    container_run.stop(timeout=1)
+
+
+# pylint: disable=E1101
+@pytest.mark.structure
+def test_gerrit_inherits_from_gerrit_base(gerrit_image):
+    assert utils.check_if_ancestor_image_is_inherited(
+        gerrit_image, "gerrit-base:latest"
+    )
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gerrit_contains_start_script(container_run):
+    exit_code, _ = container_run.exec_run("test -f /var/tools/start")
+    assert exit_code == 0
diff --git a/charts/k8s-gerrit/tests/container-images/git-gc/test_container_build_gitgc.py b/charts/k8s-gerrit/tests/container-images/git-gc/test_container_build_gitgc.py
new file mode 100644
index 0000000..a640d20
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/git-gc/test_container_build_gitgc.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+
+@pytest.mark.structure
+def test_build_gitgc(gitgc_image, tag_of_cached_container):
+    if tag_of_cached_container:
+        pytest.skip("Cached image used for testing. Build will not be tested.")
+    assert gitgc_image.id is not None
diff --git a/charts/k8s-gerrit/tests/container-images/git-gc/test_container_structure_gitgc.py b/charts/k8s-gerrit/tests/container-images/git-gc/test_container_structure_gitgc.py
new file mode 100644
index 0000000..9f03644
--- /dev/null
+++ b/charts/k8s-gerrit/tests/container-images/git-gc/test_container_structure_gitgc.py
@@ -0,0 +1,51 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+import utils
+
+
+@pytest.fixture(scope="module")
+def container_run(docker_client, container_endless_run_factory, gitgc_image):
+    container_run = container_endless_run_factory(docker_client, gitgc_image)
+    yield container_run
+    container_run.stop(timeout=1)
+
+
+# pylint: disable=E1101
+@pytest.mark.structure
+def test_gitgc_inherits_from_base(gitgc_image):
+    assert utils.check_if_ancestor_image_is_inherited(gitgc_image, "base:latest")
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gitgc_log_dir_writable_by_gerrit(container_run):
+    exit_code, _ = container_run.exec_run("touch /var/log/git/test.log")
+    assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
+def test_gitgc_contains_gc_script(container_run):
+    exit_code, _ = container_run.exec_run("test -f /var/tools/gc.sh")
+    assert exit_code == 0
+
+
+@pytest.mark.structure
+def test_gitgc_has_entrypoint(gitgc_image):
+    entrypoint = gitgc_image.attrs["ContainerConfig"]["Entrypoint"]
+    assert len(entrypoint) == 1
+    assert entrypoint[0] == "/var/tools/gc.sh"