Wipe addons/: full reset for clean re-upload
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
from . import test_remote
|
||||
from . import test_source
|
||||
from . import test_project
|
||||
from . import test_file_rel
|
||||
from . import test_file_template_rel
|
||||
from . import test_server
|
||||
from . import test_repo
|
||||
@@ -1,136 +0,0 @@
|
||||
from odoo.addons.cetmix_tower_server.tests.common import TestTowerCommon
|
||||
|
||||
|
||||
class CommonTest(TestTowerCommon):
|
||||
"""Common test class for all tests."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# Models
|
||||
cls.GitProject = cls.env["cx.tower.git.project"]
|
||||
cls.GitProjectRel = cls.env["cx.tower.git.project.rel"]
|
||||
cls.GitProjectFileTemplateRel = cls.env[
|
||||
"cx.tower.git.project.file.template.rel"
|
||||
]
|
||||
cls.GitSource = cls.env["cx.tower.git.source"]
|
||||
cls.GitRemote = cls.env["cx.tower.git.remote"]
|
||||
|
||||
# Data
|
||||
# Project
|
||||
cls.git_project_1 = cls.GitProject.create({"name": "Git Project 1"})
|
||||
|
||||
# Sources
|
||||
cls.git_source_1 = cls.GitSource.create(
|
||||
{"name": "Git Source 1", "git_project_id": cls.git_project_1.id}
|
||||
)
|
||||
cls.git_source_2 = cls.GitSource.create(
|
||||
{"name": "Git Source 2", "git_project_id": cls.git_project_1.id}
|
||||
)
|
||||
# Repositories
|
||||
cls.Repo = cls.env["cx.tower.git.repo"]
|
||||
cls.RepoOwner = cls.env["cx.tower.git.repo.owner"]
|
||||
|
||||
cls.repo_cetmix_tower = cls.Repo.create(
|
||||
{
|
||||
"name": "Cetmix Tower",
|
||||
"url": "https://github.com/cetmix-test/cetmix-tower-test.git",
|
||||
}
|
||||
)
|
||||
cls.repo_oca_web = cls.Repo.create(
|
||||
{
|
||||
"name": "OCA Web",
|
||||
"url": "https://github.com/oca-test/web-test.git",
|
||||
}
|
||||
)
|
||||
cls.repo_odoo_enterprise = cls.Repo.create(
|
||||
{
|
||||
"name": "Odoo Enterprise",
|
||||
"url": "https://github.com/odoo-test/enterprise-test.git",
|
||||
"is_private": True,
|
||||
}
|
||||
)
|
||||
cls.repo_gitlab_private = cls.Repo.create(
|
||||
{
|
||||
"name": "GitLab Private",
|
||||
"url": "git@my.gitlab.com:cetmix-test/cetmix-tower-test.git",
|
||||
"is_private": True,
|
||||
}
|
||||
)
|
||||
cls.repo_bitbucket_private = cls.Repo.create(
|
||||
{
|
||||
"name": "Bitbucket Private",
|
||||
"url": "https://bitbucket.com/cetmix-test/cetmix-tower-test-enterprise.git",
|
||||
"is_private": True,
|
||||
}
|
||||
)
|
||||
|
||||
# Same urls, different protocols (intentionally aliased)
|
||||
cls.repo_other_ssh = cls.Repo.create(
|
||||
{"url": "git@memegit.com:cetmix-test/cetmix-tower-test.git"}
|
||||
)
|
||||
cls.repo_other_https = cls.repo_other_ssh
|
||||
|
||||
# Remotes
|
||||
cls.remote_github_https = cls.GitRemote.create(
|
||||
{
|
||||
"repo_id": cls.repo_cetmix_tower.id,
|
||||
"source_id": cls.git_source_1.id,
|
||||
"head_type": "pr",
|
||||
"head": "https://github.com/cetmix-test/cetmix-tower-test/pull/123",
|
||||
"sequence": 1,
|
||||
}
|
||||
)
|
||||
cls.remote_gitlab_https = cls.GitRemote.create(
|
||||
{
|
||||
"repo_id": cls.repo_gitlab_private.id,
|
||||
"source_id": cls.git_source_1.id,
|
||||
"head_type": "branch",
|
||||
"head": "main",
|
||||
"sequence": 2,
|
||||
}
|
||||
)
|
||||
cls.remote_gitlab_ssh = cls.GitRemote.create(
|
||||
{
|
||||
"repo_id": cls.repo_gitlab_private.id,
|
||||
"source_id": cls.git_source_1.id,
|
||||
"head_type": "commit",
|
||||
"url_protocol": "ssh",
|
||||
"head": "10000000",
|
||||
"sequence": 3,
|
||||
}
|
||||
)
|
||||
cls.remote_bitbucket_https = cls.GitRemote.create(
|
||||
{
|
||||
"repo_id": cls.repo_bitbucket_private.id,
|
||||
"source_id": cls.git_source_2.id,
|
||||
"head_type": "branch",
|
||||
"head": "dev",
|
||||
"sequence": 4,
|
||||
}
|
||||
)
|
||||
cls.remote_other_ssh = cls.GitRemote.create(
|
||||
{
|
||||
"repo_id": cls.repo_other_ssh.id,
|
||||
"source_id": cls.git_source_2.id,
|
||||
"head_type": "branch",
|
||||
"url_protocol": "ssh",
|
||||
"head": "old",
|
||||
"sequence": 5,
|
||||
}
|
||||
)
|
||||
|
||||
# File
|
||||
cls.server_1_file_1 = cls.File.create(
|
||||
{
|
||||
"name": "File 1",
|
||||
"server_id": cls.server_test_1.id,
|
||||
"source": "tower",
|
||||
}
|
||||
)
|
||||
cls.file_template_1 = cls.FileTemplate.create(
|
||||
{
|
||||
"name": "File Template 1",
|
||||
}
|
||||
)
|
||||
@@ -1,390 +0,0 @@
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
from .common import CommonTest
|
||||
|
||||
|
||||
class TestFileRel(CommonTest):
|
||||
"""Test class for git file relation."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.file_1_rel = self.GitProjectRel.create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"file_id": self.server_1_file_1.id,
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
def test_file_rel_create(self):
|
||||
"""Test if file relation is created correctly"""
|
||||
|
||||
# -- 1 --
|
||||
# Check if file content is updated
|
||||
|
||||
# Get code from project
|
||||
yaml_code_from_project = (
|
||||
self.file_1_rel.git_project_id._generate_code_git_aggregator(
|
||||
self.file_1_rel
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.server_1_file_1.code,
|
||||
yaml_code_from_project,
|
||||
"File content is not updated correctly",
|
||||
)
|
||||
|
||||
# Check specific if remote is present in file
|
||||
self.assertIn(
|
||||
self.remote_other_ssh.repo_id.url_ssh,
|
||||
self.server_1_file_1.code,
|
||||
"Remote is not present in file",
|
||||
)
|
||||
|
||||
# -- 2 --
|
||||
# Modify remove and check if file content is updated
|
||||
self.remote_other_ssh.repo_id = self.Repo.create(
|
||||
{
|
||||
"url": "https://github.com/cetmix/cetmix-memes.git",
|
||||
}
|
||||
)
|
||||
self.remote_other_ssh.url_protocol = "https"
|
||||
|
||||
# Must be different from previous project code
|
||||
self.assertNotEqual(
|
||||
self.server_1_file_1.code,
|
||||
yaml_code_from_project,
|
||||
"File content is not updated correctly",
|
||||
)
|
||||
# New remote must be present in file
|
||||
self.assertIn(
|
||||
"https://github.com/cetmix/cetmix-memes.git",
|
||||
self.server_1_file_1.code,
|
||||
"Remote is not present in file",
|
||||
)
|
||||
|
||||
# -- 3 --
|
||||
# Disable source and check if file content is updated
|
||||
self.git_source_2.active = False
|
||||
self.assertNotIn(
|
||||
"https://github.com/cetmix/cetmix-memes.git",
|
||||
self.server_1_file_1.code,
|
||||
"Remote is present in file",
|
||||
)
|
||||
|
||||
def test_format_git_aggregator(self):
|
||||
"""Test if format git aggregator works correctly"""
|
||||
|
||||
# -- 1 --
|
||||
# Check if YAML code is generated correctly
|
||||
|
||||
yaml_code = """# This file is generated with Cetmix Tower https://cetmix.com/tower
|
||||
# It's designed to be used with git-aggregator tool developed by Acsone.
|
||||
# Documentation for git-aggregator: https://github.com/acsone/git-aggregator
|
||||
|
||||
# You need to set the following variables in your environment:
|
||||
# BITBUCKET_TOKEN, GITLAB_TOKEN, GITLAB_TOKEN_NAME
|
||||
# and run git-aggregator with '--expand-env' parameter.
|
||||
|
||||
./git_project_1_git_source_1:
|
||||
remotes:
|
||||
remote_1: https://github.com/cetmix-test/cetmix-tower-test.git
|
||||
remote_2: https://$GITLAB_TOKEN_NAME:$GITLAB_TOKEN@my.gitlab.com/cetmix-test/cetmix-tower-test.git
|
||||
remote_3: git@my.gitlab.com:cetmix-test/cetmix-tower-test.git
|
||||
merges:
|
||||
- remote: remote_1
|
||||
ref: refs/pull/123/head
|
||||
- remote: remote_2
|
||||
ref: main
|
||||
- remote: remote_3
|
||||
ref: '10000000'
|
||||
target: remote_1
|
||||
./git_project_1_git_source_1_2:
|
||||
remotes:
|
||||
remote_1: https://x-token-auth:$BITBUCKET_TOKEN@bitbucket.com/cetmix-test/cetmix-tower-test-enterprise.git
|
||||
remote_2: git@memegit.com:cetmix-test/cetmix-tower-test.git
|
||||
merges:
|
||||
- remote: remote_1
|
||||
ref: dev
|
||||
- remote: remote_2
|
||||
ref: old
|
||||
target: remote_1
|
||||
""" # noqa: E501
|
||||
|
||||
# Get code from project
|
||||
yaml_code_from_project = (
|
||||
self.file_1_rel.git_project_id._generate_code_git_aggregator(
|
||||
self.file_1_rel
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
yaml_code_from_project,
|
||||
yaml_code,
|
||||
"YAML code is not generated correctly",
|
||||
)
|
||||
|
||||
# -- 2 --
|
||||
# Unlink remote and check if file content is updated
|
||||
self.remote_github_https.unlink()
|
||||
yaml_code_from_project = (
|
||||
self.file_1_rel.git_project_id._generate_code_git_aggregator(
|
||||
self.file_1_rel
|
||||
)
|
||||
)
|
||||
yaml_code = """# This file is generated with Cetmix Tower https://cetmix.com/tower
|
||||
# It's designed to be used with git-aggregator tool developed by Acsone.
|
||||
# Documentation for git-aggregator: https://github.com/acsone/git-aggregator
|
||||
|
||||
# You need to set the following variables in your environment:
|
||||
# BITBUCKET_TOKEN, GITLAB_TOKEN, GITLAB_TOKEN_NAME
|
||||
# and run git-aggregator with '--expand-env' parameter.
|
||||
|
||||
./git_project_1_git_source_1:
|
||||
remotes:
|
||||
remote_2: https://$GITLAB_TOKEN_NAME:$GITLAB_TOKEN@my.gitlab.com/cetmix-test/cetmix-tower-test.git
|
||||
remote_3: git@my.gitlab.com:cetmix-test/cetmix-tower-test.git
|
||||
merges:
|
||||
- remote: remote_2
|
||||
ref: main
|
||||
- remote: remote_3
|
||||
ref: '10000000'
|
||||
target: remote_2
|
||||
./git_project_1_git_source_1_2:
|
||||
remotes:
|
||||
remote_1: https://x-token-auth:$BITBUCKET_TOKEN@bitbucket.com/cetmix-test/cetmix-tower-test-enterprise.git
|
||||
remote_2: git@memegit.com:cetmix-test/cetmix-tower-test.git
|
||||
merges:
|
||||
- remote: remote_1
|
||||
ref: dev
|
||||
- remote: remote_2
|
||||
ref: old
|
||||
target: remote_1
|
||||
""" # noqa: E501
|
||||
|
||||
self.assertEqual(
|
||||
yaml_code_from_project,
|
||||
yaml_code,
|
||||
"YAML code is not generated correctly",
|
||||
)
|
||||
|
||||
# -- 3 --
|
||||
# Unlink source and check if file content is updated
|
||||
self.git_source_2.unlink()
|
||||
yaml_code_from_project = (
|
||||
self.file_1_rel.git_project_id._generate_code_git_aggregator(
|
||||
self.file_1_rel
|
||||
)
|
||||
)
|
||||
yaml_code = """# This file is generated with Cetmix Tower https://cetmix.com/tower
|
||||
# It's designed to be used with git-aggregator tool developed by Acsone.
|
||||
# Documentation for git-aggregator: https://github.com/acsone/git-aggregator
|
||||
|
||||
# You need to set the following variables in your environment:
|
||||
# GITLAB_TOKEN, GITLAB_TOKEN_NAME
|
||||
# and run git-aggregator with '--expand-env' parameter.
|
||||
|
||||
./git_project_1_git_source_1:
|
||||
remotes:
|
||||
remote_2: https://$GITLAB_TOKEN_NAME:$GITLAB_TOKEN@my.gitlab.com/cetmix-test/cetmix-tower-test.git
|
||||
remote_3: git@my.gitlab.com:cetmix-test/cetmix-tower-test.git
|
||||
merges:
|
||||
- remote: remote_2
|
||||
ref: main
|
||||
- remote: remote_3
|
||||
ref: '10000000'
|
||||
target: remote_2
|
||||
""" # noqa: E501
|
||||
self.assertEqual(
|
||||
yaml_code_from_project,
|
||||
yaml_code,
|
||||
"YAML code is not generated correctly",
|
||||
)
|
||||
|
||||
def test_user_access(self):
|
||||
"""Test that regular users have no access to git project relations"""
|
||||
user_rel = self.GitProjectRel.with_user(self.user)
|
||||
|
||||
# Try create - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
user_rel.create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"file_id": self.server_1_file_1.id,
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Try read - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
user_rel.browse(self.file_1_rel.id).read(["name"])
|
||||
|
||||
# Try write - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
user_rel.browse(self.file_1_rel.id).write(
|
||||
{"project_format": "git_aggregator"}
|
||||
)
|
||||
|
||||
# Try unlink - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
user_rel.browse(self.file_1_rel.id).unlink()
|
||||
|
||||
def test_manager_read_access(self):
|
||||
"""Test manager read access rules"""
|
||||
manager_rel = self.GitProjectRel.with_user(self.manager)
|
||||
|
||||
# Initially manager should not have access
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.browse(self.file_1_rel.id).read(["name"])
|
||||
|
||||
# Add manager as project user - should have read access
|
||||
self.git_project_1.write({"user_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(manager_rel.browse(self.file_1_rel.id).name, "Git Project 1")
|
||||
|
||||
# Remove from project, add as server user - should have read access
|
||||
self.git_project_1.write({"user_ids": [(3, self.manager.id)]})
|
||||
self.server_test_1.write({"user_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(manager_rel.browse(self.file_1_rel.id).name, "Git Project 1")
|
||||
|
||||
# Remove from server users, add as project manager - should have read access
|
||||
self.server_test_1.write({"user_ids": [(3, self.manager.id)]})
|
||||
self.git_project_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(manager_rel.browse(self.file_1_rel.id).name, "Git Project 1")
|
||||
|
||||
# Remove from project, add as server manager - should have read access
|
||||
self.git_project_1.write({"manager_ids": [(3, self.manager.id)]})
|
||||
self.server_test_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(manager_rel.browse(self.file_1_rel.id).name, "Git Project 1")
|
||||
|
||||
def test_manager_write_access(self):
|
||||
"""Test manager write/create access rules"""
|
||||
manager_rel = self.GitProjectRel.with_user(self.manager)
|
||||
|
||||
# Create new file to avoid unique constraint violation
|
||||
file_2 = self.File.create(
|
||||
{
|
||||
"name": "test_file_2",
|
||||
"server_id": self.server_test_1.id,
|
||||
"source": "tower",
|
||||
"file_type": "text",
|
||||
}
|
||||
)
|
||||
|
||||
# Try create without being project and server manager - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"file_id": file_2.id,
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Add as project manager only - should still fail
|
||||
file_3 = self.File.create(
|
||||
{
|
||||
"name": "test_file_3",
|
||||
"server_id": self.server_test_1.id,
|
||||
"source": "tower",
|
||||
"file_type": "text",
|
||||
}
|
||||
)
|
||||
self.git_project_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"file_id": file_3.id,
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Add as server manager - should succeed
|
||||
file_4 = self.File.create(
|
||||
{
|
||||
"name": "test_file_4",
|
||||
"server_id": self.server_test_1.id,
|
||||
"source": "tower",
|
||||
"file_type": "text",
|
||||
}
|
||||
)
|
||||
self.server_test_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
rel = manager_rel.create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"file_id": file_4.id,
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
self.assertTrue(rel.exists())
|
||||
|
||||
# Test write access
|
||||
rel.write({"project_format": "git_aggregator"})
|
||||
|
||||
# Remove server manager access - should fail to write
|
||||
self.server_test_1.write({"manager_ids": [(3, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
rel.write({"project_format": "git_aggregator"})
|
||||
|
||||
# Remove project manager access - should fail to write
|
||||
self.git_project_1.write({"manager_ids": [(3, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
rel.write({"project_format": "git_aggregator"})
|
||||
|
||||
def test_manager_unlink_access(self):
|
||||
"""Test manager unlink access rules"""
|
||||
manager_rel = self.GitProjectRel.with_user(self.manager)
|
||||
|
||||
# Try delete without being project and server manager - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.browse(self.file_1_rel.id).unlink()
|
||||
|
||||
# Add as project manager only - should fail
|
||||
self.git_project_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.browse(self.file_1_rel.id).unlink()
|
||||
|
||||
# Add as server manager - should succeed
|
||||
self.server_test_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
self.file_1_rel.unlink()
|
||||
self.assertFalse(self.file_1_rel.exists())
|
||||
|
||||
def test_root_access(self):
|
||||
"""Test root access rules"""
|
||||
root_rel = self.GitProjectRel.with_user(self.root)
|
||||
|
||||
# Create new file to avoid unique constraint violation
|
||||
file_3 = self.File.create(
|
||||
{
|
||||
"name": "test_file_3",
|
||||
"server_id": self.server_test_1.id,
|
||||
"source": "tower",
|
||||
"file_type": "text",
|
||||
}
|
||||
)
|
||||
|
||||
# Create - should succeed
|
||||
rel = root_rel.create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"file_id": file_3.id,
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
self.assertTrue(rel.exists())
|
||||
|
||||
# Read - should succeed
|
||||
self.assertEqual(root_rel.browse(rel.id).name, "Git Project 1")
|
||||
|
||||
# Write - should succeed
|
||||
root_rel.browse(rel.id).write({"project_format": "git_aggregator"})
|
||||
|
||||
# Delete - should succeed
|
||||
rel.unlink()
|
||||
self.assertFalse(rel.exists())
|
||||
@@ -1,308 +0,0 @@
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
from .common import CommonTest
|
||||
|
||||
|
||||
class TestFileTemplateRel(CommonTest):
|
||||
"""Test class for git file template relation."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.file_template_1_rel = cls.GitProjectFileTemplateRel.create(
|
||||
{
|
||||
"git_project_id": cls.git_project_1.id,
|
||||
"file_template_id": cls.file_template_1.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
def test_file_template_rel_create(self):
|
||||
"""Test if file template relation is created correctly"""
|
||||
|
||||
# -- 1 --
|
||||
# Check if file content is updated
|
||||
|
||||
# Get code from project
|
||||
yaml_code_from_project = (
|
||||
self.file_template_1_rel.git_project_id._generate_code_git_aggregator(
|
||||
self.file_template_1_rel
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.file_template_1.code,
|
||||
yaml_code_from_project,
|
||||
"File template content is not updated correctly",
|
||||
)
|
||||
|
||||
# Check specific if remote is present in file
|
||||
self.assertIn(
|
||||
self.remote_other_ssh.repo_id.url_ssh,
|
||||
self.file_template_1.code,
|
||||
"Remote is not present in file template",
|
||||
)
|
||||
|
||||
# -- 2 --
|
||||
# Modify remove and check if file template content is updated
|
||||
self.remote_other_ssh.repo_id = self.Repo.create(
|
||||
{
|
||||
"url": "https://github.com/cetmix/cetmix-memes.git",
|
||||
}
|
||||
)
|
||||
self.remote_other_ssh.url_protocol = "https"
|
||||
|
||||
# Must be different from previous project code
|
||||
self.assertNotEqual(
|
||||
self.file_template_1.code,
|
||||
yaml_code_from_project,
|
||||
"File template content is not updated correctly",
|
||||
)
|
||||
# New remote must be present in file
|
||||
self.assertIn(
|
||||
"https://github.com/cetmix/cetmix-memes.git",
|
||||
self.file_template_1.code,
|
||||
"Remote is not present in file template",
|
||||
)
|
||||
|
||||
# -- 3 --
|
||||
# Disable source and check if file content is updated
|
||||
self.git_source_2.active = False
|
||||
self.assertNotIn(
|
||||
"https://github.com/cetmix/cetmix-memes.git",
|
||||
self.file_template_1.code,
|
||||
"Remote is present in file template",
|
||||
)
|
||||
|
||||
def test_format_git_aggregator(self):
|
||||
"""Test if format git aggregator works correctly"""
|
||||
|
||||
# -- 1 --
|
||||
# Check if YAML code is generated correctly
|
||||
|
||||
yaml_code = """# This file is generated with Cetmix Tower https://cetmix.com/tower
|
||||
# It's designed to be used with git-aggregator tool developed by Acsone.
|
||||
# Documentation for git-aggregator: https://github.com/acsone/git-aggregator
|
||||
|
||||
# You need to set the following variables in your environment:
|
||||
# BITBUCKET_TOKEN, GITLAB_TOKEN, GITLAB_TOKEN_NAME
|
||||
# and run git-aggregator with '--expand-env' parameter.
|
||||
|
||||
./git_project_1_git_source_1:
|
||||
remotes:
|
||||
remote_1: https://github.com/cetmix-test/cetmix-tower-test.git
|
||||
remote_2: https://$GITLAB_TOKEN_NAME:$GITLAB_TOKEN@my.gitlab.com/cetmix-test/cetmix-tower-test.git
|
||||
remote_3: git@my.gitlab.com:cetmix-test/cetmix-tower-test.git
|
||||
merges:
|
||||
- remote: remote_1
|
||||
ref: refs/pull/123/head
|
||||
- remote: remote_2
|
||||
ref: main
|
||||
- remote: remote_3
|
||||
ref: '10000000'
|
||||
target: remote_1
|
||||
./git_project_1_git_source_1_2:
|
||||
remotes:
|
||||
remote_1: https://x-token-auth:$BITBUCKET_TOKEN@bitbucket.com/cetmix-test/cetmix-tower-test-enterprise.git
|
||||
remote_2: git@memegit.com:cetmix-test/cetmix-tower-test.git
|
||||
merges:
|
||||
- remote: remote_1
|
||||
ref: dev
|
||||
- remote: remote_2
|
||||
ref: old
|
||||
target: remote_1
|
||||
""" # noqa: E501
|
||||
|
||||
# Get code from project
|
||||
yaml_code_from_project = (
|
||||
self.file_template_1_rel.git_project_id._generate_code_git_aggregator(
|
||||
self.file_template_1_rel
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
yaml_code_from_project,
|
||||
yaml_code,
|
||||
"YAML code is not generated correctly",
|
||||
)
|
||||
|
||||
def test_user_access(self):
|
||||
"""Test that regular users have no access to git project relations"""
|
||||
user_rel = self.GitProjectFileTemplateRel.with_user(self.user)
|
||||
|
||||
# Try create - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
user_rel.create(
|
||||
{
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"file_template_id": self.file_template_1.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Try read - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
user_rel.browse(self.file_template_1_rel.id).read(["name"])
|
||||
|
||||
# Try write - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
user_rel.browse(self.file_template_1_rel.id).write(
|
||||
{"project_format": "git_aggregator"}
|
||||
)
|
||||
|
||||
# Try unlink - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
user_rel.browse(self.file_template_1_rel.id).unlink()
|
||||
|
||||
def test_manager_read_access(self):
|
||||
"""Test manager read access rules"""
|
||||
manager_rel = self.GitProjectFileTemplateRel.with_user(self.manager)
|
||||
|
||||
# Initially manager should not have access
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.browse(self.file_template_1_rel.id).read(["name"])
|
||||
|
||||
# Add manager as project user - should have read access
|
||||
self.git_project_1.write({"user_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(
|
||||
manager_rel.browse(self.file_template_1_rel.id).name, "Git Project 1"
|
||||
)
|
||||
|
||||
# Remove from project, add as file template user
|
||||
# should have read access
|
||||
self.git_project_1.write({"user_ids": [(3, self.manager.id)]})
|
||||
self.file_template_1.write({"user_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(
|
||||
manager_rel.browse(self.file_template_1_rel.id).name, "Git Project 1"
|
||||
)
|
||||
|
||||
# Remove from file template users, add as project manager
|
||||
# should have read access
|
||||
self.file_template_1.write({"user_ids": [(3, self.manager.id)]})
|
||||
self.git_project_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(
|
||||
manager_rel.browse(self.file_template_1_rel.id).name, "Git Project 1"
|
||||
)
|
||||
|
||||
# Remove from project, add as file template manager
|
||||
# should have read access
|
||||
self.git_project_1.write({"manager_ids": [(3, self.manager.id)]})
|
||||
self.file_template_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(
|
||||
manager_rel.browse(self.file_template_1_rel.id).name, "Git Project 1"
|
||||
)
|
||||
|
||||
def test_manager_write_access(self):
|
||||
"""Test manager write/create access rules"""
|
||||
manager_rel = self.GitProjectFileTemplateRel.with_user(self.manager)
|
||||
|
||||
# Create new file template to avoid unique constraint violation
|
||||
file_template_2 = self.FileTemplate.create(
|
||||
{
|
||||
"name": "test_file_template_2",
|
||||
}
|
||||
)
|
||||
|
||||
# Try create without being project and file template manager - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.create(
|
||||
{
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"file_template_id": file_template_2.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Add as project manager only - should still fail
|
||||
file_template_3 = self.FileTemplate.create(
|
||||
{
|
||||
"name": "test_file_template_3",
|
||||
}
|
||||
)
|
||||
self.git_project_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.create(
|
||||
{
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"file_template_id": file_template_3.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Add as file template manager - should succeed
|
||||
file_template_4 = self.FileTemplate.create(
|
||||
{
|
||||
"name": "test_file_template_4",
|
||||
}
|
||||
)
|
||||
file_template_4.write({"manager_ids": [(4, self.manager.id)]})
|
||||
rel = manager_rel.create(
|
||||
{
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"file_template_id": file_template_4.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
self.assertTrue(rel.exists())
|
||||
|
||||
# Test write access
|
||||
rel.write({"project_format": "git_aggregator"})
|
||||
|
||||
# Remove file template manager access - should fail to write
|
||||
file_template_4.write({"manager_ids": [(3, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
rel.write({"project_format": "git_aggregator"})
|
||||
|
||||
# Remove project manager access - should fail to write
|
||||
self.git_project_1.write({"manager_ids": [(3, self.manager.id)]})
|
||||
file_template_4.write({"manager_ids": [(4, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
rel.write({"project_format": "git_aggregator"})
|
||||
|
||||
def test_manager_unlink_access(self):
|
||||
"""Test manager unlink access rules"""
|
||||
manager_rel = self.GitProjectFileTemplateRel.with_user(self.manager)
|
||||
|
||||
# Try delete without being project and server manager - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.browse(self.file_template_1_rel.id).unlink()
|
||||
|
||||
# Add as project manager only - should fail
|
||||
self.git_project_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
manager_rel.browse(self.file_template_1_rel.id).unlink()
|
||||
|
||||
# Add as file template manager - should succeed
|
||||
self.file_template_1.write({"manager_ids": [(4, self.manager.id)]})
|
||||
self.file_template_1_rel.unlink()
|
||||
self.assertFalse(self.file_template_1_rel.exists())
|
||||
|
||||
def test_root_access(self):
|
||||
"""Test root access rules"""
|
||||
root_rel = self.GitProjectFileTemplateRel.with_user(self.root)
|
||||
|
||||
# Create new file to avoid unique constraint violation
|
||||
file_template_3 = self.FileTemplate.create(
|
||||
{
|
||||
"name": "test_file_template_3",
|
||||
}
|
||||
)
|
||||
|
||||
# Create - should succeed
|
||||
rel = root_rel.create(
|
||||
{
|
||||
"git_project_id": self.git_project_1.id,
|
||||
"file_template_id": file_template_3.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
self.assertTrue(rel.exists())
|
||||
|
||||
# Read - should succeed
|
||||
self.assertEqual(root_rel.browse(rel.id).name, "Git Project 1")
|
||||
|
||||
# Write - should succeed
|
||||
root_rel.browse(rel.id).write({"project_format": "git_aggregator"})
|
||||
|
||||
# Delete - should succeed
|
||||
rel.unlink()
|
||||
self.assertFalse(rel.exists())
|
||||
@@ -1,315 +0,0 @@
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
from .common import CommonTest
|
||||
|
||||
|
||||
class TestProject(CommonTest):
|
||||
"""Test class for git project."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
# Remove user bob from all groups
|
||||
cls.remove_from_group(
|
||||
cls.user_bob,
|
||||
[
|
||||
"cetmix_tower_server.group_user",
|
||||
"cetmix_tower_server.group_manager",
|
||||
"cetmix_tower_server.group_root",
|
||||
],
|
||||
)
|
||||
|
||||
# Create another manager for testing
|
||||
cls.manager_2 = cls.Users.create(
|
||||
{
|
||||
"name": "Second Manager",
|
||||
"login": "manager2",
|
||||
"email": "manager2@test.com",
|
||||
"groups_id": [(4, cls.env.ref("cetmix_tower_server.group_manager").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create test project as root
|
||||
cls.project = cls.GitProject.create(
|
||||
{
|
||||
"name": "Test Project",
|
||||
}
|
||||
)
|
||||
|
||||
def test_user_access(self):
|
||||
"""Test that regular users have no access to git projects"""
|
||||
user_project = self.GitProject.with_user(self.user)
|
||||
|
||||
# Test CRUD operations
|
||||
with self.assertRaises(AccessError):
|
||||
user_project.create({"name": "New Project"})
|
||||
with self.assertRaises(AccessError):
|
||||
user_project.browse(self.project.id).read(["name"])
|
||||
with self.assertRaises(AccessError):
|
||||
user_project.browse(self.project.id).write({"name": "Updated Name"})
|
||||
with self.assertRaises(AccessError):
|
||||
user_project.browse(self.project.id).unlink()
|
||||
|
||||
def test_manager_read_access(self):
|
||||
"""Test manager read access rules"""
|
||||
manager_project = self.GitProject.with_user(self.manager)
|
||||
|
||||
# Manager not in user_ids or manager_ids - should not read
|
||||
with self.assertRaises(AccessError):
|
||||
manager_project.browse(self.project.id).read(["name"])
|
||||
|
||||
# Add manager to user_ids - should read
|
||||
self.project.write({"user_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(manager_project.browse(self.project.id).name, "Test Project")
|
||||
|
||||
# Remove from user_ids, add to manager_ids - should read
|
||||
self.project.write(
|
||||
{"user_ids": [(3, self.manager.id)], "manager_ids": [(4, self.manager.id)]}
|
||||
)
|
||||
self.assertEqual(manager_project.browse(self.project.id).name, "Test Project")
|
||||
|
||||
def test_manager_write_access(self):
|
||||
"""Test manager write/create access rules"""
|
||||
manager_project = self.GitProject.with_user(self.manager)
|
||||
|
||||
# Create - should succeed as manager is added by default
|
||||
new_project = manager_project.create({"name": "New Project"})
|
||||
self.assertTrue(new_project.exists())
|
||||
self.assertIn(self.manager, new_project.manager_ids)
|
||||
|
||||
# Write - not in manager_ids, should fail
|
||||
with self.assertRaises(AccessError):
|
||||
manager_project.browse(self.project.id).write({"name": "Updated Name"})
|
||||
|
||||
# Add to manager_ids - should write
|
||||
self.project.write({"manager_ids": [(4, self.manager.id)]})
|
||||
manager_project.browse(self.project.id).write({"name": "Updated Name"})
|
||||
self.assertEqual(self.project.name, "Updated Name")
|
||||
|
||||
def test_manager_unlink_access(self):
|
||||
"""Test manager unlink access rules"""
|
||||
# Create project as manager_2
|
||||
project = self.GitProject.with_user(self.manager_2).create(
|
||||
{"name": "Project to Delete"}
|
||||
)
|
||||
manager_project = self.GitProject.with_user(self.manager)
|
||||
|
||||
# Try delete as different manager - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
manager_project.browse(project.id).unlink()
|
||||
|
||||
# Add to manager_ids but not creator - should fail
|
||||
project.write({"manager_ids": [(4, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
manager_project.browse(project.id).unlink()
|
||||
|
||||
# Create as manager and try delete - should succeed
|
||||
own_project = manager_project.create({"name": "Own Project"})
|
||||
self.assertTrue(own_project.exists())
|
||||
own_project.unlink()
|
||||
self.assertFalse(own_project.exists())
|
||||
|
||||
def test_root_access(self):
|
||||
"""Test root access rules"""
|
||||
root_project = self.GitProject.with_user(self.root)
|
||||
|
||||
# Create
|
||||
new_project = root_project.create({"name": "Root Project"})
|
||||
self.assertTrue(new_project.exists())
|
||||
|
||||
# Read
|
||||
self.assertEqual(root_project.browse(self.project.id).name, "Test Project")
|
||||
|
||||
# Write
|
||||
root_project.browse(self.project.id).write({"name": "Updated by Root"})
|
||||
self.assertEqual(self.project.name, "Updated by Root")
|
||||
|
||||
# Delete
|
||||
new_project.unlink()
|
||||
self.assertFalse(new_project.exists())
|
||||
|
||||
def test_compute_user_ids(self):
|
||||
"""Test computation of user_ids and manager_ids for git projects"""
|
||||
# Add users "Bob" and "user" to the group "cetmix_tower_server.group_manager"
|
||||
self.add_to_group(self.user_bob, "cetmix_tower_server.group_manager")
|
||||
self.add_to_group(self.user, "cetmix_tower_server.group_manager")
|
||||
|
||||
# -- 1 --
|
||||
# Create project as manager
|
||||
project_as_manager = self.GitProject.with_user(self.manager).create(
|
||||
{
|
||||
"name": "Project As Manager",
|
||||
}
|
||||
)
|
||||
# Check that manager is added to both user_ids and manager_ids by default
|
||||
self.assertEqual(len(project_as_manager.user_ids), 1)
|
||||
self.assertIn(self.manager, project_as_manager.user_ids)
|
||||
self.assertEqual(len(project_as_manager.manager_ids), 1)
|
||||
self.assertIn(self.manager, project_as_manager.manager_ids)
|
||||
|
||||
# -- 2 --
|
||||
# Create servers with multiple users and managers
|
||||
server_1 = self.Server.create(
|
||||
{
|
||||
"name": "Test Server 1",
|
||||
"ip_v4_address": "localhost",
|
||||
"ssh_username": "admin",
|
||||
"ssh_password": "password",
|
||||
"os_id": self.os_debian_10.id,
|
||||
"user_ids": [(6, 0, [self.user_bob.id, self.user.id])], # Two users
|
||||
"manager_ids": [
|
||||
(6, 0, [self.manager.id, self.manager_2.id])
|
||||
], # Two managers
|
||||
}
|
||||
)
|
||||
|
||||
server_2 = self.Server.create(
|
||||
{
|
||||
"name": "Test Server 2",
|
||||
"ip_v4_address": "localhost",
|
||||
"ssh_username": "admin",
|
||||
"ssh_password": "password",
|
||||
"os_id": self.os_debian_10.id,
|
||||
"user_ids": [
|
||||
(6, 0, [self.user_bob.id, self.user.id])
|
||||
], # Same two users
|
||||
"manager_ids": [
|
||||
(6, 0, [self.manager.id, self.manager_2.id])
|
||||
], # Same two managers
|
||||
}
|
||||
)
|
||||
|
||||
# Create project and link servers
|
||||
project = self.GitProject.create(
|
||||
{
|
||||
"name": "Test Project",
|
||||
}
|
||||
)
|
||||
|
||||
# Create files and link them to the project
|
||||
for server in [server_1, server_2]:
|
||||
file = self.File.create(
|
||||
{
|
||||
"name": f"test_file_{server.name}",
|
||||
"server_id": server.id,
|
||||
}
|
||||
)
|
||||
self.GitProjectRel.create(
|
||||
{
|
||||
"server_id": server.id,
|
||||
"file_id": file.id,
|
||||
"git_project_id": project.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Invalidate cache to ensure computed fields are updated
|
||||
project.invalidate_recordset(["server_ids", "user_ids", "manager_ids"])
|
||||
|
||||
# -- 3 --
|
||||
# Test computed values with linked servers
|
||||
# Each user/manager should be counted only once even if present in both servers
|
||||
self.assertEqual(len(project.server_ids), 2)
|
||||
self.assertEqual(len(project.user_ids), 2) # Two unique users
|
||||
self.assertIn(self.user_bob, project.user_ids)
|
||||
self.assertIn(self.user, project.user_ids)
|
||||
self.assertEqual(len(project.manager_ids), 2) # Two unique managers
|
||||
self.assertIn(self.manager, project.manager_ids)
|
||||
self.assertIn(self.manager_2, project.manager_ids)
|
||||
|
||||
# -- 4 --
|
||||
# Add server with different users/managers
|
||||
server_3 = self.Server.create(
|
||||
{
|
||||
"name": "Test Server 3",
|
||||
"ip_v4_address": "localhost",
|
||||
"ssh_username": "admin",
|
||||
"ssh_password": "password",
|
||||
"os_id": self.os_debian_10.id,
|
||||
"user_ids": [(6, 0, [self.user_bob.id])], # Only one user
|
||||
"manager_ids": [(6, 0, [self.manager_2.id])], # Only second manager
|
||||
}
|
||||
)
|
||||
file_3 = self.File.create(
|
||||
{
|
||||
"name": "test_file_3",
|
||||
"server_id": server_3.id,
|
||||
}
|
||||
)
|
||||
self.GitProjectRel.create(
|
||||
{
|
||||
"server_id": server_3.id,
|
||||
"file_id": file_3.id,
|
||||
"git_project_id": project.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Invalidate cache to ensure computed fields are updated
|
||||
project.invalidate_recordset(["server_ids", "user_ids", "manager_ids"])
|
||||
|
||||
# Test that computed values are updated correctly
|
||||
# Only users/managers present in all servers should remain
|
||||
self.assertEqual(len(project.server_ids), 3)
|
||||
self.assertEqual(len(project.user_ids), 1) # Only bob is in all servers
|
||||
self.assertIn(self.user_bob, project.user_ids)
|
||||
self.assertEqual(
|
||||
len(project.manager_ids), 1
|
||||
) # Only manager_2 is in all servers
|
||||
self.assertIn(self.manager_2, project.manager_ids)
|
||||
|
||||
# -- 5 --
|
||||
# Verify that first manager can still access the project
|
||||
project_as_manager_1 = self.GitProject.with_user(self.manager).browse(
|
||||
project.id
|
||||
)
|
||||
self.assertTrue(project_as_manager_1.exists())
|
||||
self.assertEqual(project_as_manager_1.name, "Test Project")
|
||||
|
||||
def test_manager_server_based_access(self):
|
||||
"""Test manager access through server relationships"""
|
||||
manager_project = self.GitProject.with_user(self.manager)
|
||||
|
||||
# Create a server where manager is a user
|
||||
server = self.Server.create(
|
||||
{
|
||||
"name": "Test Server",
|
||||
"ip_v4_address": "localhost",
|
||||
"ssh_username": "admin",
|
||||
"ssh_password": "password",
|
||||
"os_id": self.os_debian_10.id,
|
||||
"user_ids": [(4, self.manager.id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create a file and link project to server
|
||||
file = self.File.create(
|
||||
{
|
||||
"name": "test_file",
|
||||
"server_id": server.id,
|
||||
}
|
||||
)
|
||||
self.GitProjectRel.create(
|
||||
{
|
||||
"server_id": server.id,
|
||||
"file_id": file.id,
|
||||
"git_project_id": self.project.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Manager should be able to read project through server relationship
|
||||
self.assertEqual(manager_project.browse(self.project.id).name, "Test Project")
|
||||
|
||||
# Remove manager from server users
|
||||
server.write({"user_ids": [(3, self.manager.id)]})
|
||||
|
||||
# Manager should not be able to read project anymore
|
||||
with self.assertRaises(AccessError):
|
||||
manager_project.browse(self.project.id).read(["name"])
|
||||
|
||||
# Add manager to server managers
|
||||
server.write({"manager_ids": [(4, self.manager.id)]})
|
||||
|
||||
# Manager should be able to read project again
|
||||
self.assertEqual(manager_project.browse(self.project.id).name, "Test Project")
|
||||
@@ -1,462 +0,0 @@
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
from .common import CommonTest
|
||||
|
||||
|
||||
class TestRemote(CommonTest):
|
||||
"""Test class for git remote."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
# Create another manager for testing
|
||||
cls.manager_2 = cls.Users.create(
|
||||
{
|
||||
"name": "Second Manager",
|
||||
"login": "manager2",
|
||||
"email": "manager2@test.com",
|
||||
"groups_id": [(4, cls.env.ref("cetmix_tower_server.group_manager").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create test project and source as root
|
||||
cls.project = cls.GitProject.create(
|
||||
{
|
||||
"name": "Test Project",
|
||||
}
|
||||
)
|
||||
cls.source = cls.GitSource.create(
|
||||
{
|
||||
"name": "Test Source",
|
||||
"git_project_id": cls.project.id,
|
||||
}
|
||||
)
|
||||
cls.repo_cetmix_tower = cls.Repo.create(
|
||||
{
|
||||
"name": "Cetmix Tower",
|
||||
"url": "https://github.com/cetmix-test/cetmix-tower.git",
|
||||
}
|
||||
)
|
||||
cls.remote = cls.GitRemote.create(
|
||||
{
|
||||
"repo_id": cls.repo_cetmix_tower.id,
|
||||
"source_id": cls.source.id,
|
||||
"head_type": "branch",
|
||||
"head": "main",
|
||||
}
|
||||
)
|
||||
cls.repo_test = cls.Repo.create(
|
||||
{
|
||||
"name": "Test Repository",
|
||||
"url": "https://github.com/cetmix-test/test.git",
|
||||
}
|
||||
)
|
||||
|
||||
def test_user_access(self):
|
||||
"""Test that regular users have no access to git remotes"""
|
||||
user_remote = self.GitRemote.with_user(self.user)
|
||||
|
||||
# Test CRUD operations
|
||||
with self.assertRaises(AccessError):
|
||||
user_remote.create(
|
||||
{
|
||||
"repo_id": self.repo_test.id,
|
||||
"url_protocol": "https",
|
||||
"source_id": self.source.id,
|
||||
"head": "main",
|
||||
}
|
||||
)
|
||||
with self.assertRaises(AccessError):
|
||||
user_remote.search([("id", "=", self.remote.id)])
|
||||
with self.assertRaises(AccessError):
|
||||
self.remote.with_user(self.user).write({"head": "dev"})
|
||||
with self.assertRaises(AccessError):
|
||||
self.remote.with_user(self.user).unlink()
|
||||
|
||||
def test_manager_read_access(self):
|
||||
"""Test manager read access rules"""
|
||||
manager_remote = self.GitRemote.with_user(self.manager)
|
||||
|
||||
# Manager not in project user_ids or manager_ids - should not read
|
||||
self.assertFalse(manager_remote.search([("id", "=", self.remote.id)]))
|
||||
|
||||
# Add manager to project user_ids - should read
|
||||
self.project.write({"user_ids": [(4, self.manager.id)]})
|
||||
remote = manager_remote.search([("id", "=", self.remote.id)])
|
||||
self.assertTrue(remote)
|
||||
self.assertEqual(remote.head, "main")
|
||||
|
||||
# Remove from user_ids, add to manager_ids - should read
|
||||
self.project.write(
|
||||
{"user_ids": [(3, self.manager.id)], "manager_ids": [(4, self.manager.id)]}
|
||||
)
|
||||
remote = manager_remote.search([("id", "=", self.remote.id)])
|
||||
self.assertTrue(remote.exists())
|
||||
|
||||
def test_manager_write_access(self):
|
||||
"""Test manager write/create access rules"""
|
||||
manager_remote = self.GitRemote.with_user(self.manager)
|
||||
|
||||
# Create project as manager - should be added to manager_ids automatically
|
||||
project = self.GitProject.with_user(self.manager).create(
|
||||
{
|
||||
"name": "Manager Project",
|
||||
}
|
||||
)
|
||||
source = self.GitSource.create(
|
||||
{
|
||||
"name": "Manager Source",
|
||||
"git_project_id": project.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create remote in own project - should succeed
|
||||
new_remote = manager_remote.create(
|
||||
{
|
||||
"repo_id": self.repo_test.id,
|
||||
"url_protocol": "https",
|
||||
"source_id": source.id,
|
||||
"head_type": "branch",
|
||||
"head": "main",
|
||||
}
|
||||
)
|
||||
self.assertTrue(new_remote.exists())
|
||||
|
||||
# Write to own remote - should succeed
|
||||
new_remote.write({"head": "dev"})
|
||||
self.assertEqual(new_remote.head, "dev")
|
||||
|
||||
# Write to other's remote - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
self.remote.with_user(self.manager).write({"head": "dev"})
|
||||
|
||||
def test_manager_unlink_access(self):
|
||||
"""Test manager unlink access rules"""
|
||||
# Create project and remote as manager_2
|
||||
project = self.GitProject.with_user(self.manager_2).create(
|
||||
{
|
||||
"name": "Manager 2 Project",
|
||||
}
|
||||
)
|
||||
source = self.GitSource.create(
|
||||
{
|
||||
"name": "Manager 2 Source",
|
||||
"git_project_id": project.id,
|
||||
}
|
||||
)
|
||||
remote = self.GitRemote.with_user(self.manager_2).create(
|
||||
{
|
||||
"repo_id": self.repo_test.id,
|
||||
"url_protocol": "https",
|
||||
"source_id": source.id,
|
||||
"head_type": "branch",
|
||||
"head": "main",
|
||||
}
|
||||
)
|
||||
|
||||
# Try delete as different manager - should fail even if added to manager_ids
|
||||
project.write({"manager_ids": [(4, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
remote.with_user(self.manager).unlink()
|
||||
|
||||
# Create remote as manager and try delete - should succeed
|
||||
own_remote = self.GitRemote.with_user(self.manager).create(
|
||||
{
|
||||
"repo_id": self.repo_test.id,
|
||||
"url_protocol": "https",
|
||||
"source_id": source.id,
|
||||
"head_type": "branch",
|
||||
"head": "main",
|
||||
}
|
||||
)
|
||||
self.assertTrue(own_remote.exists())
|
||||
own_remote.with_user(self.manager).unlink()
|
||||
self.assertFalse(own_remote.exists())
|
||||
|
||||
def test_root_access(self):
|
||||
"""Test root access rules"""
|
||||
root_remote = self.GitRemote.with_user(self.root)
|
||||
|
||||
# Create
|
||||
new_remote = root_remote.create(
|
||||
{
|
||||
"repo_id": self.repo_test.id,
|
||||
"url_protocol": "https",
|
||||
"source_id": self.source.id,
|
||||
"head_type": "branch",
|
||||
"head": "main",
|
||||
}
|
||||
)
|
||||
self.assertTrue(new_remote.exists())
|
||||
|
||||
# Read
|
||||
remote = root_remote.search([("id", "=", self.remote.id)])
|
||||
self.assertTrue(remote)
|
||||
self.assertEqual(remote.head, "main")
|
||||
|
||||
# Write
|
||||
self.remote.with_user(self.root).write({"head": "dev"})
|
||||
self.assertEqual(self.remote.head, "dev")
|
||||
|
||||
# Delete
|
||||
new_remote.with_user(self.root).unlink()
|
||||
self.assertFalse(new_remote.exists())
|
||||
|
||||
def test_remote_provider_protocol_and_name(self):
|
||||
"""Test if remote provider is detected correctly"""
|
||||
|
||||
# -- 1--
|
||||
# GitHub + https
|
||||
# Check if remote provider is detected correctly
|
||||
self.assertEqual(
|
||||
self.remote_github_https.repo_provider,
|
||||
"github",
|
||||
"Provider is not detected correctly",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_github_https.url_protocol,
|
||||
"https",
|
||||
"Protocol is not detected correctly",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_github_https.name,
|
||||
"remote_1",
|
||||
"Name is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 2 --
|
||||
# GitLab + ssh
|
||||
# Check if remote provider is detected correctly
|
||||
self.assertEqual(
|
||||
self.remote_gitlab_ssh.repo_provider,
|
||||
"gitlab",
|
||||
"Provider is not detected correctly",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_gitlab_ssh.url_protocol,
|
||||
"ssh",
|
||||
"Protocol is not detected correctly",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_gitlab_ssh.name,
|
||||
"remote_3",
|
||||
"Name is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 3 --
|
||||
# Bitbucket + https
|
||||
# Check if remote provider is detected correctly
|
||||
self.assertEqual(
|
||||
self.remote_bitbucket_https.repo_provider,
|
||||
"bitbucket",
|
||||
"Provider is not detected correctly",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_bitbucket_https.url_protocol,
|
||||
"https",
|
||||
"Protocol is not detected correctly",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_bitbucket_https.name,
|
||||
"remote_1",
|
||||
"Name is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 4 --
|
||||
# Other + ssh
|
||||
# Check if remote provider is detected correctly
|
||||
self.assertEqual(
|
||||
self.remote_other_ssh.repo_provider,
|
||||
"gitlab", # this is how giturlparse detects the provider
|
||||
"Provider is not detected correctly",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_other_ssh.url_protocol,
|
||||
"ssh",
|
||||
"Protocol is not detected correctly",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_other_ssh.name,
|
||||
"remote_2",
|
||||
"Name is not prepared correctly",
|
||||
)
|
||||
|
||||
def test_git_aggregator_prepare_url(self):
|
||||
"""Test if url is prepared correctly"""
|
||||
|
||||
# -- 1 --
|
||||
# GitHub + https
|
||||
self.remote_github_https.repo_id.is_private = False
|
||||
self.assertEqual(
|
||||
self.remote_github_https._git_aggregator_prepare_url(),
|
||||
self.remote_github_https.repo_id.url,
|
||||
"URL is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 2 --
|
||||
# GitHub + https -> private
|
||||
self.remote_github_https.repo_id.is_private = True
|
||||
self.assertEqual(
|
||||
self.remote_github_https._git_aggregator_prepare_url(),
|
||||
"https://$GITHUB_TOKEN:x-oauth-basic@github.com/cetmix-test/cetmix-tower-test.git",
|
||||
"URL is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 3 --
|
||||
# Gitlab + https
|
||||
self.remote_gitlab_https.repo_id.is_private = False
|
||||
self.assertEqual(
|
||||
self.remote_gitlab_https._git_aggregator_prepare_url(),
|
||||
self.remote_gitlab_https.repo_id.url,
|
||||
"URL is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 4 --
|
||||
# Gitlab + https -> private
|
||||
self.remote_gitlab_https.repo_id.is_private = True
|
||||
self.assertEqual(
|
||||
self.remote_gitlab_https._git_aggregator_prepare_url(),
|
||||
"https://$GITLAB_TOKEN_NAME:$GITLAB_TOKEN@my.gitlab.com/cetmix-test/cetmix-tower-test.git",
|
||||
"URL is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 5 --
|
||||
# Bitbucket + https
|
||||
self.remote_bitbucket_https.repo_id.is_private = False
|
||||
self.assertEqual(
|
||||
self.remote_bitbucket_https._git_aggregator_prepare_url(),
|
||||
self.remote_bitbucket_https.repo_id.url,
|
||||
"URL is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 6 --
|
||||
# Bitbucket + https -> private
|
||||
self.remote_bitbucket_https.repo_id.is_private = True
|
||||
self.assertEqual(
|
||||
self.remote_bitbucket_https._git_aggregator_prepare_url(),
|
||||
"https://x-token-auth:$BITBUCKET_TOKEN@bitbucket.com/cetmix-test/cetmix-tower-test-enterprise.git",
|
||||
"URL is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 7 --
|
||||
# Other + ssh
|
||||
self.remote_other_ssh.repo_id.is_private = False
|
||||
self.assertEqual(
|
||||
self.remote_other_ssh._git_aggregator_prepare_url(),
|
||||
self.remote_other_ssh.repo_id.url_ssh,
|
||||
"URL is not prepared correctly",
|
||||
)
|
||||
|
||||
def test_git_aggregator_prepare_head(self):
|
||||
"""Test if head is prepared correctly"""
|
||||
|
||||
# -- 1 --
|
||||
# GitHub + PR/MR as link
|
||||
self.assertEqual(
|
||||
self.remote_github_https._git_aggregator_prepare_head(),
|
||||
"refs/pull/123/head",
|
||||
"Head is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 2 --
|
||||
# GitHub + PR/MR as number
|
||||
self.remote_github_https.write({"head": "123", "head_type": "pr"})
|
||||
self.assertEqual(
|
||||
self.remote_github_https._git_aggregator_prepare_head(),
|
||||
"refs/pull/123/head",
|
||||
"Head is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 3 --
|
||||
# GitHub + branch as name
|
||||
self.remote_github_https.write({"head": "main", "head_type": "branch"})
|
||||
self.assertEqual(
|
||||
self.remote_github_https._git_aggregator_prepare_head(),
|
||||
self.remote_github_https.head,
|
||||
"Head is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 4 --
|
||||
# GitHub + branch as link
|
||||
self.remote_github_https.write(
|
||||
{
|
||||
"head": "https://github.com/cetmix-test/cetmix-tower/tree/14.0-demo-branch",
|
||||
"head_type": "branch",
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_github_https._git_aggregator_prepare_head(),
|
||||
"14.0-demo-branch",
|
||||
"Head is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 5 --
|
||||
# GitHub + commit as number
|
||||
self.remote_github_https.write({"head": "1234567890", "head_type": "commit"})
|
||||
self.assertEqual(
|
||||
self.remote_github_https._git_aggregator_prepare_head(),
|
||||
"1234567890",
|
||||
"Head is not prepared correctly",
|
||||
)
|
||||
|
||||
# -- 6 --
|
||||
# GitHub + commit as link
|
||||
self.remote_github_https.head = (
|
||||
"https://github.com/cetmix-test/cetmix-tower/commit/1234567890"
|
||||
)
|
||||
self.assertEqual(
|
||||
self.remote_github_https._git_aggregator_prepare_head(),
|
||||
"1234567890",
|
||||
"Head is not prepared correctly",
|
||||
)
|
||||
|
||||
def test_manager_server_based_access(self):
|
||||
"""Test manager access to remotes through server relationships"""
|
||||
manager_remote = self.GitRemote.with_user(self.manager)
|
||||
|
||||
# Create a server where manager is a user
|
||||
server = self.Server.create(
|
||||
{
|
||||
"name": "Test Server",
|
||||
"ip_v4_address": "localhost",
|
||||
"ssh_username": "admin",
|
||||
"ssh_password": "password",
|
||||
"os_id": self.os_debian_10.id,
|
||||
"user_ids": [(4, self.manager.id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Link project to server
|
||||
file = self.File.create(
|
||||
{
|
||||
"name": "test_file",
|
||||
"server_id": server.id,
|
||||
}
|
||||
)
|
||||
self.GitProjectRel.create(
|
||||
{
|
||||
"server_id": server.id,
|
||||
"file_id": file.id,
|
||||
"git_project_id": self.project.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Manager should be able to read remote through server relationship
|
||||
remote = manager_remote.search([("id", "=", self.remote.id)])
|
||||
self.assertTrue(remote)
|
||||
self.assertEqual(remote.head, "main")
|
||||
|
||||
# Remove manager from server users
|
||||
server.write({"user_ids": [(3, self.manager.id)]})
|
||||
|
||||
# Manager should not be able to read remote anymore
|
||||
self.assertFalse(manager_remote.search([("id", "=", self.remote.id)]))
|
||||
|
||||
# Add manager to server managers
|
||||
server.write({"manager_ids": [(4, self.manager.id)]})
|
||||
|
||||
# Manager should be able to read remote again
|
||||
remote = manager_remote.search([("id", "=", self.remote.id)])
|
||||
self.assertTrue(remote)
|
||||
self.assertEqual(remote.head, "main")
|
||||
@@ -1,84 +0,0 @@
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
from .common import CommonTest
|
||||
|
||||
|
||||
class TestRepo(CommonTest):
|
||||
"""Test class for git repository."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
def test_repo_create_from_url_https_success(self):
|
||||
"""Test if repository is created correctly"""
|
||||
# -- 1 --
|
||||
# Valid HTTPS URL
|
||||
repo = self.Repo.create(
|
||||
{
|
||||
"url": "https://github.com/memes-demo/doge-memes.git",
|
||||
}
|
||||
)
|
||||
repo.invalidate_recordset()
|
||||
|
||||
self.assertEqual(repo.name, "github.com/memes-demo/doge-memes")
|
||||
self.assertEqual(repo.host, "github.com")
|
||||
self.assertEqual(repo.owner_id.name, "memes-demo")
|
||||
self.assertEqual(repo.provider, "github")
|
||||
self.assertEqual(repo.is_private, False)
|
||||
self.assertEqual(repo.url_ssh, "git@github.com:memes-demo/doge-memes.git")
|
||||
self.assertEqual(repo.url_git, "git://github.com/memes-demo/doge-memes.git")
|
||||
|
||||
def test_repo_create_from_url_ssh_success(self):
|
||||
"""Test if repository is created correctly"""
|
||||
# -- 1 --
|
||||
# Valid SSH URL
|
||||
repo = self.Repo.create(
|
||||
{
|
||||
"url": "git@gitlab.com:chad-guy/chad-guy.git",
|
||||
}
|
||||
)
|
||||
repo.invalidate_recordset()
|
||||
|
||||
self.assertEqual(repo.name, "gitlab.com/chad-guy/chad-guy")
|
||||
self.assertEqual(repo.host, "gitlab.com")
|
||||
self.assertEqual(repo.owner_id.name, "chad-guy")
|
||||
self.assertEqual(repo.provider, "gitlab")
|
||||
self.assertEqual(repo.is_private, False)
|
||||
self.assertEqual(repo.url, "https://gitlab.com/chad-guy/chad-guy.git")
|
||||
self.assertEqual(repo.url_git, "git://gitlab.com/chad-guy/chad-guy.git")
|
||||
|
||||
def test_repo_create_from_url_git_success(self):
|
||||
"""Test if repository is created correctly"""
|
||||
# -- 1 --
|
||||
# Valid GIT URL
|
||||
repo = self.Repo.create(
|
||||
{
|
||||
"url": "git://bitbucket.com/much-pepe/pepe-memes.git",
|
||||
}
|
||||
)
|
||||
self.assertEqual(repo.name, "bitbucket.com/much-pepe/pepe-memes")
|
||||
self.assertEqual(repo.host, "bitbucket.com")
|
||||
self.assertEqual(repo.owner_id.name, "much-pepe")
|
||||
self.assertEqual(repo.provider, "bitbucket")
|
||||
self.assertEqual(repo.is_private, False)
|
||||
self.assertEqual(repo.url_ssh, "git@bitbucket.com:much-pepe/pepe-memes.git")
|
||||
self.assertEqual(repo.url, "https://bitbucket.com/much-pepe/pepe-memes.git")
|
||||
|
||||
def test_repo_create_from_url_fails(self):
|
||||
"""Test if repository creation fails with invalid URLs"""
|
||||
|
||||
# Invalid URL 1
|
||||
with self.assertRaises(ValidationError):
|
||||
self.Repo.create(
|
||||
{
|
||||
"url": "something.com",
|
||||
}
|
||||
)
|
||||
# Invalid URL 2
|
||||
with self.assertRaises(ValidationError):
|
||||
self.Repo.create(
|
||||
{
|
||||
"url": "random string",
|
||||
}
|
||||
)
|
||||
@@ -1,415 +0,0 @@
|
||||
try:
|
||||
from odoo.addons.queue_job.tests.common import trap_jobs
|
||||
except ImportError:
|
||||
trap_jobs = None
|
||||
|
||||
from .common import CommonTest
|
||||
|
||||
|
||||
class TestServer(CommonTest):
|
||||
"""Test setting git project to server from plan line."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
cls.GitProjectRel.create(
|
||||
{
|
||||
"git_project_id": cls.git_project_1.id,
|
||||
"server_id": cls.server_test_1.id,
|
||||
"file_id": cls.server_1_file_1.id,
|
||||
}
|
||||
)
|
||||
|
||||
def test_server_creation_running_flight_plan(self):
|
||||
"""Test that server is created with git project from plan line."""
|
||||
git_project = self.GitProject.create(
|
||||
{
|
||||
"name": "Test Git Project",
|
||||
"manager_ids": [(4, self.manager.id)],
|
||||
}
|
||||
)
|
||||
|
||||
file_template = self.FileTemplate.create(
|
||||
{
|
||||
"name": "Git Config Template",
|
||||
"file_name": "repos.yaml",
|
||||
"server_dir": "/var/test",
|
||||
"code": "repositories:\n test_repo:\n "
|
||||
"url: https://github.com/test/repo.git\n target: main",
|
||||
}
|
||||
)
|
||||
|
||||
command = self.Command.create(
|
||||
{
|
||||
"name": "Create Git Config File",
|
||||
"action": "file_using_template",
|
||||
"file_template_id": file_template.id,
|
||||
}
|
||||
)
|
||||
|
||||
flight_plan = self.Plan.create(
|
||||
{
|
||||
"name": "Git Project Setup Plan",
|
||||
"note": "Sets up a git project on the server",
|
||||
}
|
||||
)
|
||||
|
||||
self.plan_line.create(
|
||||
{
|
||||
"plan_id": flight_plan.id,
|
||||
"command_id": command.id,
|
||||
"sequence": 10,
|
||||
"git_project_id": git_project.id,
|
||||
}
|
||||
)
|
||||
|
||||
server_template = self.ServerTemplate.create(
|
||||
{
|
||||
"name": "Git Server Template",
|
||||
"ssh_port": 22,
|
||||
"ssh_username": "admin",
|
||||
"ssh_password": "password",
|
||||
"ssh_auth_mode": "p",
|
||||
"os_id": self.os_debian_10.id,
|
||||
"flight_plan_id": flight_plan.id,
|
||||
"manager_ids": [(4, self.manager.id)],
|
||||
}
|
||||
)
|
||||
|
||||
action = server_template.action_create_server()
|
||||
|
||||
# Open the wizard and fill in the data
|
||||
wizard = (
|
||||
self.env["cx.tower.server.template.create.wizard"]
|
||||
.with_context(**action["context"])
|
||||
.create(
|
||||
{
|
||||
"name": "Git Server",
|
||||
"ip_v4_address": "192.168.1.10",
|
||||
"server_template_id": server_template.id,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
# If cetmix_tower_server_queue module is installed, test async processing
|
||||
if self.env["ir.module.module"].search_count(
|
||||
[("name", "=", "cetmix_tower_server_queue"), ("state", "=", "installed")]
|
||||
):
|
||||
with trap_jobs() as trap:
|
||||
wizard.action_confirm()
|
||||
|
||||
# Verify that jobs were created
|
||||
self.assertGreater(
|
||||
len(trap.enqueued_jobs), 0, "Jobs should have been enqueued"
|
||||
)
|
||||
|
||||
# Execute all trapped jobs to simulate async processing
|
||||
trap.perform_enqueued_jobs()
|
||||
else:
|
||||
wizard.action_confirm()
|
||||
|
||||
# Now search for the created records after jobs have been executed
|
||||
server = self.Server.search(
|
||||
[
|
||||
("name", "=", "Git Server"),
|
||||
("server_template_id", "=", server_template.id),
|
||||
]
|
||||
)
|
||||
self.assertEqual(len(server), 1, "Exactly one server should have been created")
|
||||
|
||||
# Verify the file was created
|
||||
file = self.File.search(
|
||||
[("server_id", "=", server.id), ("name", "=", "repos.yaml")]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
len(file), 1, "Exactly one git config file should have been created"
|
||||
)
|
||||
|
||||
# Verify the git project relation exists
|
||||
git_project_rel = self.GitProjectRel.search(
|
||||
[
|
||||
("server_id", "=", server.id),
|
||||
("git_project_id", "=", git_project.id),
|
||||
("file_id", "=", file.id),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
len(git_project_rel), 1, "Exactly one git project relation should exist"
|
||||
)
|
||||
self.assertEqual(
|
||||
git_project_rel.file_id,
|
||||
file,
|
||||
"The related file should be the git config file",
|
||||
)
|
||||
self.assertEqual(
|
||||
git_project_rel.git_project_id,
|
||||
git_project,
|
||||
"The related git project should match the one in the flight plan",
|
||||
)
|
||||
self.assertEqual(
|
||||
git_project_rel.project_format,
|
||||
git_project._default_project_format(),
|
||||
"Project format should match the default format",
|
||||
)
|
||||
|
||||
def test_file_creation_with_git_project_from_custom_values(self):
|
||||
"""Test that git project relation is created when git project
|
||||
is provided from custom values in variable_values.
|
||||
"""
|
||||
git_project = self.GitProject.create(
|
||||
{
|
||||
"name": "Test Git Project From Custom Values",
|
||||
"manager_ids": [(4, self.manager.id)],
|
||||
}
|
||||
)
|
||||
|
||||
file_template = self.FileTemplate.create(
|
||||
{
|
||||
"name": "Git Config Template Custom Values",
|
||||
"file_name": "repos_custom.yaml",
|
||||
"server_dir": "/var/test",
|
||||
"code": "repositories:\n test_repo:\n "
|
||||
"url: https://github.com/test/repo.git\n target: main",
|
||||
}
|
||||
)
|
||||
|
||||
command = self.Command.create(
|
||||
{
|
||||
"name": "Create Git Config File Custom Values",
|
||||
"action": "file_using_template",
|
||||
"file_template_id": file_template.id,
|
||||
}
|
||||
)
|
||||
|
||||
flight_plan = self.Plan.create(
|
||||
{
|
||||
"name": "Git Project Setup Plan Custom Values",
|
||||
"note": "Sets up a git project on the server from custom values",
|
||||
}
|
||||
)
|
||||
|
||||
# Create plan line WITHOUT git_project_id set
|
||||
# The git project should come from custom values instead
|
||||
plan_line = self.plan_line.create(
|
||||
{
|
||||
"plan_id": flight_plan.id,
|
||||
"command_id": command.id,
|
||||
"sequence": 10,
|
||||
}
|
||||
)
|
||||
|
||||
# Create plan log
|
||||
plan_log = self.env["cx.tower.plan.log"].create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"plan_id": flight_plan.id,
|
||||
"plan_line_executed_id": plan_line.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create command log with variable_values containing __git_project__
|
||||
command_log = self.CommandLog.create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"command_id": command.id,
|
||||
"plan_log_id": plan_log.id,
|
||||
"variable_values": {"__git_project__": git_project.reference},
|
||||
}
|
||||
)
|
||||
|
||||
# Call the method directly to test the custom values path
|
||||
file = self.server_test_1._command_runner_file_using_template_create_file(
|
||||
log_record=command_log, server_dir="/var/test"
|
||||
)
|
||||
|
||||
# Verify the file was created
|
||||
self.assertTrue(file, "File should have been created")
|
||||
|
||||
# Verify the git project relation exists
|
||||
git_project_rel = self.GitProjectRel.search(
|
||||
[
|
||||
("server_id", "=", self.server_test_1.id),
|
||||
("git_project_id", "=", git_project.id),
|
||||
("file_id", "=", file.id),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
len(git_project_rel), 1, "Exactly one git project relation should exist"
|
||||
)
|
||||
self.assertEqual(
|
||||
git_project_rel.file_id,
|
||||
file,
|
||||
"The related file should be the git config file",
|
||||
)
|
||||
self.assertEqual(
|
||||
git_project_rel.git_project_id,
|
||||
git_project,
|
||||
"The related git project should match the one from custom values",
|
||||
)
|
||||
self.assertEqual(
|
||||
git_project_rel.project_format,
|
||||
git_project._default_project_format(),
|
||||
"Project format should match the default format",
|
||||
)
|
||||
|
||||
def test_file_creation_with_git_project_from_custom_values_priority(self):
|
||||
"""Test that git project from custom values takes priority
|
||||
over git project from plan line.
|
||||
"""
|
||||
git_project_custom = self.GitProject.create(
|
||||
{
|
||||
"name": "Test Git Project From Custom Values Priority",
|
||||
"manager_ids": [(4, self.manager.id)],
|
||||
}
|
||||
)
|
||||
|
||||
git_project_plan_line = self.GitProject.create(
|
||||
{
|
||||
"name": "Test Git Project From Plan Line",
|
||||
"manager_ids": [(4, self.manager.id)],
|
||||
}
|
||||
)
|
||||
|
||||
file_template = self.FileTemplate.create(
|
||||
{
|
||||
"name": "Git Config Template Priority",
|
||||
"file_name": "repos_priority.yaml",
|
||||
"server_dir": "/var/test",
|
||||
"code": "repositories:\n test_repo:\n "
|
||||
"url: https://github.com/test/repo.git\n target: main",
|
||||
}
|
||||
)
|
||||
|
||||
command = self.Command.create(
|
||||
{
|
||||
"name": "Create Git Config File Priority",
|
||||
"action": "file_using_template",
|
||||
"file_template_id": file_template.id,
|
||||
}
|
||||
)
|
||||
|
||||
flight_plan = self.Plan.create(
|
||||
{
|
||||
"name": "Git Project Setup Plan Priority",
|
||||
"note": "Tests priority of custom values over plan line",
|
||||
}
|
||||
)
|
||||
|
||||
# Create plan line WITH git_project_id set
|
||||
# But custom values should take priority
|
||||
plan_line = self.plan_line.create(
|
||||
{
|
||||
"plan_id": flight_plan.id,
|
||||
"command_id": command.id,
|
||||
"sequence": 10,
|
||||
"git_project_id": git_project_plan_line.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create plan log
|
||||
plan_log = self.env["cx.tower.plan.log"].create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"plan_id": flight_plan.id,
|
||||
"plan_line_executed_id": plan_line.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create command log with variable_values containing __git_project__
|
||||
# This should take priority over plan_line.git_project_id
|
||||
command_log = self.CommandLog.create(
|
||||
{
|
||||
"server_id": self.server_test_1.id,
|
||||
"command_id": command.id,
|
||||
"plan_log_id": plan_log.id,
|
||||
"variable_values": {"__git_project__": git_project_custom.reference},
|
||||
}
|
||||
)
|
||||
|
||||
# Call the method directly to test the custom values path
|
||||
file = self.server_test_1._command_runner_file_using_template_create_file(
|
||||
log_record=command_log, server_dir="/var/test"
|
||||
)
|
||||
|
||||
# Verify the file was created
|
||||
self.assertTrue(file, "File should have been created")
|
||||
|
||||
# Verify the git project relation uses the git project from custom values
|
||||
# (not the one from plan line)
|
||||
git_project_rel = self.GitProjectRel.search(
|
||||
[
|
||||
("server_id", "=", self.server_test_1.id),
|
||||
("git_project_id", "=", git_project_custom.id),
|
||||
("file_id", "=", file.id),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
len(git_project_rel), 1, "Exactly one git project relation should exist"
|
||||
)
|
||||
self.assertEqual(
|
||||
git_project_rel.git_project_id,
|
||||
git_project_custom,
|
||||
"The related git project should match the one from custom values, "
|
||||
"not from plan line",
|
||||
)
|
||||
|
||||
# Verify that the plan line git project was NOT used
|
||||
git_project_rel_plan_line = self.GitProjectRel.search(
|
||||
[
|
||||
("server_id", "=", self.server_test_1.id),
|
||||
("git_project_id", "=", git_project_plan_line.id),
|
||||
("file_id", "=", file.id),
|
||||
]
|
||||
)
|
||||
self.assertEqual(
|
||||
len(git_project_rel_plan_line),
|
||||
0,
|
||||
"No relation should exist for the plan line git project",
|
||||
)
|
||||
|
||||
def test_server_get_servers_by_git_ref_success(self):
|
||||
"""Check the success case of server.get_servers_by_git_ref"""
|
||||
|
||||
# 1. URL only
|
||||
servers = self.Server.get_servers_by_git_ref(
|
||||
self.remote_github_https.repo_id.url
|
||||
)
|
||||
self.assertEqual(servers, self.server_test_1)
|
||||
|
||||
# 2. Specific URL with specific head
|
||||
servers = self.Server.get_servers_by_git_ref(
|
||||
self.remote_github_https.repo_id.url, "123"
|
||||
)
|
||||
self.assertEqual(servers, self.server_test_1)
|
||||
|
||||
# 2. Specific URL with specific head and head type
|
||||
servers = self.Server.get_servers_by_git_ref(
|
||||
self.remote_github_https.repo_id.url, "123", "pr"
|
||||
)
|
||||
self.assertEqual(servers, self.server_test_1)
|
||||
|
||||
def test_server_get_servers_by_git_ref_no_match(self):
|
||||
"""Check the no match case of server.get_servers_by_git_ref"""
|
||||
|
||||
# 1. Repo link does not exist
|
||||
servers = self.Server.get_servers_by_git_ref(
|
||||
"https://github.com/other-org/other-repo.git", "main", "branch"
|
||||
)
|
||||
self.assertFalse(servers)
|
||||
|
||||
# 2. Repo link exists, but remote does not exist
|
||||
servers = self.Server.get_servers_by_git_ref(
|
||||
self.repo_cetmix_tower.url, "3311", "pr"
|
||||
)
|
||||
self.assertFalse(servers)
|
||||
|
||||
# 3. Repo link exists, but remote type does not exist
|
||||
servers = self.Server.get_servers_by_git_ref(
|
||||
self.repo_cetmix_tower.url, "main", "commit"
|
||||
)
|
||||
self.assertFalse(servers)
|
||||
@@ -1,226 +0,0 @@
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
from .common import CommonTest
|
||||
|
||||
|
||||
class TestSource(CommonTest):
|
||||
"""Test class for git source."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
# Create another manager for testing
|
||||
cls.manager_2 = cls.Users.create(
|
||||
{
|
||||
"name": "Second Manager",
|
||||
"login": "manager2",
|
||||
"email": "manager2@test.com",
|
||||
"groups_id": [(4, cls.env.ref("cetmix_tower_server.group_manager").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create test project and source as root
|
||||
cls.project = cls.GitProject.create(
|
||||
{
|
||||
"name": "Test Project",
|
||||
}
|
||||
)
|
||||
cls.source = cls.GitSource.create(
|
||||
{
|
||||
"name": "Test Source",
|
||||
"git_project_id": cls.project.id,
|
||||
}
|
||||
)
|
||||
|
||||
def test_user_access(self):
|
||||
"""Test that regular users have no access to git sources"""
|
||||
user_source = self.GitSource.with_user(self.user)
|
||||
|
||||
# Test CRUD operations
|
||||
with self.assertRaises(AccessError):
|
||||
user_source.create(
|
||||
{
|
||||
"name": "New Source",
|
||||
"git_project_id": self.project.id,
|
||||
}
|
||||
)
|
||||
with self.assertRaises(AccessError):
|
||||
user_source.browse(self.source.id).read(["name"])
|
||||
with self.assertRaises(AccessError):
|
||||
user_source.browse(self.source.id).write({"name": "Updated Name"})
|
||||
with self.assertRaises(AccessError):
|
||||
user_source.browse(self.source.id).unlink()
|
||||
|
||||
def test_manager_read_access(self):
|
||||
"""Test manager read access rules"""
|
||||
manager_source = self.GitSource.with_user(self.manager)
|
||||
|
||||
# Manager not in project user_ids or manager_ids - should not read
|
||||
with self.assertRaises(AccessError):
|
||||
manager_source.browse(self.source.id).read(["name"])
|
||||
|
||||
# Add manager to project user_ids - should read
|
||||
self.project.write({"user_ids": [(4, self.manager.id)]})
|
||||
self.assertEqual(manager_source.browse(self.source.id).name, "Test Source")
|
||||
|
||||
# Remove from user_ids, add to manager_ids - should read
|
||||
self.project.write(
|
||||
{"user_ids": [(3, self.manager.id)], "manager_ids": [(4, self.manager.id)]}
|
||||
)
|
||||
self.assertEqual(manager_source.browse(self.source.id).name, "Test Source")
|
||||
|
||||
def test_manager_write_access(self):
|
||||
"""Test manager write/create access rules"""
|
||||
manager_source = self.GitSource.with_user(self.manager)
|
||||
|
||||
# Create project as manager - should be added to manager_ids automatically
|
||||
project = self.GitProject.with_user(self.manager).create(
|
||||
{
|
||||
"name": "Manager Project",
|
||||
}
|
||||
)
|
||||
self.assertIn(self.manager, project.manager_ids)
|
||||
|
||||
# Create source in own project - should succeed
|
||||
new_source = manager_source.create(
|
||||
{
|
||||
"name": "New Source",
|
||||
"git_project_id": project.id,
|
||||
}
|
||||
)
|
||||
self.assertTrue(new_source.exists())
|
||||
|
||||
# Write to own source - should succeed
|
||||
new_source.write({"name": "Updated Name"})
|
||||
self.assertEqual(new_source.name, "Updated Name")
|
||||
|
||||
# Write to other's source - should fail
|
||||
with self.assertRaises(AccessError):
|
||||
manager_source.browse(self.source.id).write({"name": "Updated Name"})
|
||||
|
||||
def test_manager_unlink_access(self):
|
||||
"""Test manager unlink access rules"""
|
||||
# Create project and source as manager_2
|
||||
project = self.GitProject.with_user(self.manager_2).create(
|
||||
{
|
||||
"name": "Manager 2 Project",
|
||||
}
|
||||
)
|
||||
source = self.GitSource.with_user(self.manager_2).create(
|
||||
{
|
||||
"name": "Source to Delete",
|
||||
"git_project_id": project.id,
|
||||
}
|
||||
)
|
||||
manager_source = self.GitSource.with_user(self.manager)
|
||||
|
||||
# Try delete as different manager - should fail even if added to manager_ids
|
||||
project.write({"manager_ids": [(4, self.manager.id)]})
|
||||
with self.assertRaises(AccessError):
|
||||
manager_source.browse(source.id).unlink()
|
||||
|
||||
# Create source as manager and try delete - should succeed
|
||||
own_source = manager_source.create(
|
||||
{
|
||||
"name": "Own Source",
|
||||
"git_project_id": project.id,
|
||||
}
|
||||
)
|
||||
self.assertTrue(own_source.exists())
|
||||
own_source.unlink()
|
||||
self.assertFalse(own_source.exists())
|
||||
|
||||
def test_root_access(self):
|
||||
"""Test root access rules"""
|
||||
root_source = self.GitSource.with_user(self.root)
|
||||
|
||||
# Create
|
||||
new_source = root_source.create(
|
||||
{
|
||||
"name": "Root Source",
|
||||
"git_project_id": self.project.id,
|
||||
}
|
||||
)
|
||||
self.assertTrue(new_source.exists())
|
||||
|
||||
# Read
|
||||
self.assertEqual(root_source.browse(self.source.id).name, "Test Source")
|
||||
|
||||
# Write
|
||||
root_source.browse(self.source.id).write({"name": "Updated by Root"})
|
||||
self.assertEqual(self.source.name, "Updated by Root")
|
||||
|
||||
# Delete
|
||||
new_source.unlink()
|
||||
self.assertFalse(new_source.exists())
|
||||
|
||||
def test_source_git_aggregator_prepare_record(self):
|
||||
"""Test if source prepare record method works correctly."""
|
||||
|
||||
# -- 1 --
|
||||
# Source 1
|
||||
expected_result = {
|
||||
"remotes": {
|
||||
"remote_1": "https://github.com/cetmix-test/cetmix-tower-test.git",
|
||||
"remote_2": "https://$GITLAB_TOKEN_NAME:$GITLAB_TOKEN@my.gitlab.com/cetmix-test/cetmix-tower-test.git",
|
||||
"remote_3": "git@my.gitlab.com:cetmix-test/cetmix-tower-test.git",
|
||||
},
|
||||
"merges": [
|
||||
{"remote": "remote_1", "ref": "refs/pull/123/head"},
|
||||
{"remote": "remote_2", "ref": "main"},
|
||||
{"remote": "remote_3", "ref": "10000000"},
|
||||
],
|
||||
"target": "remote_1",
|
||||
}
|
||||
prepared_result = self.git_source_1._git_aggregator_prepare_record()
|
||||
self.assertEqual(
|
||||
prepared_result, expected_result, "Prepared result is not correct"
|
||||
)
|
||||
|
||||
def test_manager_server_based_access(self):
|
||||
"""Test manager access to sources through server relationships"""
|
||||
manager_source = self.GitSource.with_user(self.manager)
|
||||
|
||||
# Create a server where manager is a user
|
||||
server = self.Server.create(
|
||||
{
|
||||
"name": "Test Server",
|
||||
"ip_v4_address": "localhost",
|
||||
"ssh_username": "admin",
|
||||
"ssh_password": "password",
|
||||
"os_id": self.os_debian_10.id,
|
||||
"user_ids": [(4, self.manager.id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Link project to server
|
||||
file = self.File.create(
|
||||
{
|
||||
"name": "test_file",
|
||||
"server_id": server.id,
|
||||
}
|
||||
)
|
||||
self.GitProjectRel.create(
|
||||
{
|
||||
"server_id": server.id,
|
||||
"file_id": file.id,
|
||||
"git_project_id": self.project.id,
|
||||
"project_format": "git_aggregator",
|
||||
}
|
||||
)
|
||||
|
||||
# Manager should be able to read source through server relationship
|
||||
self.assertEqual(manager_source.browse(self.source.id).name, "Test Source")
|
||||
|
||||
# Remove manager from server users
|
||||
server.write({"user_ids": [(3, self.manager.id)]})
|
||||
|
||||
# Manager should not be able to read source anymore
|
||||
with self.assertRaises(AccessError):
|
||||
manager_source.browse(self.source.id).read(["name"])
|
||||
|
||||
# Add manager to server managers
|
||||
server.write({"manager_ids": [(4, self.manager.id)]})
|
||||
|
||||
# Manager should be able to read source again
|
||||
self.assertEqual(manager_source.browse(self.source.id).name, "Test Source")
|
||||
Reference in New Issue
Block a user