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
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)
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 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()
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
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)
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)
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)
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)
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}*")