Support alt. namespace resource uuid as tenant id to API gateway service (#130)

* Support alt. namespace resource uuid as tenant id to API gateway service

* gofmt

* Update Travis base image to Xenial release for build

* clean up unit tests

* clean up unit tests

* clean up unit tests
diff --git a/.travis.yml b/.travis.yml
index 1f19e31..bbe821b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,9 +21,9 @@
     include:
         - os: linux
           sudo: required
-          group: deprecated-2017Q3
           go: "1.9.3"
           services: docker
+          dist: xenial
 
 git:
   depth: 3
@@ -39,7 +39,8 @@
   - cd $TRAVIS_BUILD_DIR
   - GO_FILES=$(find . -iname '*.go' -type f | grep -v /vendor/)
   - test -z "$(gofmt -s -l $(echo $GO_FILES))"
-  - pip install --upgrade pip setuptools
+  #- pip install --upgrade pip setuptools
+  - pip install --user --upgrade pip setuptools
   - ./tools/travis/setup.sh
 
 install:
diff --git a/whisk/client.go b/whisk/client.go
index 45de175..91b8a79 100644
--- a/whisk/client.go
+++ b/whisk/client.go
@@ -97,6 +97,7 @@
 	Insecure          bool
 	UserAgent         string
 	ApigwAccessToken  string
+	ApigwTenantId     string
 	AdditionalHeaders http.Header
 }
 
diff --git a/whisk/wskprops.go b/whisk/wskprops.go
index 01b7d91..22e301f 100644
--- a/whisk/wskprops.go
+++ b/whisk/wskprops.go
@@ -40,13 +40,14 @@
 	DEFAULT_VERSION      = "v1"
 	DEFAULT_NAMESPACE    = "_"
 
-	NAMESPACE          = "NAMESPACE"
-	AUTH               = "AUTH"
 	APIGW_ACCESS_TOKEN = "APIGW_ACCESS_TOKEN"
-	APIVERSION         = "APIVERSION"
-	KEY                = "KEY"
-	CERT               = "CERT"
+	APIGW_TENANT_ID    = "APIGW_TENANT_ID"
 	APIHOST            = "APIHOST"
+	APIVERSION         = "APIVERSION"
+	AUTH               = "AUTH"
+	CERT               = "CERT"
+	KEY                = "KEY"
+	NAMESPACE          = "NAMESPACE"
 
 	DEFAULT_SOURCE = "wsk props"
 	WSKPROP        = "wsk props"
@@ -54,14 +55,15 @@
 )
 
 type Wskprops struct {
-	APIHost        string
-	AuthKey        string
-	Namespace      string
-	AuthAPIGWKey   string
 	APIGWSpaceSuid string
+	APIGWTenantId  string
+	APIHost        string
 	Apiversion     string
-	Key            string
+	AuthAPIGWKey   string
+	AuthKey        string
 	Cert           string
+	Key            string
+	Namespace      string
 	Source         string
 }
 
@@ -177,6 +179,7 @@
 		dep.AuthKey = GetValue(results, AUTH, dep.AuthKey)
 		dep.Namespace = GetValue(results, NAMESPACE, dep.Namespace)
 		dep.AuthAPIGWKey = GetValue(results, APIGW_ACCESS_TOKEN, dep.AuthAPIGWKey)
+		dep.APIGWTenantId = GetValue(results, APIGW_TENANT_ID, dep.APIGWTenantId)
 		if len(dep.AuthKey) > 0 {
 			dep.APIGWSpaceSuid = strings.Split(dep.AuthKey, ":")[0]
 		}
