Skip to content

Commit

Permalink
unit tests
Browse files Browse the repository at this point in the history
update unit tests

improve unit tests

remove no longer needed unit tests

add fake permissions to test reqmgr2 config

more unit test fixes and pylint corrections

further unit tests pylint

update unit tests replacing everyone by ppd
  • Loading branch information
amaltaro committed Jul 27, 2022
1 parent e4476fe commit 892adfb
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 126 deletions.
82 changes: 82 additions & 0 deletions test/python/WMCore_t/ReqMgr_t/DataStructs_t/AuthzByStatus_t.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env python
"""
Unit tests for the AuthzByStatus module
"""
import unittest

from WMCore.ReqMgr.DataStructs.AuthzByStatus import AuthzByStatus

ADMIN = {'role': ["admin_role"], 'group': ["admin_group"]}
OPS = {'role': ["admin_role", "ops_role"], 'group': ["admin_group", "ops_group"]}
PPD = {'role': ["admin_role", "ops_role", "ppd_role"],
'group': ["admin_group", "ops_group", "ppd_group"]}


class AuthzByStatusTests(unittest.TestCase):
"""Some basic tests for AuthzByStatus"""

def setUp(self):
self.authorized_roles = {"admin": ADMIN,
"ops": OPS,
"ppd": PPD}
self.authz_by_status = [{"permission": "admin",
"statuses": ["acquired", "running-open", "running-closed", "completed",
"aborted-completed", "failed", "rejected-archived",
"aborted-archived", "normal-archived"]},
{"permission": "ops",
"statuses": ["assigned", "staging", "staged", "force-complete",
"closed-out", "announced"]},
{"permission": "ppd",
"statuses": ["new", "assignment-approved", "rejected", "aborted", "NO_STATUS"]}]

# self.assertItemsEqual = self.assertCountEqual

def tearDown(self):
pass

def testNoStatus(self):
"""Test case where NO_STATUS is not provided"""
with self.assertRaises(RuntimeError):
AuthzByStatus([], {})

def testBadPermissions(self):
"""Test case for lack of group permissions"""
with self.assertRaises(RuntimeError):
AuthzByStatus([], {"admin": "a", "ops": "o"})

def testBadStatusValue(self):
"""Test case for bad statuses-based permissions"""
with self.assertRaises(RuntimeError):
AuthzByStatus([{"permission": "ALAN", "statuses": ["new", "acquired"]}],
{"admin": "a", "ops": "o", "ppd": "e", "ALAN": "aaa"})

def testBadStatusName(self):
"""Test case for an unexpected status name"""
with self.assertRaises(RuntimeError):
AuthzByStatus([{"permission": "admin", "statuses": ["new", "assigned"]},
{"permission": "ops", "statuses": ["staging", "staged"]},
{"permission": "ppd", "statuses": ["acquired", "Alan"]}],
{"admin": "a", "ops": "o", "ppd": "e"})

def testCorrectConfig(self):
"""Test correct configuration for the authorization setup"""
authzPerm = AuthzByStatus(self.authz_by_status, self.authorized_roles)

# test no status permission
resp = authzPerm.getRolesGroupsByStatus({})
self.assertCountEqual(resp, PPD)

# test admin permissions (and one allowed by Ops and PPD)
for status in {"new", "failed", "normal-archived", "staged", "aborted"}:
resp = authzPerm.getRolesGroupsByStatus({"RequestStatus": status})
self.assertCountEqual(resp, ADMIN)

# test Ops permissions (and one allowed by PPD)
for status in {"assigned", "staged", "announced", "aborted"}:
resp = authzPerm.getRolesGroupsByStatus({"RequestStatus": status})
self.assertCountEqual(resp, OPS)

# test PPD permissions
for status in {"new", "assignment-approved", "rejected", "aborted"}:
resp = authzPerm.getRolesGroupsByStatus({"RequestStatus": status})
self.assertCountEqual(resp, OPS)
138 changes: 55 additions & 83 deletions test/python/WMCore_t/ReqMgr_t/Service_t/ReqMgr_t.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,17 @@
import json
import os
import unittest
from http.client import HTTPException

from WMCore_t.ReqMgr_t.TestConfig import config

from WMCore.REST.Test import fake_authz_headers
from WMCore.ReqMgr.Auth import getWritePermission
from WMQuality.REST.RESTBaseUnitTestWithDBBackend import RESTBaseUnitTestWithDBBackend

