Page MenuHomePhorge

D232.1758864272.diff
No OneTemporary

Size
21 KB
Referenced Files
None
Subscribers
None

D232.1758864272.diff

diff --git a/src/contents/ui/FileHandler.qml b/src/contents/ui/FileHandler.qml
--- a/src/contents/ui/FileHandler.qml
+++ b/src/contents/ui/FileHandler.qml
@@ -11,65 +11,36 @@
/**
* Used to handle files described in event, such as caching(if autoCache is true) and download.
- * It is either used for caching or downloading. These two operations cannot be performed in the same FileHandler.
+ * It is either used for caching or downloading. These two operations can be performed in same FileHandler.(Set autoCache to true and then call downloadFile)
+ * But one Filehandler can only track one download/cache job.
*/
QtObject {
id: fileHandler
- required property var eventContent
/**
- * If autoCache is true, the file is automatically cached(thumbnail is downloaded if exists).
+ * Just set these four properties, any other properties will be automatically evaluated.
+ * The eventContent can be modified at any time.
+ * Modifying other properties can lead to unpredictable behavior.
*/
- required property bool autoCache
+ required property var eventContent
+ required property bool autoCache // thumbnail(if exists) will be downloaded if set to true
required property var kazvIOManager
required property var matrixSdk
- /**
- * Used to download or caching.
- * mxcUri, sha256, key, iv will be setted automatically
- * according to whether the file is encrypted or not.
- */
- property var mxcUri: ""
- property var httpVer: matrixSdk.checkSpecVersion("v1.11") ? MK.MatrixSdk.AuthenticatedMediaV1 : MK.MatrixSdk.UnauthenticatedMediaV3
- property var url: fileHandler.mxcToHttp(httpVer, mxcUri)
- property var saveFileUrl: ""
- property var mediaId: mxcUri && fileHandler.getMediaId(fileHandler.mxcUri)
- property var sha256: ""
- property var token: httpVer === MK.MatrixSdk.AuthenticatedMediaV1 ? matrixSdk.token : ""
- property var key: ""
- property var iv: ""
+ readonly property var httpVer: matrixSdk.checkSpecVersion("v1.11") ? MK.MatrixSdk.AuthenticatedMediaV1 : MK.MatrixSdk.UnauthenticatedMediaV3
+ readonly property var token: (httpVer === MK.MatrixSdk.AuthenticatedMediaV1) ? matrixSdk.token : ""
property var kazvIOJob
readonly property url localFile: kazvIOJob ? '' : cachedFile
- property real percent: fileHandler.kazvIOJob ? fileHandler.kazvIOJob.progress : 0.0 // from 0 to 1
+ readonly property real percent: fileHandler.kazvIOJob ? fileHandler.kazvIOJob.progress : 0.0 // from 0 to 1
property var result
- property bool success: fileHandler.result == MK.KazvIOBaseJob.NoError
+ readonly property bool success: fileHandler.result == MK.KazvIOBaseJob.NoError
/**
* This attribute is only used after result is set (that is, after signal resultChanged is emitted),
* and only when success is true, this attribute has a correct and valid value.
*/
property url cachedFile
- property var fileInfo: "info" in eventContent ? eventContent.info : {}
-
- property var encryptedFile: "file" in eventContent ? eventContent.file : {}
- property var encryptedFileMxcUri: "url" in encryptedFile ? encryptedFile.url : ""
- property var encryptedFileSha256: "hashes" in encryptedFile && "sha256" in encryptedFile.hashes ? encryptedFile.hashes.sha256 : ""
- // property var encryptedFileAlg: "key" in encryptedFile && "alg" in encryptedFile.key ? encryptedFile.key.alg : ""
- property var encryptedFileKey: "key" in encryptedFile && "k" in encryptedFile.key ? encryptedFile.key.k : ""
- property var encryptedFileIv: "iv" in encryptedFile ? encryptedFile.iv : ""
-
- property var encryptedThumbnail: "thumbnail_file" in fileInfo ? fileInfo.thumbnail_file : {}
- property var encryptedThumbnailMxcUri: "url" in encryptedThumbnail ? encryptedThumbnail.url : ""
- property var encryptedThumbnailSha256: "hashes" in encryptedThumbnail && "sha256" in encryptedThumbnail.hashes ? encryptedThumbnail.hashes.sha256 : ""
- // property var encryptedFileAlg: "key" in encryptedThumbnail && "alg" in encryptedThumbnail.key ? encryptedThumbnail.key.alg : ""
- property var encryptedThumbnailKey: "key" in encryptedThumbnail && "k" in encryptedThumbnail.key ? encryptedThumbnail.key.k : ""
- property var encryptedThumbnailIv: "iv" in encryptedThumbnail ? encryptedThumbnail.iv : ""
-
- property var unencryptedFileMxcUri: "url" in eventContent ? eventContent.url : ""
-
- property var unencryptedThumbnailMxcUri: "thumbnail_url" in fileInfo ? fileInfo.thumbnail_url : ""
-
/**
* Emit when start download, not emit when start cache.
* Can be used to indicate progress bar visible
@@ -82,27 +53,29 @@
}
function downloadFile(saveFileUrl) {
- fileHandler.saveFileUrl = saveFileUrl
- fileHandler.kazvIOManager.startNewDownloadJob(fileHandler.url,
- fileHandler.saveFileUrl,
- fileHandler.mediaId,
- fileHandler.sha256,
- fileHandler.token,
- fileHandler.key,
- fileHandler.iv)
- fileHandler.updateKazvIOJob(fileHandler.mediaId)
-
- fileHandler.startDownload()
+ const file = getFile();
+ if (!file) {
+ return;
+ }
+
+ const mediaId = getMediaId(file.mxcUri);
+ kazvIOManager.startNewDownloadJob(mxcToHttp(file.mxcUri), saveFileUrl, mediaId,
+ file.sha256, token, file.key, file.iv);
+ fileHandler.updateKazvIOJob(mediaId);
+ fileHandler.startDownload();
}
function cacheFile() {
- fileHandler.cachedFile = fileHandler.kazvIOManager.cacheFile(fileHandler.url,
- fileHandler.mediaId,
- fileHandler.sha256,
- fileHandler.token,
- fileHandler.key,
- fileHandler.iv)
- fileHandler.updateKazvIOJob(fileHandler.mediaId)
+ const file = getThumbnail() || getFile();
+ if (!file) {
+ console.log('invalid');
+ return;
+ }
+
+ const mediaId = getMediaId(file.mxcUri);
+ fileHandler.cachedFile = kazvIOManager.cacheFile(mxcToHttp(file.mxcUri), mediaId,
+ file.sha256, token, file.key, file.iv);
+ fileHandler.updateKazvIOJob(mediaId);
}
function updateKazvIOJob(mediaId) {
@@ -119,7 +92,7 @@
}
}
- function mxcToHttp(httpVer, mxcUri) {
+ function mxcToHttp(mxcUri) {
if (!mxcUri) {
return "";
}
@@ -132,45 +105,44 @@
}
}
- Component.onCompleted: {
- // Check if there is an encryted file or unencrypted file
- if (encryptedFileMxcUri &&
- encryptedFileSha256 &&
- encryptedFileKey &&
- encryptedFileIv) {
- fileHandler.mxcUri = encryptedFileMxcUri
- fileHandler.sha256 = encryptedFileSha256
- fileHandler.key = encryptedFileKey
- fileHandler.iv = encryptedFileIv
- } else if (unencryptedFileMxcUri) {
- fileHandler.mxcUri = unencryptedFileMxcUri
- } else {
- // The event content is incorrect or the FileHandler.qml has a bug
- return
+ function getThumbnail() {
+ return getFileOrThumbnail(eventContent?.info?.thumbnail_file, eventContent?.info?.thumbnail_url);
+ }
+
+ function getFile() {
+ return getFileOrThumbnail(eventContent?.file, eventContent?.url);
+ }
+
+ // https://spec.matrix.org/v1.16/client-server-api/#mfile
+ function getFileOrThumbnail(encryptedFile, unencryptedMxcUri) {
+ const encryptedMxcUri = encryptedFile?.url;
+ const encryptedSha256 = encryptedFile?.hashes?.sha256;
+ const encryptedKey = encryptedFile?.key?.k;
+ const encryptedIv = encryptedFile?.iv;
+
+ const isEncrypted = !!(encryptedMxcUri && encryptedSha256 && encryptedKey && encryptedIv);
+ const hasFile = !!(isEncrypted || unencryptedMxcUri);
+
+ if (!hasFile) {
+ return undefined;
}
+ return ({
+ mxcUri: isEncrypted ? encryptedMxcUri : unencryptedMxcUri,
+ sha256: isEncrypted ? encryptedSha256 : "",
+ key: isEncrypted ? encryptedKey : "",
+ iv: isEncrypted ? encryptedIv : ""
+ })
+ }
- /**
- * Thumbnail will only be downloaded in the cache
- **/
+ onEventContentChanged: {
if (fileHandler.autoCache) {
- // Check if there is an encrypted thumbnail or unencrypted thumbnail
- if (encryptedThumbnailMxcUri &&
- encryptedThumbnailSha256 &&
- encryptedThumbnailKey &&
- encryptedThumbnailIv) {
- fileHandler.mxcUri = encryptedThumbnailMxcUri
- fileHandler.sha256 = encryptedThumbnailSha256
- fileHandler.key = encryptedThumbnailKey
- fileHandler.iv = encryptedThumbnailIv
- } else if (unencryptedThumbnailMxcUri) {
- fileHandler.mxcUri = unencryptedThumbnailMxcUri
- }
- fileHandler.cacheFile()
+ fileHandler.cacheFile();
}
- fileHandler.updateKazvIOJob(fileHandler.mediaId)
+ // Check if the file is downloading
+ fileHandler.updateKazvIOJob(fileHandler.mediaId);
fileHandler.onSuccessChanged.connect(function () {
- fileHandler.kazvIOManager.deleteDownloadJob(mediaId)
- })
+ fileHandler.kazvIOManager.deleteDownloadJob(mediaId);
+ });
}
}
diff --git a/src/contents/ui/event-types/Image.qml b/src/contents/ui/event-types/Image.qml
--- a/src/contents/ui/event-types/Image.qml
+++ b/src/contents/ui/event-types/Image.qml
@@ -32,7 +32,7 @@
property var imageHeight: imageInfo.h
property var imageMaxHeight: compactMode ? Kirigami.Units.gridUnit * 5 : Infinity
- property var imageMxcUri: fileHandler.encryptedFileMxcUri || fileHandler.unencryptedFileMxcUri
+ property var imageMxcUri: fileHandler.getFile().mxcUri
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
property var jobManager: kazvIOManager
diff --git a/src/contents/ui/event-types/MediaBubble.qml b/src/contents/ui/event-types/MediaBubble.qml
--- a/src/contents/ui/event-types/MediaBubble.qml
+++ b/src/contents/ui/event-types/MediaBubble.qml
@@ -28,7 +28,7 @@
property var progressBar: Kazv.KazvIOMenu {
id: progressBar
kazvIOJob: mediaFileMenu.fileHandler.kazvIOJob
- jobId: bubble.mediaFileMenu.fileHandler.mediaId
+ jobId: bubble.mediaFileMenu.fileHandler.getMediaId(bubble.mediaFileMenu.fileHandler.getFile().mxcUri)
isUpload: false
width: parent.width
}
diff --git a/src/tests/quick-tests/tst_FileHandler.qml b/src/tests/quick-tests/tst_FileHandler.qml
--- a/src/tests/quick-tests/tst_FileHandler.qml
+++ b/src/tests/quick-tests/tst_FileHandler.qml
@@ -11,20 +11,31 @@
import 'test-helpers' as QmlHelpers
import 'test-helpers.js' as JsHelpers
+import moe.kazv.mxc.kazv as MK
+
QmlHelpers.TestItem {
id: item
property var unencryptedEventContent: ({
body: "fileName",
msgtype: "m.image",
- url: "mxc://some",
+ url: "mxc://someunencrypted",
+ })
+
+ property var unencryptedThumbnailEventContent: ({
+ body: "fileName",
+ msgtype: "m.image",
+ url: "mxc://someunencrypted",
+ info: {
+ thumbnail_url: "mxc://someunencryptedthumbnail"
+ }
})
property var encryptedEventContent: ({
body: "fileName",
msgtype: "m.image",
file: {
- url: "mxc://some",
+ url: "mxc://someencrypted",
key: {
kty: "oct",
key_ops: ["encrypt","decrypt"],
@@ -40,37 +51,59 @@
}
})
- property var oldFileHandler: Kazv.FileHandler {
- eventContent: unencryptedEventContent
- autoCache: true
- kazvIOManager: QmlHelpers.KazvIOManagerMock {}
- matrixSdk: QmlHelpers.MatrixSdkMock {
- specVersions: []
- property var mxcUriToHttp: mockHelper.noop()
+ property var encryptedThumbnailEventContent: ({
+ body: "fileName",
+ msgtype: "m.image",
+ file: {
+ url: "mxc://someencrypted",
+ key: {
+ kty: "oct",
+ key_ops: ["encrypt","decrypt"],
+ alg: "A256CTR",
+ k: "somekey",
+ ext: true,
+ },
+ iv: "someiv",
+ hashes: {
+ "sha256": "somesha256hash"
+ },
+ v: "v2",
+ },
+ info: {
+ thumbnail_file: {
+ url: "mxc://someencryptedthumbnail",
+ key: {
+ kty: "oct",
+ key_ops: ["encrypt","decrypt"],
+ alg: "A256CTR",
+ k: "somekeyofthumbnail",
+ ext: true,
+ },
+ iv: "someivofthumbnail",
+ hashes: {
+ "sha256": "somesha256hashofthumbnail"
+ },
+ v: "v2",
+ }
}
- }
+ })
- property var newFileHandler: Kazv.FileHandler {
- eventContent: unencryptedEventContent
- autoCache: true
- kazvIOManager: QmlHelpers.KazvIOManagerMock {}
- matrixSdk: QmlHelpers.MatrixSdkMock {
- property var mxcUriToHttpAuthenticatedV1: mockHelper.noop()
- }
+ property var kazvIOManager: QmlHelpers.KazvIOManagerMock {}
+ property var matrixSdk: QmlHelpers.MatrixSdkMock {}
+ property var matrixSdkUnauthenticatedMediaV3: QmlHelpers.MatrixSdkMock {
+ specVersions: []
+ property var mxcUriToHttp: mockHelper.noop()
}
-
- property var unencryptedFileHandler: Kazv.FileHandler {
- eventContent: unencryptedEventContent
- autoCache: true
- kazvIOManager: QmlHelpers.KazvIOManagerMock {}
- matrixSdk: QmlHelpers.MatrixSdkMock {}
+ property var matrixSdkAuthenticatedMediaV1: QmlHelpers.MatrixSdkMock {
+ property var mxcUriToHttpAuthenticatedV1: mockHelper.noop()
}
- property var encryptedFileHandler: Kazv.FileHandler {
- eventContent: encryptedEventContent
- autoCache: true
- kazvIOManager: QmlHelpers.KazvIOManagerMock {}
- matrixSdk: QmlHelpers.MatrixSdkMock {}
+
+ property var fileHandler: Kazv.FileHandler {
+ eventContent: ({})
+ autoCache: false
+ kazvIOManager: item.kazvIOManager
+ matrixSdk: item.matrixSdk
}
TestCase {
@@ -78,52 +111,140 @@
name: 'fileHandlerTest'
when: windowShown
- function test_specVersion() {
- compare(oldFileHandler.matrixSdk.mxcUriToHttp.calledTimes(), 1);
- compare(newFileHandler.matrixSdk.mxcUriToHttpAuthenticatedV1.calledTimes(), 1);
-
- compare(oldFileHandler.kazvIOManager.cacheFile.calledTimes(), 1);
- compare(oldFileHandler.kazvIOManager.cacheFile.lastArgs()[3], "");
- compare(newFileHandler.kazvIOManager.cacheFile.calledTimes(), 1);
- compare(newFileHandler.kazvIOManager.cacheFile.lastArgs()[3], newFileHandler.matrixSdk.token);
-
- oldFileHandler.downloadFile("fileUrl");
- compare(oldFileHandler.kazvIOManager.startNewDownloadJob.calledTimes(), 1);
- compare(oldFileHandler.kazvIOManager.startNewDownloadJob.lastArgs()[4], "");
- newFileHandler.downloadFile("fileUrl");
- compare(newFileHandler.kazvIOManager.startNewDownloadJob.calledTimes(), 1);
- compare(newFileHandler.kazvIOManager.startNewDownloadJob.lastArgs()[4], newFileHandler.matrixSdk.token);
+ function init() {
+ fileHandler.autoCache = false;
+ fileHandler.eventContent = ({});
+ fileHandler.matrixSdk = item.matrixSdk;
+ mockHelper.clearAll();
+ }
+
+ // https://spec.matrix.org/v1.16/client-server-api/#get_matrixmediav3downloadservernamemediaid
+ function test_unauthenticatedMediaV3() {
+ fileHandler.matrixSdk = matrixSdkUnauthenticatedMediaV3;
+ fileHandler.autoCache = true;
+ fileHandler.eventContent = unencryptedEventContent;
+
+ compare(fileHandler.httpVer, MK.MatrixSdk.UnauthenticatedMediaV3);
+ compare(matrixSdkUnauthenticatedMediaV3.mxcUriToHttp.calledTimes(), 1);
+ compare(matrixSdkUnauthenticatedMediaV3.mxcUriToHttp.lastArgs()[0], "mxc://someunencrypted");
+ compare(kazvIOManager.cacheFile.calledTimes(), 1);
+ compare(kazvIOManager.cacheFile.lastArgs()[3], "");
+
+ fileHandler.downloadFile("fileUrl");
+ compare(kazvIOManager.startNewDownloadJob.calledTimes(), 1);
+ compare(kazvIOManager.startNewDownloadJob.lastArgs()[4], "");
+ }
+
+ // https://spec.matrix.org/v1.16/client-server-api/#get_matrixclientv1mediadownloadservernamemediaid
+ function test_authenticatedMediaV1() {
+ fileHandler.matrixSdk = matrixSdkAuthenticatedMediaV1;
+ fileHandler.autoCache = true;
+ fileHandler.eventContent = unencryptedEventContent;
+
+ compare(fileHandler.httpVer, MK.MatrixSdk.AuthenticatedMediaV1);
+ compare(fileHandler.matrixSdk.mxcUriToHttpAuthenticatedV1.calledTimes(), 1);
+ compare(fileHandler.matrixSdk.mxcUriToHttpAuthenticatedV1.lastArgs()[0], "mxc://someunencrypted");
+ compare(kazvIOManager.cacheFile.calledTimes(), 1);
+ compare(kazvIOManager.cacheFile.lastArgs()[3], fileHandler.matrixSdk.token);
+
+ fileHandler.downloadFile("fileUrl");
+ compare(kazvIOManager.startNewDownloadJob.calledTimes(), 1);
+ compare(kazvIOManager.startNewDownloadJob.lastArgs()[4], fileHandler.matrixSdk.token);
+ }
+
+ function test_autoCacheEncrypted() {
+ fileHandler.autoCache = true;
+ fileHandler.eventContent = encryptedEventContent;
+ const cacheFunc = kazvIOManager.cacheFile;
+ compare(cacheFunc.calledTimes(), 1);
+ compare(cacheFunc.lastArgs()[0],
+ matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someencrypted"));
+ compare(cacheFunc.lastArgs()[2], "somesha256hash");
+ compare(cacheFunc.lastArgs()[4], "somekey");
+ compare(cacheFunc.lastArgs()[5], "someiv");
+ }
+
+ function test_autoCacheUnencrypted() {
+ fileHandler.autoCache = true;
+ fileHandler.eventContent = unencryptedEventContent;
+ const cacheFunc = kazvIOManager.cacheFile;
+ compare(cacheFunc.calledTimes(), 1);
+ compare(cacheFunc.lastArgs()[0],
+ matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someunencrypted"));
+ }
+
+ // Prefer thumbnail when caching
+ function test_autoCacheThumbnail() {
+ fileHandler.autoCache = true;
+ fileHandler.eventContent = unencryptedThumbnailEventContent;
+ const cacheFunc = kazvIOManager.cacheFile;
+ compare(cacheFunc.calledTimes(), 1);
+ compare(cacheFunc.lastArgs()[0],
+ matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someunencryptedthumbnail"));
}
- function test_autoCache() {
- compare(unencryptedFileHandler.kazvIOManager.cacheFile.calledTimes(), 1);
- compare(encryptedFileHandler.kazvIOManager.cacheFile.calledTimes(), 1);
+ function test_autoCacheEncryptedThumbnail() {
+ fileHandler.autoCache = true;
+ fileHandler.eventContent = encryptedThumbnailEventContent;
+ const cacheFunc = kazvIOManager.cacheFile;
+ compare(cacheFunc.calledTimes(), 1);
+ compare(cacheFunc.lastArgs()[0],
+ matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someencryptedthumbnail"));
+ compare(cacheFunc.lastArgs()[2], "somesha256hashofthumbnail");
+ compare(cacheFunc.lastArgs()[4], "somekeyofthumbnail");
+ compare(cacheFunc.lastArgs()[5], "someivofthumbnail");
}
- function test_encrypted() {
- let downloadFunc = encryptedFileHandler.kazvIOManager.startNewDownloadJob;
- encryptedFileHandler.downloadFile("fileUrl");
+ function test_downloadEncrypted() {
+ fileHandler.eventContent = encryptedEventContent;
+ fileHandler.downloadFile("fileUrl");
+ const downloadFunc = kazvIOManager.startNewDownloadJob;
compare(downloadFunc.calledTimes(), 1);
- compare(downloadFunc.lastArgs()[0], encryptedFileHandler.matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://some"));
+ compare(downloadFunc.lastArgs()[0], matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someencrypted"));
compare(downloadFunc.lastArgs()[1], "fileUrl");
compare(downloadFunc.lastArgs()[3], "somesha256hash");
- compare(downloadFunc.lastArgs()[4], encryptedFileHandler.matrixSdk.token);
compare(downloadFunc.lastArgs()[5], "somekey");
compare(downloadFunc.lastArgs()[6], "someiv");
}
- function test_unencrypted() {
- let downloadFunc = unencryptedFileHandler.kazvIOManager.startNewDownloadJob;
- unencryptedFileHandler.downloadFile("fileUrl");
+ function test_downloadUnencrypted() {
+ fileHandler.eventContent = unencryptedEventContent;
+ const downloadFunc = kazvIOManager.startNewDownloadJob;
+ fileHandler.downloadFile("fileUrl");
compare(downloadFunc.calledTimes(), 1);
- let args = downloadFunc.lastArgs();
- compare(args[0], unencryptedFileHandler.matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://some"));
- compare(args[1], "fileUrl");
- compare(args[3], "");
- compare(args[4], unencryptedFileHandler.matrixSdk.token);
- compare(args[5], "");
- compare(args[6], "");
+ const args = downloadFunc.lastArgs();
+ compare(downloadFunc.lastArgs()[0], matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someunencrypted"));
+ compare(downloadFunc.lastArgs()[1], "fileUrl");
+ compare(downloadFunc.lastArgs()[3], "");
+ compare(downloadFunc.lastArgs()[5], "");
+ compare(downloadFunc.lastArgs()[6], "");
+ }
+
+ function test_eventContentChanged() {
+ fileHandler.eventContent = encryptedEventContent;
+ const encryptedFile = fileHandler.getFile();
+ compare(encryptedFile.mxcUri, "mxc://someencrypted");
+ compare(encryptedFile.sha256, "somesha256hash");
+ compare(encryptedFile.key, "somekey");
+ compare(encryptedFile.iv, "someiv");
+ compare(fileHandler.getThumbnail(), undefined);
+
+ fileHandler.eventContent = unencryptedEventContent;
+ const unencryptedFile = fileHandler.getFile();
+ compare(unencryptedFile.mxcUri, "mxc://someunencrypted");
+ compare(unencryptedFile.sha256, "");
+ compare(unencryptedFile.key, "");
+ compare(unencryptedFile.iv, "");
+ compare(fileHandler.getThumbnail(), undefined);
+ }
+
+ function test_invalidEventContent() {
+ fileHandler.autoCache = true;
+ fileHandler.eventContent = ({});
+ compare(kazvIOManager.cacheFile.calledTimes(), 0);
+ fileHandler.downloadFile("fileUrl");
+ compare(kazvIOManager.startNewDownloadJob.calledTimes(), 0);
}
}
}

File Metadata

Mime Type
text/plain
Expires
Thu, Sep 25, 10:24 PM (14 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
469240
Default Alt Text
D232.1758864272.diff (21 KB)

Event Timeline