diff --git a/core/modules/media/config/install/system.action.media_update_metadata.yml b/core/modules/media/config/install/system.action.media_update_metadata.yml
new file mode 100644
index 0000000000..e31298e408
--- /dev/null
+++ b/core/modules/media/config/install/system.action.media_update_metadata.yml
@@ -0,0 +1,10 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - media
+id: media_update_metadata
+label: 'Update metadata'
+type: media
+plugin: media_update_metadata
+configuration: {  }
diff --git a/core/modules/media/config/schema/media.schema.yml b/core/modules/media/config/schema/media.schema.yml
index 08bf800f59..84ebc9504f 100644
--- a/core/modules/media/config/schema/media.schema.yml
+++ b/core/modules/media/config/schema/media.schema.yml
@@ -124,3 +124,7 @@ filter_settings.media_embed:
       sequence:
         type: string
         label: 'Media type'
+
+action.configuration.media_update_metadata:
+  type: action_configuration_default
+  label: 'Update metadata'
diff --git a/core/modules/media/media.links.contextual.yml b/core/modules/media/media.links.contextual.yml
index 1945ef5001..cf919f396c 100644
--- a/core/modules/media/media.links.contextual.yml
+++ b/core/modules/media/media.links.contextual.yml
@@ -3,6 +3,12 @@ entity.media.edit_form:
   group: media
   title: Edit
 
+media.update_metadata:
+  route_name: media.update_metadata
+  group: media
+  title: 'Update metadata'
+  weight: 5
+
 entity.media.delete_form:
   route_name: entity.media.delete_form
   group: media
diff --git a/core/modules/media/media.post_update.php b/core/modules/media/media.post_update.php
index d28e788662..3d055a5d10 100644
--- a/core/modules/media/media.post_update.php
+++ b/core/modules/media/media.post_update.php
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Field\Entity\BaseFieldOverride;
+use Drupal\system\Entity\Action;
 
 /**
  * Implements hook_removed_post_updates().
@@ -34,3 +35,18 @@ function media_post_update_modify_base_field_author_override() {
     $base_field_override->setDefaultValueCallback('Drupal\media\Entity\Media::getDefaultEntityOwner')->save();
   }
 }
+
+/**
+ * Install the 'Update metadata' action.
+ */
+function media_post_update_install_update_metadata_action() {
+  if (!Action::load('media_update_metadata')) {
+    Action::create([
+      'id' => 'media_update_metadata',
+      'label' => 'Update metadata',
+      'type' => 'media',
+      'plugin' => 'media_update_metadata',
+    ])
+      ->save();
+  }
+}
diff --git a/core/modules/media/media.routing.yml b/core/modules/media/media.routing.yml
index 5dc97324d7..5cd033fcf0 100644
--- a/core/modules/media/media.routing.yml
+++ b/core/modules/media/media.routing.yml
@@ -13,6 +13,14 @@ entity.media.revision:
     _entity_access: 'media_revision.view all revisions'
     media: \d+
 
+media.update_metadata:
+  path: '/media/{media}/update-metadata'
+  defaults:
+    _controller: '\Drupal\media\Controller\UpdateMetadataController::updateMetadata'
+  requirements:
+    _entity_access: 'media.update'
+    _csrf_token: 'TRUE'
+
 media.oembed_iframe:
   path: '/media/oembed'
   defaults:
