示例#1
0
def get_cbsd_state(request: CBSDRequest) -> CBSDStateResult:
    """
    Make RPC call to 'GetCBSDState' method of dp service
    """
    try:
        chan = ServiceRegistry.get_rpc_channel(
            DP_SERVICE_NAME,
            ServiceRegistry.CLOUD,
        )
    except ValueError:
        logger.error("Can't get RPC channel to %s", DP_SERVICE_NAME)
        return CBSDStateResult(radio_enabled=False)
    client = DPServiceStub(chan)
    try:
        msg_json = MessageToJson(request,
                                 including_default_value_fields=True,
                                 preserving_proto_field_name=True)
        logger.debug(f"Sending GetCBSDState request: {msg_json}")
        res = client.GetCBSDState(request, DEFAULT_GRPC_TIMEOUT)
        msg_json = MessageToJson(res,
                                 including_default_value_fields=True,
                                 preserving_proto_field_name=True)
        logger.debug(f"Received GetCBSDState reply: {msg_json}")
    except grpc.RpcError as err:
        logger.warning(
            "GetCBSDState error: [%s] %s",
            err.code(),
            err.details(),
        )
        return CBSDStateResult(radio_enabled=False)
    return res
示例#2
0
 def setUp(self):
     super().setUp()
     DBInitializer(SessionManager(self.engine)).initialize()
     grpc_channel = grpc.insecure_channel(
         f"{config.GRPC_SERVICE}:{config.GRPC_PORT}",
     )
     self.dp_client = DPServiceStub(grpc_channel)
示例#3
0
 def setUp(self):
     super().setUp()
     DBInitializer(SessionManager(self.engine)).initialize()
     grpc_channel = grpc.insecure_channel(
         f"{config.GRPC_SERVICE}:{config.GRPC_PORT}",
     )
     self.dp_client = DPServiceStub(grpc_channel)
     when_elastic_indexes_data()
     _delete_dp_elasticsearch_indices()
示例#4
0
 def setUp(self):
     super().setUp()
     grpc_channel = grpc.insecure_channel(
         f"{config.GRPC_SERVICE}:{config.GRPC_PORT}", )
     self.dp_client = DPServiceStub(grpc_channel)
     DBInitializer(SessionManager(self.engine)).initialize()
     # Indexing from previous test may not have been finished yet
     sleep(5)
     self._delete_dp_elasticsearch_indices()
示例#5
0
def get_cbsd_state(request: CBSDRequest) -> CBSDStateResult:
    """
    Make RPC call to 'GetCBSDState' method of dp service
    """
    try:
        chan = ServiceRegistry.get_rpc_channel(
            DP_SERVICE_NAME,
            ServiceRegistry.CLOUD,
        )
    except ValueError:
        logger.error('Cant get RPC channel to %s', DP_SERVICE_NAME)
        return CBSDStateResult(radio_enabled=False)
    client = DPServiceStub(chan)
    try:
        res = client.GetCBSDState(request, DEFAULT_GRPC_TIMEOUT)
    except grpc.RpcError as err:
        logger.warning(
            "GetCBSDState error: [%s] %s",
            err.code(),
            err.details(),
        )
        return CBSDStateResult(radio_enabled=False)
    return res
