"Fossies" - the Fresh Open Source Software Archive

Member "openstack-cyborg-7.0.0/cyborg/tests/unit/objects/test_fpga_ext_arq.py" (6 Oct 2021, 17337 Bytes) of package /linux/misc/openstack/openstack-cyborg-7.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 # Copyright 2019 Intel.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 from io import BytesIO
   17 import json
   18 import requests
   19 from requests import structures
   20 from requests import utils
   21 from unittest import mock
   22 
   23 from testtools.matchers import HasLength
   24 
   25 from cyborg.common import constants
   26 from cyborg.common import exception
   27 from cyborg import objects
   28 from cyborg.tests.unit.db import base
   29 from cyborg.tests.unit import fake_deployable
   30 from cyborg.tests.unit import fake_extarq
   31 
   32 
   33 class TestFPGAExtARQObject(base.DbTestCase):
   34 
   35     def setUp(self):
   36         super(TestFPGAExtARQObject, self).setUp()
   37         self.fake_fpga_db_extarqs = fake_extarq.get_fake_fpga_db_extarqs()
   38         self.fake_obj_fpga_extarqs = fake_extarq.get_fake_fpga_extarq_objs()
   39         classes = ["no_program", "bitstream_program",
   40                    "function_program", "bad_program"]
   41         self.class_fgpa_objects = dict(
   42             zip(classes, self.fake_obj_fpga_extarqs))
   43         self.class_fgpa_dbs = dict(
   44             zip(classes, self.fake_fpga_db_extarqs))
   45         self.bitstream_id = self.class_fgpa_objects["bitstream_program"][
   46             "device_profile_group"][constants.ACCEL_BITSTREAM_ID]
   47         self.function_id = self.class_fgpa_objects["function_program"][
   48             "device_profile_group"][constants.ACCEL_FUNCTION_ID]
   49         self.images_md = {
   50             "/images":
   51             [
   52                 {"id": self.bitstream_id,
   53                  "tags": ["trait:CUSTOM_FPGA_INTEL"],
   54                  constants.ACCEL_FUNCTION_ID: self.function_id},
   55             ]
   56         }
   57         self.deployable_uuids = ['0acbf8d6-e02a-4394-aae3-57557d209498']
   58         self.bdf = {"domain": "0000", "bus": "00",
   59                     "device": "01", "function": "1"}
   60         self.cpid = {
   61             "id": 0,
   62             "uuid": "e4a66b0d-b377-40d6-9cdc-6bf7e720e596",
   63             "device_id": "1",
   64             "cpid_type": "PCI",
   65             "cpid_info": json.dumps(self.bdf).encode('utf-8')
   66         }
   67 
   68     def response(self, status_code=200, content='', headers=None,
   69                  reason=None, elapsed=0, request=None, stream=False):
   70         res = requests.Response()
   71         res.status_code = status_code
   72         if isinstance(content, (dict, list)):
   73             content = json.dumps(content).encode('utf-8')
   74         if isinstance(content, str):
   75             content = content.encode('utf-8')
   76         res._content = content
   77         res._content_consumed = content
   78         res.headers = structures.CaseInsensitiveDict(headers or {})
   79         res.encoding = utils.get_encoding_from_headers(res.headers)
   80         res.reason = reason
   81         res.request = request
   82         if hasattr(request, 'url'):
   83             res.url = request.url
   84             if isinstance(request.url, bytes):
   85                 res.url = request.url.decode('utf-8')
   86 
   87         if stream:
   88             res.raw = BytesIO(content)
   89         else:
   90             res.raw = BytesIO(b'')
   91         # normally this closes the underlying connection,
   92         #  but we have nothing to free.
   93         res.close = lambda *args, **kwargs: None
   94         return res
   95 
   96     def images_get(self, url, *args, **kw):
   97         images = {"images": []}
   98         params = kw.get("params", {})
   99         bit_id = None
  100         res = None
  101         if url != "/images":
  102             bit_id = url.rsplit("/", 1)[-1]
  103             params["id"] = bit_id
  104         tags = kw.pop("tags", [])
  105         for image in self.images_md["/images"]:
  106             if tags <= image["tags"] and params.items() <= image.items():
  107                 images["images"].append(image)
  108                 res = self.response(content=image)
  109         return res if bit_id else self.response(content=images)
  110 
  111     @mock.patch('cyborg.objects.ExtARQ._from_db_object')
  112     def test_get_bitstream_id_return_None(self, mock_from_db_obj):
  113         db_extarq = self.fake_fpga_db_extarqs[0]
  114         uuid = db_extarq['uuid']
  115         mock_from_db_obj.return_value = self.fake_obj_fpga_extarqs[0]
  116         with mock.patch.object(
  117             self.dbapi, 'extarq_get') as mock_extarq_get:
  118             mock_extarq_get.return_value = db_extarq
  119             obj_extarq = objects.FPGAExtARQ.get(self.context, uuid)
  120             mock_extarq_get.assert_called_once_with(self.context, uuid)
  121             self.assertEqual(obj_extarq.arq.uuid, uuid)
  122             self.assertIsNone(obj_extarq._get_bitstream_id())
  123 
  124     @mock.patch('cyborg.objects.ExtARQ._from_db_object')
  125     def test_get_bitstream_id_return_UUID(self, mock_from_db_obj):
  126         db_extarq = self.fake_fpga_db_extarqs[1]
  127         bit_id = db_extarq['device_profile_group'][
  128             constants.ACCEL_BITSTREAM_ID]
  129         uuid = db_extarq['uuid']
  130         mock_from_db_obj.return_value = self.fake_obj_fpga_extarqs[1]
  131         with mock.patch.object(
  132             self.dbapi, 'extarq_get') as mock_extarq_get:
  133             mock_extarq_get.return_value = db_extarq
  134             obj_extarq = objects.FPGAExtARQ.get(self.context, uuid)
  135             mock_extarq_get.assert_called_once_with(self.context, uuid)
  136             self.assertEqual(obj_extarq.arq.uuid, uuid)
  137             self.assertEqual(obj_extarq._get_bitstream_id(), bit_id)
  138 
  139     @mock.patch('cyborg.objects.ExtARQ._from_db_object')
  140     def test_get_function_id_return_UUID(self, mock_from_db_obj):
  141         db_extarq = self.fake_fpga_db_extarqs[2]
  142         fun_id = db_extarq['device_profile_group'][constants.ACCEL_FUNCTION_ID]
  143         uuid = db_extarq['uuid']
  144         mock_from_db_obj.return_value = self.fake_obj_fpga_extarqs[2]
  145         with mock.patch.object(
  146             self.dbapi, 'extarq_get') as mock_extarq_get:
  147             mock_extarq_get.return_value = db_extarq
  148             obj_extarq = objects.FPGAExtARQ.get(self.context, uuid)
  149             mock_extarq_get.assert_called_once_with(self.context, uuid)
  150             self.assertEqual(obj_extarq.arq.uuid, uuid)
  151             self.assertEqual(obj_extarq._get_function_id(), fun_id)
  152 
  153     @mock.patch('cyborg.objects.ExtARQ._from_db_object_list')
  154     def test_list(self, mock_from_db_obj_list):
  155         db_extarqs = self.fake_fpga_db_extarqs
  156         mock_from_db_obj_list.return_value = self.fake_obj_fpga_extarqs
  157         with mock.patch.object(self.dbapi, 'extarq_list',
  158                                autospec=True) as mock_get_list:
  159             mock_get_list.return_value = db_extarqs
  160             obj_extarqs = objects.FPGAExtARQ.list(self.context)
  161             self.assertEqual(1, mock_get_list.call_count)
  162             self.assertThat(obj_extarqs, HasLength(4))
  163             self.assertIsInstance(obj_extarqs[0], objects.FPGAExtARQ)
  164             for i, obj_extarq in enumerate(obj_extarqs):
  165                 self.assertEqual(obj_extarq.arq.uuid, db_extarqs[i]['uuid'])
  166 
  167     @mock.patch('openstack.connection.Connection')
  168     def test_get_bitstream_md_from_bitstream_id(self, mock_conn):
  169         mock_conn.return_value = type(
  170             "Connection", (object,),
  171             {"image": type("image", (object,), {"get": self.images_get})})
  172         obj_extarq = self.class_fgpa_objects["bitstream_program"]
  173         md = obj_extarq._get_bitstream_md_from_bitstream_id(self.bitstream_id)
  174         self.assertDictEqual(self.images_md["/images"][0], md)
  175 
  176     @mock.patch('openstack.connection.Connection')
  177     def test_get_bitstream_md_from_function_id(self, mock_conn):
  178         mock_conn.return_value = type(
  179             "Connection", (object,),
  180             {"image": type("image", (object,), {"get": self.images_get})})
  181         obj_extarq = self.class_fgpa_objects["function_program"]
  182         md = obj_extarq._get_bitstream_md_from_function_id(self.function_id)
  183         self.assertDictEqual(self.images_md["/images"][0], md)
  184 
  185     @mock.patch('openstack.connection.Connection')
  186     @mock.patch('cyborg.objects.ExtARQ.update_check_state')
  187     def test_needs_programming(self, mock_check_state, mock_conn):
  188         mock_conn.return_value = type(
  189             "Connection", (object,),
  190             {"image": type("image", (object,), {"get": self.images_get})})
  191         dep_uuid = self.deployable_uuids[0]
  192         fake_dep = fake_deployable.fake_deployable_obj(
  193             self.context, uuid=dep_uuid)
  194 
  195         # function_id is require
  196         obj_extarq = self.class_fgpa_objects["function_program"]
  197         need = obj_extarq._needs_programming(self.context, fake_dep)
  198         self.assertTrue(need)
  199 
  200         # bitstream_id is require
  201         obj_extarq = self.class_fgpa_objects["bitstream_program"]
  202         need = obj_extarq._needs_programming(self.context, fake_dep)
  203         self.assertTrue(need)
  204 
  205         # Both bitstream_id and function_id are require
  206         obj_extarq = self.class_fgpa_objects["bad_program"]
  207         self.assertRaises(
  208             exception.InvalidParameterValue, obj_extarq._needs_programming,
  209             self.context, fake_dep)
  210 
  211         # None of bitstream_id or function_id is require
  212         obj_extarq = self.class_fgpa_objects["no_program"]
  213         need = obj_extarq._needs_programming(self.context, fake_dep)
  214         self.assertFalse(need)
  215 
  216     @mock.patch('openstack.connection.Connection')
  217     @mock.patch('cyborg.objects.ExtARQ.update_check_state')
  218     def test_get_bitstream_md(self, mock_check_state, mock_conn):
  219         mock_conn.return_value = type(
  220             "Connection", (object,),
  221             {"image": type("image", (object,), {"get": self.images_get})})
  222         dep_uuid = self.deployable_uuids[0]
  223         fake_dep = fake_deployable.fake_deployable_obj(
  224             self.context, uuid=dep_uuid)
  225 
  226         # function_id is require
  227         obj_extarq = self.class_fgpa_objects["function_program"]
  228         bs_id = obj_extarq._get_bitstream_id()
  229         fun_id = obj_extarq._get_function_id()
  230         md = obj_extarq.get_bitstream_md(
  231             self.context, fake_dep, fun_id, bs_id)
  232         self.assertDictEqual(self.images_md["/images"][0], md)
  233 
  234         # bitstream_id is require
  235         obj_extarq = self.class_fgpa_objects["bitstream_program"]
  236         bs_id = obj_extarq._get_bitstream_id()
  237         fun_id = obj_extarq._get_function_id()
  238         md = obj_extarq.get_bitstream_md(
  239             self.context, fake_dep, fun_id, bs_id)
  240         self.assertDictEqual(self.images_md["/images"][0], md)
  241 
  242         # Both bitstream_id and function_id are require
  243         obj_extarq = self.class_fgpa_objects["bad_program"]
  244         bs_id = obj_extarq._get_bitstream_id()
  245         fun_id = obj_extarq._get_function_id()
  246         self.assertRaises(
  247             exception.InvalidParameterValue, obj_extarq.get_bitstream_md,
  248             self.context, fake_dep, fun_id, bs_id)
  249 
  250         # None of bitstream_id or function_id is require
  251         obj_extarq = self.class_fgpa_objects["no_program"]
  252         bs_id = obj_extarq._get_bitstream_id()
  253         fun_id = obj_extarq._get_function_id()
  254         md = obj_extarq.get_bitstream_md(
  255             self.context, fake_dep, fun_id, bs_id)
  256         self.assertIsNone(md)
  257 
  258     @mock.patch('openstack.connection.Connection')
  259     @mock.patch('cyborg.objects.ExtARQ.update_check_state')
  260     def test_need_extra_bind_job(self, mock_check_state, mock_conn):
  261         mock_conn.return_value = type(
  262             "Connection", (object,),
  263             {"image": type("image", (object,), {"get": self.images_get})})
  264         dep_uuid = self.deployable_uuids[0]
  265         fake_dep = fake_deployable.fake_deployable_obj(
  266             self.context, uuid=dep_uuid)
  267 
  268         # function_id is require
  269         obj_extarq = self.class_fgpa_objects["function_program"]
  270         need = obj_extarq._need_extra_bind_job(self.context, fake_dep)
  271         self.assertTrue(need)
  272 
  273         # bitstream_id is require
  274         obj_extarq = self.class_fgpa_objects["bitstream_program"]
  275         need = obj_extarq._need_extra_bind_job(self.context, fake_dep)
  276         self.assertTrue(need)
  277 
  278         # Both bitstream_id and function_id are require
  279         obj_extarq = self.class_fgpa_objects["bad_program"]
  280         self.assertRaises(
  281             exception.InvalidParameterValue, obj_extarq._need_extra_bind_job,
  282             self.context, fake_dep)
  283 
  284         # None of bitstream_id or function_id is require
  285         obj_extarq = self.class_fgpa_objects["no_program"]
  286         need = obj_extarq._need_extra_bind_job(self.context, fake_dep)
  287         self.assertFalse(need)
  288 
  289     @mock.patch('cyborg.agent.rpcapi.AgentAPI.fpga_program')
  290     @mock.patch('openstack.connection.Connection')
  291     @mock.patch('cyborg.objects.ExtARQ.update_check_state')
  292     @mock.patch('cyborg.objects.Deployable.get_cpid_list')
  293     def test_do_programming(self, mock_cpid_list, mock_check_state, mock_conn,
  294                             mock_program):
  295         dep_uuid = self.deployable_uuids[0]
  296         fake_dep = fake_deployable.fake_deployable_obj(
  297             self.context, uuid=dep_uuid)
  298 
  299         # function_id is require
  300         obj_extarq = self.class_fgpa_objects["function_program"]
  301         obj_extarq.arq.hostname = 'newtestnode1'
  302         fake_dep.driver_name = "intel_fpga"
  303 
  304         mock_cpid_list.return_value = [self.cpid]
  305         bs_id = obj_extarq._get_bitstream_id()
  306         obj_extarq._do_programming(self.context, fake_dep, bs_id)
  307         mock_program.assert_called_once_with(
  308             self.context, 'newtestnode1', self.cpid, bs_id, "intel_fpga")
  309 
  310     @mock.patch('cyborg.common.placement_client.PlacementClient.'
  311                 '__init__')
  312     @mock.patch('cyborg.common.placement_client.PlacementClient.'
  313                 'add_traits_to_rp')
  314     @mock.patch('cyborg.common.placement_client.PlacementClient.'
  315                 'delete_traits_with_prefixes')
  316     def test_update_placement(
  317         self, mock_delete_traits, mock_add_traits, mock_placement_init):
  318         mock_placement_init.return_value = None
  319         dep_uuid = self.deployable_uuids[0]
  320         fake_dep = fake_deployable.fake_deployable_obj(
  321             self.context, uuid=dep_uuid)
  322 
  323         # function_id is require
  324         obj_extarq = self.class_fgpa_objects["function_program"]
  325         obj_extarq.arq.hostname = 'newtestnode1'
  326         # fake_dep.driver_name = "intel_fpga"
  327         fun_id = obj_extarq._get_function_id()
  328         rp_uuid = obj_extarq.arq.device_rp_uuid
  329         obj_extarq._update_placement(
  330             self.context, fun_id, fake_dep.driver_name)
  331 
  332         function_id = fun_id.upper().replace('-', '_-')
  333         vendor = fake_dep.driver_name.upper()
  334         trait_names = ["_".join((
  335             constants.FPGA_FUNCTION_ID, vendor, function_id))]
  336         mock_add_traits.assert_called_once_with(rp_uuid, trait_names)
  337         mock_delete_traits.assert_called_once_with(
  338             self.context, rp_uuid, [constants.FPGA_FUNCTION_ID])
  339 
  340     @mock.patch('cyborg.agent.rpcapi.AgentAPI.fpga_program')
  341     @mock.patch('cyborg.objects.Deployable.get_cpid_list')
  342     @mock.patch('cyborg.objects.Deployable.update')
  343     @mock.patch('cyborg.common.placement_client.PlacementClient.'
  344                 '__init__')
  345     @mock.patch('cyborg.common.placement_client.PlacementClient.'
  346                 'add_traits_to_rp')
  347     @mock.patch('cyborg.common.placement_client.PlacementClient.'
  348                 'delete_traits_with_prefixes')
  349     @mock.patch('openstack.connection.Connection')
  350     @mock.patch('cyborg.objects.ExtARQ.update_check_state')
  351     @mock.patch('cyborg.objects.ExtARQ.bind')
  352     def test_bind(
  353         self, mock_bind, mock_check_state, mock_conn, mock_delete_traits,
  354         mock_add_traits, mock_placement_init, mock_dp_update,
  355         mock_cpid_list, mock_program):
  356 
  357         mock_placement_init.return_value = None
  358         mock_conn.return_value = type(
  359             "Connection", (object,),
  360             {"image": type("image", (object,), {"get": self.images_get})})
  361 
  362         dep_uuid = self.deployable_uuids[0]
  363         fake_dep = fake_deployable.fake_deployable_obj(
  364             self.context, uuid=dep_uuid)
  365 
  366         mock_cpid_list.return_value = [self.cpid]
  367 
  368         # None of bitstream_id or function_id is require
  369         obj_extarq = self.class_fgpa_objects["no_program"]
  370         obj_extarq.bind(self.context, fake_dep)
  371         self.assertFalse(mock_program.called)
  372         self.assertFalse(mock_placement_init.called)
  373         self.assertFalse(mock_dp_update.called)
  374         mock_bind.assert_called_once_with(self.context, fake_dep)
  375 
  376         self.cpid["cpid_info"] = json.dumps(self.bdf).encode('utf-8')
  377         # function_id is require
  378         obj_extarq = self.class_fgpa_objects["function_program"]
  379         obj_extarq.bind(self.context, fake_dep)
  380         mock_bind.assert_called_with(self.context, fake_dep)
  381         self.assertEqual(mock_bind.call_count, 2)
  382 
  383         self.cpid["cpid_info"] = json.dumps(self.bdf).encode('utf-8')
  384         # bitstream_id is require
  385         obj_extarq = self.class_fgpa_objects["bitstream_program"]
  386         obj_extarq.bind(self.context, fake_dep)
  387         mock_bind.assert_called_with(self.context, fake_dep)
  388         self.assertEqual(mock_bind.call_count, 3)