Skip to content

Commit

Permalink
Allow BlobCreator's saving to be re-tried
Browse files Browse the repository at this point in the history
  • Loading branch information
grote committed Jan 7, 2025
1 parent 29cb6fa commit 8edc3bc
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import com.stevesoltys.seedvault.proto.Snapshot.Blob
import com.stevesoltys.seedvault.proto.SnapshotKt.blob
import com.stevesoltys.seedvault.repo.Padding.getPadTo
import okio.Buffer
import okio.buffer
import okio.sink
import org.calyxos.seedvault.chunker.Chunk
import org.calyxos.seedvault.core.MemoryLogger
import org.calyxos.seedvault.core.backends.AppBackupFileType
Expand Down Expand Up @@ -74,11 +72,7 @@ internal class BlobCreator(
override val size: Long get() = buffer.size
override val sha256: String get() = sha256ByteString.hex()
override fun save(outputStream: OutputStream): Long {
val outputBuffer = outputStream.sink().buffer()
val length = outputBuffer.writeAll(buffer)
// flushing is important here, otherwise data doesn't get fully written!
outputBuffer.flush()
return length
return buffer.copyTo(outputStream).size
}
}
val size = backendManager.backend.save(handle, saver)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,50 @@ internal class BlobCreatorTest : TransportTest() {
assertArrayEquals(data, inputStream.readAllBytes())
}
}

@Test
fun `test blob saver gets reused by RetryBackend`() = runBlocking {
val data = getRandomByteArray(Random.nextInt(16 * 1024 * 1024))
val chunk = Chunk(0L, data.size, data, "doesn't matter here")
val outputStream1 = ByteArrayOutputStream()
val outputStream2 = ByteArrayOutputStream()
val outputStream3 = ByteArrayOutputStream()
val paddingNum = slot<Int>()

every { crypto.getAdForVersion() } returns ad
every { crypto.newEncryptingStream(capture(passThroughOutputStream), ad) } answers {
passThroughOutputStream.captured // not really encrypting here
}
every { crypto.getRandomBytes(capture(paddingNum)) } answers {
getRandomByteArray(paddingNum.captured)
}
every { crypto.repoId } returns repoId
every { backendManager.backend } returns backend

// create blob
val saverSlot = slot<BackendSaver>()
var size1 = -1L
var size2 = -1L
coEvery { backend.save(capture(blobHandle), capture(saverSlot)) } answers {
// saver saves 3 times
size1 = saverSlot.captured.save(outputStream1)
size2 = saverSlot.captured.save(outputStream2)
saverSlot.captured.save(outputStream3)
}
val blob = blobCreator.createNewBlob(chunk)
// check that file content hash matches snapshot hash
val messageDigest = MessageDigest.getInstance("SHA-256")
val hash1 = messageDigest.digest(outputStream1.toByteArray()).toHexString()
val hash2 = messageDigest.digest(outputStream2.toByteArray()).toHexString()
val hash3 = messageDigest.digest(outputStream3.toByteArray()).toHexString()
assertEquals(hash1, blobHandle.captured.name)
assertEquals(hash2, blobHandle.captured.name)
assertEquals(hash3, blobHandle.captured.name)

// check blob metadata
assertEquals(hash1, blob.id.hexFromProto())
assertEquals(outputStream1.size(), blob.length)
assertEquals(blob.length.toLong(), size1)
assertEquals(blob.length.toLong(), size2)
}
}

0 comments on commit 8edc3bc

Please sign in to comment.