示例#6
0
class DomainProxyOrc8rTestCase(DBTestCase):
    def setUp(self):
        super().setUp()
        DBInitializer(SessionManager(self.engine)).initialize()
        grpc_channel = grpc.insecure_channel(
            f"{config.GRPC_SERVICE}:{config.GRPC_PORT}", )
        self.dp_client = DPServiceStub(grpc_channel)

    # retrying is needed because of a possible deadlock
    # with cc locking request table
    @retry(stop_max_attempt_number=5, wait_fixed=100)
    def drop_all(self):
        super().drop_all()

    def test_cbsd_sas_flow(self):
        cbsd_id = self.given_cbsd_provisioned()

        logs = self.when_logs_are_fetched(self.get_current_sas_filters())
        self.then_logs_are(logs, self.get_sas_provision_messages())

        filters = self.get_filters_for_request_type('heartbeat')
        self.then_message_is_eventually_sent(filters, keep_alive=True)

        self.delete_cbsd(cbsd_id)

    def test_sas_flow_restarted_for_updated_cbsd(self):
        cbsd_id = self.given_cbsd_provisioned()

        self.when_cbsd_is_updated(cbsd_id, OTHER_FCC_ID)

        filters = self.get_filters_for_request_type('deregistration')
        self.then_message_is_eventually_sent(filters, keep_alive=True)

        self.then_state_is_eventually(self.get_state_with_grant())

        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, self.get_cbsd_data_with_grant(OTHER_FCC_ID))

        self.delete_cbsd(cbsd_id)

    def test_activity_status(self):
        cbsd_id = self.given_cbsd_provisioned()

        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, self.get_cbsd_data_with_grant())

        self.when_cbsd_is_inactive()
        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, self.get_registered_cbsd_data())

        self.delete_cbsd(cbsd_id)

    def given_cbsd_provisioned(self) -> int:
        self.when_cbsd_is_created()
        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, self.get_unregistered_cbsd_data())

        state = self.when_cbsd_asks_for_state()
        self.then_state_is(state, self.get_empty_state())

        self.then_state_is_eventually(self.get_state_with_grant())

        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, self.get_cbsd_data_with_grant())

        return cbsd['id']

    def delete_cbsd(self, cbsd_id: int):
        filters = self.get_filters_for_request_type('deregistration')

        self.when_cbsd_is_deleted(cbsd_id)
        self.then_cbsd_is_deleted()

        state = self.when_cbsd_asks_for_state()
        self.then_state_is(state, self.get_empty_state())

        self.then_message_is_eventually_sent(filters, keep_alive=False)

    def when_cbsd_is_created(self):
        r = send_request_to_backend(
            'post',
            'cbsds',
            json=self.get_cbsd_post_data(),
        )
        self.assertEqual(r.status_code, HTTPStatus.CREATED)

    def when_cbsd_is_fetched(self) -> Dict[str, Any]:
        r = send_request_to_backend('get', 'cbsds')
        self.assertEqual(r.status_code, HTTPStatus.OK)
        data = r.json()
        self.assertEqual(data.get('total_count'), 1)
        cbsds = data.get('cbsds', [])
        self.assertEqual(len(cbsds), 1)
        return cbsds[0]

    def when_logs_are_fetched(self, params: Dict[str,
                                                 Any]) -> List[Dict[str, Any]]:
        r = send_request_to_backend('get', 'logs', params=params)
        self.assertEqual(r.status_code, HTTPStatus.OK)
        data = r.json()
        return data

    def when_cbsd_is_deleted(self, cbsd_id: int):
        r = send_request_to_backend('delete', f'cbsds/{cbsd_id}')
        self.assertEqual(r.status_code, HTTPStatus.NO_CONTENT)

    def when_cbsd_is_updated(self, cbsd_id: int, fcc_id: str):
        r = send_request_to_backend(
            'put',
            f'cbsds/{cbsd_id}',
            json=self.get_cbsd_post_data(fcc_id=fcc_id),
        )
        self.assertEqual(r.status_code, HTTPStatus.NO_CONTENT)

    def when_cbsd_asks_for_state(self) -> CBSDStateResult:
        return self.dp_client.GetCBSDState(self.get_cbsd_request())

    @staticmethod
    def when_cbsd_is_inactive():
        inactivity = 3
        polling = 1
        delta = 3
        total_wait_time = inactivity + 2 * polling + delta
        sleep(total_wait_time)

    def then_cbsd_is(self, actual: Dict[str, Any], expected: Dict[str, Any]):
        actual = actual.copy()
        del actual['id']
        grant = actual.get('grant')
        if grant:
            del grant['grant_expire_time']
            del grant['transmit_expire_time']
        self.assertEqual(actual, expected)

    def then_cbsd_is_deleted(self):
        r = send_request_to_backend('get', 'cbsds')
        self.assertEqual(r.status_code, HTTPStatus.OK)
        data = r.json()
        self.assertFalse(data.get('total_count', True))

    def then_state_is(self, actual: CBSDStateResult,
                      expected: CBSDStateResult):
        self.assertEqual(actual, expected)

    @retry(stop_max_attempt_number=30, wait_fixed=1000)
    def then_state_is_eventually(self, expected):
        actual = self.when_cbsd_asks_for_state()
        self.then_state_is(actual, expected)

    def then_logs_are(self, actual: List[Dict[str, Any]], expected: List[str]):
        actual = [x['type'] for x in actual]
        self.assertEqual(actual, expected)

    @retry(stop_max_attempt_number=60, wait_fixed=1000)
    def then_message_is_eventually_sent(self, filters: Dict[str, Any],
                                        keep_alive):
        if keep_alive:
            self.when_cbsd_asks_for_state()
        logs = self.when_logs_are_fetched(filters)
        self.assertEqual(len(logs), 1)

    @staticmethod
    def get_cbsd_request() -> CBSDRequest:
        return CBSDRequest(serial_number=SERIAL_NUMBER)

    @staticmethod
    def get_empty_state() -> CBSDStateResult:
        return CBSDStateResult(radio_enabled=False)

    @staticmethod
    def get_state_with_grant() -> CBSDStateResult:
        return CBSDStateResult(
            radio_enabled=True,
            channel=LteChannel(
                low_frequency_hz=3620_000_000,
                high_frequency_hz=3630_000_000,
                max_eirp_dbm_mhz=28.0,
            ),
        )

    @staticmethod
    def get_cbsd_post_data(fcc_id: str = SOME_FCC_ID) -> Dict[str, Any]:
        return {
            "capabilities": {
                "antenna_gain": 15,
                "max_power": 20,
                "min_power": 0,
                "number_of_antennas": 2,
            },
            "fcc_id": fcc_id,
            "serial_number": SERIAL_NUMBER,
            "user_id": USER_ID,
        }

    def get_unregistered_cbsd_data(self) -> Dict[str, Any]:
        data = self.get_cbsd_post_data()
        data.update({
            'is_active': False,
            'state': 'unregistered',
        })
        return data

    def get_registered_cbsd_data(self,
                                 fcc_id: str = SOME_FCC_ID) -> Dict[str, Any]:
        data = self.get_cbsd_post_data(fcc_id)
        data.update({
            'cbsd_id': f'{fcc_id}/{SERIAL_NUMBER}',
            'is_active': False,
            'state': 'registered',
        })
        return data

    def get_cbsd_data_with_grant(self,
                                 fcc_id: str = SOME_FCC_ID) -> Dict[str, Any]:
        data = self.get_registered_cbsd_data(fcc_id)
        data.update({
            'is_active': True,
            'grant': {
                'bandwidth_mhz': 10,
                'frequency_mhz': 3625,
                'max_eirp': 28,
                'state': 'authorized',
            },
        })
        return data

    def get_current_sas_filters(self) -> Dict[str, Any]:
        return {
            'serial_number': SERIAL_NUMBER,
            'from': 'SAS',
            'to': 'DP',
            'end': self.now(),
        }

    def get_filters_for_request_type(self,
                                     request_type: str) -> Dict[str, Any]:
        return {
            'serial_number': SERIAL_NUMBER,
            'type': f'{request_type}Response',
            'begin': self.now(),
        }

    @staticmethod
    def get_sas_provision_messages() -> List[str]:
        names = ['heartbeat', 'grant', 'spectrumInquiry', 'registration']
        return [f'{x}Response' for x in names]

    @staticmethod
    def now():
        return datetime.now(timezone.utc).isoformat()
 def then_cbsd_has_no_grants_in_sas(self, dp_client: DPServiceStub):
     state = dp_client.GetCBSDState(self._build_cbsd_request())
     self.assertEqual(self._build_empty_state_result(), state)
 def then_cbsd_is_eventually_provisioned_in_sas(self,
                                                dp_client: DPServiceStub):
     state = dp_client.GetCBSDState(self._build_cbsd_request())
     self.assertEqual(self._build_get_state_result(), state)
