def test_shipment_udate_customer_fields(self, client_alice): response = client_alice.patch(self.update_url, data={ 'customer_fields': { 'custom_field_1': 'value one', 'custom_field_2': 'value two' } }) AssertionHelper.HTTP_202(response) response = client_alice.get(self.history_url) AssertionHelper.HTTP_200(response, is_list=True, count=3) changed_fields = self.get_changed_fields( response.json()['data'][0]['fields'], 'field') assert 'customer_fields.custom_field_1' in changed_fields assert 'customer_fields.custom_field_2' in changed_fields response = client_alice.patch( self.update_url, data={'customer_fields': { 'custom_field_2': 'new value two' }}) AssertionHelper.HTTP_202(response) response = client_alice.get(self.history_url) AssertionHelper.HTTP_200(response, is_list=True, count=4) changed_fields = self.get_changed_fields( response.json()['data'][0]['fields'], 'field') assert 'customer_fields.custom_field_1' not in changed_fields assert 'customer_fields.custom_field_2' in changed_fields
def test_shipment_update_with_assignee(client_alice, shipment): url = reverse('shipment-detail', kwargs={ 'version': 'v1', 'pk': shipment.id }) valid_uuid4_data = { 'assignee_id': VALID_UUID4, } invalid_uuid4_data = { 'assignee_id': VALID_UUID4 + '12', } # A shipment cannot be updated with an invalid assignee ID response = client_alice.patch(url, data=invalid_uuid4_data) AssertionHelper.HTTP_400(response, error='Must be a valid UUID.', pointer='assignee_id') # With a valid assignee ID the request should succeed response = client_alice.patch(url, data=valid_uuid4_data) AssertionHelper.HTTP_202(response, entity_refs=AssertionHelper.EntityRef( resource='Shipment', pk=shipment.id, attributes={'assignee_id': VALID_UUID4}))
def test_shipment_creation_with_assignee(client_alice, mocked_is_shipper, mocked_storage_credential, shipment): url = reverse('shipment-list', kwargs={'version': 'v1'}) valid_uuid4_data = { 'storage_credentials_id': shipment.storage_credentials_id, 'shipper_wallet_id': shipment.shipper_wallet_id, 'carrier_wallet_id': shipment.carrier_wallet_id, 'assignee_id': VALID_UUID4, } invalid_uuid4_data = { 'storage_credentials_id': shipment.storage_credentials_id, 'shipper_wallet_id': shipment.shipper_wallet_id, 'carrier_wallet_id': shipment.carrier_wallet_id, 'assignee_id': VALID_UUID4[:-1], } # A shipment cannot be created with an invalid assignee ID response = client_alice.post(url, data=invalid_uuid4_data) AssertionHelper.HTTP_400(response, error='Must be a valid UUID.', pointer='assignee_id') # With a valid assignee ID the request should succeed response = client_alice.post(url, data=valid_uuid4_data) AssertionHelper.HTTP_202(response, entity_refs=AssertionHelper.EntityRef( resource='Shipment', attributes={'assignee_id': VALID_UUID4}))
def test_owner_can_update_with_permission_link(self, client_alice): response = client_alice.patch(self.url_valid_permission, {'carriers_scac': 'carriers_scac'}) self.entity_ref_shipment_alice.attributes = { 'carriers_scac': 'carriers_scac' } AssertionHelper.HTTP_202(response, entity_refs=self.entity_ref_shipment_alice)
def test_history_filtering(self, client_alice): initial_datetime = datetime.now() one_day_later = datetime.now() + timedelta(days=1) two_day_later = datetime.now() + timedelta(days=2) # We update the shipment 1 day in the future with freeze_time(one_day_later.isoformat()) as date_in_future: response = client_alice.patch(self.update_url, {'container_qty': '1'}) AssertionHelper.HTTP_202(response) # We set the clock to two days in the future date_in_future.move_to(two_day_later) response = client_alice.patch(self.update_url, {'package_qty': '10'}) AssertionHelper.HTTP_202(response) response = client_alice.get(self.history_url) AssertionHelper.HTTP_200(response, is_list=True, count=4) assert 'package_qty' in self.get_changed_fields( response.json()['data'][0]['fields'], 'field') response = client_alice.get( f'{self.history_url}?history_date__lte={initial_datetime.isoformat()}' ) AssertionHelper.HTTP_200(response, is_list=True, count=2) assert 'package_qty' not in self.get_changed_fields( response.json()['data'][0]['fields'], 'field') response = client_alice.get( f'{self.history_url}?history_date__gte={initial_datetime.isoformat()}' ) AssertionHelper.HTTP_200(response, is_list=True, count=2) assert 'package_qty' in self.get_changed_fields( response.json()['data'][0]['fields'], 'field') assert 'container_qty' in self.get_changed_fields( response.json()['data'][1]['fields'], 'field') response = client_alice.get(f'{self.history_url}?history_date__lte={one_day_later.isoformat()}' \ f'&history_date__gte={datetime.now().isoformat()}') AssertionHelper.HTTP_200(response, is_list=True, count=1) assert 'container_qty' in self.get_changed_fields( response.json()['data'][0]['fields'], 'field')
def test_shipment_udate_location(self, client_alice): location_attributes, content_type = create_form_content({ 'ship_from_location.name': "Location Name", 'ship_from_location.city': "City", 'ship_from_location.state': "State", 'ship_from_location.geometry': geojson.dumps(Point((42.0, 27.0))) }) response = client_alice.patch(self.update_url, data=location_attributes, content_type=content_type) AssertionHelper.HTTP_202(response) response = client_alice.get(self.history_url) AssertionHelper.HTTP_200(response, is_list=True, count=3) changed_fields = self.get_changed_fields( response.json()['data'][0]['fields'], 'field') assert 'ship_from_location' in changed_fields assert 'geometry' not in self.get_changed_fields( response.json()['data'][0]['relationships']['ship_from_location'], 'field') assert 'ship_from_location' in response.json( )['data'][0]['relationships'].keys() location_attributes, content_type = create_form_content( {'ship_from_location.phone_number': '555-555-5555'}) response = client_alice.patch(self.update_url, data=location_attributes, content_type=content_type) AssertionHelper.HTTP_202(response) response = client_alice.get(self.history_url) AssertionHelper.HTTP_200(response, is_list=True, count=4) ship_from_location_changes = response.json( )['data'][0]['relationships']['ship_from_location'] assert 'phone_number' in self.get_changed_fields( ship_from_location_changes, 'field')
def test_geofence_creates(client_alice, mocked_iot_api, mocked_profiles, mocked_engine_rpc, profiles_ids, successful_shipment_create_profiles_assertions): url = reverse('shipment-list', kwargs={'version': 'v1'}) shipment_create_request = {"geofences": [GEOFENCE_3], **profiles_ids} response = client_alice.post(url, data=shipment_create_request) AssertionHelper.HTTP_202(response, entity_refs=AssertionHelper.EntityRef( resource='Shipment', attributes=shipment_create_request)) mocked_profiles.assert_calls( successful_shipment_create_profiles_assertions)
def test_geofence_updates(client_alice, shipment_with_device, shipment): url = reverse('shipment-detail', kwargs={ 'version': 'v1', 'pk': shipment_with_device.id }) shipment_update_request = {'geofences': [GEOFENCE_1]} response = client_alice.patch(url, data=shipment_update_request) AssertionHelper.HTTP_202(response, entity_refs=AssertionHelper.EntityRef( resource='Shipment', pk=shipment.id, attributes=shipment_update_request)) shipment_update_request_formdata, content_type = create_form_content({ "geofences": json.dumps([GEOFENCE_2]), }) response = client_alice.patch(url, data=shipment_update_request_formdata, content_type=content_type) AssertionHelper.HTTP_202(response, entity_refs=AssertionHelper.EntityRef( resource='Shipment', pk=shipment.id, attributes={'geofences': [GEOFENCE_2]})) # Test shipment without a device url = reverse('shipment-detail', kwargs={ 'version': 'v1', 'pk': shipment.id }) shipment_update_request = {'geofences': [GEOFENCE_3]} response = client_alice.patch(url, data=shipment_update_request) AssertionHelper.HTTP_202(response, entity_refs=AssertionHelper.EntityRef( resource='Shipment', pk=shipment.id, attributes=shipment_update_request))
def assert_write_access(self, client, shipment_access=None, tags_access=None, documents_access=None, notes_access=None, all_access=None): if all_access is not None: shipment_access = all_access tags_access = all_access documents_access = all_access notes_access = all_access shipment_data = {'carriers_scac': 'h4x3d'} tag_data = { 'tag_type': 'foo', 'tag_value': 'bar', 'owner_id': client.handler._force_user.id, } document_data = { 'name': 'Test BOL', 'file_type': 'PDF', 'document_type': 'AIR_WAYBILL' } note_data = {'message': 'hello, world.'} if shipment_access is not None: response = client.patch(self.endpoint_urls['shipment'], shipment_data) AssertionHelper.HTTP_202( response) if shipment_access else AssertionHelper.HTTP_403( response) if tags_access is not None: response = client.post(self.endpoint_urls['tags'], tag_data) AssertionHelper.HTTP_201( response) if tags_access else AssertionHelper.HTTP_403( response) if documents_access is not None: response = client.post(self.endpoint_urls['documents'], document_data) AssertionHelper.HTTP_201( response) if documents_access else AssertionHelper.HTTP_403( response) if notes_access is not None: response = client.post(self.endpoint_urls['notes'], note_data) AssertionHelper.HTTP_201( response) if notes_access else AssertionHelper.HTTP_403( response)
def test_rw_shipment_no_tags_on_update(self, shipment_alice, client_bob, new_rw_access_request_bob, entity_ref_shipment_alice): new_rw_access_request_bob.tags_permission = PermissionLevel.NONE new_rw_access_request_bob.approved = True new_rw_access_request_bob.save() response = client_bob.patch(self.endpoint_urls['shipment'], {'carriers_scac': 'h4x3d'}) AssertionHelper.HTTP_202(response, entity_refs=entity_ref_shipment_alice) assert 'tags' not in response.json()['data']['relationships'] for included in response.json()['included']: assert included['type'] != 'ShipmentTag'
def test_with_permission_links(self, shipment_alice, client_bob, new_rw_access_request_bob, permission_link_shipment_alice): shipment_data = {'carriers_scac': 'h4x3d'} tag_data = { 'tag_type': 'foo', 'tag_value': 'bar', 'owner_id': client_bob.handler._force_user.id, } # Documents/notes are not accessible via permission link, tracking/telemetry is RO response = client_bob.get( f'{self.endpoint_urls["shipment"]}?permission_link={permission_link_shipment_alice.id}' ) AssertionHelper.HTTP_200( response, entity_refs=AssertionHelper.EntityRef( resource='Shipment', relationships={ 'tags': AssertionHelper.EntityRef(resource='ShipmentTag', pk=self.tag.id) }), included=AssertionHelper.EntityRef(resource='ShipmentTag'), ) response = client_bob.patch( f'{self.endpoint_urls["shipment"]}?permission_link={permission_link_shipment_alice.id}', shipment_data) AssertionHelper.HTTP_403(response) response = client_bob.post( f'{self.endpoint_urls["tags"]}?permission_link={permission_link_shipment_alice.id}', tag_data) AssertionHelper.HTTP_403(response) new_rw_access_request_bob.approved = True new_rw_access_request_bob.save() response = client_bob.patch( f'{self.endpoint_urls["shipment"]}?permission_link={permission_link_shipment_alice.id}', shipment_data) AssertionHelper.HTTP_202(response) response = client_bob.post( f'{self.endpoint_urls["tags"]}?permission_link={permission_link_shipment_alice.id}', tag_data) AssertionHelper.HTTP_201(response)
def test_geofence_dedup(client_alice, shipment_with_device): # Check geofence_id uniqueness url = reverse('shipment-detail', kwargs={ 'version': 'v1', 'pk': shipment_with_device.id }) shipment_update_request = { 'geofences': [ GEOFENCE_1, GEOFENCE_2, GEOFENCE_2, GEOFENCE_3, GEOFENCE_3, GEOFENCE_3 ] } response = client_alice.patch(url, data=shipment_update_request) AssertionHelper.HTTP_202(response) updated_parameters = response.json()['data']['attributes'] assert sorted(updated_parameters['geofences']) == sorted( [GEOFENCE_1, GEOFENCE_2, GEOFENCE_3])
def test_shipment_udate_fields(self, client_bob, mock_successful_wallet_owner_calls, user_bob_id): response = client_bob.patch(self.update_url, data={ 'carriers_scac': 'carrier_scac', 'pickup_act': datetime.utcnow() }) AssertionHelper.HTTP_202(response) mock_successful_wallet_owner_calls.assert_calls(self.assert_success) response = client_bob.get(self.history_url) AssertionHelper.HTTP_200(response, is_list=True, count=3) mock_successful_wallet_owner_calls.assert_calls(self.assert_success) changed_fields = self.get_changed_fields( response.json()['data'][0]['fields'], 'field') assert 'carriers_scac' in changed_fields assert 'updated_by' in changed_fields assert 'pickup_act' not in changed_fields assert response.json()['data'][0]['author'] == user_bob_id
def test_protected_shipment_date_updates(client_alice, shipment): url = reverse('shipment-detail', kwargs={ 'version': 'v1', 'pk': shipment.id }) start_date = datetime.utcnow().replace(tzinfo=pytz.UTC) - relativedelta( years=1) parameters = { 'pickup_est': start_date.isoformat(), 'pickup_act': (start_date + relativedelta(days=1)).isoformat(), 'port_arrival_est': (start_date + relativedelta(days=2)).isoformat(), 'port_arrival_act': (start_date + relativedelta(days=3)).isoformat(), 'delivery_est': (start_date + relativedelta(days=4)).isoformat(), 'delivery_act': (start_date + relativedelta(days=5)).isoformat(), } # Assert that none of the values to be updated already exist for field in parameters: assert getattr(shipment, field) != parameters[field], f'Field: {field}' response = client_alice.patch(url, data=parameters) AssertionHelper.HTTP_202(response, entity_refs=AssertionHelper.EntityRef( resource='Shipment', pk=shipment.id, )) updated_parameters = response.json()['data']['attributes'] # Assert that only the updatable fields got updated for field in parameters: if '_act' in field: assert updated_parameters[field] is None, f'Field: {field}' else: assert dt_parse(parameters[field]) == dt_parse( updated_parameters[field]), f'Field: {field}'
def test_can_create(self, client_alice, mocked_engine_rpc): self.base_call['tags'] = [ { 'tag_value': 'tag_value', 'tag_type': 'tag_type' }, { 'tag_value': 'tag_value_two', 'tag_type': 'tag_type' }, ] response = client_alice.post(self.url, self.base_call) AssertionHelper.HTTP_202(response, included=[ AssertionHelper.EntityRef(resource='ShipmentTag', attributes={ 'tag_type': 'tag_type', 'tag_value': 'tag_value' }), AssertionHelper.EntityRef(resource='ShipmentTag', attributes={ 'tag_type': 'tag_type', 'tag_value': 'tag_value_two' }) ]) self.wallet_mocking.assert_calls(self.assertions)
def test_update_shipment_device_certificate( self, client_alice, tracking_data, profiles_ids, mocker, shipment_alice_with_device, mock_successful_wallet_owner_calls, successful_shipment_create_profiles_assertions): mock_device_call = mocker.patch.object(settings.REQUESTS_SESSION, 'get') mock_device_call.return_value.status_code = 200 with open('tests/data/cert.pem', 'r') as cert_file: cert_pem = cert_file.read() map_describe = {} principals = [] for i in range(0, 4): describe = {} res = self.mocked_iot.create_keys_and_certificate() describe['certificateDescription'] = res describe['certificateDescription']['status'] = 'INACTIVE' if i == 1: expired_certificate = res['certificateId'] if i == 2: describe['certificateDescription']['status'] = 'ACTIVE' describe['certificateDescription']['certificatePem'] = cert_pem new_active_certificate = res['certificateId'] map_describe[res['certificateId']] = describe principals.append(res['certificateArn']) self.device.certificate_id = expired_certificate self.device.save() def side_effects(**kwargs): cert = kwargs['certificateId'] return map_describe[cert] with mock.patch('apps.shipments.serializers.boto3.client') as serial_client, \ mock.patch('apps.shipments.models.boto3.client') as model_client: serial_client = serial_client.return_value model_client = model_client.return_value serial_client.describe_certificate.side_effect = side_effects model_client.list_thing_principals.return_value = { 'principals': principals } model_client.describe_certificate.side_effect = side_effects signed_data = self.sign_tracking( tracking_data, self.device, certificate_id=new_active_certificate) response = client_alice.post(self.url_device, data={'payload': signed_data}) AssertionHelper.HTTP_204(response) self.device.refresh_from_db() assert self.device.certificate_id == new_active_certificate shipment_alice_with_device.device = None shipment_alice_with_device.save() self.device.certificate_id = expired_certificate self.device.save() self.device.refresh_from_db() response = client_alice.post(self.create_url, data={ 'device_id': self.device.id, **profiles_ids }) AssertionHelper.HTTP_202(response) self.device.refresh_from_db() assert self.device.certificate_id == new_active_certificate