diff --git a/core/modules/media/src/Controller/UpdateMetadataController.php b/core/modules/media/src/Controller/UpdateMetadataController.php
new file mode 100644
index 0000000000..d04ec11c9a
--- /dev/null
+++ b/core/modules/media/src/Controller/UpdateMetadataController.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Drupal\media\Controller;
+
+use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Url;
+use Drupal\media\MediaInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
+/**
+ * Controller that triggers metadata updates on a given media item.
+ *
+ * @internal
+ *   Controllers are internal.
+ */
+class UpdateMetadataController extends ControllerBase {
+
+  /**
+   * Updates metadata on a media entity and reloads the page.
+   *
+   * @param \Drupal\media\MediaInterface $media
+   *   The media item for which to update metadata.
+   *
+   * @return \Symfony\Component\HttpFoundation\RedirectResponse
+   *   A redirect response to return the user to the page they were on.
+   */
+  public function updateMetadata(MediaInterface $media) {
+    $media->enforceMetadataUpdate();
+    $this->entityTypeManager()->getStorage('media')->save($media);
+    $this->messenger()->addStatus($this->t('Updated metadata on media item %label', [
+      '%label' => $media->label(),
+    ]));
+    return new RedirectResponse($this->reloadPage());
+  }
+
+  /**
+   * Reloads the previous page or return to the media overview.
+   */
+  protected function reloadPage() {
+    if ($destination = $this->getRedirectDestination()->get()) {
+      return $destination;
+    }
+    return Url::fromRoute('entity.media.collection')->toString();
+  }
+
+}
diff --git a/core/modules/media/src/Entity/Media.php b/core/modules/media/src/Entity/Media.php
index 6649cccfd0..0470c7feb7 100644
--- a/core/modules/media/src/Entity/Media.php
+++ b/core/modules/media/src/Entity/Media.php
@@ -88,6 +88,13 @@ class Media extends EditorialContentEntityBase implements MediaInterface {
   use EntityOwnerTrait;
   use StringTranslationTrait;
 
+  /**
+   * Force media item metadata update.
+   *
+   * @var bool
+   */
+  protected $forceMetadataUpdate = FALSE;
+
   /**
    * {@inheritdoc}
    */
@@ -287,8 +294,8 @@ protected function hasSourceFieldChanged() {
    */
   protected function shouldUpdateThumbnail($is_new = FALSE) {
     // Update thumbnail if we don't have a thumbnail yet or when the source
-    // field value changes.
-    return !$this->get('thumbnail')->entity || $is_new || $this->hasSourceFieldChanged();
+    // field value changed or when it was enforced.
+    return $is_new || $this->forceMetadataUpdate || !$this->get('thumbnail')->entity || $this->hasSourceFieldChanged();
   }
 
   /**
@@ -368,29 +375,57 @@ public function prepareSave() {
         ->loadUnchanged($id);
     }
 
-    $media_source = $this->getSource();
-    foreach ($this->translations as $langcode => $data) {
-      if ($this->hasTranslation($langcode)) {
-        $translation = $this->getTranslation($langcode);
-        // Try to set fields provided by the media source and mapped in
-        // media type config.
-        foreach ($translation->bundle->entity->getFieldMap() as $metadata_attribute_name => $entity_field_name) {
-          // Only save value in entity field if empty. Do not overwrite existing
-          // data.
-          if ($translation->hasField($entity_field_name) && ($translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged())) {
-            $translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name));
-          }
-        }
+    foreach (array_keys($this->getTranslationLanguages()) as $langcode) {
+      $translation = $this->getTranslation($langcode);
 
-        // Try to set a default name for this media item if no name is provided.
-        if ($translation->get('name')->isEmpty()) {
-          $translation->setName($translation->getName());
-        }
+      // Set fields provided by the media source and mapped in the media type
+      // config.
+      $this->updateMappedMetadata($translation, $this->forceMetadataUpdate);
 
-        // Set thumbnail.
-        if ($translation->shouldUpdateThumbnail($this->isNew())) {
-          $translation->updateThumbnail();
-        }
+      // Try to set a default name for this media item if no name is provided.
+      if ($translation->get('name')->isEmpty()) {
+        $translation->setName($translation->getName());
+      }
+
+      // Set thumbnail.
+      if ($translation->shouldUpdateThumbnail($this->isNew())) {
+        $translation->updateThumbnail();
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function enforceMetadataUpdate() {
+    $this->forceMetadataUpdate = TRUE;
+
+    return $this;
+  }
+
+  /**
+   * Maps metadata values into entity field values.
+   *
+   * @param \Drupal\media\MediaInterface $translation
+   *   The media translation we are updating.
+   * @param bool $overwrite_existing
+   *   (optional) If TRUE, metadata values will always be copied into mapped
+   *   field values. If FALSE, values will be copied only if the mapped field is
+   *   empty or if the media source field changed. Defaults to FALSE.
+   */
+  protected function updateMappedMetadata(MediaInterface $translation, $overwrite_existing = FALSE) {
+    $media_source = $this->getSource();
+    foreach ($translation->bundle->entity->getFieldMap() as $metadata_attribute_name => $entity_field_name) {
+      if (!$translation->hasField($entity_field_name)) {
+        continue;
+      }
+
+      // Populate the field value in one of these scenarios:
+      // - The caller of this function asked for it explicitly.
+      // - The entity field is empty.
+      // - The media source field has changed.
+      if ($overwrite_existing || $translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged()) {
+        $translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name));
       }
     }
   }
diff --git a/core/modules/media/src/MediaInterface.php b/core/modules/media/src/MediaInterface.php
index 3aeaef56ab..5bc2dd7314 100644
--- a/core/modules/media/src/MediaInterface.php
+++ b/core/modules/media/src/MediaInterface.php
@@ -64,4 +64,11 @@ public function setCreatedTime($timestamp);
    */
   public function getSource();
 