示例#9
0
class ActiveModeControllerTestCase(DBTestCase):
    def setUp(self):
        super().setUp()
        grpc_channel = grpc.insecure_channel(
            f"{config.GRPC_SERVICE}:{config.GRPC_PORT}", )
        self.dp_client = DPServiceStub(grpc_channel)
        DBInitializer(SessionManager(self.engine)).initialize()

    # retrying is needed because of a possible deadlock
    # with cc locking request table
    @retry(stop_max_attempt_number=5, wait_fixed=100)
    def drop_all(self):
        super().drop_all()

    def test_provision_cbsd_in_sas_requested_by_dp_client(self):
        self.given_cbsd_provisioned()

    def test_grant_relinquished_after_inactivity(self):
        self.given_cbsd_provisioned()
        self.when_cbsd_is_inactive()
        self.then_cbsd_has_no_grants_in_sas(self.dp_client)

    def test_last_used_max_eirp_stays_the_same_after_inactivity(self):
        self.given_cbsd_provisioned()
        self.when_cbsd_is_inactive()
        self.then_cbsd_has_no_grants_in_sas(self.dp_client)
        self.given_cbsd_provisioned()

    def given_cbsd_provisioned(self):
        self.given_cbsd_with_transmission_parameters()
        self.dp_client.GetCBSDState(
            self._build_cbsd_request(),
            wait_for_ready=True,
        )

        self.then_cbsd_is_eventually_provisioned_in_sas(self.dp_client)

    # TODO change this when some API for domain proxy is introduced
    def given_cbsd_with_transmission_parameters(self):
        state = self.dp_client.CBSDRegister(self._build_cbsd_request())
        self.session.commit()
        self.assertEqual(self._build_empty_state_result(), state)

    @staticmethod
    def when_cbsd_is_inactive():
        inactivity = 3
        polling = 1
        delta = 3  # TODO investigate if such high delta is needed
        total_wait_time = inactivity + 2 * polling + delta
        sleep(total_wait_time)

    @retry(stop_max_attempt_number=30, wait_fixed=1000)
    def then_cbsd_is_eventually_provisioned_in_sas(self,
                                                   dp_client: DPServiceStub):
        state = dp_client.GetCBSDState(self._build_cbsd_request())
        self.assertEqual(self._build_get_state_result(), state)

    def then_cbsd_has_no_grants_in_sas(self, dp_client: DPServiceStub):
        state = dp_client.GetCBSDState(self._build_cbsd_request())
        self.assertEqual(self._build_empty_state_result(), state)

    @staticmethod
    def _build_cbsd_request() -> CBSDRequest:
        return CBSDRequest(
            user_id=USER_ID,
            fcc_id=FCC_ID,
            serial_number=SERIAL_NUMBER,
            min_power=0,
            max_power=20,
            antenna_gain=15,
            number_of_ports=2,
        )

    @staticmethod
    def _build_get_state_result() -> CBSDStateResult:
        return CBSDStateResult(
            radio_enabled=True,
            channel=LteChannel(
                low_frequency_hz=3620_000_000,
                high_frequency_hz=3630_000_000,
                max_eirp_dbm_mhz=28.0,
            ),
        )

    @staticmethod
    def _build_empty_state_result() -> CBSDStateResult:
        return CBSDStateResult(radio_enabled=False)
