def test_WINNF_FT_S_GPR_3(self, config_filename):
    """GWPZ Exclusion Zone
      One or more CBSDs, located inside a GWPZ, request Grants and are rejected
    """
    config = loadConfig(config_filename)

    # Step1: Admin Test Harness injects a GWPZ into the SAS UUT
    self._sas_admin.InjectWisp(config['gwpzRecord'])

    # Step2: Admin Test Harness triggers CPAS and waits until completion of CPAS
    self.TriggerDailyActivitiesImmediatelyAndWaitUntilComplete()

    # Step3: DP Test Harness registers N > 0 CBSDs
    cbsd_ids = self.assertRegistered(config['registrationRequests'], config['conditionalRegistrationData'])

    # Step4: DP Test Harness requests one Grant per registered CBSD
    grant_request = config['grantRequests']
    addCbsdIdsToRequests(cbsd_ids, grant_request)

    request = {'grantRequest': grant_request}
    response = self._sas.Grant(request)['grantResponse']
    self.assertEqual(len(response), len(grant_request))

    for response_num, response in enumerate(response):
      self.assertEqual(response['cbsdId'], request['grantRequest'][response_num]['cbsdId'])
      self.assertEqual(response['response']['responseCode'], 400)
    def test_WINNF_FT_S_RLQ_6(self, config_filename):
        """[Configurable] Multiple Relinquishments."""

        config = loadConfig(config_filename)
        # Very light checking of the config file.
        self.assertValidConfig(
            config, {
                'registrationRequests': list,
                'conditionalRegistrationData': list,
                'grantRequests': list,
                'relinquishmentRequestsFirst': list,
                'relinquishmentRequestsSecond': list,
                'expectedResponseCodesFirst': list,
                'expectedResponseCodesSecond': list
            })
        self.assertEqual(len(config['relinquishmentRequestsFirst']),
                         len(config['expectedResponseCodesFirst']))
        self.assertEqual(len(config['relinquishmentRequestsSecond']),
                         len(config['expectedResponseCodesSecond']))

        # Whitelist FCC IDs.
        for device in config['registrationRequests']:
            self._sas_admin.InjectFccId({
                'fccId': device['fccId'],
                'fccMaxEirp': 47
            })

        # Whitelist user IDs.
        for device in config['registrationRequests']:
            self._sas_admin.InjectUserId({'userId': device['userId']})

        # Register devices and get grants
        try:
            cbsd_ids, grant_ids = self.assertRegisteredAndGranted(
                config['registrationRequests'], config['grantRequests'],
                config['conditionalRegistrationData'])
        except Exception:
            logging.error(
                common_strings.EXPECTED_SUCCESSFUL_REGISTRATION_AND_GRANT)
            raise

        # First relinquishment
        relinquishment_request = config['relinquishmentRequestsFirst']
        addCbsdIdsToRequests(cbsd_ids, relinquishment_request)
        addGrantIdsToRequests(grant_ids, relinquishment_request)
        request = {'relinquishmentRequest': relinquishment_request}

        responses = self._sas.Relinquishment(request)['relinquishmentResponse']
        # Check relinquishment response
        self.assertEqual(len(responses),
                         len(config['expectedResponseCodesFirst']))
        relinquished_grant_ids = []
        has_error = False
        for i, response in enumerate(responses):
            expected_response_codes = config['expectedResponseCodesFirst'][i]
            logging.debug('Looking at response number %d', i)
            logging.debug(
                'Expecting to see response code in set %s in response: %s',
                expected_response_codes, response)

            # Check response code.
            response_code = response['response']['responseCode']
            if response_code not in expected_response_codes:
                has_error = True
                logging.error(
                    'Error: response %d is expected to have a responseCode in set %s but instead had responseCode %d.',
                    i, expected_response_codes, response_code)
                logging.error('Relinquishment request: %s',
                              config['relinquishmentRequestsFirst'][i])
                logging.error('Relinquishment response: %s', response)

            # "If the corresponding request contained a valid cbsdId and grantId, the
            # response shall contain the same grantId."
            if 'cbsdId' and 'grantId' in relinquishment_request[i]:
                if (relinquishment_request[i]['cbsdId']
                        in cbsd_ids) and (relinquishment_request[i]['grantId']
                                          in grant_ids):
                    cbsd_index = cbsd_ids.index(
                        relinquishment_request[i]['cbsdId'])
                    grant_index = grant_ids.index(
                        relinquishment_request[i]['grantId'])
                    # Check if CBSD ID is paired with the corresponding Grant ID.
                    if cbsd_index == grant_index:
                        self.assertEqual(response['grantId'],
                                         relinquishment_request[i]['grantId'])
                        relinquished_grant_ids.append(response['grantId'])
        del request, responses

        # Outside the 'for' loop.
        # Test will stop here if there are any errors, else continue.
        self.assertFalse(
            has_error,
            'Error found in at least one of the responses. See logs for details.'
        )

        # Second relinquishment
        relinquishment_request = config['relinquishmentRequestsSecond']
        addCbsdIdsToRequests(cbsd_ids, relinquishment_request)
        addGrantIdsToRequests(grant_ids, relinquishment_request)
        request = {'relinquishmentRequest': relinquishment_request}
        responses = self._sas.Relinquishment(request)['relinquishmentResponse']
        # Check relinquishment response
        self.assertEqual(len(responses),
                         len(config['expectedResponseCodesSecond']))
        for i, response in enumerate(responses):
            expected_response_codes = config['expectedResponseCodesSecond'][i]
            logging.debug('Looking at response number %d', i)
            logging.debug(
                'Expecting to see response code in set %s in response: %s',
                expected_response_codes, response)

            # Check response code.
            response_code = response['response']['responseCode']
            if response_code not in expected_response_codes:
                has_error = True
                logging.error(
                    'Error: response %d is expected to have a responseCode in set %s but instead had responseCode %d.',
                    i, expected_response_codes, response_code)
                logging.error('Relinquishment request: %s',
                              config['relinquishmentRequestsSecond'][i])
                logging.error('Relinquishment response: %s', response)

            if 'cbsdId' and 'grantId' in relinquishment_request[i]:
                if (relinquishment_request[i]['cbsdId']
                        in cbsd_ids) and (relinquishment_request[i]['grantId']
                                          in grant_ids):
                    cbsd_index = cbsd_ids.index(
                        relinquishment_request[i]['cbsdId'])
                    grant_index = grant_ids.index(
                        relinquishment_request[i]['grantId'])
                    if cbsd_index == grant_index:
                        if relinquishment_request[i][
                                'grantId'] not in relinquished_grant_ids:
                            self.assertEqual(
                                response['grantId'],
                                relinquishment_request[i]['grantId'])

        # Outside the 'for' loop.
        self.assertFalse(
            has_error,
            'Error found in at least one of the responses. See logs for details.'
        )
    def test_WINNF_FT_S_DRG_6(self, config_filename):
        """[Configurable] Array Deregistration."""

        config = loadConfig(config_filename)
        # Very light checking of the config file.
        self.assertValidConfig(
            config, {
                'registrationRequests': list,
                'conditionalRegistrationData': list,
                'grantRequests': list,
                'heartbeatRequests': list,
                'deregistrationRequests': list,
                'expectedResponseCodes': list
            })
        self.assertEqual(len(config['registrationRequests']),
                         len(config['grantRequests']))
        self.assertEqual(len(config['grantRequests']),
                         len(config['heartbeatRequests']))
        self.assertEqual(len(config['heartbeatRequests']),
                         len(config['deregistrationRequests']))
        self.assertEqual(len(config['deregistrationRequests']),
                         len(config['expectedResponseCodes']))

        # Whitelist FCC IDs.
        for device in config['registrationRequests']:
            self._sas_admin.InjectFccId({
                'fccId': device['fccId'],
                'fccMaxEirp': 47
            })

        # Whitelist user IDs.
        for device in config['registrationRequests']:
            self._sas_admin.InjectUserId({'userId': device['userId']})

        # Step 2 & 3: Register devices and get grants
        try:
            cbsd_ids, grant_ids = self.assertRegisteredAndGranted(
                config['registrationRequests'], config['grantRequests'],
                config['conditionalRegistrationData'])
        except Exception:
            logging.error(
                common_strings.EXPECTED_SUCCESSFUL_REGISTRATION_AND_GRANT)
            raise

        # Step 4: First Heartbeat Request
        heartbeat_request = config['heartbeatRequests']
        addCbsdIdsToRequests(cbsd_ids, heartbeat_request)
        addGrantIdsToRequests(grant_ids, heartbeat_request)
        request = {'heartbeatRequest': heartbeat_request}
        responses = self._sas.Heartbeat(request)['heartbeatResponse']
        self.assertEqual(len(responses), len(heartbeat_request))
        # Check heartbeat response
        for i, response in enumerate(responses):
            self.assertEqual(response['response']['responseCode'], 0)
        del request, responses

        # Step 5: First deregistration request
        deregister_request = config['deregistrationRequests']
        addCbsdIdsToRequests(cbsd_ids, deregister_request)
        request = {'deregistrationRequest': deregister_request}
        responses_1 = self._sas.Deregistration(
            request)['deregistrationResponse']

        # Check the deregistration response
        self.assertEqual(len(responses_1),
                         len(config['expectedResponseCodes']))
        has_error = False
        registration_request = config['registrationRequests']
        conditional_registration_data = config['conditionalRegistrationData']
        for i, response in enumerate(responses_1):
            expected_response_codes = config['expectedResponseCodes'][i]
            logging.debug('Looking at response number %d', i)
            logging.debug(
                'Expecting to see response code in set %s in response: %s',
                expected_response_codes, response)

            # Check response code.
            response_code = response['response']['responseCode']
            if response_code not in expected_response_codes:
                has_error = True
                logging.error(
                    'Error: response %d is expected to have a responseCode in set %s but instead had responseCode %d.',
                    i, expected_response_codes, response_code)
                logging.error('Deregistration request: %s',
                              config['deregistrationRequests'][i])
                logging.error('Deregistration response: %s', response)

            # "If the corresponding request contained a valid cbsdId, the
            # response shall contain the same cbsdId."
            if 'cbsdId' in deregister_request[i]:
                if deregister_request[i]['cbsdId'] in cbsd_ids:
                    self.assertEqual(response['cbsdId'],
                                     deregister_request[i]['cbsdId'])
                else:
                    self.assertFalse('cbsdId' in response)
            # remove still registered CBSDs from the next preload conditional registration
            if response['response']['responseCode'] != 0:
                cbsd_to_be_removed_from_next_reg = registration_request[i]
                indexes_conditional_to_remove = [
                    index
                    for index, c in enumerate(conditional_registration_data)
                    if c['cbsdSerialNumber'] ==
                    cbsd_to_be_removed_from_next_reg['cbsdSerialNumber']
                    and c['fccId'] == cbsd_to_be_removed_from_next_reg['fccId']
                ]
                for index in reversed(indexes_conditional_to_remove):
                    del conditional_registration_data[index]

        # Outside the 'for' loop.
        # Test will stop here if there are any errors, else continue.
        self.assertFalse(
            has_error,
            'Error found in at least one of the responses. See logs for details.'
        )

        # Step 6: Send the Deregistration request from Step 5 again
        request = {'deregistrationRequest': deregister_request}
        responses_2 = self._sas.Deregistration(
            request)['deregistrationResponse']
        # Check the deregistration response
        self.assertEqual(len(responses_2), len(deregister_request))
        self.assertEqual(len(responses_2), len(responses_1))
        # If the corresponding responseCode in the previous Deregistration Response
        # Message was 102, the responseCode shall be 102.
        for i, (response1, response2) in enumerate(
            (zip(responses_1, responses_2))):
            logging.debug('Looking at response number %d, response: %s', i,
                          response2)
            if response1['response']['responseCode'] == 102:
                self.assertEqual(response2['response']['responseCode'], 102)
            else:
                # Otherwise, the responseCode shall be INVALID_VALUE or DEREGISTER.
                self.assertTrue(
                    response2['response']['responseCode'] in [103, 105])
            self.assertFalse('cbsdId' in response2)
        del request, responses_2
        # Step 7: Send registration request from Step 2
        cbsd_ids = self.assertRegistered(registration_request,
                                         conditional_registration_data)

        # Step 8: Heartbeat Request
        heartbeat_requests = config['heartbeatRequests']
        addCbsdIdsToRequests(cbsd_ids, heartbeat_requests)
        request = {'heartbeatRequest': heartbeat_requests}
        responses = self._sas.Heartbeat(request)['heartbeatResponse']
        self.assertEqual(len(responses), len(heartbeat_requests))
        # Check heartbeat response
        for i, response in enumerate(responses):
            logging.debug('Looking at response number %d', i)
            logging.debug('Actual response: %s', response)
            self.assertTrue(response['response']['responseCode'] in [103, 500])
    def test_WINNF_FT_S_EXZ_2(self, config_filename):
        """Exclusion Zones defined in NTIA TR 15-517

    The responseCode = 400 for CBSDs located within 50meters of all Exclusion Zones
    or inside Exclusion Zones.
    """

        config = loadConfig(config_filename)

        # Very light checking of the config file.
        self.assertEqual(len(config['registrationRequestsN1']),
                         len(config['grantRequestsN1']))
        self.assertEqual(len(config['registrationRequestsN2']),
                         len(config['grantRequestsN2']))
        self.assertEqual(len(config['registrationRequestsN3']),
                         len(config['grantRequestsN3']))

        # Enforce NTIA Exlusion zones
        self._sas_admin.TriggerEnableNtiaExclusionZones()

        try:
            # Register N1 devices
            cbsd_ids_N1 = self.assertRegistered(
                config['registrationRequestsN1'],
                config['conditionalRegistrationDataN1'])

            # Register N2 devices
            cbsd_ids_N2 = self.assertRegistered(
                config['registrationRequestsN2'],
                config['conditionalRegistrationDataN2'])

            # Register N3 devices
            cbsd_ids_N3 = self.assertRegistered(
                config['registrationRequestsN3'],
                config['conditionalRegistrationDataN3'])
        except Exception as e:
            logging.error(common_strings.EXPECTED_SUCCESSFUL_REGISTRATION)

        # Trigger daily activities
        self.TriggerDailyActivitiesImmediatelyAndWaitUntilComplete()

        # Generating grant requests for N1 and validating responses
        grant_request_N1 = config['grantRequestsN1']
        addCbsdIdsToRequests(cbsd_ids_N1, grant_request_N1)

        request_N1 = {'grantRequest': grant_request_N1}
        response_N1 = self._sas.Grant(request_N1)['grantResponse']
        self.assertEqual(len(response_N1), len(grant_request_N1))

        # Generating grant requests for N2 and validating responses
        # Request grant
        grant_request_N2 = config['grantRequestsN2']
        addCbsdIdsToRequests(cbsd_ids_N2, grant_request_N2)

        request_N2 = {'grantRequest': grant_request_N2}
        response_N2 = self._sas.Grant(request_N2)['grantResponse']
        self.assertEqual(len(response_N2), len(grant_request_N2))

        for response_num, response in enumerate(response_N2):
            self.assertEqual(
                response['cbsdId'],
                request_N2['grantRequest'][response_num]['cbsdId'])
            self.assertFalse('grantId' in response)
            self.assertEqual(response['response']['responseCode'], 400)

        # Generating grant requests for N3 and validating responses
        grant_request_N3 = config['grantRequestsN3']
        addCbsdIdsToRequests(cbsd_ids_N3, grant_request_N3)

        request_N3 = {'grantRequest': grant_request_N3}
        response_N3 = self._sas.Grant(request_N3)['grantResponse']
        self.assertEqual(len(response_N3), len(grant_request_N3))

        for response_num, response in enumerate(response_N3):
            self.assertEqual(
                response['cbsdId'],
                request_N3['grantRequest'][response_num]['cbsdId'])
            self.assertFalse('grantId' in response)
            self.assertEqual(response['response']['responseCode'], 400)
    def test_WINNF_FT_S_DRG_6(self, config_filename):
        """[Configurable] Array Deregistration."""

        config = loadConfig(config_filename)
        # Very light checking of the config file.
        self.assertValidConfig(
            config, {
                'registrationRequests': list,
                'conditionalRegistrationData': list,
                'grantRequests': list,
                'heartbeatRequests': list,
                'deregistrationRequests': list,
                'expectedResponseCodes': list
            })
        self.assertEqual(len(config['registrationRequests']),
                         len(config['grantRequests']))
        self.assertEqual(len(config['grantRequests']),
                         len(config['heartbeatRequests']))
        self.assertEqual(len(config['heartbeatRequests']),
                         len(config['deregistrationRequests']))
        self.assertEqual(len(config['deregistrationRequests']),
                         len(config['expectedResponseCodes']))

        # Whitelist FCC IDs.
        for device in config['registrationRequests']:
            self._sas_admin.InjectFccId({
                'fccId': device['fccId'],
                'fccMaxEirp': 47
            })

        # Whitelist user IDs.
        for device in config['registrationRequests']:
            self._sas_admin.InjectUserId({'userId': device['userId']})

        # Step 2 & 3: Register devices and get grants
        try:
            cbsd_ids, grant_ids = self.assertRegisteredAndGranted(
                config['registrationRequests'], config['grantRequests'],
                config['conditionalRegistrationData'])
        except Exception:
            logging.error(
                common_strings.EXPECTED_SUCCESSFUL_REGISTRATION_AND_GRANT)
            raise

        # Step 4: First Heartbeat Request
        heartbeat_request = config['heartbeatRequests']
        addCbsdIdsToRequests(cbsd_ids, heartbeat_request)
        addGrantIdsToRequests(grant_ids, heartbeat_request)
        request = {'heartbeatRequest': heartbeat_request}
        responses = self._sas.Heartbeat(request)['heartbeatResponse']
        self.assertEqual(len(responses), len(heartbeat_request))
        # Check heartbeat response
        for i, response in enumerate(responses):
            self.assertEqual(response['response']['responseCode'], 0)
        del request, responses

        # Step 5: First deregistration request
        deregister_request = config['deregistrationRequests']
        addCbsdIdsToRequests(cbsd_ids, deregister_request)
        request = {'deregistrationRequest': deregister_request}
        responses_1 = self._sas.Deregistration(
            request)['deregistrationResponse']
        # Check the deregistration response
        self.assertEqual(len(responses_1),
                         len(config['expectedResponseCodes']))
        for i, response in enumerate(responses_1):
            expected_response_codes = config['expectedResponseCodes'][i]
            logging.debug('Looking at response number %d', i)
            logging.debug(
                'Expecting to see response code in set %s in response: %s',
                expected_response_codes, response)
            self.assertIn(response['response']['responseCode'],
                          expected_response_codes)
            # "If the corresponding request contained a valid cbsdId, the
            # response shall contain the same cbsdId."
            if 'cbsdId' in deregister_request[i]:
                if deregister_request[i]['cbsdId'] in cbsd_ids:
                    self.assertEqual(response['cbsdId'],
                                     deregister_request[i]['cbsdId'])
                else:
                    self.assertFalse('cbsdId' in response)

        # Step 6: Send the Deregistration request from Step 5 again
        request = {'deregistrationRequest': deregister_request}
        responses_2 = self._sas.Deregistration(
            request)['deregistrationResponse']
        # Check the deregistration response
        self.assertEqual(len(responses_2), len(deregister_request))
        self.assertEqual(len(responses_2), len(responses_1))
        # If the corresponding responseCode in the previous Deregistration Response
        # Message was 102, the responseCode shall be 102.
        for i, (response1, response2) in enumerate(
            (zip(responses_1, responses_2))):
            logging.debug('Looking at response number %d, response: %s', i,
                          response2)
            if response1['response']['responseCode'] == 102:
                self.assertEqual(response2['response']['responseCode'], 102)
            else:
                # Otherwise, the responseCode shall be INVALID_VALUE or DEREGISTER.
                self.assertTrue(
                    response2['response']['responseCode'] in [103, 105])
            self.assertFalse('cbsdId' in response2)
        del request, responses_2

        # Step 7: Send registration request from Step 2
        cbsd_ids = self.assertRegistered(config['registrationRequests'],
                                         config['conditionalRegistrationData'])

        # Step 8: Heartbeat Request
        heartbeat_requests = config['heartbeatRequests']
        addCbsdIdsToRequests(cbsd_ids, heartbeat_requests)
        request = {'heartbeatRequest': heartbeat_requests}
        responses = self._sas.Heartbeat(request)['heartbeatResponse']
        self.assertEqual(len(responses), len(heartbeat_requests))
        # Check heartbeat response
        for i, response in enumerate(responses):
            logging.debug('Looking at response number %d', i)
            logging.debug('Actual response: %s', response)
            self.assertTrue(response['response']['responseCode'] in [103, 500])
    def test_WINNF_FT_S_HBT_10(self, config_filename):
        """[Configurable] Heartbeat with optional intervening grant termination
       or blacklist."""

        config = loadConfig(config_filename)
        # Very light checking of the config file.
        self.assertValidConfig(
            config, {
                'registrationRequests': list,
                'conditionalRegistrationData': list,
                'fccIdsBlacklist': list,
                'grantRequests': list,
                'heartbeatRequests': list,
                'expectedResponseCodes': list
            })
        self.assertEqual(len(config['registrationRequests']),
                         len(config['grantRequests']))
        self.assertEqual(len(config['grantRequests']),
                         len(config['heartbeatRequests']))
        self.assertEqual(len(config['heartbeatRequests']),
                         len(config['expectedResponseCodes']))

        # Register devices
        try:
            cbsd_ids = self.assertRegistered(
                config['registrationRequests'],
                config['conditionalRegistrationData'])
        except Exception:
            logging.error(common_strings.EXPECTED_SUCCESSFUL_REGISTRATION)
            raise

        # Request grant
        grant_request = config['grantRequests']
        addCbsdIdsToRequests(cbsd_ids, grant_request)
        request = {'grantRequest': grant_request}

        # Check grant response
        response = self._sas.Grant(request)['grantResponse']
        self.assertEqual(len(response), len(grant_request))
        grant_ids = []
        grant_expire_times = []
        for _, resp in enumerate(response):
            self.assertEqual(resp['response']['responseCode'], 0)
            grant_ids.append(resp['grantId'])
            grant_expire_times.append(
                datetime.strptime(resp['grantExpireTime'],
                                  '%Y-%m-%dT%H:%M:%SZ'))
        del request, response

        # Blacklist N2 CBSDs
        for fcc_id in config['fccIdsBlacklist']:
            self._sas_admin.BlacklistByFccId({'fccId': fcc_id})
        blacklisted_cbsd_ids = []
        for cbsd_id, request in zip(cbsd_ids, config['registrationRequests']):
            if request['fccId'] in config['fccIdsBlacklist']:
                blacklisted_cbsd_ids.append(cbsd_id)

        # First Heartbeat Request
        heartbeat_request = config['heartbeatRequests']
        addCbsdIdsToRequests(cbsd_ids, heartbeat_request)
        addGrantIdsToRequests(grant_ids, heartbeat_request)
        request = {'heartbeatRequest': heartbeat_request}
        responses = self._sas.Heartbeat(request)['heartbeatResponse']
        self.assertEqual(len(responses), len(heartbeat_request))

        # Check heartbeat response
        self.assertEqual(len(responses), len(config['expectedResponseCodes']))
        for i, response in enumerate(responses):
            expected_response_codes = config['expectedResponseCodes'][i]
            logging.debug('Looking at response number %d', i)
            logging.debug(
                'Expecting to see response code in set %s in response: %s',
                expected_response_codes, response)
            self.assertIn(response['response']['responseCode'],
                          expected_response_codes)
            # Check if the request contains CBSD ID
            if 'cbsdId' in heartbeat_request[i]:
                # Check if CBSD ID is valid
                if (heartbeat_request[i]['cbsdId']
                        in cbsd_ids) and (heartbeat_request[i]['cbsdId']
                                          not in blacklisted_cbsd_ids):
                    self.assertEqual(response['cbsdId'],
                                     heartbeat_request[i]['cbsdId'])
                    # Check if the request contains Grant ID
                    if 'grantId' in heartbeat_request[i]:
                        # Check if Grant ID is valid
                        if heartbeat_request[i]['grantId'] in grant_ids:
                            cbsd_index = cbsd_ids.index(
                                heartbeat_request[i]['cbsdId'])
                            grant_index = grant_ids.index(
                                heartbeat_request[i]['grantId'])
                            # Check if CBSD ID is paired with the corresponding Grant ID.
                            if cbsd_index == grant_index:
                                self.assertEqual(
                                    response['grantId'],
                                    heartbeat_request[i]['grantId'])

            if response['response']['responseCode'] == 0:
                transmit_expire_time = datetime.strptime(
                    response['transmitExpireTime'], '%Y-%m-%dT%H:%M:%SZ')
                self.assertLess(datetime.utcnow(), transmit_expire_time)
                self.assertLessEqual(
                    (transmit_expire_time - datetime.utcnow()).total_seconds(),
                    240)
                self.assertLessEqual(transmit_expire_time,
                                     grant_expire_times[i])
                if ('grantRenew' in heartbeat_request[i]) and (
                        heartbeat_request[i]['grantRenew']):
                    grant_expire_time = datetime.strptime(
                        response['grantExpireTime'], '%Y-%m-%dT%H:%M:%SZ')
                    self.assertLess(datetime.utcnow(), grant_expire_time)
            else:
                transmit_expire_time = datetime.strptime(
                    response['transmitExpireTime'], '%Y-%m-%dT%H:%M:%SZ')
                self.assertLessEqual(transmit_expire_time, datetime.utcnow())