diff --git a/bindings/fileTransfer.go b/bindings/fileTransfer.go index 099cecc8496f254704267cb1c286b34a3355361b..74d911483de71b990ae05ee5b3b0a281ecc528f1 100644 --- a/bindings/fileTransfer.go +++ b/bindings/fileTransfer.go @@ -163,12 +163,13 @@ func (f *FileTransfer) RegisterSendProgressCallback(transferID []byte, // Resend resends a file if sending fails. This function should only be called // if the interfaces.SentProgressCallback returns an error. -func (f *FileTransfer) Resend(transferID []byte) error { +// Resend is not currently implemented. +/*func (f *FileTransfer) Resend(transferID []byte) error { // Unmarshal transfer ID tid := ftCrypto.UnmarshalTransferID(transferID) return f.m.Resend(tid) -} +}*/ // CloseSend deletes a sent file transfer from the sent transfer map and from // storage once a transfer has completed or reached the retry limit. Returns an diff --git a/storage/fileTransfer/receiveFileTransfers.go b/storage/fileTransfer/receiveFileTransfers.go index fc293fe9cb66446366f5324ad56115dd1f73299b..8dcc8649c56f75e4e82727258de0c993fdfe2b39 100644 --- a/storage/fileTransfer/receiveFileTransfers.go +++ b/storage/fileTransfer/receiveFileTransfers.go @@ -29,7 +29,7 @@ const ( const ( saveReceivedTransfersListErr = "failed to save list of received items in transfer map to storage: %+v" loadReceivedTransfersListErr = "failed to load list of received items in transfer map from storage: %+v" - loadReceivedFileTransfersErr = "failed to load received transfers from storage: %+v" + loadReceivedFileTransfersErr = "[FT] Failed to load received transfers from storage: %+v" newReceivedTransferErr = "failed to create new received transfer: %+v" getReceivedTransferErr = "received transfer with ID %s not found" @@ -37,6 +37,10 @@ const ( noFingerprintErr = "no part found with fingerprint %s" addPartErr = "failed to add part to transfer %s: %+v" deleteReceivedTransferErr = "failed to delete received transfer with ID %s from store: %+v" + + // ReceivedFileTransfersStore.load + loadReceivedTransferWarn = "[FT] Failed to load received file transfer %d of %d with ID %s: %v" + loadReceivedTransfersAllErr = "failed to load all %d transfers" ) // ReceivedFileTransfersStore contains information for tracking a received @@ -224,7 +228,7 @@ func LoadReceivedFileTransfersStore(kv *versioned.KV) ( kv: kv.Prefix(receivedFileTransfersStorePrefix), } - // get the list of transfer IDs corresponding to each received transfer from + // Get the list of transfer IDs corresponding to each received transfer from // storage transfersList, err := rft.loadTransfersList() if err != nil { @@ -265,7 +269,8 @@ func NewOrLoadReceivedFileTransfersStore(kv *versioned.KV) ( // Load transfers and fingerprints into the maps err = rft.load(transfersList) if err != nil { - return nil, errors.Errorf(loadReceivedFileTransfersErr, err) + jww.ERROR.Printf(loadReceivedFileTransfersErr, err) + return NewReceivedFileTransfersStore(kv) } return rft, nil @@ -289,7 +294,7 @@ func (rft *ReceivedFileTransfersStore) saveTransfersList() error { // received transfer from storage. func (rft *ReceivedFileTransfersStore) loadTransfersList() ( []ftCrypto.TransferID, error) { - // get transfers list from storage + // Get transfers list from storage vo, err := rft.kv.Get( receivedFileTransfersStoreKey, receivedFileTransfersStoreVersion) if err != nil { @@ -304,12 +309,16 @@ func (rft *ReceivedFileTransfersStore) loadTransfersList() ( // map. Also adds all unused fingerprints in each ReceivedTransfer to the info // map. func (rft *ReceivedFileTransfersStore) load(list []ftCrypto.TransferID) error { + var errCount int + // Load each sentTransfer from storage into the map - for _, tid := range list { + for i, tid := range list { // Load the transfer with the given transfer ID from storage rt, err := loadReceivedTransfer(tid, rft.kv) if err != nil { - return err + jww.WARN.Printf(loadReceivedTransferWarn, i, len(list), tid, err) + errCount++ + continue } // Add transfer to transfer map @@ -329,6 +338,11 @@ func (rft *ReceivedFileTransfersStore) load(list []ftCrypto.TransferID) error { } } + // Return an error if all transfers failed to load + if errCount == len(list) { + return errors.Errorf(loadReceivedTransfersAllErr, len(list)) + } + return nil } diff --git a/storage/fileTransfer/receiveFileTransfers_test.go b/storage/fileTransfer/receiveFileTransfers_test.go index 64c183b54441fef528bea1d988df0edd5b87bce5..1eee9480f9c28fa0c82dc6c8a46a4e32edee1e6e 100644 --- a/storage/fileTransfer/receiveFileTransfers_test.go +++ b/storage/fileTransfer/receiveFileTransfers_test.go @@ -197,7 +197,7 @@ func TestReceivedFileTransfersStore_GetTransfer(t *testing.T) { t.Errorf("Failed to add new transfer: %+v", err) } - // get the transfer + // Get the transfer transfer, err := rft.GetTransfer(tid) if err != nil { t.Errorf("GetTransfer returned an error: %+v", err) @@ -245,7 +245,7 @@ func TestReceivedFileTransfersStore_GetTransfer_NoTransferError(t *testing.T) { t.Errorf("Failed to add new transfer: %+v", err) } - // get the transfer + // Get the transfer invalidTid, _ := ftCrypto.NewTransferID(prng) expectedErr := fmt.Sprintf(getReceivedTransferErr, invalidTid) _, err = rft.GetTransfer(invalidTid) @@ -654,30 +654,6 @@ func TestNewOrLoadReceivedFileTransfersStore_NewReceivedFileTransfersStore(t *te } } -// Error path: tests that NewOrLoadReceivedFileTransfersStore returns the -// expected error when the first transfer loaded from storage does not exist. -func TestNewOrLoadReceivedFileTransfersStore_NoTransferInStorageError(t *testing.T) { - kv := versioned.NewKV(make(ekv.Memstore)) - expectedErr := strings.Split(loadReceivedFileTransfersErr, "%")[0] - - // Save list of one transfer ID to storage - obj := &versioned.Object{ - Version: receivedFileTransfersStoreVersion, - Timestamp: netTime.Now(), - Data: ftCrypto.UnmarshalTransferID([]byte("testID_01")).Bytes(), - } - err := kv.Prefix(receivedFileTransfersStorePrefix).Set( - receivedFileTransfersStoreKey, receivedFileTransfersStoreVersion, obj) - - // Load ReceivedFileTransfersStore from storage - _, err = NewOrLoadReceivedFileTransfersStore(kv) - if err == nil || !strings.Contains(err.Error(), expectedErr) { - t.Errorf("NewOrLoadReceivedFileTransfersStore did not return the "+ - "expected error when there is no transfer saved in storage."+ - "\nexpected: %s\nreceived: %+v", expectedErr, err) - } -} - // Tests that the list saved by ReceivedFileTransfersStore.saveTransfersList // matches the list loaded by ReceivedFileTransfersStore.load. func TestReceivedFileTransfersStore_saveTransfersList_loadTransfersList(t *testing.T) { @@ -802,6 +778,57 @@ func TestReceivedFileTransfersStore_load(t *testing.T) { } } +// Error path: tests that ReceivedFileTransfersStore.load returns an error when +// all file transfers fail to load from storage. +func TestReceivedFileTransfersStore_load_AllFail(t *testing.T) { + kv := versioned.NewKV(make(ekv.Memstore)) + rft, err := NewReceivedFileTransfersStore(kv) + if err != nil { + t.Fatalf("Failed to create new ReceivedFileTransfersStore: %+v", err) + } + + // Fill map with transfers + idList := make([]ftCrypto.TransferID, 7) + for i := range idList { + prng := NewPrng(int64(i)) + key, _ := ftCrypto.NewTransferKey(prng) + mac := []byte("transferMAC") + + idList[i], err = rft.AddTransfer(key, mac, 256, 16, 24, prng) + if err != nil { + t.Errorf("Failed to add new transfer #%d: %+v", i, err) + } + + err = rft.DeleteTransfer(idList[i]) + if err != nil { + t.Errorf("Failed to delete transfer: %+v", err) + } + } + + // Save the list + err = rft.saveTransfersList() + if err != nil { + t.Errorf("saveTransfersList returned an error: %+v", err) + } + + // Build new ReceivedFileTransfersStore + newRFT := &ReceivedFileTransfersStore{ + transfers: make(map[ftCrypto.TransferID]*ReceivedTransfer), + info: make(map[format.Fingerprint]*partInfo), + kv: kv.Prefix(receivedFileTransfersStorePrefix), + } + + expectedErr := fmt.Sprintf(loadReceivedTransfersAllErr, len(idList)) + + // Load saved transfers from storage + err = newRFT.load(idList) + if err == nil || err.Error() != expectedErr { + t.Errorf("load did not return the expected error when none of the "+ + "transfer could be loaded from storage."+ + "\nexpected: %s\nreceived: %+v", expectedErr, err) + } +} + // Tests that a transfer list marshalled with // ReceivedFileTransfersStore.marshalTransfersList and unmarshalled with // unmarshalTransfersList matches the original. diff --git a/storage/fileTransfer/sentFileTransfers.go b/storage/fileTransfer/sentFileTransfers.go index 682c22defcd372bd2f94bd46bd413f78294990e1..eb14f0e8b0a33e090e9ebed9810ac9db58a1aa1a 100644 --- a/storage/fileTransfer/sentFileTransfers.go +++ b/storage/fileTransfer/sentFileTransfers.go @@ -32,12 +32,16 @@ const ( const ( saveSentTransfersListErr = "failed to save list of sent items in transfer map to storage: %+v" loadSentTransfersListErr = "failed to load list of sent items in transfer map from storage: %+v" - loadSentTransfersErr = "failed to load sent transfers from storage: %+v" + loadSentTransfersErr = "[FT] Failed to load sent transfers from storage: %+v" newSentTransferErr = "failed to create new sent transfer: %+v" getSentTransferErr = "sent file transfer not found" cancelCallbackErr = "[FT] Transfer with ID %s: %+v" deleteSentTransferErr = "failed to delete sent transfer with ID %s from store: %+v" + + // SentFileTransfersStore.loadTransfers + loadSentTransferWarn = "[FT] Failed to load sent file transfer %d of %d with ID %s: %v" + loadSentTransfersAllErr = "failed to load all %d transfers" ) // SentFileTransfersStore contains information for tracking sent file transfers. @@ -149,7 +153,7 @@ func (sft *SentFileTransfersStore) GetUnsentParts() ( defer sft.mux.Unlock() unsentParts := map[ftCrypto.TransferID][]uint16{} - // get list of unsent part numbers for each transfer + // Get list of unsent part numbers for each transfer for tid, st := range sft.transfers { unsentPartNums, err := st.GetUnsentPartNums() if err != nil { @@ -168,7 +172,7 @@ func (sft *SentFileTransfersStore) GetSentRounds() map[id.Round][]ftCrypto.Trans defer sft.mux.Unlock() sentRounds := map[id.Round][]ftCrypto.TransferID{} - // get list of round IDs that transfers have in-progress rounds on + // Get list of round IDs that transfers have in-progress rounds on for tid, st := range sft.transfers { for _, rid := range st.GetSentRounds() { sentRounds[rid] = append(sentRounds[rid], tid) @@ -193,7 +197,7 @@ func (sft *SentFileTransfersStore) GetUnsentPartsAndSentRounds() ( sentRounds := map[id.Round][]ftCrypto.TransferID{} for tid, st := range sft.transfers { - // get list of unsent part numbers for each transfer + // Get list of unsent part numbers for each transfer stUnsentParts, err := st.GetUnsentPartNums() if err != nil { return nil, nil, err @@ -202,7 +206,7 @@ func (sft *SentFileTransfersStore) GetUnsentPartsAndSentRounds() ( unsentParts[tid] = stUnsentParts } - // get list of round IDs that transfers have in-progress rounds on + // Get list of round IDs that transfers have in-progress rounds on for _, rid := range st.GetSentRounds() { sentRounds[rid] = append(sentRounds[rid], tid) } @@ -223,7 +227,7 @@ func LoadSentFileTransfersStore(kv *versioned.KV) (*SentFileTransfersStore, erro kv: kv.Prefix(sentFileTransfersStorePrefix), } - // get the list of transfer IDs corresponding to each sent transfer from + // Get the list of transfer IDs corresponding to each sent transfer from // storage transfersList, err := sft.loadTransfersList() if err != nil { @@ -254,8 +258,7 @@ func NewOrLoadSentFileTransfersStore(kv *versioned.KV) (*SentFileTransfersStore, vo, err := sft.kv.Get( sentFileTransfersStoreKey, sentFileTransfersStoreVersion) if err != nil { - newSFT, err := NewSentFileTransfersStore(kv) - return newSFT, err + return NewSentFileTransfersStore(kv) } // Unmarshal data into list of saved transfer IDs @@ -264,7 +267,8 @@ func NewOrLoadSentFileTransfersStore(kv *versioned.KV) (*SentFileTransfersStore, // Load each transfer in the list from storage into the map err = sft.loadTransfers(transfersList) if err != nil { - return nil, errors.Errorf(loadSentTransfersErr, err) + jww.WARN.Printf(loadSentTransfersErr, err) + return NewSentFileTransfersStore(kv) } return sft, nil @@ -288,7 +292,7 @@ func (sft *SentFileTransfersStore) saveTransfersList() error { // sent transfer from storage. func (sft *SentFileTransfersStore) loadTransfersList() ([]ftCrypto.TransferID, error) { - // get transfers list from storage + // Get transfers list from storage vo, err := sft.kv.Get( sentFileTransfersStoreKey, sentFileTransfersStoreVersion) if err != nil { @@ -304,15 +308,22 @@ func (sft *SentFileTransfersStore) loadTransfersList() ([]ftCrypto.TransferID, // to add them back into the queue. func (sft *SentFileTransfersStore) loadTransfers(list []ftCrypto.TransferID) error { var err error + var errCount int // Load each sentTransfer from storage into the map - for _, tid := range list { + for i, tid := range list { sft.transfers[tid], err = loadSentTransfer(tid, sft.kv) if err != nil { - return err + jww.WARN.Printf(loadSentTransferWarn, i, len(list), tid, err) + errCount++ } } + // Return an error if all transfers failed to load + if errCount == len(list) { + return errors.Errorf(loadSentTransfersAllErr, len(list)) + } + return nil } diff --git a/storage/fileTransfer/sentFileTransfers_test.go b/storage/fileTransfer/sentFileTransfers_test.go index 0de6b1f5ed30a7e088946d2ed28ff8bfaf8ace0e..336cbb4ca17b577a13e0728f3c499fd2a924fdd3 100644 --- a/storage/fileTransfer/sentFileTransfers_test.go +++ b/storage/fileTransfer/sentFileTransfers_test.go @@ -8,6 +8,7 @@ package fileTransfer import ( + "fmt" "gitlab.com/elixxir/client/storage/versioned" ftCrypto "gitlab.com/elixxir/crypto/fileTransfer" "gitlab.com/elixxir/ekv" @@ -582,30 +583,6 @@ func TestNewOrLoadSentFileTransfersStore_NewSentFileTransfersStore(t *testing.T) } } -// Error path: tests that the NewOrLoadSentFileTransfersStore returns the -// expected error when the first transfer loaded from storage does not exist. -func TestNewOrLoadSentFileTransfersStore_NoTransferInStorageError(t *testing.T) { - kv := versioned.NewKV(make(ekv.Memstore)) - expectedErr := strings.Split(loadSentTransfersErr, "%")[0] - - // Save list of one transfer ID to storage - obj := &versioned.Object{ - Version: sentFileTransfersStoreVersion, - Timestamp: netTime.Now(), - Data: ftCrypto.UnmarshalTransferID([]byte("testID_01")).Bytes(), - } - err := kv.Prefix(sentFileTransfersStorePrefix).Set( - sentFileTransfersStoreKey, sentFileTransfersStoreVersion, obj) - - // Load SentFileTransfersStore from storage - _, err = NewOrLoadSentFileTransfersStore(kv) - if err == nil || !strings.Contains(err.Error(), expectedErr) { - t.Errorf("NewOrLoadSentFileTransfersStore did not return the expected "+ - "error when there is no transfer saved in storage."+ - "\nexpected: %s\nreceived: %+v", expectedErr, err) - } -} - // Tests that SentFileTransfersStore.saveTransfersList saves all the transfer // IDs to storage by loading them from storage via // SentFileTransfersStore.loadTransfersList and comparing the list to the list @@ -629,7 +606,7 @@ func TestSentFileTransfersStore_saveTransfersList_loadTransfersList(t *testing.T t.Errorf("saveTransfersList returned an error: %+v", err) } - // get list from storage + // Get list from storage list, err := sft.loadTransfersList() if err != nil { t.Errorf("loadTransfersList returned an error: %+v", err) @@ -646,7 +623,7 @@ func TestSentFileTransfersStore_saveTransfersList_loadTransfersList(t *testing.T } // Tests that the transfer loaded by SentFileTransfersStore.loadTransfers from -// storage matches the original in memory +// storage matches the original in memory. func TestSentFileTransfersStore_loadTransfers(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) sft := &SentFileTransfersStore{ @@ -686,6 +663,37 @@ func TestSentFileTransfersStore_loadTransfers(t *testing.T) { } } +// Error path: tests that SentFileTransfersStore.loadTransfers returns an error +// when all file transfers fail to load from storage. +func TestSentFileTransfersStore_loadTransfers_AllErrors(t *testing.T) { + kv := versioned.NewKV(make(ekv.Memstore)).Prefix(sentFileTransfersStorePrefix) + + // Add 10 transfers to map in memory + list := make([]ftCrypto.TransferID, 10) + for i := range list { + tid, st := newRandomSentTransfer(16, 24, kv, t) + list[i] = tid + err := st.delete() + if err != nil { + t.Errorf("Failed to delete transfer: %+v", err) + } + } + + expectedErr := fmt.Sprintf(loadSentTransfersAllErr, len(list)) + + // Load the transfers into a new SentFileTransfersStore + loadedSft := &SentFileTransfersStore{ + transfers: make(map[ftCrypto.TransferID]*SentTransfer), + kv: kv, + } + err := loadedSft.loadTransfers(list) + if err == nil || err.Error() != expectedErr { + t.Errorf("loadTransfers did not return the expected error when none "+ + "of the transfer could be loaded from storage."+ + "\nexpected: %s\nreceived: %+v", expectedErr, err) + } +} + // Tests that a transfer list marshalled with // SentFileTransfersStore.marshalTransfersList and unmarshalled with // unmarshalTransfersList matches the original.