示例#10
0
class DomainProxyOrc8rTestCase(DBTestCase):
    @classmethod
    def setUpClass(cls):
        wait_for_elastic_to_start()

    def setUp(self):
        super().setUp()
        DBInitializer(SessionManager(self.engine)).initialize()
        grpc_channel = grpc.insecure_channel(
            f"{config.GRPC_SERVICE}:{config.GRPC_PORT}",
        )
        self.dp_client = DPServiceStub(grpc_channel)
        when_elastic_indexes_data()
        _delete_dp_elasticsearch_indices()

    def tearDown(self):
        super().tearDown()
        _delete_dp_elasticsearch_indices()

    # retrying is needed because of a possible deadlock
    # with cc locking request table
    @retry(stop_max_attempt_number=5, wait_fixed=100)
    def drop_all(self):
        super().drop_all()

    def test_cbsd_sas_flow(self):
        cbsd_id = self.given_cbsd_provisioned(CbsdAPIDataBuilder())

        with self.while_cbsd_is_active():
            when_elastic_indexes_data()

            logs = self.when_logs_are_fetched(get_current_sas_filters())
            self.then_logs_are(logs, self.get_sas_provision_messages())

            filters = get_filters_for_request_type('heartbeat')
            self.then_message_is_eventually_sent(filters)

        self.delete_cbsd(cbsd_id)

    def test_sas_flow_restarted_for_updated_cbsd(self):
        cbsd_id = self.given_cbsd_provisioned(CbsdAPIDataBuilder())

        with self.while_cbsd_is_active():
            builder = CbsdAPIDataBuilder().with_fcc_id(OTHER_FCC_ID)
            self.when_cbsd_is_updated(cbsd_id, builder.build_post_data())

            filters = get_filters_for_request_type('deregistration')
            self.then_message_is_eventually_sent(filters)

            self.then_state_is_eventually(builder.build_grant_state_data())

            cbsd = self.when_cbsd_is_fetched()
            self.then_cbsd_is(cbsd, builder.build_registered_active_data())

        self.delete_cbsd(cbsd_id)

    def test_activity_status(self):
        builder = CbsdAPIDataBuilder()
        cbsd_id = self.given_cbsd_provisioned(builder)

        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, builder.build_registered_active_data())

        self.when_cbsd_is_inactive()
        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, builder.build_registered_inactive_data())

        self.delete_cbsd(cbsd_id)

    def test_frequency_preferences(self):
        builder = CbsdAPIDataBuilder(). \
            with_frequency_preferences(5, [3625]). \
            with_expected_grant(5, 3625, 31)
        cbsd_id = self.given_cbsd_provisioned(builder)

        self.delete_cbsd(cbsd_id)

    def test_creating_cbsd_with_the_same_unique_fields_returns_409(self):
        builder = CbsdAPIDataBuilder()

        self.when_cbsd_is_created(builder.build_post_data())
        self.when_cbsd_is_created(builder.build_post_data(), expected_status=HTTPStatus.CONFLICT)

    def test_updating_cbsd_returns_409_when_setting_existing_serial_num(self):
        builder = CbsdAPIDataBuilder()

        cbsd1_payload = builder.build_post_data_with_serial_number("foo")
        cbsd2_payload = builder.build_post_data_with_serial_number("bar")
        self.when_cbsd_is_created(cbsd1_payload)  # cbsd_id = 1
        self.when_cbsd_is_created(cbsd2_payload)  # cbsd_id = 2
        self.when_cbsd_is_updated(
            cbsd_id=2,
            data=cbsd1_payload,
            expected_status=HTTPStatus.CONFLICT,
        )

    def test_fetching_logs_with_custom_filters(self):
        self.given_cbsd_provisioned(CbsdAPIDataBuilder())
        when_elastic_indexes_data()

        sas_to_dp_end_date_only = {
            'serial_number': SERIAL_NUMBER,
            'from': SAS,
            'to': DP,
            'end': now(),
        }
        sas_to_dp_begin_date_only = {
            'serial_number': SERIAL_NUMBER,
            'from': SAS,
            'to': DP,
            'begin': DATETIME_WAY_BACK,
        }
        sas_to_dp_end_date_too_early = {
            'serial_number': SERIAL_NUMBER,
            'from': SAS,
            'to': DP,
            'end': DATETIME_WAY_BACK,
        }
        dp_to_sas = {
            'serial_number': SERIAL_NUMBER,
            'from': DP,
            'to': SAS,
        }
        dp_to_sas_incorrect_serial_number = {
            'serial_number': 'incorrect_serial_number',
            'from': DP,
            'to': SAS,
        }
        sas_to_dp_with_limit = {
            'limit': '100',
            'from': SAS,
            'to': DP,
        }
        sas_to_dp_with_limit_and_too_large_offset = {
            'limit': '100',
            'offset': '100',
            'from': SAS,
            'to': DP,
        }
        scenarios = [
            (sas_to_dp_end_date_only, operator.eq, 4, HTTPStatus.OK),
            (sas_to_dp_begin_date_only, operator.eq, 4, HTTPStatus.OK),
            (sas_to_dp_end_date_too_early, operator.eq, 0, HTTPStatus.OK),
            (dp_to_sas, operator.gt, 0, HTTPStatus.OK),
            (dp_to_sas_incorrect_serial_number, operator.eq, 0, HTTPStatus.OK),
            (sas_to_dp_with_limit, operator.eq, 4, HTTPStatus.OK),
            (sas_to_dp_with_limit_and_too_large_offset, operator.eq, 0, HTTPStatus.OK),
        ]

        for params in scenarios:
            self._verify_logs_count(params)

    def given_cbsd_provisioned(self, builder: CbsdAPIDataBuilder) -> int:
        self.when_cbsd_is_created(builder.build_post_data())
        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, builder.build_unregistered_data())

        state = self.when_cbsd_asks_for_state()
        self.then_state_is(state, get_empty_state())

        self.then_state_is_eventually(builder.build_grant_state_data())

        cbsd = self.when_cbsd_is_fetched()
        self.then_cbsd_is(cbsd, builder.build_registered_active_data())

        return cbsd['id']

    def when_cbsd_is_created(self, data: Dict[str, Any], expected_status: int = HTTPStatus.CREATED):
        r = send_request_to_backend('post', 'cbsds', json=data)
        self.assertEqual(r.status_code, expected_status)

    def when_cbsd_is_fetched(self) -> Dict[str, Any]:
        r = send_request_to_backend('get', 'cbsds')
        self.assertEqual(r.status_code, HTTPStatus.OK)
        data = r.json()
        self.assertEqual(data.get('total_count'), 1)
        cbsds = data.get('cbsds', [])
        self.assertEqual(len(cbsds), 1)
        return cbsds[0]

    def when_logs_are_fetched(self, params: Dict[str, Any]) -> Dict[str, Any]:
        r = send_request_to_backend('get', 'logs', params=params)
        self.assertEqual(r.status_code, HTTPStatus.OK)
        data = r.json()
        return data

    def when_cbsd_is_deleted(self, cbsd_id: int):
        r = send_request_to_backend('delete', f'cbsds/{cbsd_id}')
        self.assertEqual(r.status_code, HTTPStatus.NO_CONTENT)

    def when_cbsd_is_updated(self, cbsd_id: int, data: Dict[str, Any], expected_status: int = HTTPStatus.NO_CONTENT):
        r = send_request_to_backend('put', f'cbsds/{cbsd_id}', json=data)
        self.assertEqual(r.status_code, expected_status)

    def when_cbsd_asks_for_state(self) -> CBSDStateResult:
        return self.dp_client.GetCBSDState(get_cbsd_request())

    @staticmethod
    def when_cbsd_is_inactive():
        inactivity = 3
        polling = 1
        delta = 3
        total_wait_time = inactivity + 2 * polling + delta
        sleep(total_wait_time)

    @contextmanager
    def while_cbsd_is_active(self):
        done = Event()

        def keep_asking_for_state():
            while not done.wait(timeout=1):
                self.when_cbsd_asks_for_state()

        t = Thread(target=keep_asking_for_state)
        try:
            t.start()
            yield
        finally:
            done.set()
            t.join()

    def then_cbsd_is(self, actual: Dict[str, Any], expected: Dict[str, Any]):
        actual = actual.copy()
        del actual['id']
        grant = actual.get('grant')
        if grant:
            del grant['grant_expire_time']
            del grant['transmit_expire_time']
        self.assertEqual(actual, expected)

    def then_cbsd_is_deleted(self):
        r = send_request_to_backend('get', 'cbsds')
        self.assertEqual(r.status_code, HTTPStatus.OK)
        data = r.json()
        self.assertFalse(data.get('total_count', True))

    def then_state_is(self, actual: CBSDStateResult, expected: CBSDStateResult):
        self.assertEqual(actual, expected)

    @retry(stop_max_attempt_number=30, wait_fixed=1000)
    def then_state_is_eventually(self, expected):
        actual = self.when_cbsd_asks_for_state()
        self.then_state_is(actual, expected)

    def then_logs_are(self, actual: Dict[str, Any], expected: List[str]):
        actual = [x['type'] for x in actual['logs']]
        self.assertEqual(actual, expected)

    @retry(stop_max_attempt_number=60, wait_fixed=1000)
    def then_message_is_eventually_sent(self, filters: Dict[str, Any]):
        logs = self.when_logs_are_fetched(filters)
        self.assertEqual(logs["total_count"], 1)

    def delete_cbsd(self, cbsd_id: int):
        filters = get_filters_for_request_type('deregistration')

        self.when_cbsd_is_deleted(cbsd_id)
        self.then_cbsd_is_deleted()

        state = self.when_cbsd_asks_for_state()
        self.then_state_is(state, get_empty_state())

        self.then_message_is_eventually_sent(filters)

    @staticmethod
    def get_sas_provision_messages() -> List[str]:
        names = ['heartbeat', 'grant', 'spectrumInquiry', 'registration']
        return [f'{x}Response' for x in names]

    def _verify_logs_count(self, params):
        using_filters, _operator, expected_count, expected_status = params
        logs = self.when_logs_are_fetched(using_filters)

        comparison = _operator(len(logs["logs"]), expected_count)
        self.assertTrue(comparison)
