mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-18 13:41:21 +01:00
add api test case for garbage collection (#6366)
Add API test case for garbage collection, and add swagger.yaml, GC and chart feature were updated in swagger.yaml. Signed-off-by: danfengliu <danfengl@vmware.com>
This commit is contained in:
parent
b406d7ccc0
commit
c4bf65162c
@ -2575,7 +2575,9 @@ paths:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Get job log successfully.
|
||||
description: Get successfully.
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: Illegal format of provided ID value.
|
||||
'401':
|
||||
@ -2776,7 +2778,11 @@ paths:
|
||||
description: The project name
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/definitions/ChartInfoList'
|
||||
description: Searched for charts of project in Harbor successfully.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ChartInfoEntry'
|
||||
'401':
|
||||
$ref: '#/definitions/UnauthorizedChartAPIError'
|
||||
'403':
|
||||
@ -4279,9 +4285,15 @@ definitions:
|
||||
total_versions:
|
||||
type: integer
|
||||
description: Total count of chart versions
|
||||
latest_version:
|
||||
type: string
|
||||
description: latest version of chart
|
||||
created:
|
||||
type: string
|
||||
description: The created time of chart
|
||||
updated:
|
||||
type: string
|
||||
description: The created time of chart
|
||||
icon:
|
||||
type: string
|
||||
description: The icon path of chart
|
||||
@ -4430,19 +4442,35 @@ definitions:
|
||||
GCResult:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
id:
|
||||
type: integer
|
||||
description: the id of gc job.
|
||||
job_name:
|
||||
type: string
|
||||
description: the job name of gc job.
|
||||
job_kind:
|
||||
type: string
|
||||
description: the job kind of gc job.
|
||||
schedule:
|
||||
$ref: '#/definitions/GCScheduleSchedule'
|
||||
job_status:
|
||||
type: string
|
||||
description: the status of gc job.
|
||||
deleted:
|
||||
type: boolean
|
||||
description: the result of gc job.
|
||||
msg:
|
||||
description: if gc job was deleted.
|
||||
creation_time:
|
||||
type: string
|
||||
description: the details of gc job.
|
||||
starttime:
|
||||
description: the creation time of gc job.
|
||||
update_time:
|
||||
type: string
|
||||
description: the start time of gc job.
|
||||
endtime:
|
||||
type: string
|
||||
description: the end time of gc job.
|
||||
description: the update time of gc job.
|
||||
GCSchedule:
|
||||
type: object
|
||||
properties:
|
||||
schedule:
|
||||
$ref: '#/definitions/GCScheduleSchedule'
|
||||
GCScheduleSchedule:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
|
@ -25,7 +25,7 @@ def push_image_to_project(project_name, registry, username, password, image, tag
|
||||
_docker_api.docker_image_pull(image, tag = tag)
|
||||
time.sleep(2)
|
||||
|
||||
new_harbor_registry, new_tag = _docker_api.docker_image_tag(image, r'{}/{}/{}'.format(registry, project_name, image))
|
||||
new_harbor_registry, new_tag = _docker_api.docker_image_tag(r'{}:{}'.format(image, tag), r'{}/{}/{}'.format(registry, project_name, image))
|
||||
time.sleep(2)
|
||||
|
||||
_docker_api.docker_image_push(new_harbor_registry, new_tag)
|
||||
|
149
tests/apitests/python/library/system.py
Normal file
149
tests/apitests/python/library/system.py
Normal file
@ -0,0 +1,149 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import time
|
||||
import re
|
||||
import base
|
||||
import swagger_client
|
||||
from swagger_client.rest import ApiException
|
||||
|
||||
class System(base.Base):
|
||||
def get_gc_history(self, expect_status_code = 200, expect_response_body = None, **kwargs):
|
||||
client = self._get_client(**kwargs)
|
||||
|
||||
try:
|
||||
data, status_code, _ = client.system_gc_get_with_http_info()
|
||||
except ApiException as e:
|
||||
if e.status == expect_status_code:
|
||||
if expect_response_body is not None and e.body.strip() != expect_response_body.strip():
|
||||
raise Exception(r"Get configuration response body is not as expected {} actual status is {}.".format(expect_response_body.strip(), e.body.strip()))
|
||||
else:
|
||||
return e.reason, e.body
|
||||
else:
|
||||
raise Exception(r"Get configuration result is not as expected {} actual status is {}.".format(expect_status_code, e.status))
|
||||
base._assert_status_code(expect_status_code, status_code)
|
||||
return data
|
||||
|
||||
def get_gc_status_by_id(self, job_id, expect_status_code = 200, expect_response_body = None, **kwargs):
|
||||
client = self._get_client(**kwargs)
|
||||
|
||||
try:
|
||||
data, status_code, _ = client.system_gc_id_get_with_http_info(job_id)
|
||||
except ApiException as e:
|
||||
if e.status == expect_status_code:
|
||||
if expect_response_body is not None and e.body.strip() != expect_response_body.strip():
|
||||
raise Exception(r"Get configuration response body is not as expected {} actual status is {}.".format(expect_response_body.strip(), e.body.strip()))
|
||||
else:
|
||||
return e.reason, e.body
|
||||
else:
|
||||
raise Exception(r"Get configuration result is not as expected {} actual status is {}.".format(expect_status_code, e.status))
|
||||
base._assert_status_code(expect_status_code, status_code)
|
||||
return data
|
||||
|
||||
def get_gc_log_by_id(self, job_id, expect_status_code = 200, expect_response_body = None, **kwargs):
|
||||
client = self._get_client(**kwargs)
|
||||
|
||||
try:
|
||||
data, status_code, _ = client.system_gc_id_log_get_with_http_info(job_id)
|
||||
except ApiException as e:
|
||||
if e.status == expect_status_code:
|
||||
if expect_response_body is not None and e.body.strip() != expect_response_body.strip():
|
||||
raise Exception(r"Get configuration response body is not as expected {} actual status is {}.".format(expect_response_body.strip(), e.body.strip()))
|
||||
else:
|
||||
return e.reason, e.body
|
||||
else:
|
||||
raise Exception(r"Get configuration result is not as expected {} actual status is {}.".format(expect_status_code, e.status))
|
||||
base._assert_status_code(expect_status_code, status_code)
|
||||
return data
|
||||
|
||||
def get_gc_schedule(self, expect_status_code = 200, expect_response_body = None, **kwargs):
|
||||
client = self._get_client(**kwargs)
|
||||
|
||||
try:
|
||||
data, status_code, _ = client.system_gc_schedule_get_with_http_info()
|
||||
except ApiException as e:
|
||||
if e.status == expect_status_code:
|
||||
if expect_response_body is not None and e.body.strip() != expect_response_body.strip():
|
||||
raise Exception(r"Get configuration response body is not as expected {} actual status is {}.".format(expect_response_body.strip(), e.body.strip()))
|
||||
else:
|
||||
return e.reason, e.body
|
||||
else:
|
||||
raise Exception(r"Get configuration result is not as expected {} actual status is {}.".format(expect_status_code, e.status))
|
||||
base._assert_status_code(expect_status_code, status_code)
|
||||
return data
|
||||
|
||||
def set_gc_schedule(self, schedule_type = 'None', offtime = None, weekday = None, expect_status_code = 200, expect_response_body = None, **kwargs):
|
||||
client = self._get_client(**kwargs)
|
||||
gc_schedule = swagger_client.GCSchedule()
|
||||
gc_schedule.type = schedule_type
|
||||
if offtime is not None:
|
||||
gc_schedule.offtime = offtime
|
||||
if weekday is not None:
|
||||
gc_schedule.weekday = weekday
|
||||
try:
|
||||
data, status_code, _ = client.system_gc_schedule_put_with_http_info(gc_schedule)
|
||||
except ApiException as e:
|
||||
if e.status == expect_status_code:
|
||||
if expect_response_body is not None and e.body.strip() != expect_response_body.strip():
|
||||
raise Exception(r"Get configuration response body is not as expected {} actual status is {}.".format(expect_response_body.strip(), e.body.strip()))
|
||||
else:
|
||||
return e.reason, e.body
|
||||
else:
|
||||
raise Exception(r"Get configuration result is not as expected {} actual status is {}.".format(expect_status_code, e.status))
|
||||
base._assert_status_code(expect_status_code, status_code)
|
||||
return data
|
||||
|
||||
def create_gc_schedule(self, schedule_type, offtime = None, weekday = None, expect_status_code = 201, expect_response_body = None, **kwargs):
|
||||
client = self._get_client(**kwargs)
|
||||
gcscheduleschedule = swagger_client.GCScheduleSchedule()
|
||||
gcscheduleschedule.type = schedule_type
|
||||
if offtime is not None:
|
||||
gcscheduleschedule.offtime = offtime
|
||||
if weekday is not None:
|
||||
gcscheduleschedule.weekday = weekday
|
||||
|
||||
gc_schedule = swagger_client.GCSchedule(gcscheduleschedule)
|
||||
try:
|
||||
_, status_code, header = client.system_gc_schedule_post_with_http_info(gc_schedule)
|
||||
except ApiException as e:
|
||||
if e.status == expect_status_code:
|
||||
if expect_response_body is not None and e.body.strip() != expect_response_body.strip():
|
||||
raise Exception(r"Create GC schedule response body is not as expected {} actual status is {}.".format(expect_response_body.strip(), e.body.strip()))
|
||||
else:
|
||||
return e.reason, e.body
|
||||
else:
|
||||
raise Exception(r"Create GC schedule result is not as expected {} actual status is {}.".format(expect_status_code, e.status))
|
||||
base._assert_status_code(expect_status_code, status_code)
|
||||
return base._get_id_from_header(header)
|
||||
|
||||
def gc_now(self, **kwargs):
|
||||
gc_id = self.create_gc_schedule('Manual', **kwargs)
|
||||
return gc_id
|
||||
|
||||
def validate_gc_job_status(self, gc_id, expected_gc_status, **kwargs):
|
||||
get_gc_status_finish = False
|
||||
timeout_count = 20
|
||||
while not (get_gc_status_finish):
|
||||
time.sleep(5)
|
||||
status = self.get_gc_status_by_id(gc_id, **kwargs)
|
||||
if len(status) is not 1:
|
||||
raise Exception(r"Get GC status count expected 1 actual count is {}.".format(len(status)))
|
||||
if status[0].job_status == expected_gc_status:
|
||||
get_gc_status_finish = True
|
||||
timeout_count = timeout_count - 1
|
||||
|
||||
if not (get_gc_status_finish):
|
||||
raise Exception("Scan image result is not as expected {} actual scan status is {}".format(expected_scan_status, actual_scan_status))
|
||||
|
||||
def validate_deletion_success(self, gc_id, **kwargs):
|
||||
log_content = self.get_gc_log_by_id(gc_id, **kwargs)
|
||||
key_message = "blobs eligible for deletion"
|
||||
key_message_pos = log_content.find(key_message)
|
||||
full_message = log_content[key_message_pos-30 : key_message_pos + len(key_message)]
|
||||
deleted_files_count_list = re.findall(r'\s+(\d+)\s+blobs eligible for deletion', full_message)
|
||||
|
||||
if len(deleted_files_count_list) != 1:
|
||||
raise Exception(r"Fail to get blobs eligible for deletion in log file, failure is {}.".format(len(deleted_files_count_list)))
|
||||
deleted_files_count = int(deleted_files_count_list[0])
|
||||
if deleted_files_count == 0:
|
||||
raise Exception(r"Get blobs eligible for deletion count is {}, while we expect more than 1.".format(deleted_files_count))
|
||||
|
92
tests/apitests/python/test_garbage_collection.py
Normal file
92
tests/apitests/python/test_garbage_collection.py
Normal file
@ -0,0 +1,92 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
from testutils import ADMIN_CLIENT
|
||||
from testutils import TEARDOWN
|
||||
from library.user import User
|
||||
from library.system import System
|
||||
from library.project import Project
|
||||
from library.repository import Repository
|
||||
from library.repository import push_image_to_project
|
||||
from testutils import harbor_server
|
||||
from library.base import _assert_status_code
|
||||
|
||||
class TestProjects(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUp(self):
|
||||
system = System()
|
||||
self.system= system
|
||||
|
||||
project = Project()
|
||||
self.project= project
|
||||
|
||||
user = User()
|
||||
self.user= user
|
||||
|
||||
repo = Repository()
|
||||
self.repo= repo
|
||||
|
||||
@classmethod
|
||||
def tearDown(self):
|
||||
print "Case completed"
|
||||
|
||||
@unittest.skipIf(TEARDOWN == False, "Test data won't be erased.")
|
||||
def test_ClearData(self):
|
||||
#2. Delete project(PA);
|
||||
self.project.delete_project(TestProjects.project_gc_id, **TestProjects.USER_GC_CLIENT)
|
||||
|
||||
#3. Delete user(UA);
|
||||
self.user.delete_user(TestProjects.user_gc_id, **ADMIN_CLIENT)
|
||||
|
||||
def testGarbageCollection(self):
|
||||
"""
|
||||
Test case:
|
||||
Garbage Collection
|
||||
Test step and expected result:
|
||||
1. Create a new user(UA);
|
||||
2. Create a new project(PA) by user(UA);
|
||||
3. Push a new image(IA) in project(PA) by admin;
|
||||
4. Delete repository(RA) by user(UA);
|
||||
5. Get repository by user(UA), it should get nothing;
|
||||
6. Tigger garbage collection operation;
|
||||
7. Check garbage collection job was finished;
|
||||
8. Get garbage collection log, check there is number of files was deleted.
|
||||
Tear down:
|
||||
1. Delete project(PA);
|
||||
2. Delete user(UA).
|
||||
"""
|
||||
url = ADMIN_CLIENT["endpoint"]
|
||||
admin_name = ADMIN_CLIENT["username"]
|
||||
admin_password = ADMIN_CLIENT["password"]
|
||||
user_gc_password = "Aa123456"
|
||||
|
||||
#1. Create a new user(UA);
|
||||
TestProjects.user_gc_id, user_gc_name = self.user.create_user_success(user_password = user_gc_password, **ADMIN_CLIENT)
|
||||
|
||||
TestProjects.USER_GC_CLIENT=dict(endpoint = url, username = user_gc_name, password = user_gc_password)
|
||||
|
||||
#2. Create a new project(PA) by user(UA);
|
||||
TestProjects.project_gc_id, project_gc_name = self.project.create_project(metadata = {"public": "false"}, **TestProjects.USER_GC_CLIENT)
|
||||
|
||||
#3. Push a new image(IA) in project(PA) by admin;
|
||||
repo_name, _ = push_image_to_project(project_gc_name, harbor_server, admin_name, admin_password, "tomcat", "latest")
|
||||
|
||||
#4. Delete repository(RA) by user(UA);
|
||||
self.repo.delete_repoitory(repo_name, **TestProjects.USER_GC_CLIENT)
|
||||
|
||||
#5. Get repository by user(UA), it should get nothing;
|
||||
repo_data = self.repo.get_repository(TestProjects.project_gc_id, **TestProjects.USER_GC_CLIENT)
|
||||
_assert_status_code(len(repo_data), 0)
|
||||
|
||||
#6. Tigger garbage collection operation;
|
||||
gc_id = self.system.gc_now(**ADMIN_CLIENT)
|
||||
|
||||
#7. Check garbage collection job was finished;
|
||||
self.system.validate_gc_job_status(gc_id, "finished", **ADMIN_CLIENT)
|
||||
|
||||
#8. Get garbage collection log, check there is number of files was deleted.
|
||||
self.system.validate_deletion_success(gc_id, **ADMIN_CLIENT)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -33,3 +33,5 @@ Test Case - Manage Project Member
|
||||
Harbor API Test ./tests/apitests/python/test_manage_project_member.py
|
||||
Test Case - Project Level Policy Content Trust
|
||||
Harbor API Test ./tests/apitests/python/test_project_level_policy_content_trust.py
|
||||
Test Case - Garbage Collection
|
||||
Harbor API Test ./tests/apitests/python/test_garbage_collection.py
|
Loading…
Reference in New Issue
Block a user