split update into local/remote
diff --git a/src/client.rs b/src/client.rs
index 1f9dca1..5c5ed59 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,7 +1,5 @@
 //! Clients for high level interactions with TUF repositories.
 
-use chrono::offset::Utc;
-
 use Result;
 use crypto;
 use error::Error;
@@ -40,38 +38,66 @@
         }
     }
 
-    /// Update TUF metadata from local and remote repositories.
+    /// Update TUF metadata from the local repository.
     ///
     /// Returns `true` if an update occurred and `false` otherwise.
-    // TODO this might need to be split into `update_local` and `update_remote` to be useful to
-    // implementers.
-    pub fn update(&mut self) -> Result<bool> {
-        if self.update_root()? && self.update_timestamp()? {
-            self.update_snapshot()
-        } else {
-            Ok(false)
-        }
+    pub fn update_local(&mut self) -> Result<bool> {
+        let r = Self::update_root(&mut self.tuf, &mut self.local, &self.config.max_root_size)?;
+        let ts = match Self::update_timestamp(
+            &mut self.tuf,
+            &mut self.local,
+            &self.config.max_timestamp_size,
+        ) {
+            Ok(b) => b,
+            Err(e) => {
+                warn!(
+                    "Error updating timestamp metadata from local sources: {:?}",
+                    e
+                );
+                false
+            }
+        };
+        let sn = match Self::update_snapshot(&mut self.tuf, &mut self.local) {
+            Ok(b) => b,
+            Err(e) => {
+                warn!(
+                    "Error updating snapshot metadata from local sources: {:?}",
+                    e
+                );
+                false
+            }
+        };
+        let ta = match Self::update_targets(&mut self.tuf, &mut self.local) {
+            Ok(b) => b,
+            Err(e) => {
+                warn!(
+                    "Error updating targets metadata from local sources: {:?}",
+                    e
+                );
+                false
+            }
+        };
+
+        Ok(r || ts || sn || ta)
+    }
+
+    /// Update TUF metadata from the remote repository.
+    ///
+    /// Returns `true` if an update occurred and `false` otherwise.
+    pub fn update_remote(&mut self) -> Result<bool> {
+        Ok(
+            Self::update_root(&mut self.tuf, &mut self.remote, &self.config.max_root_size)? ||
+                Self::update_timestamp(
+                    &mut self.tuf,
+                    &mut self.remote,
+                    &self.config.max_timestamp_size,
+                )? || Self::update_snapshot(&mut self.tuf, &mut self.remote)? ||
+                Self::update_targets(&mut self.tuf, &mut self.local)?,
+        )
     }
 
     /// Returns `true` if an update occurred and `false` otherwise.
-    fn update_root(&mut self) -> Result<bool> {
-        let local_updated =
-            Self::update_root_chain(&mut self.tuf, &self.config.max_root_size, &mut self.local)?;
-        let remote_updated =
-            Self::update_root_chain(&mut self.tuf, &self.config.max_root_size, &mut self.remote)?;
-
-        if self.tuf.root().expires() <= &Utc::now() {
-            Err(Error::ExpiredMetadata(Role::Root))
-        } else {
-            Ok(local_updated || remote_updated)
-        }
-    }
-
-    fn update_root_chain<T>(
-        tuf: &mut Tuf<D>,
-        max_root_size: &Option<usize>,
-        repo: &mut T,
-    ) -> Result<bool>
+    fn update_root<T>(tuf: &mut Tuf<D>, repo: &mut T, max_root_size: &Option<usize>) -> Result<bool>
     where
         T: Repository<D>,
     {
@@ -118,33 +144,35 @@
     }
 
     /// Returns `true` if an update occurred and `false` otherwise.
-    fn update_timestamp(&mut self) -> Result<bool> {
-        let ts = self.local.fetch_metadata(
+    fn update_timestamp<T>(
+        tuf: &mut Tuf<D>,
+        repo: &mut T,
+        max_timestamp_size: &Option<usize>,
+    ) -> Result<bool>
+    where
+        T: Repository<D>,
+    {
+        let ts = repo.fetch_metadata(
             &Role::Timestamp,
             &MetadataVersion::None,
-            &self.config.max_timestamp_size,
+            max_timestamp_size,
             None,
         )?;
-        self.tuf.update_timestamp(ts)?;
-
-        let ts = self.remote.fetch_metadata(
-            &Role::Timestamp,
-            &MetadataVersion::None,
-            &self.config.max_timestamp_size,
-            None,
-        )?;
-        self.tuf.update_timestamp(ts)
+        tuf.update_timestamp(ts)
     }
 
     /// Returns `true` if an update occurred and `false` otherwise.
-    fn update_snapshot(&mut self) -> Result<bool> {
-        let snapshot_description = match self.tuf.timestamp() {
+    fn update_snapshot<T>(tuf: &mut Tuf<D>, repo: &mut T) -> Result<bool>
+    where
+        T: Repository<D>,
+    {
+        let snapshot_description = match tuf.timestamp() {
             Some(ts) => {
                 match ts.meta().get(&MetadataPath::from_role(&Role::Timestamp)) {
                     Some(d) => Ok(d),
                     None => Err(Error::VerificationFailure(
                         "Timestamp metadata did not contain a description of the \
-                                current snapshot metadata"
+                                current snapshot metadata."
                             .into(),
                     )),
                 }
@@ -158,25 +186,52 @@
             None => None,
         };
 
-        let snap = self.local.fetch_metadata(
+        let snap = repo.fetch_metadata(
             &Role::Snapshot,
             &MetadataVersion::None,
             &snapshot_description.length(),
             hashes,
         )?;
-        self.tuf.update_snapshot(snap)?;
+        tuf.update_snapshot(snap)
+    }
 
-        let snap = self.remote.fetch_metadata(
-            &Role::Snapshot,
+    /// Returns `true` if an update occurred and `false` otherwise.
+    fn update_targets<T>(tuf: &mut Tuf<D>, repo: &mut T) -> Result<bool>
+    where
+        T: Repository<D>,
+    {
+        let targets_description = match tuf.snapshot() {
+            Some(sn) => {
+                match sn.meta().get(&MetadataPath::from_role(&Role::Targets)) {
+                    Some(d) => Ok(d),
+                    None => Err(Error::VerificationFailure(
+                        "Snapshot metadata did not contain a description of the \
+                                current targets metadata."
+                            .into(),
+                    )),
+                }
+            }
+            None => Err(Error::MissingMetadata(Role::Snapshot)),
+        }?
+            .clone();
+
+        let hashes = match targets_description.hashes() {
+            Some(hashes) => Some(crypto::hash_preference(hashes)?),
+            None => None,
+        };
+
+        let targets = repo.fetch_metadata(
+            &Role::Targets,
             &MetadataVersion::None,
-            &snapshot_description.length(),
+            &targets_description.length(),
             hashes,
         )?;
-        self.tuf.update_snapshot(snap)
+        tuf.update_targets(targets)
     }
 }
 
 /// Configuration for a TUF `Client`.
+#[derive(Debug)]
 pub struct Config {
     max_root_size: Option<usize>,
     max_timestamp_size: Option<usize>,
@@ -190,6 +245,7 @@
 }
 
 /// Helper for building and validating a TUF `Config`.
+#[derive(Debug, PartialEq)]
 pub struct ConfigBuilder {
     max_root_size: Option<usize>,
     max_timestamp_size: Option<usize>,
@@ -218,6 +274,16 @@
 }
 
 impl Default for ConfigBuilder {
+    /// ```
+    /// use tuf::client::ConfigBuilder;
+    ///
+    /// let default = ConfigBuilder::default();
+    /// let config = ConfigBuilder::default()
+    ///     .max_root_size(Some(1024 * 1024))
+    ///     .max_timestamp_size(Some(32 * 1024));
+    /// assert_eq!(config, default);
+    /// assert!(default.finish().is_ok())
+    /// ```
     fn default() -> Self {
         ConfigBuilder {
             max_root_size: Some(1024 * 1024),
diff --git a/src/interchange/mod.rs b/src/interchange/mod.rs
index f202f99..42bbbd2 100644
--- a/src/interchange/mod.rs
+++ b/src/interchange/mod.rs
@@ -49,6 +49,11 @@
 impl DataInterchange for JsonDataInterchange {
     type RawData = json::Value;
 
+    /// ```
+    /// use tuf::interchange::{DataInterchange, JsonDataInterchange};
+    ///
+    /// assert_eq!(JsonDataInterchange::extension(), "json");
+    /// ```
     fn extension() -> &'static str {
         "json"
     }
diff --git a/src/tuf.rs b/src/tuf.rs
index 54e6ab4..54bc41b 100644
--- a/src/tuf.rs
+++ b/src/tuf.rs
@@ -64,6 +64,11 @@
         &self.root
     }
 
+    /// An immutable reference to the optional snapshot metadata.
+    pub fn snapshot(&self) -> Option<&SnapshotMetadata> {
+        self.snapshot.as_ref()
+    }
+
     /// An immutable reference to the optional targets metadata.
     pub fn targets(&self) -> Option<&TargetsMetadata> {
         self.targets.as_ref()
@@ -202,9 +207,9 @@
                     "Attempted to roll back snapshot metadata at version {} to {}.",
                     current_version,
                     snapshot.version()
-                )))
+                )));
             } else if snapshot.version() == current_version {
-                return Ok(false)
+                return Ok(false);
             } else {
                 snapshot
             }
@@ -261,9 +266,9 @@
                     "Attempted to roll back targets metadata at version {} to {}.",
                     current_version,
                     targets.version()
-                )))
+                )));
             } else if targets.version() == current_version {
-                return Ok(false)
+                return Ok(false);
             } else {
                 targets
             }