@@ -3,7 +3,9 @@ package helper
33import (
44 "bufio"
55 "fmt"
6+ "io"
67 "os"
8+ "strings"
79
810 "github.com/greenplum-db/gpbackup/utils"
911 "golang.org/x/sys/unix"
2123)
2224
2325type restoreReaderTestImpl struct {
24- waitCount int
26+ waitCount int
27+ discardedBytes int64
28+ discardErr error
2529}
2630
2731func (r * restoreReaderTestImpl ) waitForPlugin () error {
@@ -45,7 +49,16 @@ func (r *restoreReaderTestImpl) closeFileHandle() {
4549}
4650
4751func (r * restoreReaderTestImpl ) getReaderType () ReaderType {
48- return "nil"
52+ return SUBSET
53+ }
54+
55+ func (r * restoreReaderTestImpl ) discardData (num int64 ) (int64 , error ) {
56+ if r .discardErr != nil {
57+ return 0 , r .discardErr
58+ }
59+
60+ r .discardedBytes += num
61+ return num , nil
4962}
5063
5164type helperTestStep struct {
@@ -198,6 +211,47 @@ func (pt *testPluginCmd) Wait() error {
198211func (pt * testPluginCmd ) errLog () {
199212}
200213
214+ type limitReader struct {
215+ remainder int
216+ err error
217+ }
218+
219+ func (r * limitReader ) Read (p []byte ) (n int , err error ) {
220+ if r .remainder <= 0 {
221+ return 0 , r .err
222+ }
223+
224+ if len (p ) > r .remainder {
225+ p = p [0 :r .remainder ]
226+ }
227+
228+ n = len (p )
229+ for i := 0 ; i < n ; i ++ {
230+ p [i ] = 1
231+ }
232+ r .remainder -= n
233+ return
234+ }
235+
236+ type limitWriter struct {
237+ remainder int
238+ }
239+
240+ func (w * limitWriter ) Write (p []byte ) (n int , err error ) {
241+ if w .remainder < len (p ) {
242+ n = w .remainder
243+ } else {
244+ n = len (p )
245+ }
246+
247+ if w .remainder == 0 {
248+ err = io .ErrShortWrite
249+ }
250+
251+ w .remainder -= n
252+ return
253+ }
254+
201255var _ = Describe ("helper tests" , func () {
202256 var pluginConfig utils.PluginConfig
203257 var isSubset bool
@@ -243,7 +297,7 @@ var _ = Describe("helper tests", func() {
243297 pluginConfig .Options ["restore_subset" ] = "on"
244298 * onErrorContinue = true
245299 isSubset = getSubsetFlag (fileToRead , & pluginConfig )
246- Expect (isSubset ).To (Equal (false ))
300+ Expect (isSubset ).To (Equal (true ))
247301 })
248302 It ("when restore_subset is off, --on-error-continue is false, compression \" gz\" is used" , func () {
249303 pluginConfig .Options ["restore_subset" ] = "off"
@@ -416,6 +470,52 @@ var _ = Describe("helper tests", func() {
416470 err := doRestoreAgentInternal (helper )
417471 Expect (err ).To (BeNil ())
418472 })
473+ It ("discard data if skip file is discovered with single datafile" , func () {
474+ * singleDataFile = true
475+ * isResizeRestore = false
476+ * tocFile = testTocFile
477+
478+ writeTestTOC (testTocFile )
479+ defer func () {
480+ _ = os .Remove (* tocFile )
481+ }()
482+
483+ oidBatch := []oidWithBatch {
484+ {1 /* The first oid from TOC */ , 0 },
485+ }
486+
487+ expectedScenario := []helperTestStep {
488+ {"mock_1_0" , false , 1 , true , "Can not open pipe for table 1, check_skip_file shall called, skip file exists" },
489+ }
490+
491+ helper := newHelperTest (oidBatch , expectedScenario )
492+ err := doRestoreAgentInternal (helper )
493+ Expect (err ).ToNot (HaveOccurred ())
494+ Expect (helper .restoreData .discardedBytes ).To (Equal (int64 (18 )))
495+ })
496+ It ("discard error data if skip file is discovered with single datafile" , func () {
497+ * singleDataFile = true
498+ * isResizeRestore = false
499+ * tocFile = testTocFile
500+
501+ writeTestTOC (testTocFile )
502+ defer func () {
503+ _ = os .Remove (* tocFile )
504+ }()
505+
506+ oidBatch := []oidWithBatch {
507+ {1 /* The first oid from TOC */ , 0 },
508+ }
509+
510+ expectedScenario := []helperTestStep {
511+ {"mock_1_0" , false , 1 , true , "Can not open pipe for table 1, check_skip_file shall called, skip file exists" },
512+ }
513+
514+ helper := newHelperTest (oidBatch , expectedScenario )
515+ helper .restoreData .discardErr = io .EOF
516+ err := doRestoreAgentInternal (helper )
517+ Expect (err ).To (Equal (io .EOF ))
518+ })
419519 It ("calls Wait in waitForPlugin doRestoreAgent for single data file" , func () {
420520 * singleDataFile = true
421521 * isResizeRestore = false
@@ -476,6 +576,10 @@ var _ = Describe("helper tests", func() {
476576 })
477577 })
478578 Describe ("RestoreReader tests" , func () {
579+ AfterEach (func () {
580+ * onErrorContinue = false
581+ writer = nil
582+ })
479583 It ("waitForPlugin normal completion" , func () {
480584 test_cmd1 := testPluginCmd {hasProcess_ : true }
481585 test_reader := new (RestoreReader )
@@ -504,20 +608,123 @@ var _ = Describe("helper tests", func() {
504608 Expect (err ).To (HaveOccurred ())
505609 Expect (err .Error ()).To (Equal (msg ))
506610 })
611+ It ("CopyData, readerType is SUBSET. Normal completion" , func () {
612+ writer = bufio .NewWriterSize (& limitWriter {100 }, 5 )
613+
614+ test_reader := RestoreReader {
615+ readerType : SUBSET ,
616+ bufReader : bufio .NewReader (& limitReader {100 , io .EOF }),
617+ }
618+
619+ bytesRead , err := test_reader .copyData (18 )
620+ Expect (bytesRead ).To (Equal (int64 (18 )))
621+ Expect (err ).ToNot (HaveOccurred ())
622+ })
623+ It ("CopyData, readerType is SUBSET. Error on write" , func () {
624+ * onErrorContinue = true
625+ bufSize := 5
626+ toRead := int64 (18 )
627+ writer = bufio .NewWriterSize (& limitWriter {7 }, bufSize )
628+
629+ test_reader := RestoreReader {
630+ readerType : SUBSET ,
631+ bufReader : bufio .NewReader (& limitReader {100 , io .EOF }),
632+ }
633+
634+ bytesRead , err := test_reader .copyData (toRead )
635+ Expect (bytesRead ).To (Equal (toRead ))
636+ Expect (errors .Is (err , io .ErrShortWrite )).To (Equal (true ))
637+ str := fmt .Sprintf ("copied %d bytes from %d: " , bufSize * 2 , toRead )
638+ Expect (strings .HasPrefix (err .Error (), str )).To (Equal (true ))
639+
640+ })
641+ It ("CopyData, readerType is SUBSET. EOF" , func () {
642+ * onErrorContinue = true
643+ writer = bufio .NewWriterSize (& limitWriter {100 }, 5 )
644+
645+ test_reader := RestoreReader {
646+ readerType : SUBSET ,
647+ bufReader : bufio .NewReader (& limitReader {25 , io .EOF }),
648+ }
649+
650+ bytesRead , err := test_reader .copyData (30 )
651+ Expect (bytesRead ).To (Equal (int64 (25 )))
652+ Expect (err ).To (Equal (io .EOF ))
653+ })
654+ It ("CopyData, readerType is SUBSET. Error on write and EOF" , func () {
655+ * onErrorContinue = true
656+ bufSize := 5
657+ toCopy := int64 (30 )
658+ rLmt := int64 (25 )
659+ writer = bufio .NewWriterSize (& limitWriter {7 }, bufSize )
660+
661+ test_reader := RestoreReader {
662+ readerType : SUBSET ,
663+ bufReader : bufio .NewReader (& limitReader {int (rLmt ), io .EOF }),
664+ }
665+
666+ bytesRead , err := test_reader .copyData (toCopy )
667+ Expect (bytesRead ).To (Equal (rLmt ))
668+ Expect (errors .Is (err , io .ErrShortWrite )).To (Equal (true ))
669+ Expect (errors .Is (err , io .EOF )).To (Equal (true ))
670+ readBeforeErr := int64 (bufSize * 2 )
671+ prefix := fmt .Sprintf ("discard error in copyData: discarded %d bytes from %d: " , rLmt - readBeforeErr , toCopy - readBeforeErr )
672+ Expect (strings .HasPrefix (err .Error (), prefix )).To (Equal (true ))
673+ strCopied := fmt .Sprintf ("copied %d bytes from %d: " , readBeforeErr , toCopy )
674+ Expect (strings .Contains (err .Error (), strCopied )).To (Equal (true ))
675+
676+ bytesRead , err = test_reader .copyData (10 )
677+ Expect (bytesRead ).To (Equal (int64 (0 )))
678+ Expect (err .Error ()).To (Equal ("10 bytes to copy, but discard error has already occurred. Skipping read." ))
679+
680+ bytesRead , err = test_reader .discardData (5 )
681+ Expect (bytesRead ).To (Equal (int64 (0 )))
682+ Expect (err .Error ()).To (Equal ("5 bytes to discard, but discard error has already occurred. Skipping read." ))
683+ })
684+ It ("CopyData, readerType is SUBSET. Error on write and on read" , func () {
685+ * onErrorContinue = true
686+ bufSize := 5
687+ toCopy := int64 (30 )
688+ rLmt := int64 (25 )
689+ writer = bufio .NewWriterSize (& limitWriter {7 }, bufSize )
690+
691+ test_reader := RestoreReader {
692+ readerType : SUBSET ,
693+ bufReader : bufio .NewReader (& limitReader {int (rLmt ), io .ErrNoProgress }),
694+ }
695+
696+ bytesRead , err := test_reader .copyData (toCopy )
697+ Expect (bytesRead ).To (Equal (rLmt ))
698+ Expect (errors .Is (err , io .ErrShortWrite )).To (Equal (true ))
699+ Expect (errors .Is (err , io .ErrNoProgress )).To (Equal (true ))
700+ readBeforeErr := int64 (bufSize * 2 )
701+ prefix := fmt .Sprintf ("discard error in copyData: discarded %d bytes from %d: " , rLmt - readBeforeErr , toCopy - readBeforeErr )
702+ Expect (strings .HasPrefix (err .Error (), prefix )).To (Equal (true ))
703+ strCopied := fmt .Sprintf ("copied %d bytes from %d: " , readBeforeErr , toCopy )
704+ Expect (strings .Contains (err .Error (), strCopied )).To (Equal (true ))
705+
706+ bytesRead , err = test_reader .copyData (10 )
707+ Expect (bytesRead ).To (Equal (int64 (0 )))
708+ Expect (err .Error ()).To (Equal ("10 bytes to copy, but discard error has already occurred. Skipping read." ))
709+
710+ bytesRead , err = test_reader .discardData (5 )
711+ Expect (bytesRead ).To (Equal (int64 (0 )))
712+ Expect (err .Error ()).To (Equal ("5 bytes to discard, but discard error has already occurred. Skipping read." ))
713+ })
507714 })
508715})
509716
510717func writeTestTOC (tocFile string ) {
511718 // Write test TOC. We are not going to read data using it, so dataLength is a random number
512719 dataLength := 100
513720 customTOC := fmt .Sprintf (`dataentries:
514- 1:
721+ 1:
515722 startbyte: 0
516723 endbyte: 18
517- 2:
724+ 2:
518725 startbyte: 18
519726 endbyte: %[1]d
520- 3:
727+ 3:
521728 startbyte: %[1]d
522729 endbyte: %d
523730` , dataLength + 18 , dataLength + 18 + 18 )
0 commit comments