req_args = {"RequestType": "ReReco", "RequestStatus": None}
ADMIN_PERMISSION = getWritePermission(req_args)
ADMIN = {'role': ["admin_role"], 'group': ["admin_group"]}
OPS = {'role': ["ops_role"], 'group': ["ops_group"]}
PPD = {'role': ["ppd_role"], 'group': ["ppd_group"]}

req_args = {"RequestType": "ReReco", "RequestStatus": "completed"}
DEFAULT_STATUS_PERMISSION = getWritePermission(req_args)

req_args = {"RequestType": "ReReco", "RequestStatus": "new"}
CREATE_PERMISSION = getWritePermission(req_args)

DEFAULT_PERMISSION = DEFAULT_STATUS_PERMISSION

req_args = {"RequestType": "ReReco", "RequestStatus": "assinged"}
ASSIGN_PERMISSION = getWritePermission(req_args)

# this needs to move in better location
def insertDataToCouch(couchUrl, couchDBName, data):
Expand All @@ -35,12 +26,13 @@ def insertDataToCouch(couchUrl, couchDBName, data):
doc = database.commit(data)
return doc


def getAuthHeader(hmacData, reqAuth):
roles = {}
for role in reqAuth['role']:
roles[role] = {'group': reqAuth['group']}

return fake_authz_headers(hmacData, dn = "/TEST/DN/CN", roles = roles, format = "dict")
return fake_authz_headers(hmacData, dn="/TEST/DN/CN", roles=roles, format="dict")


