Adds unit tests and K8s artifacts
[icn.git] / cmd / bpa-restapi-agent / internal / app / image.go
index 28cda77..2c117a3 100644 (file)
@@ -1,25 +1,25 @@
 package app
 
 import (
+       "bpa-restapi-agent/internal/db"
        "encoding/json"
        "os"
        "os/user"
        "path"
-       "bpa-restapi-agent/internal/db"
 
        pkgerrors "github.com/pkg/errors"
 )
 
 // Image contains the parameters needed for Image information
 type Image struct {
-       Owner                           string               `json:"owner"`
-       ClusterName         string               `json:"cluster_name"`
-       Type                string               `json:"type"`
-       ImageName           string               `json:"image_name"`
-       ImageOffset                                     *int                                                       `json:"image_offset"`
-       ImageLength                                     int                                                                      `json:"image_length"`
-       UploadComplete                  *bool                                                            `json:"upload_complete"`
-       Description         ImageRecordList      `json:"description"`
+       Owner          string          `json:"owner"`
+       ClusterName    string          `json:"cluster_name"`
+       Type           string          `json:"type"`
+       ImageName      string          `json:"image_name"`
+       ImageOffset    *int            `json:"image_offset"`
+       ImageLength    int             `json:"image_length"`
+       UploadComplete *bool           `json:"upload_complete"`
+       Description    ImageRecordList `json:"description"`
 }
 
 type ImageRecordList struct {
@@ -28,9 +28,7 @@ type ImageRecordList struct {
 
 // ImageKey is the key structure that is used in the database
 type ImageKey struct {
-       // Owner            string     `json:"owner"`
-       // ClusterName      string     `json:"cluster_name"`
-       ImageName        string     `json:"image_name"`
+       ImageName string `json:"image_name"`
 }
 
 // We will use json marshalling to convert to string to
@@ -54,32 +52,56 @@ type ImageManager interface {
        GetDirPath(imageName string) (string, string, error)
 }
 
+// Interface to aid unit test by mocking third party packages
+type Utility interface {
+       GetCurrentUser() (*user.User, error)
+       DBCreate(storeName string, key ImageKey, meta string, c Image) error
+       DBRead(storeName string, key ImageKey, meta string) ([]byte, error)
+       DBUnmarshal(value []byte) (Image, error)
+       OSMakeDir(dirpath string, perm int) error
+       OSCreateFile(filePath string) error
+       GetPath(user *user.User, imageName string, storeName string) (string, string)
+       DBDelete(storeName string, key ImageKey, meta string) error
+       OSRemove(filePath string) error
+       DBUpdate(storeName string, key ImageKey, tagMeta string, c Image) error
+}
+
 // ImageClient implements the ImageManager
 // It will also be used to maintain some localized state
 type ImageClient struct {
+       util      Utility
        storeName string
        tagMeta   string
 }
 
+type DBService struct {
+}
+
 // To Do - Fix repetition in
 // NewImageClient returns an instance of the ImageClient
 // which implements the ImageManager
 func NewBinaryImageClient() *ImageClient {
+    service := DBService{}
        return &ImageClient{
+        util: service,
                storeName: "binary_images",
                tagMeta:   "metadata",
        }
 }
 
 func NewContainerImageClient() *ImageClient {
+    service := DBService{}
        return &ImageClient{
+        util: service,
                storeName: "container_images",
                tagMeta:   "metadata",
        }
 }
 
 func NewOSImageClient() *ImageClient {
+    service := DBService{}
        return &ImageClient{
+        util: service,
                storeName: "os_images",
                tagMeta:   "metadata",
        }
@@ -87,11 +109,8 @@ func NewOSImageClient() *ImageClient {
 
 // Create an entry for the Image resource in the database`
 func (v *ImageClient) Create(c Image) (Image, error) {
-
        //Construct composite key consisting of name
        key := ImageKey{
-               // Owner:       c.Owner,
-               // ClusterName: c.ClusterName,
                ImageName: c.ImageName,
        }
 
@@ -101,12 +120,12 @@ func (v *ImageClient) Create(c Image) (Image, error) {
                return Image{}, pkgerrors.New("Image already exists")
        }
 
-       err = db.DBconn.Create(v.storeName, key, v.tagMeta, c)
+       err = v.util.DBCreate(v.storeName, key, v.tagMeta, c)
        if err != nil {
                return Image{}, pkgerrors.Wrap(err, "Creating DB Entry")
        }
 
-       err = v.CreateFile(v.storeName, c)
+       err = v.CreateFile(c)
        if err != nil {
                return Image{}, pkgerrors.Wrap(err, "Creating File in FS")
        }
@@ -114,28 +133,53 @@ func (v *ImageClient) Create(c Image) (Image, error) {
        return c, nil
 }
 
+func (d DBService) DBCreate(storeName string, key ImageKey, meta string, c Image) error {
+
+       //Construct composite key consisting of name
+       err := db.DBconn.Create(storeName, key, meta, c)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Creating DB Entry")
+       }
+
+       return nil
+}
+
 // Create file
 
-func (v *ImageClient) CreateFile(dirName string, c Image) error {
+func (v *ImageClient) CreateFile(c Image) error {
        filePath, dirPath, err := v.GetDirPath(c.ImageName)
        if err != nil {
                return pkgerrors.Wrap(err, "Get file path")
        }
-  err = os.MkdirAll(dirPath, 0744)
-  if err != nil {
+       err = v.util.OSMakeDir(dirPath, 0744)
+       if err != nil {
                return pkgerrors.Wrap(err, "Make image directory")
-  }
-       file1, err := os.Create(filePath)
+       }
+       err = v.util.OSCreateFile(filePath)
        if err != nil {
                return pkgerrors.Wrap(err, "Create image file")
        }
 
-       defer file1.Close()
-
+       return nil
+}
 
-  return nil
+func (d DBService) OSMakeDir(dirPath string, perm int) error {
+       err := os.MkdirAll(dirPath, 0744)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Make image directory")
+       }
+       return nil
 }
 
+func (d DBService) OSCreateFile(filePath string) error {
+       file1, err := os.Create(filePath)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Create image file")
+       }
+       defer file1.Close()
+
+       return nil
+}
 
 // Get returns Image for corresponding to name
 func (v *ImageClient) Get(imageName string) (Image, error) {
@@ -147,15 +191,14 @@ func (v *ImageClient) Get(imageName string) (Image, error) {
                ImageName: imageName,
        }
 
-       value, err := db.DBconn.Read(v.storeName, key, v.tagMeta)
+       value, err := v.util.DBRead(v.storeName, key, v.tagMeta)
        if err != nil {
                return Image{}, pkgerrors.Wrap(err, "Get Image")
        }
 
        //value is a byte array
        if value != nil {
-               c := Image{}
-               err = db.DBconn.Unmarshal(value, &c)
+               c, err := v.util.DBUnmarshal(value)
                if err != nil {
                        return Image{}, pkgerrors.Wrap(err, "Unmarshaling Value")
                }
@@ -165,6 +208,25 @@ func (v *ImageClient) Get(imageName string) (Image, error) {
        return Image{}, pkgerrors.New("Error getting Connection")
 }
 
+func (d DBService) DBRead(storeName string, key ImageKey, meta string) ([]byte, error) {
+       value, err := db.DBconn.Read(storeName, key, meta)
+       if err != nil {
+               return []byte{}, pkgerrors.Wrap(err, "Get Image")
+       }
+
+       return value, nil
+}
+
+func (d DBService) DBUnmarshal(value []byte) (Image, error) {
+       c := Image{}
+       err := db.DBconn.Unmarshal(value, &c)
+       if err != nil {
+               return Image{}, pkgerrors.Wrap(err, "Unmarshaling Value")
+       }
+
+       return c, nil
+}
+
 func (v *ImageClient) GetImageRecordByName(imgName string,
        imageRecordName string) (map[string]string, error) {
 
@@ -183,13 +245,8 @@ func (v *ImageClient) GetImageRecordByName(imgName string,
 }
 
 func (v *ImageClient) GetDirPath(imageName string) (string, string, error) {
-       u, err := user.Current()
-       if err != nil {
-               return "", "", pkgerrors.Wrap(err, "Current user")
-       }
-       home := u.HomeDir
-       dirPath := path.Join(home, "images", v.storeName)
-       filePath := path.Join(dirPath, imageName)
+       u, err := v.util.GetCurrentUser()
+       filePath, dirPath := v.util.GetPath(u, imageName, v.storeName)
 
        return filePath, dirPath, err
 }
@@ -203,20 +260,33 @@ func (v *ImageClient) Delete(imageName string) error {
                // ClusterName: clusterName,
                ImageName: imageName,
        }
-       err := db.DBconn.Delete(v.storeName, key, v.tagMeta)
-       if err != nil {
-               return pkgerrors.Wrap(err, "Delete Image")
-       }
+       err := v.util.DBDelete(v.storeName, key, v.tagMeta)
 
        //Delete image from FS
        filePath, _, err := v.GetDirPath(imageName)
        if err != nil {
                return pkgerrors.Wrap(err, "Get file path")
        }
-       err = os.Remove(filePath)
+       err = v.util.OSRemove(filePath)
+
+       return nil
+}
+
+func (d DBService) OSRemove(filePath string) error {
+       err := os.Remove(filePath)
        if err != nil {
                return pkgerrors.Wrap(err, "Delete image file")
        }
+
+       return nil
+}
+
+func (d DBService) DBDelete(storeName string, key ImageKey, tagMeta string) error {
+       err := db.DBconn.Delete(storeName, key, tagMeta)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Delete Image")
+       }
+
        return nil
 }
 
@@ -233,10 +303,34 @@ func (v *ImageClient) Update(imageName string, c Image) (Image, error) {
                return Image{}, pkgerrors.New("Update Error - Image doesn't exist")
        }
 
-       err = db.DBconn.Update(v.storeName, key, v.tagMeta, c)
+       err = v.util.DBUpdate(v.storeName, key, v.tagMeta, c)
+
+       return c, nil
+}
+
+func (d DBService) DBUpdate(storeName string, key ImageKey, tagMeta string, c Image) error {
+       err := db.DBconn.Update(storeName, key, tagMeta, c)
        if err != nil {
-               return Image{}, pkgerrors.Wrap(err, "Updating DB Entry")
+               return pkgerrors.Wrap(err, "Updating DB Entry")
        }
 
-       return c, nil
+       return nil
+}
+
+// Define GetCurrentUser
+func (d DBService) GetCurrentUser() (*user.User, error) {
+       u, err := user.Current()
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Current user")
+       }
+
+       return u, nil
+}
+
+func (d DBService) GetPath(user *user.User, imageName string, storeName string) (string, string) {
+       home := user.HomeDir
+       dirPath := path.Join(home, "images", storeName)
+       filePath := path.Join(dirPath, imageName)
+
+       return filePath, dirPath
 }