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:
danfengliu 2018-11-27 19:17:41 +08:00 committed by GitHub
parent b406d7ccc0
commit c4bf65162c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 284 additions and 13 deletions

View File

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

View File

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

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

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

View File

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