From a9512ff790147de08f74b4d0601c20920b798ebc Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 7 Aug 2014 22:31:24 -0600 Subject: [PATCH] Add Create() to the backups abstraction. --- state/backups/backups.go | 46 ++++++++++++++++++++++++++ state/backups/backups_test.go | 62 +++++++++++++++++++++++++++++++++++ state/backups/export_test.go | 31 ++++++++++++++++++ 3 files changed, 139 insertions(+) diff --git a/state/backups/backups.go b/state/backups/backups.go index e2506928431..0a5aa0ecf98 100644 --- a/state/backups/backups.go +++ b/state/backups/backups.go @@ -6,14 +6,28 @@ package backups import ( + "github.com/juju/errors" "github.com/juju/loggo" "github.com/juju/utils/filestorage" + + "github.com/juju/juju/state/backups/db" + "github.com/juju/juju/state/backups/files" + "github.com/juju/juju/state/backups/metadata" ) var logger = loggo.GetLogger("juju.state.backups") +var ( + getFilesToBackUp = files.GetFilesToBackUp + getDBDumper (func(db.ConnInfo) db.Dumper) = db.NewDumper + runCreate = create +) + // Backups is an abstraction around all juju backup-related functionality. type Backups interface { + // Create creates and stores a new juju backup archive and returns + // its associated metadata. + Create(dbInfo *db.ConnInfo, origin *metadata.Origin, notes string) (*metadata.Metadata, error) } type backups struct { @@ -28,3 +42,35 @@ func NewBackups(stor filestorage.FileStorage) Backups { } return &b } + +// Create creates and stores a new juju backup archive and returns +// its associated metadata. +func (b *backups) Create(dbInfo *db.ConnInfo, origin *metadata.Origin, notes string) (*metadata.Metadata, error) { + // Prep the metadata. + meta := metadata.NewMetadata(*origin, notes, nil) + + // Create the archive. + filesToBackUp, err := getFilesToBackUp("") + if err != nil { + return nil, errors.Annotate(err, "error listing files to back up") + } + dumper := getDBDumper(*dbInfo) + args := createArgs{filesToBackUp, dumper} + result, err := runCreate(&args) + if err != nil { + return nil, errors.Annotate(err, "error creating backup archive") + } + defer result.archiveFile.Close() + + // Store the archive. + err = meta.Finish(result.size, result.checksum, "", nil) + if err != nil { + return nil, errors.Annotate(err, "error updating metadata") + } + _, err = b.storage.Add(meta, result.archiveFile) + if err != nil { + return nil, errors.Annotate(err, "error storing backup archive") + } + + return meta, nil +} diff --git a/state/backups/backups_test.go b/state/backups/backups_test.go index b284e852050..abb9c7f8e76 100644 --- a/state/backups/backups_test.go +++ b/state/backups/backups_test.go @@ -4,10 +4,16 @@ package backups_test import ( + "bytes" + "io/ioutil" + + jc "github.com/juju/testing/checkers" "github.com/juju/utils/filestorage" gc "launchpad.net/gocheck" "github.com/juju/juju/state/backups" + "github.com/juju/juju/state/backups/db" + "github.com/juju/juju/state/backups/metadata" "github.com/juju/juju/testing" ) @@ -35,3 +41,59 @@ func (s *backupsSuite) TestNewBackups(c *gc.C) { c.Check(api, gc.NotNil) } + +func (s *backupsSuite) TestCreateOkay(c *gc.C) { + // Patch the internals. + archiveFile := ioutil.NopCloser(bytes.NewBufferString("")) + result := backups.NewTestCreateResult(archiveFile, 10, "") + received, testCreate := backups.NewTestCreate(result, nil) + s.PatchValue(backups.RunCreate, testCreate) + + rootDir := "" + s.PatchValue(backups.GetFilesToBackUp, func(root string) ([]string, error) { + rootDir = root + return []string{""}, nil + }) + + var receivedDBInfo *db.ConnInfo + s.PatchValue(backups.GetDBDumper, func(info db.ConnInfo) db.Dumper { + receivedDBInfo = &info + return nil + }) + + // Run the backup. + dbInfo := &db.ConnInfo{"a", "b", "c"} + origin := metadata.NewOrigin("", "", "") + meta, err := s.api.Create(dbInfo, origin, "some notes") + + // Test the call values. + filesToBackUp, _ := backups.ExposeCreateArgs(received) + c.Check(filesToBackUp, jc.SameContents, []string{""}) + + err = receivedDBInfo.Validate() + c.Assert(err, gc.IsNil) + c.Check(receivedDBInfo.Address, gc.Equals, "a") + c.Check(receivedDBInfo.Username, gc.Equals, "b") + c.Check(receivedDBInfo.Password, gc.Equals, "c") + + c.Check(rootDir, gc.Equals, "") + + // Check the resulting metadata. + c.Check(meta.ID(), gc.Not(gc.Equals), "") + c.Check(meta.Size(), gc.Equals, int64(10)) + c.Check(meta.Checksum(), gc.Equals, "") + c.Check(meta.Stored(), gc.Equals, true) + metaOrigin := meta.Origin() + c.Check(metaOrigin.Environment(), gc.Equals, "") + c.Check(metaOrigin.Machine(), gc.Equals, "") + c.Check(metaOrigin.Hostname(), gc.Equals, "") + c.Check(meta.Notes(), gc.Equals, "some notes") + + // Check the file storage. + storedMeta, storedFile, err := s.storage.Get(meta.ID()) + c.Check(err, gc.IsNil) + c.Check(storedMeta, gc.DeepEquals, meta) + data, err := ioutil.ReadAll(storedFile) + c.Assert(err, gc.IsNil) + c.Check(string(data), gc.Equals, "") +} diff --git a/state/backups/export_test.go b/state/backups/export_test.go index d72c37933f3..323f477dc5a 100644 --- a/state/backups/export_test.go +++ b/state/backups/export_test.go @@ -11,6 +11,10 @@ import ( var ( Create = create + + GetFilesToBackUp = &getFilesToBackUp + GetDBDumper = &getDBDumper + RunCreate = &runCreate ) func ExposeCreateResult(result *createResult) (io.ReadCloser, int64, string) { @@ -24,3 +28,30 @@ func NewTestCreateArgs(filesToBackUp []string, db db.Dumper) *createArgs { } return &args } + +func ExposeCreateArgs(args *createArgs) ([]string, db.Dumper) { + return args.filesToBackUp, args.db +} + +func NewTestCreateResult(file io.ReadCloser, size int64, checksum string) *createResult { + result := createResult{ + archiveFile: file, + size: size, + checksum: checksum, + } + return &result +} + +func NewTestCreate(result *createResult, err error) (*createArgs, func(*createArgs) (*createResult, error)) { + var received createArgs + + testCreate := func(args *createArgs) (*createResult, error) { + received = *args + if err != nil { + return nil, err + } + return result, nil + } + + return &received, testCreate +}