示例#11
0
 def setUpClass(cls) -> None:
     super().setUpClass()
     cls.maxDiff = None
     grpc_channel = grpc.insecure_channel(
         f"{config.GRPC_SERVICE}:{config.GRPC_PORT}", )
     cls.dp_client = DPServiceStub(grpc_channel)
示例#12
0
class ActiveModeControllerTestCase(DBTestCase):
    @classmethod
    def setUpClass(cls):
        wait_for_elastic_to_start()

    def setUp(self):
        super().setUp()
        grpc_channel = grpc.insecure_channel(
            f"{config.GRPC_SERVICE}:{config.GRPC_PORT}", )
        self.dp_client = DPServiceStub(grpc_channel)
        DBInitializer(SessionManager(self.engine)).initialize()
        # Indexing from previous test may not have been finished yet
        sleep(5)
        self._delete_dp_elasticsearch_indices()

    # retrying is needed because of a possible deadlock
    # with cc locking request table
    @retry(stop_max_attempt_number=5, wait_fixed=100)
    def drop_all(self):
        super().drop_all()

    def tearDown(self):
        super().tearDown()
        self._delete_dp_elasticsearch_indices()

    def test_provision_cbsd_in_sas_requested_by_dp_client(self):
        self.given_cbsd_provisioned()

    def test_logs_are_written_to_elasticsearch(self):
        self.given_cbsd_provisioned()
        # Giving ElasticSearch time to index logs
        sleep(5)
        self.then_elasticsearch_contains_logs()

    def test_grant_relinquished_after_inactivity(self):
        self.given_cbsd_provisioned()
        self.when_cbsd_is_inactive()
        self.then_cbsd_has_no_grants_in_sas(self.dp_client)

    def test_last_used_max_eirp_stays_the_same_after_inactivity(self):
        self.given_cbsd_provisioned()
        self.when_cbsd_is_inactive()
        self.then_cbsd_has_no_grants_in_sas(self.dp_client)
        self.given_cbsd_provisioned()

    def given_cbsd_provisioned(self):
        self.given_cbsd_with_transmission_parameters()
        self.dp_client.GetCBSDState(self._build_cbsd_request())

        self.then_cbsd_is_eventually_provisioned_in_sas(self.dp_client)

    def then_elasticsearch_contains_logs(self):
        actual = requests.get(
            f"{config.ELASTICSEARCH_URL}/dp*/_search?size=100").json()
        log_field_names = [
            "log_from",
            "log_to",
            "log_name",
            "log_message",
            "cbsd_serial_number",
            "network_id",
            "fcc_id",
        ]
        actual_log_types = defaultdict(int)
        logs = actual["hits"]["hits"]
        for log in logs:
            actual_log_types[log["_source"]["log_name"]] += 1
            for fn in log_field_names:
                self.assertIn(fn, log["_source"].keys())

        self.assertEqual(1, actual_log_types["CBSDRegisterRequest"])
        self.assertEqual(1, actual_log_types["CBSDRegisterResponse"])
        self.assertEqual(1, actual_log_types["registrationRequest"])
        self.assertEqual(1, actual_log_types["registrationResponse"])
        self.assertEqual(1, actual_log_types["spectrumInquiryRequest"])
        self.assertEqual(1, actual_log_types["spectrumInquiryResponse"])
        self.assertEqual(1, actual_log_types["spectrumInquiryResponse"])
        self.assertEqual(1, actual_log_types["grantRequest"])
        self.assertEqual(1, actual_log_types["grantResponse"])
        self.assertEqual(1, actual_log_types["heartbeatRequest"])
        # The number of GetCBSDStateRequest and heartbeatResponse may differ between tests, so only asserting they have been logged
        self.assertGreater(actual_log_types["heartbeatResponse"], 0)
        self.assertGreater(actual_log_types["GetCBSDStateRequest"], 0)
        self.assertGreater(actual_log_types["GetCBSDStateResponse"], 0)

    # TODO change this when some API for domain proxy is introduced
    def given_cbsd_with_transmission_parameters(self):
        state = self.dp_client.CBSDRegister(
            self._build_cbsd_request(),
            wait_for_ready=True,
        )
        self.session.commit()
        self.assertEqual(self._build_empty_state_result(), state)

    @staticmethod
    def when_cbsd_is_inactive():
        inactivity = 3
        polling = 1
        delta = 3  # TODO investigate if such high delta is needed
        total_wait_time = inactivity + 2 * polling + delta
        sleep(total_wait_time)

    @retry(stop_max_attempt_number=30, wait_fixed=1000)
    def then_cbsd_is_eventually_provisioned_in_sas(self,
                                                   dp_client: DPServiceStub):
        state = dp_client.GetCBSDState(self._build_cbsd_request())
        self.assertEqual(self._build_get_state_result(), state)

    def then_cbsd_has_no_grants_in_sas(self, dp_client: DPServiceStub):
        state = dp_client.GetCBSDState(self._build_cbsd_request())
        self.assertEqual(self._build_empty_state_result(), state)

    @staticmethod
    def _build_cbsd_request() -> CBSDRequest:
        return CBSDRequest(
            user_id=USER_ID,
            fcc_id=FCC_ID,
            serial_number=SERIAL_NUMBER,
            min_power=0,
            max_power=20,
            antenna_gain=15,
            number_of_ports=2,
        )

    @staticmethod
    def _build_get_state_result() -> CBSDStateResult:
        return CBSDStateResult(
            radio_enabled=True,
            channel=LteChannel(
                low_frequency_hz=3620_000_000,
                high_frequency_hz=3630_000_000,
                max_eirp_dbm_mhz=28.0,
            ),
        )

    @staticmethod
    def _build_empty_state_result() -> CBSDStateResult:
        return CBSDStateResult(radio_enabled=False)

    def _delete_dp_elasticsearch_indices(self):
        requests.delete(
            f"{config.ELASTICSEARCH_URL}/{config.ELASTICSEARCH_INDEX}*")