diff options
Diffstat (limited to 'modules/field/field.test')
-rw-r--r-- | modules/field/field.test | 279 |
1 files changed, 264 insertions, 15 deletions
diff --git a/modules/field/field.test b/modules/field/field.test index 7b61a4410..e2a4674d8 100644 --- a/modules/field/field.test +++ b/modules/field/field.test @@ -135,7 +135,8 @@ class FieldAttachTestCase extends DrupalWebTestCase { for ($i = 1; $i <= 3; $i++) { $field_names[$i] = 'field_' . $i; $field = array('field_name' => $field_names[$i], 'type' => 'test_field'); - field_create_field($field); + $field = field_create_field($field); + $field_ids[$i] = $field['id']; foreach ($field_bundles_map[$i] as $bundle) { $instance = array( 'field_name' => $field_names[$i], @@ -176,7 +177,7 @@ class FieldAttachTestCase extends DrupalWebTestCase { // Check that the single-field load option works. $entity = field_test_create_stub_entity(1, 1, $bundles[1]); - field_attach_load($entity_type, array(1 => $entity), FIELD_LOAD_CURRENT, array('field_name' => $field_names[1])); + field_attach_load($entity_type, array(1 => $entity), FIELD_LOAD_CURRENT, array('field_id' => $field_ids[1])); $this->assertEqual($entity->{$field_names[1]}[0]['value'], $values[1][$field_names[1]], t('Entity %index: expected value was found.', array('%index' => 1))); $this->assertEqual($entity->{$field_names[1]}[0]['additional_key'], 'additional_value', t('Entity %index: extra information was found', array('%index' => 1))); $this->assert(!isset($entity->{$field_names[2]}), t('Entity %index: field %field_name is not loaded.', array('%index' => 2, '%field_name' => $field_names[2]))); @@ -305,7 +306,7 @@ class FieldAttachTestCase extends DrupalWebTestCase { // Query on the object's values. for ($delta = 0; $delta < $cardinality; $delta++) { $conditions = array(array('value', $values[$delta])); - $result = field_attach_query($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertTrue(isset($result[$entity_types[1]][1]), t('Query on value %delta returns the object', array('%delta' => $delta))); } @@ -314,31 +315,31 @@ class FieldAttachTestCase extends DrupalWebTestCase { $different_value = mt_rand(1, 127); } while (in_array($different_value, $values)); $conditions = array(array('value', $different_value)); - $result = field_attach_query($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertFalse(isset($result[$entity_types[1]][1]), t("Query on a value that is not in the object doesn't return the object")); // Query on the value shared by both objects, and discriminate using // additional conditions. $conditions = array(array('value', $common_value)); - $result = field_attach_query($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertTrue(isset($result[$entity_types[1]][1]) && isset($result[$entity_types[2]][2]), t('Query on a value common to both objects returns both objects')); $conditions = array(array('type', $entity_types[1]), array('value', $common_value)); - $result = field_attach_query($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertTrue(isset($result[$entity_types[1]][1]) && !isset($result[$entity_types[2]][2]), t("Query on a value common to both objects and a 'type' condition only returns the relevant object")); $conditions = array(array('bundle', $entities[1]->fttype), array('value', $common_value)); - $result = field_attach_query($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertTrue(isset($result[$entity_types[1]][1]) && !isset($result[$entity_types[2]][2]), t("Query on a value common to both objects and a 'bundle' condition only returns the relevant object")); $conditions = array(array('entity_id', $entities[1]->ftid), array('value', $common_value)); - $result = field_attach_query($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertTrue(isset($result[$entity_types[1]][1]) && !isset($result[$entity_types[2]][2]), t("Query on a value common to both objects and an 'entity_id' condition only returns the relevant object")); // Test result format. $conditions = array(array('value', $values[0])); - $result = field_attach_query($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $expected = array( $entity_types[1] => array( $entities[1]->ftid => field_test_create_stub_entity($entities[1]->ftid, $entities[1]->ftvid), @@ -371,7 +372,7 @@ class FieldAttachTestCase extends DrupalWebTestCase { // back the right ones. $cursor = 0; foreach (array(1 => 1, 3 => 3, 5 => 5, 8 => 8, 13 => 3) as $count => $expect) { - $found = field_attach_query($this->field_name, array(array('bundle', 'offset_bundle')), $count, $cursor); + $found = field_attach_query($this->field_id, array(array('bundle', 'offset_bundle')), $count, $cursor); if (isset($found['test_entity'])) { $this->assertEqual(count($found['test_entity']), $expect, t('Requested @count, expected @expect, got @found, cursor @cursor', array('@count' => $count, '@expect' => $expect, '@found' => count($found['test_entity']), '@cursor' => $cursor))); foreach ($found['test_entity'] as $id => $entity) { @@ -414,7 +415,7 @@ class FieldAttachTestCase extends DrupalWebTestCase { // Query on the object's values. for ($delta = 0; $delta < $cardinality; $delta++) { $conditions = array(array('value', $values[$delta])); - $result = field_attach_query_revisions($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query_revisions($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertTrue(isset($result[$entity_type][1]), t('Query on value %delta returns the object', array('%delta' => $delta))); } @@ -423,23 +424,23 @@ class FieldAttachTestCase extends DrupalWebTestCase { $different_value = mt_rand(1, 127); } while (in_array($different_value, $values)); $conditions = array(array('value', $different_value)); - $result = field_attach_query_revisions($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query_revisions($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertFalse(isset($result[$entity_type][1]), t("Query on a value that is not in the object doesn't return the object")); // Query on the value shared by both objects, and discriminate using // additional conditions. $conditions = array(array('value', $common_value)); - $result = field_attach_query_revisions($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query_revisions($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertTrue(isset($result[$entity_type][1]) && isset($result[$entity_type][2]), t('Query on a value common to both objects returns both objects')); $conditions = array(array('revision_id', $entities[1]->ftvid), array('value', $common_value)); - $result = field_attach_query_revisions($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query_revisions($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $this->assertTrue(isset($result[$entity_type][1]) && !isset($result[$entity_type][2]), t("Query on a value common to both objects and a 'revision_id' condition only returns the relevant object")); // Test FIELD_QUERY_RETURN_IDS result format. $conditions = array(array('value', $values[0])); - $result = field_attach_query_revisions($this->field_name, $conditions, FIELD_QUERY_NO_LIMIT); + $result = field_attach_query_revisions($this->field_id, $conditions, FIELD_QUERY_NO_LIMIT); $expected = array( $entity_type => array( $entities[1]->ftid => field_test_create_stub_entity($entities[1]->ftid, $entities[1]->ftvid), @@ -712,6 +713,12 @@ class FieldAttachTestCase extends DrupalWebTestCase { field_attach_insert($cached_type, $entity); $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on insert')); + // Load a single field, and check that no cache entry is present. + $entity = clone($entity_init); + field_attach_load($cached_type, array($entity->ftid => $entity), FIELD_LOAD_CURRENT, array('field_id' => $this->field_id)); + $cache = cache_get($cid, 'cache_field'); + $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on loading a single field')); + // Load, and check that a cache entry is present with the expected values. $entity = clone($entity_init); field_attach_load($cached_type, array($entity->ftid => $entity)); @@ -1782,3 +1789,245 @@ class FieldInstanceCrudTestCase extends DrupalWebTestCase { $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), t('A non-deleted field instance is not marked for deletion.')); } } + +/** + * Unit test class for field bulk delete and batch purge functionality. + */ +class FieldBulkDeleteTestCase extends DrupalWebTestCase { + protected $field; + + public static function getInfo() { + return array( + 'name' => 'Field bulk delete tests', + 'description'=> 'Bulk delete fields and instances, and clean up afterwards.', + 'group' => 'Field', + ); + } + + /** + * Generate random values for a field_test field. + * + * @param $cardinality + * Number of values to generate. + * @return + * An array of random values, in the format expected for field values. + */ + function _generateTestFieldValues($cardinality) { + $values = array(); + for ($i = 0; $i < $cardinality; $i++) { + // field_test fields treat 0 as 'empty value'. + $values[$i]['value'] = mt_rand(1, 127); + } + return $values; + } + + /** + * Convenience function for Field API tests. + * + * Given an array of potentially fully-populated objects and an + * optional field name, generate an array of stub objects of the + * same fieldable type which contains the data for the field name + * (if given). + * + * @param $obj_type + * The entity type of $objects. + * @param $objects + * An array of objects of type $obj_type. + * @param $field_name + * Optional; a field name whose data should be copied from + * $objects into the returned stub objects. + * @return + * An array of stub objects corresponding to $objects. + */ + function _generateStubObjects($obj_type, $objects, $field_name = NULL) { + $stubs = array(); + foreach ($objects as $obj) { + $stub = field_attach_create_stub_object($obj_type, field_attach_extract_ids($obj_type, $obj)); + if (isset($field_name)) { + $stub->{$field_name} = $obj->{$field_name}; + } + $stubs[] = $stub; + } + return $stubs; + } + + function setUp() { + parent::setUp('field_test'); + + // Clean up data from previous test cases. + $this->fields = array(); + $this->instances = array(); + + // Create two bundles. + $this->bundles = array('bb_1' => 'bb_1', 'bb_2' => 'bb_2'); + foreach ($this->bundles as $name => $desc) { + field_test_create_bundle($name, $desc); + } + + // Create two fields. + $field = array('field_name' => 'bf_1', 'type' => 'test_field', 'cardinality' => 1); + $this->fields[] = field_create_field($field); + $field = array('field_name' => 'bf_2', 'type' => 'test_field', 'cardinality' => 4); + $this->fields[] = field_create_field($field); + + // For each bundle, create an instance of each field, and 10 + // objects with values for each field. + $id = 0; + $this->entity_type = 'test_entity'; + foreach ($this->bundles as $bundle) { + foreach ($this->fields as $field) { + $instance = array( + 'field_name' => $field['field_name'], + 'bundle' => $bundle, + 'widget' => array( + 'type' => 'test_field_widget', + ) + ); + $this->instances[] = field_create_instance($instance); + } + + for ($i = 0; $i < 10; $i++) { + $entity = field_test_create_stub_entity($id, $id, $bundle); + foreach ($this->fields as $field) { + $entity->{$field['field_name']} = $this->_generateTestFieldValues($field['cardinality']); + } + $this->entities[$id] = $entity; + field_attach_insert($this->entity_type, $entity); + $id++; + } + } + } + + /** + * Verify that deleting an instance leaves the field data items in + * the database and that the appropriate Field API functions can + * operate on the deleted data and instance. + * + * This tests how field_attach_query() interacts with + * field_delete_instance() and could be moved to FieldCrudTestCase, + * but depends on this class's setUp(). + */ + function testDeleteFieldInstance() { + $bundle = reset($this->bundles); + $field = reset($this->fields); + + // There are 10 objects of this bundle. + $found = field_attach_query($field['id'], array(array('bundle', $bundle)), FIELD_QUERY_NO_LIMIT); + $this->assertEqual(count($found['test_entity']), 10, 'Correct number of objects found before deleting'); + + // Delete the instance. + field_delete_instance($field['field_name'], $bundle); + + // The instance still exists, deleted. + $instances = field_read_instances(array('field_id' => $field['id'], 'deleted' => 1), array('include_deleted' => 1, 'include_inactive' => 1)); + $this->assertEqual(count($instances), 1, 'There is one deleted instance'); + $this->assertEqual($instances[0]['bundle'], $bundle, 'The deleted instance is for the correct bundle'); + + // There are 0 objects of this bundle with non-deleted data. + $found = field_attach_query($field['id'], array(array('bundle', $bundle)), FIELD_QUERY_NO_LIMIT); + $this->assertTrue(!isset($found['test_entity']), 'No objects found after deleting'); + + // There are 10 objects of this bundle when deleted fields are allowed, and + // their values are correct. + $found = field_attach_query($field['id'], array(array('bundle', $bundle), array('deleted', 1)), FIELD_QUERY_NO_LIMIT); + field_attach_load($this->entity_type, $found[$this->entity_type], FIELD_LOAD_CURRENT, array('field_id' => $field['id'], 'deleted' => 1)); + $this->assertEqual(count($found['test_entity']), 10, 'Correct number of objects found after deleting'); + foreach ($found['test_entity'] as $id => $obj) { + $this->assertEqual($this->entities[$id]->{$field['field_name']}, $obj->{$field['field_name']}, "Object $id with deleted data loaded correctly"); + } + } + + /** + * Verify that field data items and instances are purged when an + * instance is deleted. + */ + function testPurgeInstance() { + field_test_memorize(); + + $bundle = reset($this->bundles); + $field = reset($this->fields); + + // Delete the instance. + field_delete_instance($field['field_name'], $bundle); + + // No field hooks were called. + $mem = field_test_memorize(); + $this->assertEqual(count($mem), 0, 'No field hooks were called'); + + $batch_size = 2; + for ($count = 8; $count >= 0; $count -= 2) { + // Purge two objects. + field_purge_batch($batch_size); + + // There are $count deleted objects left. + $found = field_attach_query($field['id'], array(array('bundle', $bundle), array('deleted', 1)), FIELD_QUERY_NO_LIMIT); + $this->assertEqual($count ? count($found['test_entity']) : count($found), $count, 'Correct number of objects found after purging 2'); + } + + // hook_field_delete() was called on a pseudo-object for each object. Each + // pseudo object has a $field property that matches the original object, + // but no others. + $mem = field_test_memorize(); + $this->assertEqual(count($mem['field_test_field_delete']), 10, 'hook_field_delete was called for the right number of objects'); + $stubs = $this->_generateStubObjects($this->entity_type, $this->entities, $field['field_name']); + $count = count($stubs); + foreach ($mem['field_test_field_delete'] as $args) { + $obj = $args[1]; + $this->assertEqual($stubs[$obj->ftid], $obj, 'hook_field_delete() called with the correct stub'); + unset($stubs[$obj->ftid]); + } + $this->assertEqual(count($stubs), $count-10, 'hook_field_delete was called with each object once'); + + // The instance still exists, deleted. + $instances = field_read_instances(array('field_id' => $field['id'], 'deleted' => 1), array('include_deleted' => 1, 'include_inactive' => 1)); + $this->assertEqual(count($instances), 1, 'There is one deleted instance'); + + // Purge the instance. + field_purge_batch($batch_size); + + // The instance is gone. + $instances = field_read_instances(array('field_id' => $field['id'], 'deleted' => 1), array('include_deleted' => 1, 'include_inactive' => 1)); + $this->assertEqual(count($instances), 0, 'The instance is gone'); + + // The field still exists, not deleted, because it has a second instance. + $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1, 'include_inactive' => 1)); + $this->assertEqual($field, $fields[$field['id']], 'The field exists and is not deleted'); + } + + /** + * Verify that fields are preserved and purged correctly as multiple + * instances are deleted and purged. + */ + function testPurgeField() { + $field = reset($this->fields); + + foreach ($this->bundles as $bundle) { + // Delete the instance. + field_delete_instance($field['field_name'], $bundle); + + // Purge the data. + field_purge_batch(10); + + // Purge again to purge the instance. + field_purge_batch(0); + + // The field still exists, not deleted, because it was never deleted. + $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1, 'include_inactive' => 1)); + $this->assertEqual($field, $fields[$field['id']], 'The field exists and is not deleted'); + } + + // Delete the field. + field_delete_field($field['field_name']); + + // The field still exists, deleted. + $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1, 'include_inactive' => 1)); + $this->assertEqual($fields[$field['id']]['deleted'], 1, 'The field exists and is deleted'); + + // Purge the field. + field_purge_batch(0); + + // The field is gone. + $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1, 'include_inactive' => 1)); + $this->assertEqual(count($fields), 0, 'The field is purged.'); + } +} |