Просмотр исходного кода

Add unmarshal for all Asset types

Kaelan Patel 4 лет назад
Родитель
Сommit
fa37d6fb0c
2 измененных файлов с 923 добавлено и 9 удалено
  1. 509 1
      pkg/kubecost/asset.go
  2. 414 8
      pkg/kubecost/asset_unmarshal_test.go

+ 509 - 1
pkg/kubecost/asset.go

@@ -9,7 +9,7 @@ import (
 	"sync"
 	"time"
 
-	gojson "encoding/json"
+	gojson "encoding/json" // gojson is default golang json, required for RawMessage decoding
 
 	"github.com/kubecost/cost-model/pkg/log"
 	"github.com/kubecost/cost-model/pkg/util/json"
@@ -607,6 +607,66 @@ func (a *Any) MarshalJSON() ([]byte, error) {
 	return buffer.Bytes(), nil
 }
 
+func (a *Any) UnmarshalJSON(b []byte) error {
+
+	var f interface{}
+
+	err := json.Unmarshal(b, &f)
+	if err != nil {
+		return err
+	}
+
+	err = a.InterfaceToAny(f)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (a *Any) InterfaceToAny(itf interface{}) error {
+
+	fmap := itf.(map[string]interface{})
+
+	// parse properties map to AssetProperties
+	fproperties := fmap["properties"].(map[string]interface{})
+	properties := toAssetProp(fproperties)
+
+	// parse labels map to AssetLabels
+	labels := make(map[string]string)
+	for k, v := range fmap["labels"].(map[string]interface{}) {
+		labels[k] = v.(string)
+	}
+
+	// parse start and end strings to time.Time
+	start, err := time.Parse(time.RFC3339, fmap["start"].(string))
+	if err != nil {
+		return err
+	}
+	end, err := time.Parse(time.RFC3339, fmap["end"].(string))
+	if err != nil {
+		return err
+	}
+
+	a.properties = &properties
+	a.labels = labels
+	a.start = start
+	a.end = end
+	a.window = Window{
+		start: &start,
+		end:   &end,
+	}
+
+	if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
+		a.adjustment = adjustment.(float64)
+	}
+	if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
+		a.Cost = Cost.(float64) - a.adjustment
+	}
+
+	return nil
+}
+
 // String implements fmt.Stringer
 func (a *Any) String() string {
 	return toString(a)
@@ -851,6 +911,69 @@ func (ca *Cloud) MarshalJSON() ([]byte, error) {
 	return buffer.Bytes(), nil
 }
 
+func (ca *Cloud) UnmarshalJSON(b []byte) error {
+
+	var f interface{}
+
+	err := json.Unmarshal(b, &f)
+	if err != nil {
+		return err
+	}
+
+	err = ca.InterfaceToCloud(f)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (ca *Cloud) InterfaceToCloud(itf interface{}) error {
+
+	fmap := itf.(map[string]interface{})
+
+	// parse properties map to AssetProperties
+	fproperties := fmap["properties"].(map[string]interface{})
+	properties := toAssetProp(fproperties)
+
+	// parse labels map to AssetLabels
+	labels := make(map[string]string)
+	for k, v := range fmap["labels"].(map[string]interface{}) {
+		labels[k] = v.(string)
+	}
+
+	// parse start and end strings to time.Time
+	start, err := time.Parse(time.RFC3339, fmap["start"].(string))
+	if err != nil {
+		return err
+	}
+	end, err := time.Parse(time.RFC3339, fmap["end"].(string))
+	if err != nil {
+		return err
+	}
+
+	ca.properties = &properties
+	ca.labels = labels
+	ca.start = start
+	ca.end = end
+	ca.window = Window{
+		start: &start,
+		end:   &end,
+	}
+
+	if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
+		ca.adjustment = adjustment.(float64)
+	}
+	if Credit, err := getTypedVal(fmap["credit"]); err == nil {
+		ca.Credit = Credit.(float64)
+	}
+	if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
+		ca.Cost = Cost.(float64) - ca.adjustment - ca.Credit
+	}
+
+	return nil
+}
+
 // String implements fmt.Stringer
 func (ca *Cloud) String() string {
 	return toString(ca)
@@ -1049,6 +1172,61 @@ func (cm *ClusterManagement) MarshalJSON() ([]byte, error) {
 	return buffer.Bytes(), nil
 }
 
+func (cm *ClusterManagement) UnmarshalJSON(b []byte) error {
+
+	var f interface{}
+
+	err := json.Unmarshal(b, &f)
+	if err != nil {
+		return err
+	}
+
+	err = cm.InterfaceToClusterManagement(f)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (cm *ClusterManagement) InterfaceToClusterManagement(itf interface{}) error {
+
+	fmap := itf.(map[string]interface{})
+
+	// parse properties map to AssetProperties
+	fproperties := fmap["properties"].(map[string]interface{})
+	properties := toAssetProp(fproperties)
+
+	// parse labels map to AssetLabels
+	labels := make(map[string]string)
+	for k, v := range fmap["labels"].(map[string]interface{}) {
+		labels[k] = v.(string)
+	}
+
+	// parse start and end strings to time.Time
+	start, err := time.Parse(time.RFC3339, fmap["start"].(string))
+	if err != nil {
+		return err
+	}
+	end, err := time.Parse(time.RFC3339, fmap["end"].(string))
+	if err != nil {
+		return err
+	}
+
+	cm.properties = &properties
+	cm.labels = labels
+	cm.window = Window{
+		start: &start,
+		end:   &end,
+	}
+
+	if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
+		cm.Cost = Cost.(float64)
+	}
+
+	return nil
+}
+
 // String implements fmt.Stringer
 func (cm *ClusterManagement) String() string {
 	return toString(cm)
@@ -1334,6 +1512,80 @@ func (d *Disk) MarshalJSON() ([]byte, error) {
 	return buffer.Bytes(), nil
 }
 
+func (d *Disk) UnmarshalJSON(b []byte) error {
+
+	var f interface{}
+
+	err := json.Unmarshal(b, &f)
+	if err != nil {
+		return err
+	}
+
+	err = d.InterfaceToDisk(f)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (d *Disk) InterfaceToDisk(itf interface{}) error {
+
+	fmap := itf.(map[string]interface{})
+
+	// parse properties map to AssetProperties
+	fproperties := fmap["properties"].(map[string]interface{})
+	properties := toAssetProp(fproperties)
+
+	// parse labels map to AssetLabels
+	labels := make(map[string]string)
+	for k, v := range fmap["labels"].(map[string]interface{}) {
+		labels[k] = v.(string)
+	}
+
+	// parse start and end strings to time.Time
+	start, err := time.Parse(time.RFC3339, fmap["start"].(string))
+	if err != nil {
+		return err
+	}
+	end, err := time.Parse(time.RFC3339, fmap["end"].(string))
+	if err != nil {
+		return err
+	}
+
+	fbreakdown := fmap["breakdown"].(map[string]interface{})
+
+	breakdown := toBreakdown(fbreakdown)
+
+	d.properties = &properties
+	d.labels = labels
+	d.start = start
+	d.end = end
+	d.window = Window{
+		start: &start,
+		end:   &end,
+	}
+	d.Breakdown = &breakdown
+
+	if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
+		d.adjustment = adjustment.(float64)
+	}
+	if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
+		d.Cost = Cost.(float64) - d.adjustment
+	}
+	if ByteHours, err := getTypedVal(fmap["byteHours"]); err == nil {
+		d.ByteHours = ByteHours.(float64)
+	}
+
+	// d.Local is not marhsaled, and cannot be calculated from marshaled values.
+	// Currently, it is just ignored and not set in the resulting unmarshal to Disk
+	//  be aware that this means a resulting Disk from an unmarshal is therefore NOT
+	// equal to the originally marshaled Disk.
+
+	return nil
+
+}
+
 // String implements fmt.Stringer
 func (d *Disk) String() string {
 	return toString(d)
@@ -1648,6 +1900,67 @@ func (n *Network) MarshalJSON() ([]byte, error) {
 	return buffer.Bytes(), nil
 }
 
+func (n *Network) UnmarshalJSON(b []byte) error {
+
+	var f interface{}
+
+	err := json.Unmarshal(b, &f)
+	if err != nil {
+		return err
+	}
+
+	err = n.InterfaceToNetwork(f)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (n *Network) InterfaceToNetwork(itf interface{}) error {
+
+	fmap := itf.(map[string]interface{})
+
+	// parse properties map to AssetProperties
+	fproperties := fmap["properties"].(map[string]interface{})
+	properties := toAssetProp(fproperties)
+
+	// parse labels map to AssetLabels
+	labels := make(map[string]string)
+	for k, v := range fmap["labels"].(map[string]interface{}) {
+		labels[k] = v.(string)
+	}
+
+	// parse start and end strings to time.Time
+	start, err := time.Parse(time.RFC3339, fmap["start"].(string))
+	if err != nil {
+		return err
+	}
+	end, err := time.Parse(time.RFC3339, fmap["end"].(string))
+	if err != nil {
+		return err
+	}
+
+	n.properties = &properties
+	n.labels = labels
+	n.start = start
+	n.end = end
+	n.window = Window{
+		start: &start,
+		end:   &end,
+	}
+
+	if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
+		n.adjustment = adjustment.(float64)
+	}
+	if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
+		n.Cost = Cost.(float64) - n.adjustment
+	}
+
+	return nil
+
+}
+
 // String implements fmt.Stringer
 func (n *Network) String() string {
 	return toString(n)
@@ -2410,6 +2723,67 @@ func (lb *LoadBalancer) MarshalJSON() ([]byte, error) {
 	return buffer.Bytes(), nil
 }
 
+func (lb *LoadBalancer) UnmarshalJSON(b []byte) error {
+
+	var f interface{}
+
+	err := json.Unmarshal(b, &f)
+	if err != nil {
+		return err
+	}
+
+	err = lb.InterfaceToLoadBalancer(f)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (lb *LoadBalancer) InterfaceToLoadBalancer(itf interface{}) error {
+
+	fmap := itf.(map[string]interface{})
+
+	// parse properties map to AssetProperties
+	fproperties := fmap["properties"].(map[string]interface{})
+	properties := toAssetProp(fproperties)
+
+	// parse labels map to AssetLabels
+	labels := make(map[string]string)
+	for k, v := range fmap["labels"].(map[string]interface{}) {
+		labels[k] = v.(string)
+	}
+
+	// parse start and end strings to time.Time
+	start, err := time.Parse(time.RFC3339, fmap["start"].(string))
+	if err != nil {
+		return err
+	}
+	end, err := time.Parse(time.RFC3339, fmap["end"].(string))
+	if err != nil {
+		return err
+	}
+
+	lb.properties = &properties
+	lb.labels = labels
+	lb.start = start
+	lb.end = end
+	lb.window = Window{
+		start: &start,
+		end:   &end,
+	}
+
+	if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
+		lb.adjustment = adjustment.(float64)
+	}
+	if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
+		lb.Cost = Cost.(float64) - lb.adjustment
+	}
+
+	return nil
+
+}
+
 // String implements fmt.Stringer
 func (lb *LoadBalancer) String() string {
 	return toString(lb)
@@ -2620,6 +2994,62 @@ func (sa *SharedAsset) MarshalJSON() ([]byte, error) {
 	return buffer.Bytes(), nil
 }
 
+func (sa *SharedAsset) UnmarshalJSON(b []byte) error {
+
+	var f interface{}
+
+	err := json.Unmarshal(b, &f)
+	if err != nil {
+		return err
+	}
+
+	err = sa.InterfaceToSharedAsset(f)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (sa *SharedAsset) InterfaceToSharedAsset(itf interface{}) error {
+
+	fmap := itf.(map[string]interface{})
+
+	// parse properties map to AssetProperties
+	fproperties := fmap["properties"].(map[string]interface{})
+	properties := toAssetProp(fproperties)
+
+	// parse labels map to AssetLabels
+	labels := make(map[string]string)
+	for k, v := range fmap["labels"].(map[string]interface{}) {
+		labels[k] = v.(string)
+	}
+
+	// parse start and end strings to time.Time
+	start, err := time.Parse(time.RFC3339, fmap["start"].(string))
+	if err != nil {
+		return err
+	}
+	end, err := time.Parse(time.RFC3339, fmap["end"].(string))
+	if err != nil {
+		return err
+	}
+
+	sa.properties = &properties
+	sa.labels = labels
+	sa.window = Window{
+		start: &start,
+		end:   &end,
+	}
+
+	if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
+		sa.Cost = Cost.(float64)
+	}
+
+	return nil
+
+}
+
 // String implements fmt.Stringer
 func (sa *SharedAsset) String() string {
 	return toString(sa)
@@ -2655,6 +3085,50 @@ func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
 		fmap := f.(map[string]interface{})
 
 		switch t := fmap["type"]; t {
+		case "Cloud":
+
+			var ca Cloud
+			err := ca.InterfaceToCloud(f)
+
+			if err != nil {
+				return err
+			}
+
+			newAssetMap[key] = &ca
+
+		case "ClusterManagement":
+
+			var cm ClusterManagement
+			err := cm.InterfaceToClusterManagement(f)
+
+			if err != nil {
+				return err
+			}
+
+			newAssetMap[key] = &cm
+
+		case "Disk":
+
+			var d Disk
+			err := d.InterfaceToDisk(f)
+
+			if err != nil {
+				return err
+			}
+
+			newAssetMap[key] = &d
+
+		case "Network":
+
+			var nw Network
+			err := nw.InterfaceToNetwork(f)
+
+			if err != nil {
+				return err
+			}
+
+			newAssetMap[key] = &nw
+
 		case "Node":
 
 			var n Node
@@ -2665,6 +3139,40 @@ func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
 			}
 
 			newAssetMap[key] = &n
+
+		case "LoadBalancer":
+
+			var lb LoadBalancer
+			err := lb.InterfaceToLoadBalancer(f)
+
+			if err != nil {
+				return err
+			}
+
+			newAssetMap[key] = &lb
+
+		case "Shared":
+
+			var sa SharedAsset
+			err := sa.InterfaceToSharedAsset(f)
+
+			if err != nil {
+				return err
+			}
+
+			newAssetMap[key] = &sa
+
+		default:
+
+			var a Any
+			err := a.InterfaceToAny(f)
+
+			if err != nil {
+				return err
+			}
+
+			newAssetMap[key] = &a
+
 		}
 	}
 

+ 414 - 8
pkg/kubecost/asset_unmarshal_test.go

@@ -2,6 +2,7 @@ package kubecost
 
 import (
 	"encoding/json"
+	"fmt"
 	"testing"
 	"time"
 )
@@ -10,6 +11,265 @@ var s = time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC)
 var e = start1.Add(day)
 var unmarshalWindow = NewWindow(&s, &e)
 
