Merge "Update config manager to handle user config for each situation."
diff --git a/public/acloud_common.py b/public/acloud_common.py
index 87e4a9d..c0189fb 100755
--- a/public/acloud_common.py
+++ b/public/acloud_common.py
@@ -16,8 +16,6 @@
 
 """Common code used by both acloud and acloud_kernel tools."""
 
-DEFAULT_CONFIG_FILE = "acloud.config"
-
 
 def AddCommonArguments(parser):
     """Adds arguments common to parsers.
@@ -33,7 +31,7 @@
         "--config_file",
         type=str,
         dest="config_file",
-        default=DEFAULT_CONFIG_FILE,
+        default=None,
         help="Path to the config file, default to acloud.config"
         "in the current working directory")
     parser.add_argument(
diff --git a/public/config.py b/public/config.py
index 22c7523..e7c1b3f 100755
--- a/public/config.py
+++ b/public/config.py
@@ -48,22 +48,30 @@
 
 from google.protobuf import text_format
 
+# pylint: disable=no-name-in-module,import-error
 from acloud.internal.proto import internal_config_pb2
 from acloud.internal.proto import user_config_pb2
 from acloud.public import errors
 
 _CONFIG_DATA_PATH = os.path.join(
     os.path.dirname(os.path.abspath(__file__)), "data")
+_DEFAULT_CONFIG_FILE = "acloud.config"
 
 logger = logging.getLogger(__name__)
 
 
+def GetDefaultConfigFile():
+    """Get config default path."""
+    config_path = os.path.expanduser("~")
+    return os.path.join(config_path, _DEFAULT_CONFIG_FILE)
+
+
 class AcloudConfig(object):
     """A class that holds all configurations for acloud."""
 
     REQUIRED_FIELD = [
-        "project", "zone", "machine_type", "network", "storage_bucket_name",
-        "min_machine_size", "disk_image_name", "disk_image_mime_type"
+        "machine_type", "network", "min_machine_size",
+        "disk_image_name", "disk_image_mime_type"
     ]
 
     def __init__(self, usr_cfg, internal_cfg):
@@ -207,7 +215,7 @@
     def __init__(self,
                  user_config_path,
                  internal_config_path=_DEFAULT_INTERNAL_CONFIG_PATH):
-        """Initialize.
+        """Initialize with user specified paths to configs.
 
         Args:
             user_config_path: path to the user config.
@@ -217,19 +225,41 @@
         self._internal_config_path = internal_config_path
 
     def Load(self):
-        """Load the configurations."""
+        """Load the configurations.
+
+        Load user config with some special design.
+        1. User specified user config:
+            a.User config exist: Load config.
+            b.User config didn't exist: Raise exception.
+        2. User didn't specify user config, use default config:
+            a.Default config exist: Load config.
+            b.Default config didn't exist: provide empty usr_cfg.
+        """
         internal_cfg = None
         usr_cfg = None
         try:
             with open(self._internal_config_path) as config_file:
                 internal_cfg = self.LoadConfigFromProtocolBuffer(
                     config_file, internal_config_pb2.InternalConfig)
-
-            with open(self._user_config_path, "r") as config_file:
-                usr_cfg = self.LoadConfigFromProtocolBuffer(
-                    config_file, user_config_pb2.UserConfig)
         except OSError as e:
             raise errors.ConfigError("Could not load config files: %s" % str(e))
+        # Load user config file
+        if self._user_config_path:
+            if os.path.exists(self._user_config_path):
+                with open(self._user_config_path, "r") as config_file:
+                    usr_cfg = self.LoadConfigFromProtocolBuffer(
+                        config_file, user_config_pb2.UserConfig)
+            else:
+                raise errors.ConfigError("The file doesn't exist: %s" %
+                                         (self._user_config_path))
+        else:
+            self._user_config_path = GetDefaultConfigFile()
+            if os.path.exists(self._user_config_path):
+                with open(self._user_config_path, "r") as config_file:
+                    usr_cfg = self.LoadConfigFromProtocolBuffer(
+                        config_file, user_config_pb2.UserConfig)
+            else:
+                usr_cfg = user_config_pb2.UserConfig()
         return AcloudConfig(usr_cfg, internal_cfg)
 
     @staticmethod
diff --git a/public/config_test.py b/public/config_test.py
index 7e78727..ea21a8c 100644
--- a/public/config_test.py
+++ b/public/config_test.py
@@ -16,8 +16,10 @@
 
 """Tests for acloud.public.config."""
 import unittest
+import os
 import mock
 
+# pylint: disable=no-name-in-module,import-error
 from acloud.internal.proto import internal_config_pb2
 from acloud.internal.proto import user_config_pb2
 from acloud.public import config
@@ -122,6 +124,45 @@
             {key: val for key, val in cfg.metadata_variable.iteritems()},
             {"metadata_1": "metadata_value_1"})
 
+    # pylint: disable=protected-access
+    @mock.patch("os.path.exists")
+    def testLoadUserConfigLogic(self, mock_file_exist):
+        """Test load user config logic.
+
+        Load user config with some special design.
+        1. User specified user config:
+            If user config didn't exist: Raise exception.
+        2. User didn't specify user config, use default config:
+            If default config didn't exist: Initialize empty data.
+        """
+        config_specify = config.AcloudConfigManager(self.config_file)
+        self.config_file.read.return_value = self.USER_CONFIG
+        self.assertEqual(config_specify._user_config_path, self.config_file)
+        mock_file_exist.return_value = False
+        with self.assertRaises(errors.ConfigError):
+            config_specify.Load()
+        # Test default config
+        config_unspecify = config.AcloudConfigManager(None)
+        cfg = config_unspecify.Load()
+        self.assertEqual(config_unspecify._user_config_path, config.GetDefaultConfigFile())
+        self.assertEqual(cfg.project, "")
+        self.assertEqual(cfg.zone, "")
+        # Test user config exist
+        mock_file_exist.return_value = True
+        backup_file = config.GetDefaultConfigFile() + ".backup"
+        if os.path.exists(config.GetDefaultConfigFile()):
+            os.rename(config.GetDefaultConfigFile(), backup_file)
+        with open(config.GetDefaultConfigFile(), "w") as cfg_file:
+            cfg_file.writelines(self.USER_CONFIG)
+        config_exist = config.AcloudConfigManager(None)
+        cfg = config_exist.Load()
+        self.assertEqual(cfg.project, "fake-project")
+        self.assertEqual(cfg.zone, "us-central1-f")
+        self.assertEqual(cfg.client_id, "fake_client_id")
+        self.assertEqual(cfg.client_secret, "fake_client_secret")
+        if os.path.exists(backup_file):
+            os.rename(backup_file, config.GetDefaultConfigFile())
+
     def testLoadInternalConfig(self):
         """Test loading internal config."""
         self.config_file.read.return_value = self.INTERNAL_CONFIG