Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / core / modules / content_moderation / tests / src / Kernel / ContentModerationStateTest.php
1 <?php
2
3 namespace Drupal\Tests\content_moderation\Kernel;
4
5 use Drupal\content_moderation\Entity\ContentModerationState;
6 use Drupal\Core\Entity\EntityInterface;
7 use Drupal\Core\Entity\EntityPublishedInterface;
8 use Drupal\Core\Entity\EntityStorageException;
9 use Drupal\Core\Language\LanguageInterface;
10 use Drupal\entity_test\Entity\EntityTestRev;
11 use Drupal\KernelTests\KernelTestBase;
12 use Drupal\language\Entity\ConfigurableLanguage;
13 use Drupal\node\Entity\Node;
14 use Drupal\node\Entity\NodeType;
15 use Drupal\workflows\Entity\Workflow;
16
17 /**
18  * Tests links between a content entity and a content_moderation_state entity.
19  *
20  * @group content_moderation
21  */
22 class ContentModerationStateTest extends KernelTestBase {
23
24   /**
25    * {@inheritdoc}
26    */
27   public static $modules = [
28     'entity_test',
29     'node',
30     'block',
31     'block_content',
32     'media',
33     'media_test_source',
34     'image',
35     'file',
36     'field',
37     'content_moderation',
38     'user',
39     'system',
40     'language',
41     'content_translation',
42     'text',
43     'workflows',
44   ];
45
46   /**
47    * @var \Drupal\Core\Entity\EntityTypeManager
48    */
49   protected $entityTypeManager;
50
51   /**
52    * {@inheritdoc}
53    */
54   protected function setUp() {
55     parent::setUp();
56
57     $this->installSchema('node', 'node_access');
58     $this->installEntitySchema('node');
59     $this->installEntitySchema('user');
60     $this->installEntitySchema('entity_test_rev');
61     $this->installEntitySchema('entity_test_no_bundle');
62     $this->installEntitySchema('entity_test_mulrevpub');
63     $this->installEntitySchema('block_content');
64     $this->installEntitySchema('media');
65     $this->installEntitySchema('file');
66     $this->installEntitySchema('content_moderation_state');
67     $this->installConfig('content_moderation');
68     $this->installSchema('file', 'file_usage');
69     $this->installConfig(['field', 'system', 'image', 'file', 'media']);
70
71     $this->entityTypeManager = $this->container->get('entity_type.manager');
72   }
73
74   /**
75    * Tests basic monolingual content moderation through the API.
76    *
77    * @dataProvider basicModerationTestCases
78    */
79   public function testBasicModeration($entity_type_id) {
80     $entity = $this->createEntity($entity_type_id);
81     if ($entity instanceof EntityPublishedInterface) {
82       $entity->setUnpublished();
83     }
84     $entity->save();
85     $entity = $this->reloadEntity($entity);
86     $this->assertEquals('draft', $entity->moderation_state->value);
87
88     $entity->moderation_state->value = 'published';
89     $entity->save();
90
91     $entity = $this->reloadEntity($entity);
92     $this->assertEquals('published', $entity->moderation_state->value);
93
94     // Change the state without saving the node.
95     $content_moderation_state = ContentModerationState::load(1);
96     $content_moderation_state->set('moderation_state', 'draft');
97     $content_moderation_state->setNewRevision(TRUE);
98     $content_moderation_state->save();
99
100     $entity = $this->reloadEntity($entity, 3);
101     $this->assertEquals('draft', $entity->moderation_state->value);
102     if ($entity instanceof EntityPublishedInterface) {
103       $this->assertFalse($entity->isPublished());
104     }
105
106     // Get the default revision.
107     $entity = $this->reloadEntity($entity);
108     if ($entity instanceof EntityPublishedInterface) {
109       $this->assertTrue((bool) $entity->isPublished());
110     }
111     $this->assertEquals(2, $entity->getRevisionId());
112
113     $entity->moderation_state->value = 'published';
114     $entity->save();
115
116     $entity = $this->reloadEntity($entity, 4);
117     $this->assertEquals('published', $entity->moderation_state->value);
118
119     // Get the default revision.
120     $entity = $this->reloadEntity($entity);
121     if ($entity instanceof EntityPublishedInterface) {
122       $this->assertTrue((bool) $entity->isPublished());
123     }
124     $this->assertEquals(4, $entity->getRevisionId());
125
126     // Update the node to archived which will then be the default revision.
127     $entity->moderation_state->value = 'archived';
128     $entity->save();
129
130     // Revert to the previous (published) revision.
131     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
132     $previous_revision = $entity_storage->loadRevision(4);
133     $previous_revision->isDefaultRevision(TRUE);
134     $previous_revision->setNewRevision(TRUE);
135     $previous_revision->save();
136
137     // Get the default revision.
138     $entity = $this->reloadEntity($entity);
139     $this->assertEquals('published', $entity->moderation_state->value);
140     if ($entity instanceof EntityPublishedInterface) {
141       $this->assertTrue($entity->isPublished());
142     }
143
144     // Set an invalid moderation state.
145     $this->setExpectedException(EntityStorageException::class);
146     $entity->moderation_state->value = 'foobar';
147     $entity->save();
148   }
149
150   /**
151    * Test cases for basic moderation test.
152    */
153   public function basicModerationTestCases() {
154     return [
155       'Nodes' => [
156         'node',
157       ],
158       'Block content' => [
159         'block_content',
160       ],
161       'Media' => [
162         'media',
163       ],
164       'Test entity - revisions, data table, and published interface' => [
165         'entity_test_mulrevpub',
166       ],
167       'Entity Test with revisions' => [
168         'entity_test_rev',
169       ],
170       'Entity without bundle' => [
171         'entity_test_no_bundle',
172       ],
173     ];
174   }
175
176   /**
177    * Tests removal of content moderation state entity.
178    *
179    * @dataProvider basicModerationTestCases
180    */
181   public function testContentModerationStateDataRemoval($entity_type_id) {
182     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
183     $entity = $this->createEntity($entity_type_id);
184     $entity->save();
185     $entity = $this->reloadEntity($entity);
186     $entity->delete();
187     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
188     $this->assertFalse($content_moderation_state);
189   }
190
191   /**
192    * Tests removal of content moderation state entity revisions.
193    *
194    * @dataProvider basicModerationTestCases
195    */
196   public function testContentModerationStateRevisionDataRemoval($entity_type_id) {
197     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
198     $entity = $this->createEntity($entity_type_id);
199     $entity->save();
200     $revision = clone $entity;
201     $revision->isDefaultRevision(FALSE);
202     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
203     $this->assertTrue($content_moderation_state);
204     $entity = $this->reloadEntity($entity);
205     $entity->setNewRevision(TRUE);
206     $entity->save();
207     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
208     $entity_storage->deleteRevision($revision->getRevisionId());
209     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
210     $this->assertFalse($content_moderation_state);
211     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
212     $this->assertTrue($content_moderation_state);
213   }
214
215   /**
216    * Tests removal of content moderation state pending entity revisions.
217    *
218    * @dataProvider basicModerationTestCases
219    */
220   public function testContentModerationStatePendingRevisionDataRemoval($entity_type_id) {
221     $entity = $this->createEntity($entity_type_id);
222     $entity->moderation_state = 'published';
223     $entity->save();
224     $entity->setNewRevision(TRUE);
225     $entity->moderation_state = 'draft';
226     $entity->save();
227
228     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
229     $this->assertTrue($content_moderation_state);
230
231     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
232     $entity_storage->deleteRevision($entity->getRevisionId());
233
234     $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
235     $this->assertFalse($content_moderation_state);
236   }
237
238   /**
239    * Tests removal of content moderation state translations.
240    *
241    * @dataProvider basicModerationTestCases
242    */
243   public function testContentModerationStateTranslationDataRemoval($entity_type_id) {
244     // Test content moderation state translation deletion.
245     if ($this->entityTypeManager->getDefinition($entity_type_id)->isTranslatable()) {
246       /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
247       $entity = $this->createEntity($entity_type_id);
248       $langcode = 'it';
249       ConfigurableLanguage::createFromLangcode($langcode)
250         ->save();
251       $entity->save();
252       $translation = $entity->addTranslation($langcode, ['title' => 'Titolo test']);
253       // Make sure we add values for all of the required fields.
254       if ($entity_type_id == 'block_content') {
255         $translation->info = $this->randomString();
256       }
257       $translation->save();
258       $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
259       $this->assertTrue($content_moderation_state->hasTranslation($langcode));
260       $entity->removeTranslation($langcode);
261       $entity->save();
262       $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
263       $this->assertFalse($content_moderation_state->hasTranslation($langcode));
264     }
265   }
266
267   /**
268    * Tests basic multilingual content moderation through the API.
269    */
270   public function testMultilingualModeration() {
271     // Enable French.
272     ConfigurableLanguage::createFromLangcode('fr')->save();
273     $node_type = NodeType::create([
274       'type' => 'example',
275     ]);
276     $node_type->save();
277
278     $workflow = Workflow::load('editorial');
279     $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
280     $workflow->save();
281
282     $english_node = Node::create([
283       'type' => 'example',
284       'title' => 'Test title',
285     ]);
286     // Revision 1 (en).
287     $english_node
288       ->setUnpublished()
289       ->save();
290     $this->assertEquals('draft', $english_node->moderation_state->value);
291     $this->assertFalse($english_node->isPublished());
292
293     // Create a French translation.
294     $french_node = $english_node->addTranslation('fr', ['title' => 'French title']);
295     $french_node->setUnpublished();
296     // Revision 1 (fr).
297     $french_node->save();
298     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
299     $this->assertEquals('draft', $french_node->moderation_state->value);
300     $this->assertFalse($french_node->isPublished());
301
302     // Move English node to create another draft.
303     $english_node = $this->reloadEntity($english_node);
304     $english_node->moderation_state->value = 'draft';
305     // Revision 2 (en, fr).
306     $english_node->save();
307     $english_node = $this->reloadEntity($english_node);
308     $this->assertEquals('draft', $english_node->moderation_state->value);
309
310     // French node should still be in draft.
311     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
312     $this->assertEquals('draft', $french_node->moderation_state->value);
313
314     // Publish the French node.
315     $french_node->moderation_state->value = 'published';
316     // Revision 3 (en, fr).
317     $french_node->save();
318     $french_node = $this->reloadEntity($french_node)->getTranslation('fr');
319     $this->assertTrue($french_node->isPublished());
320     $this->assertEquals('published', $french_node->moderation_state->value);
321     $this->assertTrue($french_node->isPublished());
322     $english_node = $french_node->getTranslation('en');
323     $this->assertEquals('draft', $english_node->moderation_state->value);
324
325     // Publish the English node.
326     $english_node->moderation_state->value = 'published';
327     // Revision 4 (en, fr).
328     $english_node->save();
329     $english_node = $this->reloadEntity($english_node);
330     $this->assertTrue($english_node->isPublished());
331
332     // Move the French node back to draft.
333     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
334     $this->assertTrue($french_node->isPublished());
335     $french_node->moderation_state->value = 'draft';
336     // Revision 5 (en, fr).
337     $french_node->save();
338     $french_node = $this->reloadEntity($english_node, 5)->getTranslation('fr');
339     $this->assertFalse($french_node->isPublished());
340     $this->assertTrue($french_node->getTranslation('en')->isPublished());
341
342     // Republish the French node.
343     $french_node->moderation_state->value = 'published';
344     // Revision 6 (en, fr).
345     $french_node->save();
346     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
347     $this->assertTrue($french_node->isPublished());
348
349     // Change the EN state without saving the node.
350     $content_moderation_state = ContentModerationState::load(1);
351     $content_moderation_state->set('moderation_state', 'draft');
352     $content_moderation_state->setNewRevision(TRUE);
353     // Revision 7 (en, fr).
354     $content_moderation_state->save();
355     $english_node = $this->reloadEntity($french_node, $french_node->getRevisionId() + 1);
356
357     $this->assertEquals('draft', $english_node->moderation_state->value);
358     $french_node = $this->reloadEntity($english_node)->getTranslation('fr');
359     $this->assertEquals('published', $french_node->moderation_state->value);
360
361     // This should unpublish the French node.
362     $content_moderation_state = ContentModerationState::load(1);
363     $content_moderation_state = $content_moderation_state->getTranslation('fr');
364     $content_moderation_state->set('moderation_state', 'draft');
365     $content_moderation_state->setNewRevision(TRUE);
366     // Revision 8 (en, fr).
367     $content_moderation_state->save();
368
369     $english_node = $this->reloadEntity($english_node, $english_node->getRevisionId());
370     $this->assertEquals('draft', $english_node->moderation_state->value);
371     $french_node = $this->reloadEntity($english_node, '8')->getTranslation('fr');
372     $this->assertEquals('draft', $french_node->moderation_state->value);
373     // Switching the moderation state to an unpublished state should update the
374     // entity.
375     $this->assertFalse($french_node->isPublished());
376
377     // Get the default english node.
378     $english_node = $this->reloadEntity($english_node);
379     $this->assertTrue($english_node->isPublished());
380     $this->assertEquals(6, $english_node->getRevisionId());
381   }
382
383   /**
384    * Tests moderation when the moderation_state field has a config override.
385    */
386   public function testModerationWithFieldConfigOverride() {
387     NodeType::create([
388       'type' => 'test_type',
389     ])->save();
390
391     $workflow = Workflow::load('editorial');
392     $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'test_type');
393     $workflow->save();
394
395     $fields = $this->container->get('entity_field.manager')->getFieldDefinitions('node', 'test_type');
396     $field_config = $fields['moderation_state']->getConfig('test_type');
397     $field_config->setLabel('Field Override!');
398     $field_config->save();
399
400     $node = Node::create([
401       'title' => 'Test node',
402       'type' => 'test_type',
403     ]);
404     $node->save();
405     $this->assertFalse($node->isPublished());
406     $this->assertEquals('draft', $node->moderation_state->value);
407
408     $node->moderation_state = 'published';
409     $node->save();
410     $this->assertTrue($node->isPublished());
411     $this->assertEquals('published', $node->moderation_state->value);
412   }
413
414   /**
415    * Tests that entities with special languages can be moderated.
416    */
417   public function testModerationWithSpecialLanguages() {
418     $workflow = Workflow::load('editorial');
419     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
420     $workflow->save();
421
422     // Create a test entity.
423     $entity = EntityTestRev::create([
424       'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
425     ]);
426     $entity->save();
427     $this->assertEquals('draft', $entity->moderation_state->value);
428
429     $entity->moderation_state->value = 'published';
430     $entity->save();
431
432     $this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
433   }
434
435   /**
436    * Tests that a non-translatable entity type with a langcode can be moderated.
437    */
438   public function testNonTranslatableEntityTypeModeration() {
439     $workflow = Workflow::load('editorial');
440     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
441     $workflow->save();
442
443     // Check that the tested entity type is not translatable.
444     $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
445     $this->assertFalse($entity_type->isTranslatable(), 'The test entity type is not translatable.');
446
447     // Create a test entity.
448     $entity = EntityTestRev::create();
449     $entity->save();
450     $this->assertEquals('draft', $entity->moderation_state->value);
451
452     $entity->moderation_state->value = 'published';
453     $entity->save();
454
455     $this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
456   }
457
458   /**
459    * Tests that a non-translatable entity type without a langcode can be
460    * moderated.
461    */
462   public function testNonLangcodeEntityTypeModeration() {
463     // Unset the langcode entity key for 'entity_test_rev'.
464     $entity_type = clone \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
465     $keys = $entity_type->getKeys();
466     unset($keys['langcode']);
467     $entity_type->set('entity_keys', $keys);
468     \Drupal::state()->set('entity_test_rev.entity_type', $entity_type);
469
470     // Update the entity type in order to remove the 'langcode' field.
471     \Drupal::entityDefinitionUpdateManager()->applyUpdates();
472
473     $workflow = Workflow::load('editorial');
474     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
475     $workflow->save();
476
477     // Check that the tested entity type is not translatable and does not have a
478     // 'langcode' entity key.
479     $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_rev');
480     $this->assertFalse($entity_type->isTranslatable(), 'The test entity type is not translatable.');
481     $this->assertFalse($entity_type->getKey('langcode'), "The test entity type does not have a 'langcode' entity key.");
482
483     // Create a test entity.
484     $entity = EntityTestRev::create();
485     $entity->save();
486     $this->assertEquals('draft', $entity->moderation_state->value);
487
488     $entity->moderation_state->value = 'published';
489     $entity->save();
490
491     $this->assertEquals('published', EntityTestRev::load($entity->id())->moderation_state->value);
492   }
493
494   /**
495    * Tests the dependencies of the workflow when using content moderation.
496    */
497   public function testWorkflowDependencies() {
498     $node_type = NodeType::create([
499       'type' => 'example',
500     ]);
501     $node_type->save();
502
503     $workflow = Workflow::load('editorial');
504     // Test both a config and non-config based bundle and entity type.
505     $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
506     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
507     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_no_bundle', 'entity_test_no_bundle');
508     $workflow->save();
509
510     $this->assertEquals([
511       'module' => [
512         'content_moderation',
513         'entity_test',
514       ],
515       'config' => [
516         'node.type.example',
517       ],
518     ], $workflow->getDependencies());
519
520     $this->assertEquals([
521       'entity_test_no_bundle',
522       'entity_test_rev',
523       'node'
524     ], $workflow->getTypePlugin()->getEntityTypes());
525
526     // Delete the node type and ensure it is removed from the workflow.
527     $node_type->delete();
528     $workflow = Workflow::load('editorial');
529     $entity_types = $workflow->getTypePlugin()->getEntityTypes();
530     $this->assertFalse(in_array('node', $entity_types));
531
532     // Uninstall entity test and ensure it's removed from the workflow.
533     $this->container->get('config.manager')->uninstall('module', 'entity_test');
534     $workflow = Workflow::load('editorial');
535     $entity_types = $workflow->getTypePlugin()->getEntityTypes();
536     $this->assertEquals([], $entity_types);
537   }
538
539   /**
540    * Test the content moderation workflow dependencies for non-config bundles.
541    */
542   public function testWorkflowNonConfigBundleDependencies() {
543     // Create a bundle not based on any particular configuration.
544     entity_test_create_bundle('test_bundle');
545
546     $workflow = Workflow::load('editorial');
547     $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test', 'test_bundle');
548     $workflow->save();
549
550     // Ensure the bundle is correctly added to the workflow.
551     $this->assertEquals([
552       'module' => [
553         'content_moderation',
554         'entity_test',
555       ],
556     ], $workflow->getDependencies());
557     $this->assertEquals([
558       'test_bundle',
559     ], $workflow->getTypePlugin()->getBundlesForEntityType('entity_test'));
560
561     // Delete the test bundle to ensure the workflow entity responds
562     // appropriately.
563     entity_test_delete_bundle('test_bundle');
564
565     $workflow = Workflow::load('editorial');
566     $this->assertEquals([], $workflow->getTypePlugin()->getBundlesForEntityType('entity_test'));
567     $this->assertEquals([
568       'module' => [
569         'content_moderation',
570       ],
571     ], $workflow->getDependencies());
572   }
573
574   /**
575    * Test the revision default state of the moderation state entity revisions.
576    *
577    * @param string $entity_type_id
578    *   The ID of entity type to be tested.
579    *
580    * @dataProvider basicModerationTestCases
581    */
582   public function testRevisionDefaultState($entity_type_id) {
583     // Check that the revision default state of the moderated entity and the
584     // content moderation state entity always match.
585     /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
586     $storage = $this->entityTypeManager->getStorage($entity_type_id);
587     /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $cms_storage */
588     $cms_storage = $this->entityTypeManager->getStorage('content_moderation_state');
589
590     $entity = $this->createEntity($entity_type_id);
591     $entity->get('moderation_state')->value = 'published';
592     $storage->save($entity);
593     /** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
594     $cms_entity = $cms_storage->loadUnchanged(1);
595     $this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
596
597     $entity->get('moderation_state')->value = 'published';
598     $storage->save($entity);
599     /** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
600     $cms_entity = $cms_storage->loadUnchanged(1);
601     $this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
602
603     $entity->get('moderation_state')->value = 'draft';
604     $storage->save($entity);
605     /** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
606     $cms_entity = $cms_storage->loadUnchanged(1);
607     $this->assertEquals($entity->getLoadedRevisionId() - 1, $cms_entity->get('content_entity_revision_id')->value);
608
609     $entity->get('moderation_state')->value = 'published';
610     $storage->save($entity);
611     /** @var \Drupal\Core\Entity\ContentEntityInterface $cms_entity */
612     $cms_entity = $cms_storage->loadUnchanged(1);
613     $this->assertEquals($entity->getLoadedRevisionId(), $cms_entity->get('content_entity_revision_id')->value);
614   }
615
616   /**
617    * Creates an entity.
618    *
619    * The entity will have required fields populated and the corresponding bundle
620    * will be enabled for content moderation.
621    *
622    * @param string $entity_type_id
623    *   The entity type ID.
624    *
625    * @return \Drupal\Core\Entity\ContentEntityInterface
626    *   The created entity.
627    */
628   protected function createEntity($entity_type_id) {
629     $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
630
631     $bundle_id = $entity_type_id;
632     // Set up a bundle entity type for the specified entity type, if needed.
633     if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) {
634       $bundle_entity_type = $this->entityTypeManager->getDefinition($bundle_entity_type_id);
635       $bundle_entity_storage = $this->entityTypeManager->getStorage($bundle_entity_type_id);
636
637       $bundle_id = 'example';
638       if (!$bundle_entity_storage->load($bundle_id)) {
639         $bundle_entity = $bundle_entity_storage->create([
640           $bundle_entity_type->getKey('id') => 'example',
641         ]);
642         if ($entity_type_id == 'media') {
643           $bundle_entity->set('source', 'test');
644           $bundle_entity->save();
645           $source_field = $bundle_entity->getSource()->createSourceField($bundle_entity);
646           $source_field->getFieldStorageDefinition()->save();
647           $source_field->save();
648           $bundle_entity->set('source_configuration', [
649             'source_field' => $source_field->getName(),
650           ]);
651         }
652         $bundle_entity->save();
653       }
654     }
655
656     $workflow = Workflow::load('editorial');
657     $workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
658     $workflow->save();
659
660     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
661     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
662     $entity = $entity_storage->create([
663       $entity_type->getKey('label') => 'Test title',
664       $entity_type->getKey('bundle') => $bundle_id,
665     ]);
666     // Make sure we add values for all of the required fields.
667     if ($entity_type_id == 'block_content') {
668       $entity->info = $this->randomString();
669     }
670     return $entity;
671   }
672
673   /**
674    * Reloads the entity after clearing the static cache.
675    *
676    * @param \Drupal\Core\Entity\EntityInterface $entity
677    *   The entity to reload.
678    * @param int|bool $revision_id
679    *   The specific revision ID to load. Defaults FALSE and just loads the
680    *   default revision.
681    *
682    * @return \Drupal\Core\Entity\EntityInterface
683    *   The reloaded entity.
684    */
685   protected function reloadEntity(EntityInterface $entity, $revision_id = FALSE) {
686     $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());
687     $storage->resetCache([$entity->id()]);
688     if ($revision_id) {
689       return $storage->loadRevision($revision_id);
690     }
691     return $storage->load($entity->id());
692   }
693
694 }