def test_WINNF_FT_S_SSS_15(self, config_filename): """Certificate with inapplicable fields presented during Full Activity Dump """ config = loadConfig(config_filename) # Reset the SAS UUT self.SasReset() # Notify SAS UUT about peer SAS certificate_hash = getCertificateFingerprint(config['sasCert']) self._sas_admin.InjectPeerSas({'certificateHash': certificate_hash,\ 'url': SAS_TEST_HARNESS_URL }) self.assertTlsHandshakeSucceed(self._sas_admin._base_url, ['AES128-GCM-SHA256'], config['sasCert'], config['sasKey']) trigger_succeed = False # Initiate Full Activity Dump try: self.TriggerFullActivityDumpAndWaitUntilComplete( config['sasCert'], config['sasKey']) trigger_succeed = True except HTTPError as e: # Check if HTTP status is 403 self.assertEqual(e.error_code, 403) self.assertFalse(trigger_succeed, "Full Activity Dump is expected to fail")
def test_WINNF_FT_S_SSS_11(self, config_filename): """Blacklisted certificate presented by SAS Test Harness. Checks that SAS UUT response with fatal alert message. """ # Reset SAS UUT self.SasReset() # Read the configuration config = loadConfig(config_filename) # Read the fingerprint from the certificate certificate_hash = getCertificateFingerprint(config['sasCert']) self._sas_admin.InjectPeerSas({ 'certificateHash': certificate_hash, 'url': SAS_TEST_HARNESS_URL }) # Tls handshake fails or Http 403 self.assertTlsHandshakeFailureOrHttp403(client_cert=config['sasCert'], client_key=config['sasKey'], is_sas=True) logging.info( "TLS handshake failed as the sas certificate has blacklisted")
def test_WINNF_FT_S_SSS_10(self, config_filename): """Certificate of wrong type presented during Full Activity Dump. Checks that SAS UUT response with fatal alert message. """ config = loadConfig(config_filename) # Reset the SAS UUT self.SasReset() # Notify SAS UUT about peer SAS certificate_hash = getCertificateFingerprint(config['sasCert']) self._sas_admin.InjectPeerSas({'certificateHash': certificate_hash,\ 'url': SAS_TEST_HARNESS_URL}) try: self.assertTlsHandshakeFailure(client_cert=config['sasCert'], client_key=config['sasKey']) except AssertionError: trigger_succeed = False try: self.TriggerFullActivityDumpAndWaitUntilComplete( config['sasCert'], config['sasKey']) trigger_succeed = True except HTTPError as e: # Check if HTTP status is 403 self.assertEqual(e.error_code, 403) self.assertFalse(trigger_succeed, "Full Activity Dump is expected to fail")
def test_WINNF_FT_S_SSS_12(self, config_filename): """Expired certificate presented by SAS Test Harness. Checks that SAS UUT response with fatal alert message. """ self.SasReset() config = loadConfig(config_filename) certificate_hash = getCertificateFingerprint(config['sasCert']) self._sas_admin.InjectPeerSas({ 'certificateHash': certificate_hash, 'url': SAS_TEST_HARNESS_URL }) self.assertTlsHandshakeFailureOrHttp403(client_cert=config['sasCert'], client_key=config['sasKey'], is_sas=True)
def test_WINNF_FT_S_SSS_18(self, config_filename): """Security requirement for Full Activity Dump message Request """ config = loadConfig(config_filename) # Reset the SAS UUT self.SasReset() # Notify SAS UUT about peer SAS certificate_hash = getCertificateFingerprint( config['validCertKeyPair']['cert']) self._sas_admin.InjectPeerSas({'certificateHash': certificate_hash,\ 'url': SAS_TEST_HARNESS_URL }) # Load a Device device_a = json.load( open(os.path.join('testcases', 'testdata', 'device_a.json'))) # Load grant request grant_a = json.load( open(os.path.join('testcases', 'testdata', 'grant_0.json'))) cbsd_ids, grant_ids = self.assertRegisteredAndGranted([device_a], [grant_a]) # Initiate Full Activity Dump with valid cert, key pair fadResponse = self.TriggerFullActivityDumpAndWaitUntilComplete(config['validCertKeyPair']['cert'], \ config['validCertKeyPair']['key']) self.assertContainsRequiredFields("FullActivityDump.schema.json", fadResponse) url = fadResponse['files'][0]['url'] # Attempting FAD record download with different invalid cert,key pair try: # This uses the same base_url as GetFullActivityDump(). self.assertTlsHandshakeFailure( self._sas.sas_sas_active_base_url, client_cert=config['invalidCertKeyPair']['cert'], client_key=config['invalidCertKeyPair']['key']) except AssertionError as e: try: self._sas.DownloadFile(url,config['invalidCertKeyPair']['cert'], \ config['invalidCertKeyPair']['key']) except HTTPError as e: self.assertEqual(e.error_code, 403) else: self.fail("FAD record file download should have failed")
def test_WINNF_FT_S_SSS_13(self, config_filename): """ Disallowed TLS method attempted during registration. Checks that SAS UUT response with fatal alert message. """ self.SasReset() # Load the configuration config = loadConfig(config_filename) # Read the fingerprint from the certificate certificate_hash = getCertificateFingerprint(config['sasCert']) self._sas_admin.InjectPeerSas({ 'certificateHash': certificate_hash, 'url': SAS_TEST_HARNESS_URL }) self.assertTlsHandshakeFailureOrHttp403(client_cert=config['sasCert'], client_key=config['sasKey'], ssl_method=SSL.TLSv1_1_METHOD, is_sas=True)
def test_WINNF_FT_S_SSS_14(self, config_filename): """ Invalid cipher suite presented during registration. Checks that SAS UUT response with fatal alert message. """ self.SasReset() # Load the configuration config = loadConfig(config_filename) # Read the fingerprint from the certificate certificate_hash = getCertificateFingerprint(config['sasCert']) self._sas_admin.InjectPeerSas({ 'certificateHash': certificate_hash, 'url': SAS_TEST_HARNESS_URL }) self.assertTlsHandshakeFailureOrHttp403( client_cert=config['sasCert'], client_key=config['sasKey'], ciphers='ECDHE-RSA-AES256-GCM-SHA384', is_sas=True)
def triggerFadGenerationAndRetrievePpaZone(self, ssl_cert, ssl_key): """Triggers FAD and Retrieves PPA Zone Record. Pulls FAD from SAS UUT. Retrieves the ZoneData Records from FAD, checks that only one record is present. Args: ssl_cert: Path to SAS type cert file to be used for pulling FAD record. ssl_key: Path to SAS type key file to be used for pulling FAD record. Returns: A PPA record of format of ZoneData Object. """ # Notify the SAS UUT about the SAS Test Harness. certificate_hash = getCertificateFingerprint(ssl_cert) self._sas_admin.InjectPeerSas({ 'certificateHash': certificate_hash, 'url': SAS_TEST_HARNESS_URL }) # As SAS is reset at the beginning of the test, the FAD records should # contain only one zone record containing the PPA that was generated. # Hence the first zone record is retrieved. uut_fad = getFullActivityDumpSasUut(self._sas, self._sas_admin, ssl_cert, ssl_key) # Check if the retrieved FAD that has valid and at least one # PPA zone record. uut_ppa_zone_data = uut_fad.getZoneRecords() self.assertEquals( len(uut_ppa_zone_data), 1, msg='There is no single PPA Zone record received from SAS' ' UUT') return uut_ppa_zone_data[0]
def doSasTestCipher(self, cipher, client_cert, client_key, client_url): """Does a cipher test as described in SSS tests 1 to 5 specification. Args: cipher: the cipher openSSL string name to test. client_cert: path to (peer) SAS client certificate file in PEM format to use. client_key: path to associated key file in PEM format to use. client_url: base URL of the (peer) SAS client. """ self._sas.UpdateSasRequestUrl(cipher) # Does a regular SAS registration self.SasReset() certificate_hash = getCertificateFingerprint(client_cert) self._sas_admin.InjectPeerSas({ 'certificateHash': certificate_hash, 'url': client_url }) # Using pyOpenSSL low level API, does the SAS UUT server TLS session checks. self.assertTlsHandshakeSucceed(self._sas.sas_sas_active_base_url, [cipher], client_cert, client_key) self._sas_admin.TriggerFullActivityDump() with CiphersOverload(self._sas, [cipher], client_cert, client_key): self._sas.GetFullActivityDump(client_cert, client_key)
def test_WINNF_FT_S_FAD_2(self, config_filename): """Full Activity Dump Pull Command by SAS UUT. Checks SAS UUT can successfully request a Full Activity Dump and utilize the retrieved data. Checks SAS UUT responds with HeartbeatResponse either GRANT_TERMINATED or INVALID_VALUE, indicating a terminated Grant. """ config = loadConfig(config_filename) device_c2 = config['registrationRequestC2'] device_c4 = config['registrationRequestC4'] grant_g2 = config['grantRequestG2'] grant_g4 = config['grantRequestG4'] sas_test_harness_dump_records = [ config['sasTestHarnessDumpRecords']['cbsdRecords'], config['sasTestHarnessDumpRecords']['ppaRecords'], config['sasTestHarnessDumpRecords']['escSensorRecords'] ] # Initialize SAS Test Harness Server instance to dump FAD records sas_test_harness = SasTestHarnessServer( config['sasTestHarnessConfig']['sasTestHarnessName'], config['sasTestHarnessConfig']['hostName'], config['sasTestHarnessConfig']['port'], config['sasTestHarnessConfig']['serverCert'], config['sasTestHarnessConfig']['serverKey'], config['sasTestHarnessConfig']['caCert']) self.InjectTestHarnessFccIds( config['sasTestHarnessDumpRecords']['cbsdRecords']) sas_test_harness.writeFadRecords(sas_test_harness_dump_records) # Start the server sas_test_harness.start() # Whitelist the FCCID and UserID for CBSD C2 in SAS UUT self._sas_admin.InjectFccId({'fccId': device_c2['fccId']}) self._sas_admin.InjectUserId({'userId': device_c2['userId']}) # Whitelist the FCCID and UserID for CBSD C4 in SAS UUT self._sas_admin.InjectFccId({'fccId': device_c4['fccId']}) self._sas_admin.InjectUserId({'userId': device_c4['userId']}) # Whitelist the FCCID and UserID of the devices loaded to SAS-test_harness in SAS UUT for cbsdRecord in config['sasTestHarnessDumpRecords']['cbsdRecords']: self._sas_admin.InjectFccId( {'fccId': cbsdRecord['registration']['fccId']}) # Pre-load conditional registration data for C2 and C4 CBSDs. if ('conditionalRegistrationData' in config) and (config['conditionalRegistrationData']): self._sas_admin.PreloadRegistrationData( config['conditionalRegistrationData']) # Register devices C2 and C4, request grants G2 and G4 respectively with SAS UUT. # Ensure the registration and grant requests are successful. try: cbsd_ids, grant_ids = self.assertRegisteredAndGranted( [device_c2, device_c4], [grant_g2, grant_g4]) except Exception: logging.error( common_strings.EXPECTED_SUCCESSFUL_REGISTRATION_AND_GRANT) raise # Send the Heartbeat request for the Grant G2 and G4 of CBSD C2 and C4 # respectively to SAS UUT. transmit_expire_times = self.assertHeartbeatsSuccessful( cbsd_ids, grant_ids, ['GRANTED', 'GRANTED']) # Notify the SAS UUT about the SAS Test Harness certificate_hash = getCertificateFingerprint( config['sasTestHarnessConfig']['serverCert']) self._sas_admin.InjectPeerSas({ 'certificateHash': certificate_hash, 'url': sas_test_harness.getBaseUrl() }) # Injecting the PAL Records of the PPA into SAS UUT. for pal_record in config['palRecords']: try: self._sas_admin.InjectPalDatabaseRecord(pal_record) except Exception: logging.error(common_strings.CONFIG_ERROR_SUSPECTED) raise # Trigger CPAS in the SAS UUT and wait until complete. self.TriggerDailyActivitiesImmediatelyAndWaitUntilComplete() # Send the Heartbeat request again for the G2 and G4 to SAS UUT request = { 'heartbeatRequest': [{ 'cbsdId': cbsd_ids[0], 'grantId': grant_ids[0], 'operationState': 'GRANTED' }, { 'cbsdId': cbsd_ids[1], 'grantId': grant_ids[1], 'operationState': 'GRANTED' }] } response = self._sas.Heartbeat(request)['heartbeatResponse'] # Check the length of request and response match. self.assertEqual(len(request['heartbeatRequest']), len(response)) # Check grant response, must be response code 0. for resp in response: self.assertTrue(resp['response']['responseCode'] in (103, 500)) # As Python garbage collector is not very consistent, directory is not getting deleted. # Hence, explicitly stopping SAS Test Hanress and cleaning up sas_test_harness.shutdown() del sas_test_harness
def test_WINNF_FT_S_FAD_1(self, config_filename): """ This test verifies that a SAS UUT can successfully respond to a full activity dump request from a SAS Test Harness SAS UUT approves the request and responds, with correct content and format for both dump message and files """ # load config file config = loadConfig(config_filename) # Very light checking of the config file. self.assertEqual(len(config['registrationRequests']), len(config['grantRequests'])) # check that the config file contains consistent PAL&PPA data for index, grant in enumerate(config['grantRequests']): grant_frequency_range = grant['operationParam'][ 'operationFrequencyRange'] for ppa in config['ppaRecords']: if index in ppa['ppaClusterList']: frequency_ranges_of_pals = [{'frequencyRange' : {'lowFrequency' : pal['channelAssignment']['primaryAssignment']['lowFrequency'],\ 'highFrequency' : pal['channelAssignment']['primaryAssignment']['highFrequency']}} \ for pal in config['palRecords'] if pal['palId'] in ppa['ppaRecord']['ppaInfo']['palId']] self.assertLessEqual( 1, frequency_ranges_of_pals, 'Empty list of Frequency Ranges in the PAL config') low_freq = min([ freq_range['frequencyRange']['lowFrequency'] for freq_range in frequency_ranges_of_pals ]) high_freq = max([ freq_range['frequencyRange']['highFrequency'] for freq_range in frequency_ranges_of_pals ]) self.assertChannelsContainFrequencyRange( frequency_ranges_of_pals, { 'lowFrequency': low_freq, 'highFrequency': high_freq }) # check that the grant in config file is not mixed of PAL and GAA channels if low_freq <= grant_frequency_range[ 'lowFrequency'] <= high_freq: self.assertLessEqual( grant_frequency_range['highFrequency'], high_freq, 'incorrect high frequency of the grant with index {0}, makes it GAA&PAL Mixed Grant' .format(index)) if low_freq <= grant_frequency_range[ 'highFrequency'] <= high_freq: self.assertGreaterEqual( grant_frequency_range['lowFrequency'], low_freq, 'incorrect low frequency of the grant with index {0}, makes it a GAA&PAL Mixed Grant' .format(index)) for index, device in enumerate(config['registrationRequests']): # check azimuth in the CBSD config, if the beamwidth is not 0 or 360 and the azimuth is not provided, CBSD registration may be rejected reg_conditional_device_data_list = [reg for reg in \ config['conditionalRegistrationData']['registrationData'] if reg['fccId'] == device['fccId'] and \ reg['cbsdSerialNumber'] == device['cbsdSerialNumber'] ] if len(reg_conditional_device_data_list) == 1: reg_conditional_installation_param = reg_conditional_device_data_list[ 0]['installationParam'] elif len(reg_conditional_device_data_list) > 1: self.fail( 'invalid conditional Registration Data, multi conditional Registration configs for the cbsd with index: {0} ' .format(index)) else: reg_conditional_installation_param = {} registeration_antenna_azimuth = device['installationParam']['antennaAzimuth'] \ if 'installationParam' in device and 'antennaAzimuth' in device['installationParam'] \ else reg_conditional_installation_param['antennaAzimuth'] \ if 'antennaAzimuth' in reg_conditional_installation_param else None registeration_antenna_beamwidth = device['installationParam']['antennaBeamwidth'] \ if 'installationParam' in device and 'antennaBeamwidth' in device['installationParam'] \ else reg_conditional_installation_param['antennaBeamwidth'] \ if 'antennaBeamwidth' in reg_conditional_installation_param else None if registeration_antenna_beamwidth != None and registeration_antenna_beamwidth not in [0, 360]\ and registeration_antenna_azimuth is None: self.fail( 'invalid config, missing azimuth value for CBSD config with index: {0} ' .format(index)) # inject FCC ID and User ID of CBSD self._sas_admin.InjectFccId({ 'fccId': device['fccId'], 'fccMaxEirp': 47 }) self._sas_admin.InjectUserId({'userId': device['userId']}) # Pre-load conditional registration data for N3 CBSDs. self._sas_admin.PreloadRegistrationData( config['conditionalRegistrationData']) # Register N1 CBSDs. request = {'registrationRequest': config['registrationRequests']} responses = self._sas.Registration(request)['registrationResponse'] # Check registration responses and get cbsd Id self.assertEqual(len(responses), len(config['registrationRequests'])) cbsd_ids = [] for response in responses: self.assertEqual(response['response']['responseCode'], 0) cbsd_ids.append(response['cbsdId']) # inject PALs and N2 PPAs ppa_ids = [] for pal in config['palRecords']: try: self._sas_admin.InjectPalDatabaseRecord(pal) except Exception: logging.error(common_strings.CONFIG_ERROR_SUSPECTED) raise for ppa in config['ppaRecords']: # fill the PPA cbsdReferenceIds with values according to admin testing API spec ppa['ppaRecord']['ppaInfo']['cbsdReferenceId'] = [] for index in ppa['ppaClusterList']: ppa['ppaRecord']['ppaInfo']['cbsdReferenceId'].append( cbsd_ids[index]) try: ppa_ids.append( self._sas_admin.InjectZoneData( {'record': ppa['ppaRecord']})) except Exception: logging.error(common_strings.CONFIG_ERROR_SUSPECTED) raise # re-fill the PPA cbsdReferenceIds with the values expected in the dump according to SAS-SAS TS ppa['ppaRecord']['ppaInfo']['cbsdReferenceId'] = [] for index in ppa['ppaClusterList']: cbsd = config['registrationRequests'][index] ppa['ppaRecord']['ppaInfo']['cbsdReferenceId'].append( generateCbsdReferenceId(cbsd['fccId'], cbsd['cbsdSerialNumber'])) grants = config['grantRequests'] for index, response in enumerate(responses): self.assertEqual(response['response']['responseCode'], 0) grants[index]['cbsdId'] = response['cbsdId'] # send grant request with N1 grants del responses grant_responses = self._sas.Grant({'grantRequest': grants})['grantResponse'] # check grant response self.assertEqual(len(grant_responses), len(config['grantRequests'])) for grant_response in grant_responses: self.assertEqual(grant_response['response']['responseCode'], 0) # inject N3 Esc sensor for esc_sensor in config['escSensorRecords']: try: self._sas_admin.InjectEscSensorDataRecord( {'record': esc_sensor}) except Exception: logging.error(common_strings.CONFIG_ERROR_SUSPECTED) raise # step 7 # Notify the SAS UUT about the SAS Test Harness for sas_th in config['sasTestHarnessConfigs']: certificate_hash = getCertificateFingerprint(sas_th['serverCert']) url = 'https://' + sas_th['hostName'] + ':' + str(sas_th['port']) self._sas_admin.InjectPeerSas({ 'certificateHash': certificate_hash, 'url': url }) sas_th_config = config['sasTestHarnessConfigs'][0] response = self.TriggerFullActivityDumpAndWaitUntilComplete( sas_th_config['serverCert'], sas_th_config['serverKey']) # verify that all the SASes get the same response : # check dump message format self.assertContainsRequiredFields("FullActivityDump.schema.json", response) # an array for each record type cbsd_dump_data = [] ppa_dump_data = [] esc_sensor_dump_data = [] # step 8 and check # download dump files and fill corresponding arrays downloaded_files = {} for dump_file in response['files']: self.assertContainsRequiredFields("ActivityDumpFile.schema.json", dump_file) downloaded_file = None if dump_file['recordType'] != 'coordination': downloaded_file = self._sas.DownloadFile(dump_file['url'],\ sas_th_config['serverCert'], sas_th_config['serverKey']) # The downloaded_file is being modified in the assertions below, # and hence we need a deep copy to verify that dump files are the # same when requested by different SASs. downloaded_files[dump_file['url']] = copy.deepcopy( downloaded_file) if dump_file['recordType'] == 'cbsd': cbsd_dump_data.extend(downloaded_file['recordData']) elif dump_file['recordType'] == 'esc_sensor': esc_sensor_dump_data.extend(downloaded_file['recordData']) elif dump_file['recordType'] == 'zone': ppa_dump_data.extend(downloaded_file['recordData']) else: self.assertEqual('coordination', dump_file['recordType']) # verify the length of records equal to the inserted ones self.assertEqual(len(config['registrationRequests']), len(cbsd_dump_data)) self.assertEqual(len(config['ppaRecords']), len(ppa_dump_data)) self.assertEqual(len(config['escSensorRecords']), len(esc_sensor_dump_data)) # verify the schema of record and first two parts of PPA record Id for ppa_record in ppa_dump_data: self.assertContainsRequiredFields("ZoneData.schema.json", ppa_record) self.assertEqual(ppa_record['id'].split("/")[0], 'zone') self.assertEqual(ppa_record['id'].split("/")[1], 'ppa') self.assertEqual(ppa_record['id'].split("/")[2], self._sas._sas_admin_id) del ppa_record['id'] # remove creator from value check del ppa_record['creator'] # verify that the injected ppas exist in the dump files # check GeoJson Winding of PPA record utils.HasCorrectGeoJsonWinding( ppa_record['zone']['features'][0]['geometry']) exist_in_dump = False for ppa_conf in config['ppaRecords']: ppa = ppa_conf['ppaRecord'] if 'id' in ppa: del ppa['id'] # remove creator from value check if 'creator' in ppa: del ppa['creator'] exist_in_dump = exist_in_dump or areTwoPpasEqual( ppa_record, ppa) if exist_in_dump: break self.assertTrue(exist_in_dump) # verify the schema of record and two first parts of esc sensor record Id for esc_record in esc_sensor_dump_data: self.assertContainsRequiredFields("EscSensorRecord.schema.json", esc_record) self.assertEqual(esc_record['id'].split("/")[0], 'esc_sensor') self.assertEqual(esc_record['id'].split("/")[1], self._sas._sas_admin_id) del esc_record['id'] # verify that all the injected Esc sensors exist in the dump files exist_in_dump = False for esc in config['escSensorRecords']: if 'id' in esc: del esc['id'] exist_in_dump = exist_in_dump or compareDictWithUnorderedLists( esc_record, esc) if exist_in_dump: break self.assertTrue(exist_in_dump) # verify that retrieved cbsd dump files have correct schema for cbsd_record in cbsd_dump_data: self.assertContainsRequiredFields("CbsdData.schema.json", cbsd_record) self.assertFalse("cbsdInfo" in cbsd_record) # verify all the previous activities on CBSDs and Grants exist in the dump files self.assertCbsdRecord(config['registrationRequests'], grants, grant_responses, cbsd_dump_data, config['conditionalRegistrationData']) # step 10 check all SAS Test Harnesses retrieve all of the data in the Full Activity Dump from the SAS UUT for sas_th in config['sasTestHarnessConfigs'][1:]: dump_message = self._sas.GetFullActivityDump( sas_th['serverCert'], sas_th['serverKey']) # check that dump message is the same as the message retreived by the first SAS TH compareDictWithUnorderedLists(response, dump_message) # check that dump files are the same as the files retreived by the first SAS TH for dump_file in dump_message['files']: if dump_file['recordType'] != 'coordination': downloaded_file = self._sas.DownloadFile(dump_file['url'],\ sas_th['serverCert'], sas_th['serverKey']) self.assertDictEqual(downloaded_files[dump_file['url']], downloaded_file)
def test_WINNF_FT_S_PPR_3(self, config_filename): config = loadConfig(config_filename) # Light config checking. self.assertValidConfig( config, { 'domainProxy': dict, 'ppaRecord': dict, 'ppaClusterList': list, 'palRecords': list, 'sasTestHarnessDumpRecords': dict, 'sasTestHarnessConfig': dict }) self.assertEqual( len(config['sasTestHarnessDumpRecords']['ppaRecords']), 1, 'Only one PPA is supported.') # Make sure ID formats are correct. ppa = config['sasTestHarnessDumpRecords']['ppaRecords'][0] self.assertGreater( len(ppa['ppaInfo']['cbsdReferenceId']), 0, 'Must have at least one ID on the cluster list.') for cbsd_ref_id in ppa['ppaInfo']['cbsdReferenceId']: self.assertFalse( cbsd_ref_id.startswith('cbsd/'), 'IDs in the cluster list should not start with "cbsd/".') for cbsd in config['sasTestHarnessDumpRecords']['cbsdRecords']: self.assertTrue(cbsd['id'].startswith('cbsd/'), 'IDs of individual CBSDs must start with "cbsd/".') # Initialize test-wide variables, and state variables. self.config = config self.active_dpas = [] self.sas_test_harness_objects = [] self.domain_proxy_objects = [] self.protected_entity_records = {} self.num_peer_sases = 1 self.cpas_executor = ThreadPoolExecutor(max_workers=1) self.agg_interf_check_executor = ThreadPoolExecutor(max_workers=1) self.sas_uut_fad = None self.test_harness_fads = [] # List for consistency with MCP code. self.all_dpa_checks_succeeded = True # Notify SAS UUT that a peer SAS exists (and start the SAS server) logging.info('Step 1: activate one SAS test harness and notify SAS UUT.') test_harness = config['sasTestHarnessConfig'] logging.info('Creating SAS TH with config %s', test_harness) # Initialize SAS Test Harness Server instance to dump FAD records sas_test_harness_object = SasTestHarnessServer( test_harness['sasTestHarnessName'], test_harness['hostName'], test_harness['port'], test_harness['serverCert'], test_harness['serverKey'], test_harness['caCert']) self.InjectTestHarnessFccIds( config['sasTestHarnessDumpRecords']['cbsdRecords']) sas_test_harness_dump_records = [ config['sasTestHarnessDumpRecords']['cbsdRecords'], config['sasTestHarnessDumpRecords']['ppaRecords'] ] sas_test_harness_object.writeFadRecords(sas_test_harness_dump_records) # Start the server sas_test_harness_object.start() # Inform SAS UUT about SAS Test Harness. certificate_hash = getCertificateFingerprint(test_harness['serverCert']) self._sas_admin.InjectPeerSas({'certificateHash': certificate_hash, 'url': sas_test_harness_object.getBaseUrl()}) # Store required info in the test harness. self.fad_cert = test_harness['serverCert'] self.fad_key = test_harness['serverKey'] self.sas_test_harness_objects.append(sas_test_harness_object) # Extract PPA record from peer SAS and add to local protected entities. peer_sas_ppa = config['sasTestHarnessDumpRecords']['ppaRecords'][0] # The ID for each CBSD's record is of the format "cbsd/$REFERENCE_ID". The # IDs on the cluster list are of the format "$REFERENCE_ID". Here we prepend # "cbsd/" so that the values will be correctly matched in the zone purge # reference model. cluster_list = peer_sas_ppa['ppaInfo']['cbsdReferenceId'] for i in range(len(cluster_list)): cluster_list[i] = 'cbsd/%s' % cluster_list[i] self.protected_entity_records['ppaRecords'] = [peer_sas_ppa] # Inject all PALs (used by SAS UUT PPA and peer SAS PPA) logging.info('Step 2: inject PAL records.') for index, pal_record in enumerate(config['palRecords']): try: logging.info('Injecting PAL record #%d', index) self._sas_admin.InjectPalDatabaseRecord(pal_record) except Exception: logging.error(common_strings.CONFIG_ERROR_SUSPECTED) raise self.protected_entity_records['palRecords'] = config['palRecords'] # Register, inject PPA, and request grants. logging.info('Steps 3 - 5: register, inject PPA, request grants.') domain_proxy_config = config['domainProxy'] domain_proxy = test_harness_objects.DomainProxy(self, domain_proxy_config['cert'], domain_proxy_config['key']) self.domain_proxy_objects.append(domain_proxy) (sas_uut_ppa_record_with_cbsd_ids, sas_uut_ppa_record_with_reference_ids ) = domain_proxy.registerCbsdsAndRequestGrantsWithPpa( domain_proxy_config['registrationRequests'], domain_proxy_config['grantRequests'], config['ppaRecord'], config['ppaClusterList'], domain_proxy_config['conditionalRegistrationData']) # Make sure SAS UUT's PPA is also checked for protection. # At this point, we use the "with reference IDs" version because the pre-IAP # filtering code compares against the CBSD reference ID in the FAD. self.protected_entity_records['ppaRecords'].append( sas_uut_ppa_record_with_reference_ids) # FAD exchange. logging.info('Step 6 + 7: FAD exchange.') self.sas_uut_fad = getFullActivityDumpSasUut(self._sas, self._sas_admin, self.fad_cert, self.fad_key) self.test_harness_fads.append( getFullActivityDumpSasTestHarness( self.sas_test_harness_objects[0].getSasTestHarnessInterface())) # Trigger CPAS in SAS UUT, and wait until completion. logging.info('Step 8: trigger CPAS.') self.cpas = self.cpas_executor.submit( self.TriggerDailyActivitiesImmediatelyAndWaitUntilComplete) logging.info('Step 9: execute IAP reference model.') # Pre-IAP filtering. pre_iap_filtering.preIapReferenceModel(self.protected_entity_records, self.sas_uut_fad, self.test_harness_fads) # IAP reference model. self.performIap() logging.info('Waiting for CPAS to complete (started in step 8).') self.cpas.result() logging.info('CPAS started in step 8 complete.') # Heartbeat, relinquish, grant, heartbeat logging.info('Steps 10 - 13: heartbeat, relinquish, grant, heartbeat.') domain_proxy.performHeartbeatAndUpdateGrants() # Aggregate interference check logging.info( 'Step 14 and CHECK: calculating and checking aggregate interference.') # Before performing this check, we need to update the cluster list of SAS # UUT's PPA to use the CBSD IDs -- rather than reference IDs -- since this # is what the function getAuthorizedGrantsFromDomainProxies() expects. Note # that we must keep the indexing the same since # self.ppa_ap_iap_ref_values_list assumes consistent ordering of protected # entities. self.protected_entity_records['ppaRecords'][ 1] = sas_uut_ppa_record_with_cbsd_ids self.performIapAndDpaChecks()