[Merge] lp:~mandel/udm/add-uploads into lp:udm
Sergio Schvezov
sergio.schvezov at canonical.com
Sun Jun 22 23:34:12 UTC 2014
Review: Needs Fixing
Two more errors commented INLINE
Diff comments:
> === added file 'uploader.go'
> --- uploader.go 1970-01-01 00:00:00 +0000
> +++ uploader.go 2014-06-20 09:15:22 +0000
> @@ -0,0 +1,406 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * Authors:
> + * Manuel de la Pena: manuel.delapena at canonical.com
> + *
> + * This file is part of ubuntu-download-manager.
> + *
> + * ubuntu-download-manager is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * ubuntu-download-manager is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +// Package udm provides a go interface to work with the ubuntu download manager
> +package udm
> +
> +import (
> + "errors"
> + "fmt"
> + "launchpad.net/go-dbus/v1"
> + "runtime"
> +)
> +
> +const (
> + UPLOAD_SERVICE = "com.canonical.applications.Uploader"
> + UPLOAD_INTERFACE = "com.canonical.applications.Upload"
> + UPLOAD_MANAGER_INTERFACE = "com.canonical.applications.UploadManager"
> +)
> +
> +// Upload is the common interface of an upload. It provides all the required
> +// methods to interact with an upload created by udm.
> +type Upload interface {
> + Progress() (uint64, error)
> + Metadata() (map[string]string, error)
> + SetThrottle(uint64) error
> + Throttle() (uint64, error)
> + AllowMobileUpload(bool) error
> + IsMobileUpload() (bool, error)
> + Start() error
> + Cancel() error
> + Started() chan bool
> + UploadProgress() chan Progress
> + Canceled() chan bool
> + Finished() chan string
> + Error() chan error
> +}
> +
> +// FileUpload represents a single file being uploaded by udm.
> +type FileUpload struct {
> + conn *dbus.Connection
> + proxy proxy
> + path dbus.ObjectPath
> + started chan bool
> + started_w watch
> + canceled chan bool
> + canceled_w watch
> + finished chan string
> + finished_w watch
> + errors chan error
> + error_w watch
> + progress chan Progress
> + progress_w watch
> +}
> +
> +func (upload *FileUpload) free() {
> + // cancel all watches so that goroutines are done and close the
> + // channels
> + upload.started_w.Cancel()
> + upload.canceled_w.Cancel()
> + upload.finished_w.Cancel()
> + upload.error_w.Cancel()
> + upload.progress_w.Cancel()
> +}
> +
> +func cleanUploadData(upload *FileUpload) {
> + upload.free()
> +}
> +
> +func newFileUpload(conn *dbus.Connection, path dbus.ObjectPath) (*FileUpload, error) {
> + proxy := conn.Object(DOWNLOAD_SERVICE, path)
> + started_ch := make(chan bool)
> + started_w, err := connectToSignal(conn, path, "started")
> + if err != nil {
> + return nil, err
> + }
> +
> + canceled_ch := make(chan bool)
> + canceled_w, err := connectToSignal(conn, path, "canceled")
> + if err != nil {
> + return nil, err
> + }
> +
> + finished_ch := make(chan string)
> + finished_w, err := connectToSignal(conn, path, "finished")
> + if err != nil {
> + return nil, err
> + }
> +
> + errors_ch := make(chan error)
> + errors_w, err := connectToSignal(conn, path, "error")
> + if err != nil {
> + return nil, err
> + }
> +
> + progress_ch := make(chan Progress)
> + progress_w, err := connectToSignal(conn, path, "progress")
> + if err != nil {
> + return nil, err
> + }
> +
> + u := FileUpload{conn, proxy, path, started_ch, started_w, canceled_ch, canceled_w, finished_ch, finished_w, errors_ch, errors_w, progress_ch, progress_w}
> +
> + // connect to the diff signals so that we have nice channels that do
> + // not expose dbus watchers
> + u.connectToStarted()
> + u.connectToCanceled()
> + u.connectToFinished()
> + u.connectToError()
> + u.connectToProgress()
> + runtime.SetFinalizer(&u, cleanUploadData)
> + return &u, nil
> +}
> +
> +// Process returns the process so far in uploading the file.
> +func (upload *FileUpload) Progress() (progress uint64, err error) {
> + reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "progress")
> + if err != nil {
> + return 0, err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return 0, fmt.Errorf("DBus Error: %", reply.ErrorName)
> + }
> +
> + if err = readArgs(reply, &progress); err != nil {
> + return 0, err
> + }
> + return progress, nil
> +}
> +
> +// Metadata returns the metadata that was provided at creating time to the upload.
> +func (upload *FileUpload) Metadata() (metadata map[string]string, err error) {
> + reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "metadata")
> + if err != nil {
> + return nil, err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return nil, fmt.Errorf("DBus Error: %", reply.ErrorName)
> + }
> +
> + if err = readArgs(reply, &metadata); err != nil {
> + return nil, err
> + }
> + return metadata, nil
> +}
> +
> +// SetThrottle sets the network throttle to be used in the upload.
> +func (upload *FileUpload) SetThrottle(throttle uint64) (err error) {
> + reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "setThrottle", throttle)
> + if err != nil {
> + return err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return fmt.Errorf("DBus Error: %", reply.ErrorName)
> + }
> +
> + return nil
> +}
> +
> +// Throttle returns the network throttle that is currently used in the upload.
> +func (upload *FileUpload) Throttle() (throttle uint64, err error) {
> + reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "throttle")
> + if err != nil {
> + return 0, err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return 0, fmt.Errorf("DBus Error: %", reply.ErrorName)
> + }
> +
> + if err = readArgs(reply, &throttle); err != nil {
> + return 0, err
> + }
> + return throttle, nil
> +}
> +
> +// AllowMobileUpload returns if the download is allow to use the mobile connect
> +// connection.
> +func (upload *FileUpload) AllowMobileUpload(allowed bool) (err error) {
> + reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "allowMobileUpload", allowed)
> + if err != nil {
> + return err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return fmt.Errorf("DBus Error: %", reply.ErrorName)
> + }
> +
> + return nil
> +}
> +
> +// IsMobileUpload returns if the download will be performed over the mobile data.
> +func (upload *FileUpload) IsMobileUpload() (allowed bool, err error) {
> + reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "isMobileUploadAllowed", allowed)
> + if err != nil {
> + return false, err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return false, fmt.Errorf("DBus Error: %", reply.ErrorName)
> + }
> +
> + if err = readArgs(reply, &allowed); err != nil {
> + return false, err
> + }
> + return allowed, nil
> +}
> +
> +func (upload *FileUpload) Start() (err error) {
> + reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "start")
> + if err != nil {
> + return err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return fmt.Errorf("DBus Error: %", reply.ErrorName)
> + }
> +
> + return nil
> +}
> +
> +// Cancel cancels an upload that was in process and deletes any local files
> +// that were created.
> +func (upload *FileUpload) Cancel() (err error) {
> + reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "cancel")
> + if err != nil {
> + return err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return fmt.Errorf("DBus Error: %", reply.ErrorName)
> + }
> +
> + return nil
> +}
> +
> +func (upload *FileUpload) connectToStarted() {
> +
> + go func() {
> + for msg := range upload.started_w.Channel() {
> + var started bool
> + readArgs(msg, &started)
> + upload.started <- started
> + }
> + close(upload.started)
> + }()
> +}
> +
> +// Started returns a channel that will be used to communicate the started signals.
> +func (upload *FileUpload) Started() chan bool {
> + return upload.started
> +}
> +
> +func (upload *FileUpload) connectToCanceled() {
> + go func() {
> + for msg := range upload.canceled_w.Channel() {
> + var canceled bool
> + readArgs(msg, &canceled)
> + upload.canceled <- canceled
> + }
> + close(upload.canceled)
> + }()
> +}
> +
> +// Canceled returns a channel that will be used to communicate the canceled signals.
> +func (upload *FileUpload) Canceled() chan bool {
> + return upload.canceled
> +}
> +
> +func (upload *FileUpload) connectToFinished() {
> + go func() {
> + for msg := range upload.finished_w.Channel() {
> + var path string
> + readArgs(msg, &path)
> + upload.finished <- path
> + }
> + close(upload.finished)
> + }()
> +}
> +
> +// Finished returns a channel that will ne used to communicate the finished signals.
> +func (upload *FileUpload) Finished() chan string {
> + return upload.finished
> +}
> +
> +func (upload *FileUpload) connectToError() {
> + go func() {
> + for msg := range upload.error_w.Channel() {
> + var reason string
> + readArgs(msg, &reason)
> + upload.errors <- errors.New(reason)
> + }
> + close(upload.errors)
> + }()
> +}
> +
> +// Error returns the channel that will be used to communicate the error signals.
> +func (upload *FileUpload) Error() chan error {
> + return upload.errors
> +}
> +
> +func (upload *FileUpload) connectToProgress() {
> + go func() {
> + for msg := range upload.progress_w.Channel() {
> + var received uint64
> + var total uint64
> + readArgs(msg, &received, &total)
> + upload.progress <- Progress{received, total}
> + }
> + close(upload.progress)
> + }()
> +}
> +
> +// UploadProgress returns a channel that will be used to communicate the progress
> +// signals.
> +func (upload *FileUpload) UploadProgress() chan Progress {
> + return upload.progress
> +}
> +
> +type UploadManager struct {
> + conn *dbus.Connection
> + proxy *dbus.ObjectProxy
> +}
> +
> +// NewUploadManager creates a new manager that can be used to create download in the
> +// udm daemon.
> +func NewUploadManager() (*UploadManager, error) {
> + conn, err := dbus.Connect(dbus.SessionBus)
> + if err != nil {
> + return nil, err
> + }
> +
> + if err != nil {
> + return nil, err
> + }
> +
> + proxy := conn.Object(UPLOAD_SERVICE, "/")
> + d := UploadManager{conn, proxy}
> + return &d, nil
> +}
> +
> +func (man *UploadManager) CreateUpload(url string, file string, metadata map[string]interface{}, headers map[string]string) (upload Upload, err error) {
> + var t map[string]*dbus.Variant
> + for key, value := range metadata {
> + t[key] = &dbus.Variant{Value: value}
> + }
> + s := struct {
> + U string
> + F string
> + M map[string]*dbus.Variant
> + HD map[string]string
> + }{url, file, t, headers}
> + var path dbus.ObjectPath
> + reply, err := man.proxy.Call(UPLOAD_MANAGER_INTERFACE, "createUpload", s)
> + if err != nil {
> + return nil, err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return 0, fmt.Errorf("DBus Error: %", reply.ErrorName)
this should return nil, error
> + }
> +
> + if err = readArgs(reply, &path); err != nil {
> + return nil, err
> + }
> + upload, err = newFileUpload(man.conn, path)
> + return upload, err
> +}
> +
> +func (man *UploadManager) CreateMmsUpload(url string, file string, hostname string, port int32) (upload Upload, err error) {
> + var path dbus.ObjectPath
> + reply, err := man.proxy.Call(UPLOAD_MANAGER_INTERFACE, "createMmsUpload", url, file, hostname, port)
> + if err != nil {
> + return nil, err
> + }
> +
> + if reply != nil && reply.Type == dbus.TypeError {
> + return 0, fmt.Errorf("DBus Error: %", reply.ErrorName)
this should return nil, error
> + }
> +
> + if err = readArgs(reply, &path); err != nil {
> + return nil, err
> + }
> + upload, err = newFileUpload(man.conn, path)
> + return upload, err
> +}
>
> === added file 'uploader_test.go'
> --- uploader_test.go 1970-01-01 00:00:00 +0000
> +++ uploader_test.go 2014-06-20 09:15:22 +0000
> @@ -0,0 +1,215 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * Authors:
> + * Manuel de la Pena: manuel.delapena at canonical.com
> + *
> + * This file is part of ubuntu-download-manager.
> + *
> + * ubuntu-download-manager is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * ubuntu-download-manager is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +package udm
> +
> +import (
> + "errors"
> + . "gopkg.in/check.v1"
> + "launchpad.net/go-dbus/v1"
> + "reflect"
> +)
> +
> +type UploadSuite struct {
> + proxy *fakeProxy
> + upload *FileUpload
> + msg_args []interface{}
> + msg_args_err error
> + started_ch chan bool
> + started_w watch
> + canceled_ch chan bool
> + canceled_w watch
> + finished_ch chan string
> + finished_w watch
> + errors_ch chan error
> + errors_w watch
> + progress_ch chan Progress
> + progress_w watch
> +}
> +
> +var _ = Suite(&UploadSuite{})
> +
> +func (s *UploadSuite) SetUpTest(c *C) {
> + s.proxy = &fakeProxy{}
> + s.started_ch = make(chan bool)
> + s.started_w = newFakeWatch()
> + s.canceled_ch = make(chan bool)
> + s.canceled_w = newFakeWatch()
> + s.finished_ch = make(chan string)
> + s.finished_w = newFakeWatch()
> + s.errors_ch = make(chan error)
> + s.errors_w = newFakeWatch()
> + s.progress_ch = make(chan Progress)
> + s.progress_w = newFakeWatch()
> + s.upload = &FileUpload{nil, s.proxy, "", s.started_ch, s.started_w, s.canceled_ch, s.canceled_w, s.finished_ch, s.finished_w, s.errors_ch, s.errors_w, s.progress_ch, s.progress_w}
> +
> + readArgs = func(msg *dbus.Message, args ...interface{}) error {
> + for i, arg := range args {
> + v := reflect.ValueOf(arg)
> + e := v.Elem()
> + switch s.msg_args[i].(type) {
> + default:
> + return errors.New("unexpected type")
> + case bool:
> + e.SetBool(s.msg_args[i].(bool))
> + case uint64:
> + e.SetUint(s.msg_args[i].(uint64))
> + }
> + }
> + return s.msg_args_err
> + }
> +}
> +
> +func (s *UploadSuite) TestProgressError(c *C) {
> + s.proxy.Result = newDBusError()
> + progress, err := s.upload.Progress()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "progress")
> + c.Assert(progress, Equals, uint64(0))
> + c.Assert(err, NotNil)
> +}
> +
> +func (s *UploadSuite) TestProgress(c *C) {
> + expected_progress := uint64(98)
> + s.proxy.Result = newDBusReturn()
> + s.msg_args = make([]interface{}, 1)
> + s.msg_args[0] = expected_progress
> + s.msg_args_err = nil
> + progress, err := s.upload.Progress()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "progress")
> + c.Assert(err, IsNil)
> + c.Assert(progress, Equals, expected_progress)
> +}
> +
> +func (s *UploadSuite) TestMetadataError(c *C) {
> + s.proxy.Result = newDBusError()
> + metadata, err := s.upload.Metadata()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "metadata")
> + c.Assert(metadata, IsNil)
> + c.Assert(err, NotNil)
> +}
> +
> +func (s *UploadSuite) TestSetThrotthleError(c *C) {
> + throttle := uint64(9)
> + s.proxy.Result = newDBusError()
> + err := s.upload.SetThrottle(throttle)
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "setThrottle")
> + c.Assert(err, NotNil)
> + c.Assert(s.proxy.Args[0], Equals, throttle)
> +}
> +
> +func (s *UploadSuite) TestSetThrottle(c *C) {
> + s.proxy.Result = newDBusReturn()
> + err := s.upload.SetThrottle(uint64(9))
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "setThrottle")
> + c.Assert(err, IsNil)
> +}
> +
> +func (s *UploadSuite) TestThrottle(c *C) {
> + expected_throttle := uint64(98)
> + s.proxy.Result = newDBusReturn()
> + s.msg_args = make([]interface{}, 1)
> + s.msg_args[0] = expected_throttle
> + s.msg_args_err = nil
> + throttle, err := s.upload.Throttle()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "throttle")
> + c.Assert(err, IsNil)
> + c.Assert(throttle, Equals, expected_throttle)
> +}
> +
> +func (s *UploadSuite) TestAllowMobileUploadError(c *C) {
> + s.proxy.Result = newDBusError()
> + err := s.upload.AllowMobileUpload(true)
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "allowMobileUpload")
> + c.Assert(err, NotNil)
> +}
> +
> +func (s *UploadSuite) TestAllowMobileUpload(c *C) {
> + expected_allowed := true
> + s.proxy.Result = newDBusReturn()
> + err := s.upload.AllowMobileUpload(expected_allowed)
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "allowMobileUpload")
> + c.Assert(err, IsNil)
> + c.Assert(s.proxy.Args[0], Equals, expected_allowed)
> +}
> +
> +func (s *UploadSuite) TestIsMobileUploadError(c *C) {
> + s.proxy.Result = newDBusError()
> + allowed, err := s.upload.IsMobileUpload()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "isMobileUploadAllowed")
> + c.Assert(allowed, Equals, false)
> + c.Assert(err, NotNil)
> +}
> +
> +func (s *UploadSuite) TestIsMobileUpload(c *C) {
> + expected_allowed := true
> + s.proxy.Result = newDBusReturn()
> + s.msg_args = make([]interface{}, 1)
> + s.msg_args[0] = expected_allowed
> + s.msg_args_err = nil
> + allowed, err := s.upload.IsMobileUpload()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "isMobileUploadAllowed")
> + c.Assert(err, IsNil)
> + c.Assert(allowed, Equals, expected_allowed)
> +}
> +
> +func (s *UploadSuite) TestStartDBusError(c *C) {
> + s.proxy.Result = newDBusError()
> + err := s.upload.Start()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "start")
> + c.Assert(err, NotNil)
> +}
> +
> +func (s *UploadSuite) TestStartError(c *C) {
> + s.proxy.Result = newDBusReturn()
> + s.proxy.Err = errors.New("Fake error")
> + err := s.upload.Start()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "start")
> + c.Assert(err, NotNil)
> +}
> +
> +func (s *UploadSuite) TestCancelDBusError(c *C) {
> + s.proxy.Result = newDBusError()
> + err := s.upload.Cancel()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "cancel")
> + c.Assert(err, NotNil)
> +}
> +
> +func (s *UploadSuite) TestCancelError(c *C) {
> + s.proxy.Result = newDBusReturn()
> + s.proxy.Err = errors.New("Fake error")
> + err := s.upload.Cancel()
> + c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE)
> + c.Assert(s.proxy.MethodName, Equals, "cancel")
> + c.Assert(err, NotNil)
> +}
>
--
https://code.launchpad.net/~mandel/udm/add-uploads/+merge/219201
Your team Ubuntu Phablet Team is subscribed to branch lp:udm.
More information about the Ubuntu-reviews
mailing list