+func TestAny_Unmarshal(t *testing.T) {
+
+	any1 := NewAsset(*unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	any1.SetProperties(&AssetProperties{
+		Name:       "any1",
+		Cluster:    "cluster1",
+		ProviderID: "any1",
+	})
+	any1.Cost = 9.0
+	any1.SetAdjustment(1.0)
+
+	bytes, _ := json.Marshal(any1)
+
+	var testany Any
+	any2 := &testany
+
+	err := json.Unmarshal(bytes, any2)
+
+	// Check if unmarshal was successful
+	if err != nil {
+		t.Fatalf("Any Unmarshal: unexpected error: %s", err)
+	}
+
+	// Check if all fields in initial Any equal those in Any from unmarshal
+	if !any1.properties.Equal(any2.properties) {
+		t.Fatalf("Any Unmarshal: properties mutated in unmarshal")
+	}
+	if !any1.labels.Equal(any2.labels) {
+		t.Fatalf("Any Unmarshal: labels mutated in unmarshal")
+	}
+	if !any1.window.Equal(any2.window) {
+		t.Fatalf("Any Unmarshal: window mutated in unmarshal")
+	}
+	if !any1.start.Equal(any2.start) {
+		t.Fatalf("Any Unmarshal: start mutated in unmarshal")
+	}
+	if !any1.end.Equal(any2.end) {
+		t.Fatalf("Any Unmarshal: end mutated in unmarshal")
+	}
+	if any1.adjustment != any2.adjustment {
+		t.Fatalf("Any Unmarshal: adjustment mutated in unmarshal")
+	}
+	if any1.Cost != any2.Cost {
+		t.Fatalf("Any Unmarshal: cost mutated in unmarshal")
+	}
+
+	// As a final check, make sure the above checks out
+	if !any1.Equal(any2) {
+		t.Fatalf("Any Unmarshal: Any mutated in unmarshal")
+	}
+
+}
+
+func TestCloud_Unmarshal(t *testing.T) {
+
+	cloud1 := NewCloud("Compute", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	cloud1.SetLabels(map[string]string{
+		"namespace": "namespace1",
+		"env":       "env1",
+		"product":   "product1",
+	})
+	cloud1.Cost = 10.00
+	cloud1.Credit = -1.0
+
+	bytes, _ := json.Marshal(cloud1)
+
+	var testcloud Cloud
+	cloud2 := &testcloud
+
+	err := json.Unmarshal(bytes, cloud2)
+
+	// Check if unmarshal was successful
+	if err != nil {
+		t.Fatalf("Cloud Unmarshal: unexpected error: %s", err)
+	}
+
+	// Check if all fields in initial Cloud equal those in Cloud from unmarshal
+	if !cloud1.properties.Equal(cloud2.properties) {
+		t.Fatalf("Cloud Unmarshal: properties mutated in unmarshal")
+	}
+	if !cloud1.labels.Equal(cloud2.labels) {
+		t.Fatalf("Cloud Unmarshal: labels mutated in unmarshal")
+	}
+	if !cloud1.window.Equal(cloud2.window) {
+		t.Fatalf("Cloud Unmarshal: window mutated in unmarshal")
+	}
+	if !cloud1.start.Equal(cloud2.start) {
+		t.Fatalf("Cloud Unmarshal: start mutated in unmarshal")
+	}
+	if !cloud1.end.Equal(cloud2.end) {
+		t.Fatalf("Cloud Unmarshal: end mutated in unmarshal")
+	}
+	if cloud1.adjustment != cloud2.adjustment {
+		t.Fatalf("Cloud Unmarshal: adjustment mutated in unmarshal")
+	}
+	if cloud1.Cost != cloud2.Cost {
+		t.Fatalf("Cloud Unmarshal: cost mutated in unmarshal")
+	}
+	if cloud1.Credit != cloud2.Credit {
+		t.Fatalf("Cloud Unmarshal: credit mutated in unmarshal")
+	}
+
+	// As a final check, make sure the above checks out
+	if !cloud1.Equal(cloud2) {
+		t.Fatalf("Cloud Unmarshal: Cloud mutated in unmarshal")
+	}
+
+}
+
+func TestClusterManagement_Unmarshal(t *testing.T) {
+
+	cm1 := NewClusterManagement("gcp", "cluster1", unmarshalWindow)
+	cm1.Cost = 9.0
+
+	bytes, _ := json.Marshal(cm1)
+
+	var testcm ClusterManagement
+	cm2 := &testcm
+
+	err := json.Unmarshal(bytes, cm2)
+
+	// Check if unmarshal was successful
+	if err != nil {
+		t.Fatalf("ClusterManagement Unmarshal: unexpected error: %s", err)
+	}
+
+	// Check if all fields in initial ClusterManagement equal those in ClusterManagement from unmarshal
+	if !cm1.properties.Equal(cm2.properties) {
+		t.Fatalf("ClusterManagement Unmarshal: properties mutated in unmarshal")
+	}
+	if !cm1.labels.Equal(cm2.labels) {
+		t.Fatalf("ClusterManagement Unmarshal: labels mutated in unmarshal")
+	}
+	if !cm1.window.Equal(cm2.window) {
+		t.Fatalf("ClusterManagement Unmarshal: window mutated in unmarshal")
+	}
+	if cm1.Cost != cm2.Cost {
+		t.Fatalf("ClusterManagement Unmarshal: cost mutated in unmarshal")
+	}
+
+	// As a final check, make sure the above checks out
+	if !cm1.Equal(cm2) {
+		t.Fatalf("ClusterManagement Unmarshal: ClusterManagement mutated in unmarshal")
+	}
+
+}
+
+func TestDisk_Unmarshal(t *testing.T) {
+
+	hours := unmarshalWindow.Duration().Hours()
+
+	disk1 := NewDisk("disk1", "cluster1", "disk1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	disk1.ByteHours = 60.0 * gb * hours
+	disk1.Cost = 4.0
+	disk1.Local = 1.0
+	disk1.SetAdjustment(1.0)
+	disk1.Breakdown = &Breakdown{
+		Idle:   0.1,
+		System: 0.2,
+		User:   0.3,
+		Other:  0.4,
+	}
+
+	bytes, _ := json.Marshal(disk1)
+
+	var testdisk Disk
+	disk2 := &testdisk
+
+	err := json.Unmarshal(bytes, disk2)
+
+	// Check if unmarshal was successful
+	if err != nil {
+		t.Fatalf("Disk Unmarshal: unexpected error: %s", err)
+	}
+
+	// Check if all fields in initial Disk equal those in Disk from unmarshal
+	if !disk1.properties.Equal(disk2.properties) {
+		t.Fatalf("Disk Unmarshal: properties mutated in unmarshal")
+	}
+	if !disk1.labels.Equal(disk2.labels) {
+		t.Fatalf("Disk Unmarshal: labels mutated in unmarshal")
+	}
+	if !disk1.window.Equal(disk2.window) {
+		t.Fatalf("Disk Unmarshal: window mutated in unmarshal")
+	}
+	if !disk1.Breakdown.Equal(disk2.Breakdown) {
+		t.Fatalf("Disk Unmarshal: Breakdown mutated in unmarshal")
+	}
+	if !disk1.start.Equal(disk2.start) {
+		t.Fatalf("Disk Unmarshal: start mutated in unmarshal")
+	}
+	if !disk1.end.Equal(disk2.end) {
+		t.Fatalf("Disk Unmarshal: end mutated in unmarshal")
+	}
+	if disk1.adjustment != disk2.adjustment {
+		t.Fatalf("Disk Unmarshal: adjustment mutated in unmarshal")
+	}
+	if disk1.ByteHours != disk2.ByteHours {
+		t.Fatalf("Disk Unmarshal: ByteHours mutated in unmarshal")
+	}
+	if disk1.Cost != disk2.Cost {
+		t.Fatalf("Disk Unmarshal: cost mutated in unmarshal")
+	}
+
+	// Local from Disk is not marhsaled, and cannot be calculated from marshaled values.
+	// Currently, it is just ignored and not set in the resulting unmarshal to Disk. Thus,
+	// it is also ignored in this test; be aware that this means a resulting Disk from an
+	// unmarshal is therefore NOT equal to the originally marshaled Disk.
+
+}
+
+func TestNetwork_Unmarshal(t *testing.T) {
+
+	network1 := NewNetwork("network1", "cluster1", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	network1.Cost = 4.0
+	network1.SetAdjustment(1.0)
+
+	bytes, _ := json.Marshal(network1)
+
+	var testnw Network
+	network2 := &testnw
+
+	err := json.Unmarshal(bytes, network2)
+
+	// Check if unmarshal was successful
+	if err != nil {
+		t.Fatalf("Network Unmarshal: unexpected error: %s", err)
+	}
+
+	// Check if all fields in initial Network equal those in Network from unmarshal
+	if !network1.properties.Equal(network2.properties) {
+		t.Fatalf("Network Unmarshal: properties mutated in unmarshal")
+	}
+	if !network1.labels.Equal(network2.labels) {
+		t.Fatalf("Network Unmarshal: labels mutated in unmarshal")
+	}
+	if !network1.window.Equal(network2.window) {
+		t.Fatalf("Network Unmarshal: window mutated in unmarshal")
+	}
+	if !network1.start.Equal(network2.start) {
+		t.Fatalf("Network Unmarshal: start mutated in unmarshal")
+	}
+	if !network1.end.Equal(network2.end) {
+		t.Fatalf("Network Unmarshal: end mutated in unmarshal")
+	}
+	if network1.adjustment != network2.adjustment {
+		t.Fatalf("Network Unmarshal: adjustment mutated in unmarshal")
+	}
+	if network1.Cost != network2.Cost {
+		t.Fatalf("Network Unmarshal: cost mutated in unmarshal")
+	}
+
+	// As a final check, make sure the above checks out
+	if !network1.Equal(network2) {
+		t.Fatalf("Network Unmarshal: Network mutated in unmarshal")
+	}
+
+}
+
 func TestNode_Unmarshal(t *testing.T) {
 
 	hours := unmarshalWindow.Duration().Hours()
@@ -38,8 +298,8 @@ func TestNode_Unmarshal(t *testing.T) {
 
 	bytes, _ := json.Marshal(node1)
 
-	var thisnode Node
-	node2 := &thisnode
+	var testnode Node
+	node2 := &testnode
 
 	err := json.Unmarshal(bytes, node2)
 
@@ -111,17 +371,108 @@ func TestNode_Unmarshal(t *testing.T) {
 
 }
 
+func TestLoadBalancer_Unmarshal(t *testing.T) {
+
+	lb1 := NewLoadBalancer("loadbalancer1", "cluster1", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	lb1.Cost = 12.0
+	lb1.SetAdjustment(4.0)
+
+	bytes, _ := json.Marshal(lb1)
+
+	var testlb LoadBalancer
+	lb2 := &testlb
+
+	err := json.Unmarshal(bytes, lb2)
+
+	// Check if unmarshal was successful
+	if err != nil {
+		t.Fatalf("LoadBalancer Unmarshal: unexpected error: %s", err)
+	}
+
+	// Check if all fields in initial LoadBalancer equal those in LoadBalancer from unmarshal
+	if !lb1.properties.Equal(lb2.properties) {
+		t.Fatalf("LoadBalancer Unmarshal: properties mutated in unmarshal")
+	}
+	if !lb1.labels.Equal(lb2.labels) {
+		t.Fatalf("LoadBalancer Unmarshal: labels mutated in unmarshal")
+	}
+	if !lb1.window.Equal(lb2.window) {
+		t.Fatalf("LoadBalancer Unmarshal: window mutated in unmarshal")
+	}
+	if !lb1.start.Equal(lb2.start) {
+		t.Fatalf("LoadBalancer Unmarshal: start mutated in unmarshal")
+	}
+	if !lb1.end.Equal(lb2.end) {
+		t.Fatalf("LoadBalancer Unmarshal: end mutated in unmarshal")
+	}
+	if lb1.adjustment != lb2.adjustment {
+		t.Fatalf("LoadBalancer Unmarshal: adjustment mutated in unmarshal")
+	}
+	if lb1.Cost != lb2.Cost {
+		t.Fatalf("LoadBalancer Unmarshal: cost mutated in unmarshal")
+	}
+
+	// As a final check, make sure the above checks out
+	if !lb1.Equal(lb2) {
+		t.Fatalf("LoadBalancer Unmarshal: LoadBalancer mutated in unmarshal")
+	}
+
+}
+
+func TestSharedAsset_Unmarshal(t *testing.T) {
+
+	sa1 := NewSharedAsset("sharedasset1", unmarshalWindow)
+	sa1.Cost = 7.0
+
+	bytes, _ := json.Marshal(sa1)
+
+	var testsa SharedAsset
+	sa2 := &testsa
+
+	err := json.Unmarshal(bytes, sa2)
+
+	// Check if unmarshal was successful
+	if err != nil {
+		t.Fatalf("SharedAsset Unmarshal: unexpected error: %s", err)
+	}
+
+	// Check if all fields in initial SharedAsset equal those in SharedAsset from unmarshal
+	if !sa1.properties.Equal(sa2.properties) {
+		t.Fatalf("SharedAsset Unmarshal: properties mutated in unmarshal")
+	}
+	if !sa1.labels.Equal(sa2.labels) {
+		t.Fatalf("SharedAsset Unmarshal: labels mutated in unmarshal")
+	}
+	if !sa1.window.Equal(sa2.window) {
+		t.Fatalf("SharedAsset Unmarshal: window mutated in unmarshal")
+	}
+	if sa1.Cost != sa2.Cost {
+		t.Fatalf("SharedAsset Unmarshal: cost mutated in unmarshal")
+	}
+
+	// As a final check, make sure the above checks out
+	if !sa1.Equal(sa2) {
+		t.Fatalf("SharedAsset Unmarshal: SharedAsset mutated in unmarshal")
+	}
+
+}
+
 func TestAssetset_Unmarshal(t *testing.T) {
 
 	var s time.Time
 	var e time.Time
 	unmarshalWindow := NewWindow(&s, &e)
 
-	node1 := NewNode("node1", "cluster1", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
-	node2 := NewNode("node2", "cluster1", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
-	node3 := NewNode("node3", "cluster1", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	any := NewAsset(*unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	cloud := NewCloud("Compute", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	cm := NewClusterManagement("gcp", "cluster1", unmarshalWindow)
+	disk := NewDisk("disk1", "cluster1", "disk1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	network := NewNetwork("network1", "cluster1", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	node := NewNode("node1", "cluster1", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	lb := NewLoadBalancer("loadbalancer1", "cluster1", "provider1", *unmarshalWindow.start, *unmarshalWindow.end, unmarshalWindow)
+	sa := NewSharedAsset("sharedasset1", unmarshalWindow)
 
-	assetList := []Asset{node1, node2, node3}
+	assetList := []Asset{any, cloud, cm, disk, network, node, lb, sa}
 
 	assetset := NewAssetSet(s, e, assetList...)
 	bytes, _ := json.Marshal(assetset)
@@ -131,6 +482,9 @@ func TestAssetset_Unmarshal(t *testing.T) {
 
 	err := json.Unmarshal(bytes, assetUnmarshalResponse)
 
+	//fmt.Println(assetset.assets)
+	//fmt.Println(assetUnmarshalResponse.assets)
+
 	// Check if unmarshal was successful
 	if err != nil {
 		t.Fatalf("AssetSet Unmarshal: unexpected error: %s", err)
@@ -141,8 +495,60 @@ func TestAssetset_Unmarshal(t *testing.T) {
 
 		if unmarshaledAsset, exists := assetUnmarshalResponse.assets[key]; exists {
 
-			if !asset.Equal(unmarshaledAsset) {
-				t.Fatalf("AssetSet Unmarshal: asset at key '%s' from unmarshaled AssetSetResponse does not match corresponding asset from AssetSet", key)
+			// As Disk is not marshaled with all fields, the resultant Disk will be unequal. Test all fields we have instead.
+			if unmarshaledAsset.Type().String() == "Disk" {
+
+				udiskEq := func(d1 Asset, d2 Asset) bool {
+
+					asset, _ := asset.(*Disk)
+					unmarshaledAsset, _ := unmarshaledAsset.(*Disk)
+
+					if !asset.Labels().Equal(unmarshaledAsset.Labels()) {
+						return false
+					}
+					if !asset.Properties().Equal(unmarshaledAsset.Properties()) {
+						return false
+					}
+
+					if !asset.Start().Equal(unmarshaledAsset.Start()) {
+						return false
+					}
+					if !asset.End().Equal(unmarshaledAsset.End()) {
+						return false
+					}
+					if !asset.window.Equal(unmarshaledAsset.window) {
+						return false
+					}
+					if asset.adjustment != unmarshaledAsset.adjustment {
+						return false
+					}
+					if asset.Cost != unmarshaledAsset.Cost {
+						return false
+					}
+					if asset.ByteHours != unmarshaledAsset.ByteHours {
+						return false
+					}
+					if !asset.Breakdown.Equal(unmarshaledAsset.Breakdown) {
+						return false
+					}
+
+					return true
+				}
+
+				if res := udiskEq(asset, unmarshaledAsset); !res {
+					t.Fatalf("AssetSet Unmarshal: asset at key '%s' from unmarshaled AssetSetResponse does not match corresponding asset from AssetSet", key)
+				}
+
+			} else {
+
+				if !asset.Equal(unmarshaledAsset) {
+
+					fmt.Println(asset)
+					fmt.Println(unmarshaledAsset)
+
+					t.Fatalf("AssetSet Unmarshal: asset at key '%s' from unmarshaled AssetSetResponse does not match corresponding asset from AssetSet", key)
+				}
+
 			}
 
 		} else {