@@ -194,6 +197,7 @@
 	results, err := ReadProps(path)
 
 	if err == nil {
+		// TODO Determine why we have a hardcoed "test.auth" file here, is this only for unit tests? documented?
 		authPath := GetValue(results, TEST_AUTH_FILE, "")
 		b, err := ioutil.ReadFile(authPath)
 		if err == nil {
@@ -281,6 +285,7 @@
 		AuthKey:        "",
 		Namespace:      DEFAULT_NAMESPACE,
 		AuthAPIGWKey:   "",
+		APIGWTenantId:  "",
 		APIGWSpaceSuid: "",
 		Apiversion:     DEFAULT_VERSION,
 		Key:            "",
diff --git a/whisk/wskprops_test.go b/whisk/wskprops_test.go
index ff49574..942e827 100644
--- a/whisk/wskprops_test.go
+++ b/whisk/wskprops_test.go
@@ -28,7 +28,7 @@
 )
 
 const (
-	TEST_FILE                  = "TEST_AUTH_FILE"
+	TEST_AUTH_FILE_NAME        = "TEST_AUTH_FILE"
 	NON_EXISTING_TEST_FILE     = "NON_EXISTING_TEST_FILE"
 	EXPECTED_OPENWHISK_HOST    = "192.168.9.100"
 	EXPECTED_OPENWHISK_PORT    = "443"
@@ -38,6 +38,7 @@
 	EXPECTED_HOST              = EXPECTED_OPENWHISK_HOST + ":" + EXPECTED_OPENWHISK_PORT
 	EXPECTED_AUTH_API_KEY      = "EXPECTED_AUTH_API_KEY"
 	EXPECTED_API_GW_SPACE_SUID = "32kc46b1-71f6-4ed5-8c54-816aa4f8c502"
+	EXPECTED_APIGW_TENANT_ID   = "crn:v1:providername:public:servicename:region:a/1234567890abcdef0987654321fedcba:faaa50ec-dce9-4a23-9aaa-a8cb5c7648dc::"
 	APIGW_SPACE_SUID           = "APIGW_SPACE_SUID"
 	EXPECTED_API_VERSION       = "v1"
 	EXPECTED_CERT              = "EXPECTED_CERT"
@@ -115,29 +116,30 @@
 
 func (pi FakePropertiesImp) GetPropsFromWskprops(path string) *Wskprops {
 	dep := Wskprops{
-		APIHost:        GetValue(pi.StoredValues_LOCAL_CONF, APIHOST, ""),
-		AuthKey:        GetValue(pi.StoredValues_LOCAL_CONF, AUTH, ""),
-		Namespace:      GetValue(pi.StoredValues_LOCAL_CONF, NAMESPACE, ""),
-		AuthAPIGWKey:   GetValue(pi.StoredValues_LOCAL_CONF, APIGW_ACCESS_TOKEN, ""),
 		APIGWSpaceSuid: GetValue(pi.StoredValues_LOCAL_CONF, APIGW_SPACE_SUID, ""),
+		APIGWTenantId:  GetValue(pi.StoredValues_LOCAL_CONF, APIGW_TENANT_ID, ""),
+		APIHost:        GetValue(pi.StoredValues_LOCAL_CONF, APIHOST, ""),
+		Apiversion:     GetValue(pi.StoredValues_LOCAL_CONF, APIVERSION, ""),
+		AuthAPIGWKey:   GetValue(pi.StoredValues_LOCAL_CONF, APIGW_ACCESS_TOKEN, ""),
+		AuthKey:        GetValue(pi.StoredValues_LOCAL_CONF, AUTH, ""),
 		Cert:           GetValue(pi.StoredValues_LOCAL_CONF, CERT, ""),
 		Key:            GetValue(pi.StoredValues_LOCAL_CONF, KEY, ""),
-		Apiversion:     GetValue(pi.StoredValues_LOCAL_CONF, APIVERSION, ""),
+		Namespace:      GetValue(pi.StoredValues_LOCAL_CONF, NAMESPACE, ""),
 	}
-
 	return &dep
 }
 
 func (pi FakePropertiesImp) GetPropsFromWhiskProperties() *Wskprops {
 	dep := Wskprops{
-		APIHost:        pi.StoredValues_WHISK[APIHOST],
-		AuthKey:        pi.StoredValues_WHISK[AUTH],
-		Namespace:      pi.StoredValues_WHISK[NAMESPACE],
-		AuthAPIGWKey:   pi.StoredValues_WHISK[APIGW_ACCESS_TOKEN],
 		APIGWSpaceSuid: pi.StoredValues_WHISK[APIGW_SPACE_SUID],
+		APIGWTenantId:  pi.StoredValues_WHISK[APIGW_TENANT_ID],
+		APIHost:        pi.StoredValues_WHISK[APIHOST],
+		Apiversion:     pi.StoredValues_WHISK[APIVERSION],
+		AuthAPIGWKey:   pi.StoredValues_WHISK[APIGW_ACCESS_TOKEN],
+		AuthKey:        pi.StoredValues_WHISK[AUTH],
 		Cert:           pi.StoredValues_WHISK[CERT],
 		Key:            pi.StoredValues_WHISK[KEY],
-		Apiversion:     pi.StoredValues_WHISK[APIVERSION],
+		Namespace:      pi.StoredValues_WHISK[NAMESPACE],
 	}
 	return &dep
 }
@@ -161,14 +163,17 @@
 }
 
 func TestGetPropsFromWhiskProperties(t *testing.T) {
+
+	// Variant 1 ------------------------------------------------------------------
 	lines := []string{EXPECTED_TEST_AUTH_KEY}
-	CreateFile(lines, TEST_FILE)
+	CreateFile(lines, TEST_AUTH_FILE_NAME)
 
 	fakeOSPackage := FakeOSPackage{
 		StoredValues: map[string]string{
 			OPENWHISK_HOME: getCurrentDir(),
 		},
 	}
+
 	pi := PropertiesImp{
 		OsPackage: fakeOSPackage,
 	}
@@ -184,15 +189,19 @@
 	assert.Equal(t, "", dep.Cert)
 	assert.Equal(t, WHISK_PROPERTY, dep.Source)
 
-	lines = []string{TEST_AUTH_FILE + "=" + TEST_FILE, OPENWHISK_PRO + "=" + EXPECTED_OPENWHISK_PRO,
-		OPENWHISK_PORT + "=" + EXPECTED_OPENWHISK_PORT,
+	// Variant 2 ------------------------------------------------------------------
+	lines = []string{
 		OPENWHISK_HOST + "=" + EXPECTED_OPENWHISK_HOST,
+		OPENWHISK_PORT + "=" + EXPECTED_OPENWHISK_PORT,
+		OPENWHISK_PRO + "=" + EXPECTED_OPENWHISK_PRO,
+		TEST_AUTH_FILE + "=" + TEST_AUTH_FILE_NAME,
 	}
-
 	CreateFile(lines, OPENWHISK_PROPERTIES)
+
 	pi = PropertiesImp{
 		OsPackage: fakeOSPackage,
 	}
+
 	dep = pi.GetPropsFromWhiskProperties()
 	assert.Equal(t, DEFAULT_NAMESPACE, dep.Namespace)
 	assert.Equal(t, EXPECTED_TEST_AUTH_KEY, dep.AuthKey)
@@ -205,15 +214,23 @@
 	assert.Equal(t, WHISK_PROPERTY, dep.Source)
 
 	DeleteFile(OPENWHISK_PROPERTIES)
-
+	DeleteFile(TEST_AUTH_FILE_NAME)
+	// Make sure the "non-existant" test.auth key file really does not exist
 	DeleteFile(NON_EXISTING_TEST_FILE)
-	lines = []string{TEST_AUTH_FILE + "=" + NON_EXISTING_TEST_FILE, OPENWHISK_PRO + "=" + EXPECTED_OPENWHISK_PRO,
+
+	// Variant 3 ------------------------------------------------------------------
+	lines = []string{
+		OPENWHISK_HOST + "=" + EXPECTED_OPENWHISK_HOST,
 		OPENWHISK_PORT + "=" + EXPECTED_OPENWHISK_PORT,
-		OPENWHISK_HOST + "=" + EXPECTED_OPENWHISK_HOST}
+		OPENWHISK_PRO + "=" + EXPECTED_OPENWHISK_PRO,
+		TEST_AUTH_FILE + "=" + NON_EXISTING_TEST_FILE,
+	}
+
 	CreateFile(lines, OPENWHISK_PROPERTIES)
 	pi = PropertiesImp{
 		OsPackage: fakeOSPackage,
 	}
+
 	dep = pi.GetPropsFromWhiskProperties()
 	assert.Equal(t, DEFAULT_NAMESPACE, dep.Namespace)
 	assert.Equal(t, "", dep.AuthKey)
@@ -225,15 +242,20 @@
 	assert.Equal(t, "", dep.Cert)
 	assert.Equal(t, WHISK_PROPERTY, dep.Source)
 	DeleteFile(OPENWHISK_PROPERTIES)
-
-	DeleteFile(TEST_FILE)
 }
 
 func TestGetPropsFromWskprops(t *testing.T) {
-	lines := []string{APIHOST + "=" + EXPECTED_HOST, AUTH + "=" + EXPECTED_TEST_AUTH_KEY,
+	lines := []string{
+		APIGW_ACCESS_TOKEN + "=" + EXPECTED_AUTH_API_KEY,
+		APIGW_TENANT_ID + "=" + EXPECTED_APIGW_TENANT_ID,
+		APIHOST + "=" + EXPECTED_HOST,
+		APIVERSION + "=" + EXPECTED_API_VERSION,
+		AUTH + "=" + EXPECTED_TEST_AUTH_KEY,
+		CERT + "=" + EXPECTED_CERT,
+		KEY + "=" + EXPECTED_KEY,
 		NAMESPACE + "=" + DEFAULT_NAMESPACE,
-		APIGW_ACCESS_TOKEN + "=" + EXPECTED_AUTH_API_KEY, APIVERSION + "=" + EXPECTED_API_VERSION,
-		KEY + "=" + EXPECTED_KEY, CERT + "=" + EXPECTED_CERT}
+	}
+
 	CreateFile(lines, DEFAULT_LOCAL_CONFIG)
 
 	fakeOSPackage := FakeOSPackage{
@@ -259,13 +281,14 @@
 	path := getCurrentDir() + "/" + DEFAULT_LOCAL_CONFIG
 	dep = pi.GetPropsFromWskprops(path)
 	assert.Equal(t, DEFAULT_NAMESPACE, dep.Namespace)
-	assert.Equal(t, EXPECTED_TEST_AUTH_KEY, dep.AuthKey)
-	assert.Equal(t, EXPECTED_AUTH_API_KEY, dep.AuthAPIGWKey)
-	assert.Equal(t, EXPECTED_HOST, dep.APIHost)
 	assert.Equal(t, EXPECTED_API_GW_SPACE_SUID, dep.APIGWSpaceSuid)
+	assert.Equal(t, EXPECTED_APIGW_TENANT_ID, dep.APIGWTenantId)
 	assert.Equal(t, EXPECTED_API_VERSION, dep.Apiversion)
-	assert.Equal(t, EXPECTED_KEY, dep.Key)
+	assert.Equal(t, EXPECTED_AUTH_API_KEY, dep.AuthAPIGWKey)
 	assert.Equal(t, EXPECTED_CERT, dep.Cert)
+	assert.Equal(t, EXPECTED_HOST, dep.APIHost)
+	assert.Equal(t, EXPECTED_KEY, dep.Key)
+	assert.Equal(t, EXPECTED_TEST_AUTH_KEY, dep.AuthKey)
 	assert.Equal(t, WSKPROP, dep.Source)
 
 	DeleteFile(DEFAULT_LOCAL_CONFIG)