+  /**
+   * Force metadata update in prepareSave().
+   *
+   * @return $this
+   */
+  public function enforceMetadataUpdate();
+
 }
diff --git a/core/modules/media/src/MediaListBuilder.php b/core/modules/media/src/MediaListBuilder.php
index 44ae6a8b7c..1b5afbf294 100644
--- a/core/modules/media/src/MediaListBuilder.php
+++ b/core/modules/media/src/MediaListBuilder.php
@@ -9,6 +9,7 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Url;
 
 /**
  * Provides a listing of media items.
@@ -159,4 +160,21 @@ protected function getEntityIds() {
     return $query->execute();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    if ($entity->access('update')) {
+      $operations['update_metadata'] = [
+        'title' => t('Update metadata'),
+        'url' => $this->ensureDestination(new Url('media.update_metadata', [
+          'media' => $entity->id(),
+        ])),
+        'weight' => 150,
+      ];
+    }
+    return $operations;
+  }
+
 }
diff --git a/core/modules/media/src/Plugin/Action/UpdateMetadataAction.php b/core/modules/media/src/Plugin/Action/UpdateMetadataAction.php
new file mode 100644
index 0000000000..d125923793
--- /dev/null
+++ b/core/modules/media/src/Plugin/Action/UpdateMetadataAction.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\media\Plugin\Action;
+
+use Drupal\Core\Action\ActionBase;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Updates metadata (including the thumbnail) of a media entity.
+ *
+ * @Action(
+ *   id = "media_update_metadata",
+ *   action_label = @Translation("Update metadata")
+ * )
+ */
+class UpdateMetadataAction extends ActionBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The media entity storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $mediaStorage;
+
+  /**
+   * Creates a new UpdateMetadataAction plugin instance.
+   *
+   * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
+   *   The entity storage.
+   * @param array $configuration
+   *   The plugin configuration array.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   */
+  public function __construct(EntityStorageInterface $entity_storage, array $configuration, $plugin_id, $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->mediaStorage = $entity_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $container->get('entity_type.manager')->getStorage('media'),
+      $configuration,
+      $plugin_id,
+      $plugin_definition
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute($entity = NULL) {
+    if ($entity) {
+      /** @var \Drupal\media\MediaInterface $entity */
+      $entity->enforceMetadataUpdate();
+      $this->mediaStorage->save($entity);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
+    /** @var \Drupal\Core\Entity\EntityInterface $object */
+    $result = $object->access('update', $account, TRUE);
+    return $return_as_object ? $result : $result->isAllowed();
+  }
+
+}
diff --git a/core/modules/media/tests/src/Functional/MediaBulkFormTest.php b/core/modules/media/tests/src/Functional/MediaBulkFormTest.php
index d65f34e2b0..a6006777d2 100644
--- a/core/modules/media/tests/src/Functional/MediaBulkFormTest.php
+++ b/core/modules/media/tests/src/Functional/MediaBulkFormTest.php
@@ -72,12 +72,14 @@ public function testBulkForm() {
 
     // Check the operations are accessible to the logged in user.
     $this->drupalGet('test-media-bulk-form');
-    // Current available actions: Delete, Save, Publish, Unpublish.
+    // Current available actions: Delete, Save, Publish, Unpublish, Update
+    // Metadata.
     $available_actions = [
       'media_delete_action',
       'media_publish_action',
       'media_save_action',
       'media_unpublish_action',
+      'media_update_metadata',
     ];
     foreach ($available_actions as $action_name) {
       $assert_session->optionExists('action', $action_name);
diff --git a/core/modules/media/tests/src/Functional/MediaContextualLinksTest.php b/core/modules/media/tests/src/Functional/MediaContextualLinksTest.php
deleted file mode 100644
index f5cf9a81bc..0000000000
--- a/core/modules/media/tests/src/Functional/MediaContextualLinksTest.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-namespace Drupal\Tests\media\Functional;
-
-use Drupal\media\Entity\Media;
-
-/**
- * Tests views contextual links on media items.
- *
- * @group media
- */
-class MediaContextualLinksTest extends MediaFunctionalTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected static $modules = [
-    'contextual',
-  ];
-
-  /**
-   * {@inheritdoc}
-   */
-  protected $defaultTheme = 'stark';
-
-  /**
-   * Tests contextual links.
-   */
-  public function testMediaContextualLinks() {
-    \Drupal::configFactory()
-      ->getEditable('media.settings')
-      ->set('standalone_url', TRUE)
-      ->save(TRUE);
-
-    $this->container->get('router.builder')->rebuild();
-
-    // Create a media type.
-    $mediaType = $this->createMediaType('test');
-
-    // Create a media item.
-    $media = Media::create([
-      'bundle' => $mediaType->id(),
-      'name' => 'Unnamed',
-    ]);
-    $media->save();
-
-    $user = $this->drupalCreateUser([
-      'administer media',
-      'access contextual links',
-    ]);
-    $this->drupalLogin($user);
-
-    $this->drupalGet('media/' . $media->id());
-    $this->assertSession()->elementAttributeContains('css', 'div[data-contextual-id]', 'data-contextual-id', 'media:media=' . $media->id() . ':');
-  }
-
-}
diff --git a/core/modules/media/tests/src/Functional/MediaOverviewPageTest.php b/core/modules/media/tests/src/Functional/MediaOverviewPageTest.php
index ce6146cde5..ff903c07c1 100644
--- a/core/modules/media/tests/src/Functional/MediaOverviewPageTest.php
+++ b/core/modules/media/tests/src/Functional/MediaOverviewPageTest.php
@@ -139,6 +139,9 @@ public function testMediaOverviewPage() {
     $delete_link1 = $assert_session->elementExists('css', 'td.views-field-operations li.delete a', $row1);
     $this->assertSame('Delete', $delete_link1->getText());
     $assert_session->linkByHrefExists('/media/' . $media1->id() . '/delete');
+    $update_metadata_link1 = $assert_session->elementExists('css', 'td.views-field-operations li.update-metadata a', $row1);
+    $this->assertSame('Update metadata', $update_metadata_link1->getText());
+    $assert_session->linkByHrefExists('/media/' . $media1->id() . '/update-metadata');
 
     // Make the user the owner of the unpublished media item and assert the
     // media item is only visible with the 'view own unpublished media'
diff --git a/core/modules/media/tests/src/Functional/MediaUpdateMetadataControllerTest.php b/core/modules/media/tests/src/Functional/MediaUpdateMetadataControllerTest.php
new file mode 100644
index 0000000000..b64b51f770
--- /dev/null
+++ b/core/modules/media/tests/src/Functional/MediaUpdateMetadataControllerTest.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\Tests\media\Functional;
+
+use Drupal\file\Entity\File as FileEntity;
+use Drupal\media\Entity\Media;
+use Drupal\media\Plugin\media\Source\File;
+
+/**
+ * Tests the media "Update Metadata" controller.
+ *
+ * @group media
+ */
+class MediaUpdateMetadataControllerTest extends MediaFunctionalTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * Test that by going to the update metadata page, we update the metadata.
+   */
+  public function testUpdateMetadataController() {
+    $assert_session = $this->assertSession();
+
+    $media_type = $this->createMediaType('file');
+    $source_plugin = $media_type->getSource();
+
+    // Initially the "name" metadata is the filename.
+    $file = FileEntity::create([
+      'uri' => 'public://foo.txt',
+      'uid' => 1,
+    ]);
+    $file->setPermanent();
+    $file->save();
+
+    /** @var \Drupal\media\MediaInterface $media */
+    $media = Media::create([
+      'bundle' => $media_type->id(),
+      'uid' => 1,
+      'field_media_file' => [
+        'target_id' => $file->id(),
+      ],
+    ]);
+    $media->save();
+
+    $name_metadata = $source_plugin->getMetadata($media, File::METADATA_ATTRIBUTE_NAME);
+    $this->assertSame('foo.txt', $name_metadata);
+
+    // Rename the file, simulating a remote metadata change.
+    $file_id = $source_plugin->getSourceFieldValue($media);
+    /** @var \Drupal\file\FileInterface $file */
+    $file = $this->container->get('entity_type.manager')
+      ->getStorage('file')
+      ->load($file_id);
+    $file->setFilename('bar.txt');
+    $file->save();
+
+    // Go to the update metadata page and verify the controller triggered an
+    // update.
+    $media_id = $media->id();
+    $site_base_path = base_path();
+
+    $this->drupalGet("/admin/content/media");
+    $this->assertSession()->elementExists(
+      'xpath',
+      "//ul[contains(@class, dropbutton)]/li/a[starts-with(@href, '{$site_base_path}media/{$media_id}/update-metadata')]"
+    )->click();
+
+    $assert_session->statusCodeEquals(200);
+
+    $name_metadata = $source_plugin->getMetadata($media, File::METADATA_ATTRIBUTE_NAME);
+    $this->assertSame('bar.txt', $name_metadata);
+  }
+
+}
diff --git a/core/modules/media/tests/src/FunctionalJavascript/MediaContextualLinksTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaContextualLinksTest.php
new file mode 100644
index 0000000000..d9619f520a
--- /dev/null
+++ b/core/modules/media/tests/src/FunctionalJavascript/MediaContextualLinksTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Drupal\Tests\media\FunctionalJavascript;
+
+use Drupal\media\Entity\Media;
+
+/**
+ * Tests views contextual links on media items.
+ *
+ * @group media
+ */
+class MediaContextualLinksTest extends MediaJavascriptTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'contextual',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    // This test is going to test the display, so we need the standalone URL.
+    \Drupal::configFactory()
+      ->getEditable('media.settings')
+      ->set('standalone_url', TRUE)
+      ->save(TRUE);
+
+    $this->container->get('router.builder')->rebuild();
+  }
+
+  /**
+   * Tests contextual links.
+   */
+  public function testMediaContextualLinks() {
+    // Create a media type.
+    $mediaType = $this->createMediaType('test');
+
+    // Create a media item.
+    $media = Media::create([
+      'bundle' => $mediaType->id(),
+      'name' => 'Unnamed',
+    ]);
+    $media->save();
+
+    $user = $this->drupalCreateUser([
+      'administer media',
+      'access contextual links',
+      'view media',
+    ]);
+    $this->drupalLogin($user);
+
+    $this->drupalGet('media/' . $media->id());
+
+    // Contextual links are populated by javascript after the page is loaded.
+    // Wait until they are on the page, click on the pencil so we make sure they
+    // are visible, and then we can assert their contents.
+    $this->assertSession()->waitForElement('css', 'div[data-contextual-id] ul.contextual-links');
+    $this->getSession()->executeScript("jQuery('.contextual .trigger').toggleClass('visually-hidden');");
+    $this->cssSelect('.contextual button')[0]->press();
+
+    // The contextual links container is there.
+    $this->assertSession()->elementAttributeContains('css', 'div[data-contextual-id]', 'data-contextual-id', 'media:media=' . $media->id() . ':');
+
+    // The "Edit" link is there.
+    $this->assertSession()->elementTextContains('css', 'ul.contextual-links li:first-child a', 'Edit');
+
+    // The "Update metadata" link is there.
+    $this->assertSession()->elementTextContains('css', 'ul.contextual-links li:nth-child(2) a', 'Update metadata');
+
+    // The "Delete" link is there.
+    $this->assertSession()->elementTextContains('css', 'ul.contextual-links li:nth-child(3) a', 'Delete');
+  }
+
+}
diff --git a/core/modules/media/tests/src/Kernel/MediaUpdateMetadataTest.php b/core/modules/media/tests/src/Kernel/MediaUpdateMetadataTest.php
new file mode 100644
index 0000000000..c42bb48561
--- /dev/null
+++ b/core/modules/media/tests/src/Kernel/MediaUpdateMetadataTest.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Drupal\Tests\media\Kernel;
+
+use Drupal\media\Plugin\media\Source\File;
+
+/**
+ * Tests the update metadata method on Media entities.
+ *
+ * @group media
+ */
+class MediaUpdateMetadataTest extends MediaKernelTestBase {
+
+  /**
+   * Tests the update metadata operation.
+   */
+  public function testUpdateMetadata() {
+    $media_type = $this->createMediaType('file');
+    $source_plugin = $media_type->getSource();
+
+    // Initially the "name" metadata is the filename.
+    $media = $this->generateMedia('foo.txt', $media_type);
+    $media->save();
+    $name_metadata = $source_plugin->getMetadata($media, File::METADATA_ATTRIBUTE_NAME);
+    $this->assertSame('foo.txt', $name_metadata);
+
+    // Rename the file, simulating a remote metadata change.
+    $file_id = $source_plugin->getSourceFieldValue($media);
+    /** @var \Drupal\file\FileInterface $file */
+    $file = $this->container->get('entity_type.manager')
+      ->getStorage('file')
+      ->load($file_id);
+    $file->setFilename('bar.txt');
+    $file->save();
+
+    // Update metadata, we should now pick the new name.
+    $media->enforceMetadataUpdate()->save();
+
+    $name_metadata = $source_plugin->getMetadata($media, File::METADATA_ATTRIBUTE_NAME);
+    $this->assertSame('bar.txt', $name_metadata);
+  }
+
+}
