Wipe addons/: full reset for clean re-upload

This commit is contained in:
Tower Deploy
2026-04-27 11:20:53 +03:00
parent 2cf3b5185d
commit 9bb80002c8
363 changed files with 0 additions and 112641 deletions

View File

@@ -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

View File

@@ -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",
}
)

View File

@@ -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())

View File

@@ -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())

View File

@@ -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")

View File

@@ -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")

View File

@@ -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",
}
)

View File

@@ -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)

View File

@@ -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")