class ReqMgrTest(RESTBaseUnitTestWithDBBackend):
Expand All @@ -54,89 +46,87 @@ class ReqMgrTest(RESTBaseUnitTestWithDBBackend):
Not the correctness of functions. That will be tested in different module.
"""

def setFakeDN(self):
# put into ReqMgr auxiliary database under "software" document scram/cmsms
# which we'll need a little for request injection
#Warning: this assumes the same structure in jenkins wmcore_root/test
self.admin_header = getAuthHeader(self.test_authz_key.data, ADMIN_PERMISSION)
self.create_header = getAuthHeader(self.test_authz_key.data, CREATE_PERMISSION)
self.default_header = getAuthHeader(self.test_authz_key.data, DEFAULT_PERMISSION)
self.assign_header = getAuthHeader(self.test_authz_key.data, ASSIGN_PERMISSION)
self.default_status_header = getAuthHeader(self.test_authz_key.data, DEFAULT_STATUS_PERMISSION)

def setUp(self):
# Warning: this assumes the same structure in jenkins wmcore_root/test
self.admin_header = getAuthHeader(self.test_authz_key.data, ADMIN)
self.ops_header = getAuthHeader(self.test_authz_key.data, OPS)
self.ppd_header = getAuthHeader(self.test_authz_key.data, PPD)

def setUp(self, initRoot=True):
self.setConfig(config)
self.setCouchDBs([(config.views.data.couch_reqmgr_db, "ReqMgr"),
(config.views.data.couch_reqmgr_aux_db, None)])
self.setSchemaModules([])

RESTBaseUnitTestWithDBBackend.setUp(self)
super().setUp(initRoot=initRoot)

self.setFakeDN()
#print "%s" % self.test_authz_key.data
self.default_status_header = getAuthHeader(self.test_authz_key.data, DEFAULT_STATUS_PERMISSION)
# print "%s" % self.test_authz_key.data
# self.default_status_header = getAuthHeader(self.test_authz_key.data, PPD)

normPath = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..'))
rerecoPath = os.path.join(normPath, 'data/ReqMgr/requests/DMWM/ReReco_RunBlockWhite.json')
with open(rerecoPath) as jObj:
with open(rerecoPath, encoding='utf-8') as jObj:
rerecoArgs = json.load(jObj)
self.rerecoCreateArgs = rerecoArgs["createRequest"]
self.rerecoCreateArgs["PrepID"] = "test_prepid"
self.rerecoAssignArgs = rerecoArgs["assignRequest"]
# overwrite rereco args
self.rerecoAssignArgs["AcquisitionEra"] = "test_aqc"
self.rerecoAssignArgs["Dashboard"] = "test"
self.rerecoAssignArgs["ProcessingString"] = "ProcStr_ReReco"
self.rerecoAssignArgs["SiteWhitelist"] = ["T2_CH_CERN"]

taskChainPath = os.path.join(normPath, 'data/ReqMgr/requests/DMWM/TaskChain_InclParents.json')
with open(taskChainPath) as jObj:
taskChainPath = os.path.join(normPath, 'data/ReqMgr/requests/DMWM/TC_LHE_PFN.json')
with open(taskChainPath, encoding='utf-8') as jObj:
lheArgs = json.load(jObj)
self.lheStep0CreateArgs = lheArgs["createRequest"]
self.lheStep0AssignArgs = lheArgs["assignRequest"]
self.lheStep0AssignArgs["AcquisitionEra"] = "test_aqc"

cmsswDoc = {"_id": "software"}
cmsswDoc[self.rerecoCreateArgs["ScramArch"]] = []
cmsswDoc[self.rerecoCreateArgs["ScramArch"]] = []
cmsswDoc[self.rerecoCreateArgs["ScramArch"]].append(self.rerecoCreateArgs["CMSSWVersion"])
insertDataToCouch(os.getenv("COUCHURL"), config.views.data.couch_reqmgr_aux_db, cmsswDoc)


def tearDown(self):
RESTBaseUnitTestWithDBBackend.tearDown(self)


def getRequestWithNoStale(self, query):
prefixWithNoStale = "data/request?_nostale=true&"
return self.jsonSender.get(prefixWithNoStale + query,
incoming_headers=self.default_header)
incoming_headers=self.ppd_header)

def postRequestWithAuth(self, data):
return self.jsonSender.post('data/request', data, incoming_headers=self.create_header)
return self.jsonSender.post('data/request', data, incoming_headers=self.ppd_header)

def putRequestWithAuth(self, requestName, data):
def putRequestWithAuth(self, requestName, data, clientHeaders):
"""
WMCore.REST doesn take query for the put request.
data need to send on the body
"""
return self.jsonSender.put('data/request/%s' % requestName, data,
incoming_headers=self.assign_header)
incoming_headers=clientHeaders)

def getMultiRequestsWithAuth(self, data):
return self.jsonSender.post('data/request/bynames', data, incoming_headers=self.create_header)
return self.jsonSender.post('data/request/bynames', data, incoming_headers=self.ops_header)

def cloneRequestWithAuth(self, requestName, params = {}):
def cloneRequestWithAuth(self, requestName, params=None):
"""
WMCore.REST doesn take query for the put request.
data need to send on the body
"""
params["OriginalRequestName"] = requestName
return self.jsonSender.put('data/request/clone', params,
incoming_headers=self.assign_header)
params = params or {}
# params["OriginalRequestName"] = requestName
return self.jsonSender.put('data/request/clone/%s' % requestName, params,
incoming_headers=self.ops_header)

def resultLength(self, response, format="dict"):
# result is dict format
if format == "dict":
return len(response[0]['result'][0])
elif format == "list":
return len(response[0]['result'])
def resultLength(self, response):
# e.g. of response object: ({'result': []}, 200, 'OK', False)
return len(response[0]['result'])

def insertRequest(self, args):
# test post method
Expand Down Expand Up @@ -165,18 +155,12 @@ def testRequestSimpleCycle(self):
self.assertEqual(response[1], 200, "get by status")
self.assertEqual(self.resultLength(response), 1)

#this create cache
# need to find the way to reste Etag or not getting from the cache
# response = self.getRequestWithNoStale('status=assigned')
# self.assertEqual(response[1], 200, "get by status")
# self.assertEqual(self.resultLength(response), 0)

# get by prepID
response = self.getRequestWithNoStale('prep_id=%s' % self.rerecoCreateArgs["PrepID"])
self.assertEqual(response[1], 200)
self.assertEqual(self.resultLength(response), 1)
#import pdb
#pdb.set_trace()
# import pdb
# pdb.set_trace()
response = self.getRequestWithNoStale('campaign=%s' % self.rerecoCreateArgs["Campaign"])
self.assertEqual(response[1], 200)
self.assertEqual(self.resultLength(response), 1)
Expand All @@ -185,58 +169,46 @@ def testRequestSimpleCycle(self):
self.assertEqual(response[1], 200)
self.assertEqual(self.resultLength(response), 1)

response = self.getRequestWithNoStale('mc_pileup=%s' % self.rerecoCreateArgs["MCPileup"])
self.assertEqual(response[1], 200)
self.assertEqual(self.resultLength(response), 1)

response = self.getRequestWithNoStale('data_pileup=%s' % self.rerecoCreateArgs["DataPileup"])
self.assertEqual(response[1], 200)
self.assertEqual(self.resultLength(response), 1)


# test put request with just status change
data = {'RequestStatus': 'assignment-approved'}
self.putRequestWithAuth(requestName, data)
self.putRequestWithAuth(requestName, data, self.ppd_header)
response = self.getRequestWithNoStale('status=assignment-approved')
self.assertEqual(response[1], 200, "put request status change")
self.assertEqual(self.resultLength(response), 1)

# assign with team
# test put request with just status change
# PPD should not be able to assign requests
data = {'RequestStatus': 'assigned'}
data.update(self.rerecoAssignArgs)
self.putRequestWithAuth(requestName, data)
with self.assertRaises(HTTPException):
self.putRequestWithAuth(requestName, data, self.ppd_header)
response = self.getRequestWithNoStale('status=assigned')
self.assertEqual(response[1], 200, "put request status change")
print(response)
self.assertEqual(self.resultLength(response), 0)

# now try the same transition, but with Ops credentials
self.putRequestWithAuth(requestName, data, self.ops_header)
response = self.getRequestWithNoStale('status=assigned')
self.assertEqual(response[1], 200, "put request status change")
self.assertEqual(self.resultLength(response), 1)

response = self.getRequestWithNoStale('status=assigned&team=%s' %
self.rerecoAssignArgs['Team'])
self.rerecoAssignArgs['Team'])
self.assertEqual(response[1], 200, "put request status change")
self.assertEqual(self.resultLength(response), 1)

response = self.getMultiRequestsWithAuth([requestName])
self.assertEqual(self.resultLength(response), 1)
self.assertEqual(list(response[0]['result'][0])[0], requestName)

#response = self.cloneRequestWithAuth(requestName)
#self.assertEqual(response[1], 200, "put request clone")
#response = self.getRequestWithNoStale('status=new')
#self.assertEqual(self.resultLength(response), 1)

def atestRequestCombinedGetCall(self):
"""
test request composite get call
"""

# test post method
from pprint import pprint
del self.rerecoCreateArgs["CMSSWVersion"]
pprint(self.rerecoCreateArgs)
rerecoReqName = self.insertRequest(self.rerecoCreateArgs)
lheReqName = self.insertRequest(self.lheStep0CreateArgs)
## test get method
# get by name

## test get method and get by name
response = self.getRequestWithNoStale('name=%s&name=%s' % (rerecoReqName, lheReqName))
self.assertEqual(response[1], 200, "get by name")
self.assertEqual(self.resultLength(response), 2)
Expand All @@ -250,13 +222,12 @@ def atestRequestCombinedGetCall(self):
response = self.getRequestWithNoStale('prep_id=%s' % self.rerecoCreateArgs["PrepID"])
self.assertEqual(response[1], 200)
self.assertEqual(self.resultLength(response), 2)
#import pdb
#pdb.set_trace()
# import pdb
# pdb.set_trace()
response = self.getRequestWithNoStale('campaign=%s' % self.rerecoCreateArgs["Campaign"])
self.assertEqual(response[1], 200)
self.assertEqual(self.resultLength(response), 2)


def atestRequestClone(self):
requestName = self.insertRequest(self.rerecoCreateArgs)
response = self.cloneRequestWithAuth(requestName)
Expand All @@ -265,5 +236,6 @@ def atestRequestClone(self):
response = self.getRequestWithNoStale('status=new')
self.assertEqual(self.resultLength(response), 2)


if __name__ == '__main__':
unittest.main()
17 changes: 14 additions & 3 deletions test/python/WMCore_t/ReqMgr_t/TestConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@
data.couch_workqueue_db = "workqueue"
data.central_logdb_url = LOG_DB_URL
data.log_reporter = LOG_REPORTER
# Fake permissions for unit tests
data.authorized_roles = {"admin": {'role': ["admin_role"], 'group': ["admin_group"]},
"ops": {'role': ["admin_role", "ops_role"],
'group': ["admin_group", "ops_group"]},
"ppd": {'role': ["admin_role", "ops_role", "ppd_role"],
'group': ["admin_group", "ops_group", "ppd_group"]}}
data.authz_by_status = [{"permission": "admin",
"statuses": ["acquired", "running-open", "running-closed", "completed", "aborted-completed",
"failed", "rejected-archived", "aborted-archived", "normal-archived"]},
{"permission": "ops",
"statuses": ["assigned", "staging", "staged", "force-complete",
"closed-out", "announced"]},
{"permission": "ppd",
"statuses": ["new", "assignment-approved", "rejected", "aborted", "NO_STATUS"]}]

# number of past days since when to display requests in the default view
data.default_view_requests_since_num_days = 30 # days
Expand Down Expand Up @@ -114,8 +128,5 @@

config.views.data.couch_host = getenv("COUCHURL", None)



# end of deployment/reqmgr2/config-localhost.py
# ---------------------------------------------------------------------------

Loading

0 comments on commit 892adfb

Please sign in to comment.