Browse Source

Test Android file wire formats and nonempty directory status

master
evgeny 3 days ago
parent
commit
468aeeebc7
  1. 8
      tests/test_member_files.c
  2. 79
      tools/chatgui-android/app/src/test/java/com/utun/chat/data/MemberFilesProtocolTest.kt

8
tests/test_member_files.c

@ -133,6 +133,12 @@ static void storage_test(const char* directory) {
snprintf(q.path, sizeof(q.path), "renamed"); memset(q.version, 0, 16); run(s, 55, 77, MF_STAT, MF_OK);
memcpy(q.version, r.version, 16); run(s, 55, 88, MF_REMOVE_PATH, MF_ACCESS_DENIED); run(s, 55, 77, MF_REMOVE_PATH, MF_OK);
snprintf(q.path, sizeof(q.path), "folder"); memset(q.version, 0, 16); run(s, 55, 77, MF_MKDIR, MF_OK);
snprintf(q.path, sizeof(q.path), "folder/child"); run(s, 55, 77, MF_MKDIR, MF_OK);
snprintf(q.path, sizeof(q.path), "folder"); run(s, 55, 77, MF_STAT, MF_OK); memcpy(q.version, r.version, 16);
run(s, 55, 77, MF_REMOVE_PATH, MF_DIRECTORY_NOT_EMPTY);
memset(q.version, 0, 16); snprintf(q.path, sizeof(q.path), "folder/child"); run(s, 55, 77, MF_STAT, MF_OK);
memcpy(q.version, r.version, 16); run(s, 55, 77, MF_REMOVE_PATH, MF_OK);
memset(q.version, 0, 16);
q.path[0] = 0; run(s, 55, 88, MF_LIST, MF_OK); EXPECT(r.data_len > 0, "directory listing");
#ifndef _WIN32
char link[2048]; snprintf(link, sizeof(link), "%s/55/77/link", directory);
@ -257,7 +263,7 @@ static void count_test(const char* directory) {
check_counts(s, 10, 101, 2, 2); check_counts(s, 10, 202, 1, 0);
count_mutation(s, 10, 101, "folder", "moved", MF_RENAME, MF_OK);
check_counts(s, 10, 101, 2, 2);
count_mutation(s, 10, 101, "moved", NULL, MF_REMOVE_PATH, MF_IO_ERROR);
count_mutation(s, 10, 101, "moved", NULL, MF_REMOVE_PATH, MF_DIRECTORY_NOT_EMPTY);
check_counts(s, 10, 101, 2, 2);
count_mutation(s, 10, 101, "moved/zero", NULL, MF_REMOVE_PATH, MF_OK);
mf_storage_execute(s, 10, 101, &q, &r); EXPECT(r.status == MF_OK, "file remove replay");

79
tools/chatgui-android/app/src/test/java/com/utun/chat/data/MemberFilesProtocolTest.kt

@ -0,0 +1,79 @@
package com.utun.chat.data
import org.junit.Assert.*
import org.junit.Test
import java.nio.ByteBuffer
import java.nio.ByteOrder
class MemberFilesProtocolTest {
private val uid = 0xfedcba9876543210uL.toLong()
private fun buffer(size: Int) = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN)
private fun reply(path: String = "", status: Int = 0): ByteArray {
val wire = MemberFilesProtocol.request(71, uid, MemberFilesProtocol.LIST, path)
wire[1] = 2; wire[3] = status.toByte()
return buffer(16 + wire.size).putLong(uid).putLong(23).put(wire).array()
}
private fun entry(name: String, type: Int = 1, size: Long = 400): ByteArray {
val bytes = name.toByteArray()
return buffer(35 + bytes.size).putShort(bytes.size.toShort()).put(type.toByte()).putLong(size).putLong(123)
.put(ByteArray(16) { 7 }).put(bytes).array()
}
@Test fun unicodeNamesAndUnsignedIdentityRoundTrip() {
val r = MemberFilesProtocol.response(reply("Документы/😀.pdf"))
assertEquals(uid, r.group); assertEquals(uid, r.owner); assertEquals(23L, r.server)
assertEquals(71L, r.id); assertEquals("Документы/😀.pdf", r.path)
val e = MemberFilesProtocol.entries(entry("😀.pdf")).single()
assertEquals("😀.pdf", e.name); assertEquals(400L, e.size); assertEquals(123L, e.mtime)
assertArrayEquals(ByteArray(16) { 7 }, e.version)
}
@Test fun portablePathsAndUtf8ByteLimits() {
listOf("", "photos/夏.jpg", "Документы/😀.pdf", "a".repeat(255)).forEach { assertTrue(it, MemberFilesProtocol.validPath(it)) }
listOf("../file", "a//b", "/a", "a/", ".hidden", "a\\b", "CON.txt", "com1", "a.", "a ", "a\u0000b",
"a".repeat(256), "я".repeat(128), (1..61).joinToString("/") { "a" }, "bad\uD800")
.forEach { assertFalse(it, MemberFilesProtocol.validPath(it)) }
assertFalse(MemberFilesProtocol.validPath("", false))
assertTrue(MemberFilesProtocol.servicePath("Avatars/file")); assertFalse(MemberFilesProtocol.servicePath("photos/avatars"))
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.child("docs", "a/b") }
}
@Test fun paginationAndMutationKeepTheSnapshotToken() {
val token = ByteArray(16) { it.toByte() }
val wire = MemberFilesProtocol.request(71, uid, MemberFilesProtocol.RENAME, "docs/a", "docs/b", version = token)
assertArrayEquals(token, wire.copyOfRange(45, 61))
wire[1] = 2
val r = MemberFilesProtocol.response(buffer(16 + wire.size).putLong(uid).putLong(23).put(wire).array())
assertEquals("docs/a", r.path); assertArrayEquals(token, r.version)
val page = MemberFilesProtocol.request(72, uid, MemberFilesProtocol.LIST, "docs", cursor = 82, version = token)
assertEquals(82L, ByteBuffer.wrap(page).order(ByteOrder.LITTLE_ENDIAN).getLong(37))
assertThrows(IllegalArgumentException::class.java) {
MemberFilesProtocol.request(71, uid, MemberFilesProtocol.REMOVE, "")
}
}
@Test fun malformedDirectoryCannotBecomeASuccessfulPartialList() {
val e = entry("file")
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.entries(e + e) }
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.entries(e.copyOf(e.size - 1)) }
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.entries(entry("../x")) }
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.entries(entry("x", 3)) }
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.entries(entry("x", size = -1)) }
assertThrows(Exception::class.java) { MemberFilesProtocol.entries(entry("x").also { it[35] = 0xff.toByte() }) }
}
@Test fun errorsAndMalformedFramingArePreserved() {
assertEquals(14, MemberFilesProtocol.response(reply(status = 14)).status)
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.response(reply(status = 15)) }
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.response(reply().copyOf(140)) }
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.response(reply().also { it[134] = 2 }) }
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.response(reply("abc").also { it[141] = 0 }) }
}
@Test fun quotaAndProgressValidate64BitValues() {
val q = MemberFilesProtocol.quota(buffer(40).putLong(12).putLong(1000).putLong(34).putLong(5).putLong(6).array())
assertEquals(34L, q.reserved); assertEquals(6L, q.directories)
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.quota(ByteArray(40)) }
val wire = buffer(51).putLong(71).putLong(uid).putLong(23).putLong(uid).putLong(20).putLong(40).putShort(0).put(1).array()
val progress = MemberFilesProtocol.progress(wire)
assertFalse(progress.finished); assertEquals(uid, progress.owner); assertEquals(20L, progress.done)
wire[50] = 2; wire[48] = 12
assertTrue(MemberFilesProtocol.progress(wire).finished); assertEquals(12, MemberFilesProtocol.progress(wire).status)
ByteBuffer.wrap(wire).order(ByteOrder.LITTLE_ENDIAN).putLong(32, 41)
assertThrows(IllegalArgumentException::class.java) { MemberFilesProtocol.progress(wire) }
}
}
Loading…
Cancel
Save