0
0
mirror of https://github.com/signalapp/libsignal.git synced 2024-09-19 19:42:19 +02:00

Move all "testing-fns" APIs into libsignal-bridge-testing

This means they'll be shipped to clients, but still filtered out of
the device builds on Android (via having two separate libraries on
disk) and iOS (by not being included in non-simulator builds). The
biggest benefit of this is dropping the :android:makeTestJniLibraries
step for running libsignal's Android tests.
This commit is contained in:
Jordan Rose 2024-08-23 16:12:00 -07:00
parent d2d68763a2
commit a8814d16f8
34 changed files with 368 additions and 346 deletions

View File

@ -292,7 +292,7 @@ jobs:
- name: Verify that the JNI bindings are up to date
run: rust/bridge/jni/bin/gen_java_decl.py --verify
- run: ./gradlew build assembleDebugAndroidTest android:lintDebug -PandroidArchs=arm,arm64 -PandroidTestingArchs=x86_64 | tee ./gradle-output.txt
- run: ./gradlew build assembleDebugAndroidTest android:lintDebug -PandroidArchs=arm,arm64,x86_64 | tee ./gradle-output.txt
working-directory: java
shell: bash # Explicitly setting the shell turns on pipefail in GitHub Actions

View File

@ -43,7 +43,7 @@ jobs:
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: jniLibs
path: java/android/src/androidTest/jniLibs/*
path: java/android/src/main/jniLibs/*
retention-days: 2
- name: Upload full JARs
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
@ -144,7 +144,7 @@ jobs:
uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4
with:
name: jniLibs
path: java/android/src/androidTest/jniLibs/
path: java/android/src/main/jniLibs/
# From reactivecircus/android-emulator-runner
- name: AVD cache
@ -173,7 +173,7 @@ jobs:
api-level: 21
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -noaudio -no-boot-anim
script: ./gradlew android:connectedCheck -x makeJniLibrariesDesktop -x android:makeJniLibraries -x android:makeTestJniLibraries
script: ./gradlew android:connectedCheck -x makeJniLibrariesDesktop -x android:makeJniLibraries
working-directory: java
aarch64:

8
Cargo.lock generated
View File

@ -2019,16 +2019,24 @@ dependencies = [
name = "libsignal-bridge-testing"
version = "0.1.0"
dependencies = [
"attest",
"futures-util",
"http 1.1.0",
"jni 0.21.1",
"libsignal-bridge-macros",
"libsignal-bridge-types",
"libsignal-message-backup",
"libsignal-net",
"libsignal-protocol",
"linkme",
"neon",
"nonzero_ext",
"paste",
"prost",
"scopeguard",
"strum",
"tokio",
"uuid",
]
[[package]]

View File

@ -50,10 +50,6 @@ android {
}
packagingOptions {
jniLibs {
pickFirst 'lib/*/libsignal_jni.so'
pickFirst 'lib/*/libsignal_jni_testing.so'
}
// Defer stripping to the Android app project.
doNotStrip '**/*.so'
}
@ -123,7 +119,6 @@ dependencies {
preBuild {
dependsOn 'collectAssets'
dependsOn 'makeJniLibraries'
dependsOn 'makeTestJniLibraries'
}
String[] archsFromProperty(String prop) {
@ -136,21 +131,9 @@ task makeJniLibraries(type:Exec) {
def archs = archsFromProperty('androidArchs') ?: ['android']
def debugLevelLogsFlag = project.hasProperty('debugLevelLogs') ? ['--debug-level-logs'] : []
def debugFlag = project.hasProperty('debugRust') ? ['--debug'] : []
// Explicitly specify 'bash' for Windows compatibility.
commandLine 'bash', '../build_jni.sh', *debugLevelLogsFlag, *archs
environment 'ANDROID_NDK_HOME', android.ndkDirectory
}
task makeTestJniLibraries(type:Exec) {
group 'Rust'
description 'Build JNI libraries for Android for testing'
def archs = archsFromProperty('androidTestingArchs') ?: archsFromProperty('androidArchs') ?: ['android']
// While it might make sense for tests to always have debug level logs on,
// we would lose most of the shared incremental build between test and non-test that way.
def debugLevelLogsFlag = project.hasProperty('debugLevelLogs') ? ['--debug-level-logs'] : []
// Explicitly specify 'bash' for Windows compatibility.
commandLine 'bash', '../build_jni.sh', '--testing', *debugLevelLogsFlag, *archs
commandLine 'bash', '../build_jni.sh', *debugLevelLogsFlag, *debugFlag, *archs
environment 'ANDROID_NDK_HOME', android.ndkDirectory
}

View File

@ -19,20 +19,15 @@ SERVER_LIB_DIR=java/server/src/main/resources
export CARGO_PROFILE_RELEASE_DEBUG=1 # enable line tables
export RUSTFLAGS="--cfg aes_armv8 --cfg polyval_armv8 ${RUSTFLAGS:-}" # Enable ARMv8 cryptography acceleration when available
BUILD_FOR_TEST=
DEBUG_LEVEL_LOGS=
while [ "${1:-}" != "" ]; do
case "${1:-}" in
--testing )
BUILD_FOR_TEST=1
shift
;;
--debug-level-logs )
DEBUG_LEVEL_LOGS=1
shift
;;
-* )
echo "Unrecognized flag $1; expected --testing or --debug-level-logs" >&2
echo "Unrecognized flag $1; expected --debug-level-logs" >&2
exit 2
;;
*)
@ -75,6 +70,7 @@ build_desktop_for_arch () {
export CPATH="/usr/${cpuarch}-linux-gnu/include"
fi
fi
echo_then_run cargo build -p libsignal-jni -p libsignal-jni-testing --release ${FEATURES:+--features "${FEATURES[*]}"} --target "$1"
copy_built_library "target/${1}/release" signal_jni "$lib_dir" "signal_jni_${suffix}"
copy_built_library "target/${1}/release" signal_jni_testing "$lib_dir" "signal_jni_testing_${suffix}"
@ -95,7 +91,6 @@ while [ "${1:-}" != "" ]; do
# Using LTO works around this at the cost of a slightly slower build.
# https://github.com/rust-lang/rfcs/issues/2771
export CARGO_PROFILE_RELEASE_LTO=thin
FEATURES+=("testing-fns")
host_triple=$(rustc -vV | sed -n 's|host: ||p')
if [[ "$1" == "server-all" ]]; then
build_desktop_for_arch x86_64-unknown-linux-gnu "$host_triple" $lib_dir
@ -162,11 +157,6 @@ export TARGET_AR="${ANDROID_TOOLCHAIN_DIR}/llvm-ar"
# Comment out the following to allow the 32-bit backend on 32-bit targets.
export RUSTFLAGS="--cfg curve25519_dalek_bits=\"64\" ${RUSTFLAGS:-}"
if [ $BUILD_FOR_TEST ]; then
FEATURES+=("testing-fns")
ANDROID_LIB_DIR="${ANDROID_LIB_DIR}/../../androidTest/jniLibs"
fi
target_for_abi() {
case "$1" in
arm64-v8a)

View File

@ -9,7 +9,7 @@ import static org.junit.Assert.assertArrayEquals;
import java.io.ByteArrayInputStream;
import org.junit.Test;
import org.signal.libsignal.internal.Native;
import org.signal.libsignal.internal.NativeTesting;
public class InputStreamTest {
@ -17,6 +17,7 @@ public class InputStreamTest {
public void testReadIntoEmptyBuffer() {
byte[] data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes();
assertArrayEquals(
Native.TESTING_InputStreamReadIntoZeroLengthSlice(new ByteArrayInputStream(data)), data);
NativeTesting.TESTING_InputStreamReadIntoZeroLengthSlice(new ByteArrayInputStream(data)),
data);
}
}

View File

@ -15,8 +15,8 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.junit.Test;
import org.signal.libsignal.attest.AttestationDataException;
import org.signal.libsignal.internal.Native;
import org.signal.libsignal.internal.NativeHandleGuard;
import org.signal.libsignal.internal.NativeTesting;
import org.signal.libsignal.protocol.ServiceId;
public class CdsiLookupResponseTest {
@ -45,7 +45,7 @@ public class CdsiLookupResponseTest {
Future<Object> response;
try (NativeHandleGuard guard = new NativeHandleGuard(context)) {
response = Native.TESTING_CdsiLookupResponseConvert(guard.nativeHandle());
response = NativeTesting.TESTING_CdsiLookupResponseConvert(guard.nativeHandle());
}
CdsiLookupResponse actual = (CdsiLookupResponse) response.get();
@ -90,7 +90,7 @@ public class CdsiLookupResponseTest {
assertThrows(
"for " + errorDescription,
expectedErrorType,
() -> Native.TESTING_CdsiLookupErrorConvert(errorDescription));
() -> NativeTesting.TESTING_CdsiLookupErrorConvert(errorDescription));
assertEquals(e.getMessage(), expectedMessage);
return e;
}

View File

@ -12,7 +12,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.junit.Assume;
import org.junit.Test;
import org.signal.libsignal.internal.Native;
import org.signal.libsignal.internal.NativeTesting;
import org.signal.libsignal.util.TestEnvironment;
public class ChatServiceTest {
@ -34,14 +34,14 @@ public class ChatServiceTest {
public void testConvertResponse() throws Exception {
// empty body
final ChatService.Response response1 =
(ChatService.Response) Native.TESTING_ChatServiceResponseConvert(false);
(ChatService.Response) NativeTesting.TESTING_ChatServiceResponseConvert(false);
assertEquals(EXPECTED_STATUS, response1.status());
assertEquals(EXPECTED_MESSAGE, response1.message());
assertArrayEquals(new byte[0], response1.body());
assertEquals(EXPECTED_HEADERS, response1.headers());
final ChatService.Response response2 =
(ChatService.Response) Native.TESTING_ChatServiceResponseConvert(true);
(ChatService.Response) NativeTesting.TESTING_ChatServiceResponseConvert(true);
assertEquals(EXPECTED_STATUS, response2.status());
assertEquals(EXPECTED_MESSAGE, response2.message());
assertArrayEquals(EXPECTED_CONTENT, response2.body());
@ -51,7 +51,7 @@ public class ChatServiceTest {
@Test
public void testConvertDebugInfo() throws Exception {
final ChatService.DebugInfo debugInfo =
(ChatService.DebugInfo) Native.TESTING_ChatServiceDebugInfoConvert();
(ChatService.DebugInfo) NativeTesting.TESTING_ChatServiceDebugInfoConvert();
assertEquals(IpType.IPv4, debugInfo.ipType());
assertEquals(200, debugInfo.durationMs());
assertEquals("connection_info", debugInfo.connectionInfo());
@ -60,7 +60,8 @@ public class ChatServiceTest {
@Test
public void testConvertResponseAndDebugInfo() throws Exception {
final ChatService.ResponseAndDebugInfo responseAndDebugInfo =
(ChatService.ResponseAndDebugInfo) Native.TESTING_ChatServiceResponseAndDebugInfoConvert();
(ChatService.ResponseAndDebugInfo)
NativeTesting.TESTING_ChatServiceResponseAndDebugInfoConvert();
final ChatService.Response response = responseAndDebugInfo.response();
assertEquals(EXPECTED_STATUS, response.status());
@ -95,7 +96,7 @@ public class ChatServiceTest {
return assertThrows(
"for " + errorDescription,
expectedErrorType,
() -> Native.TESTING_ChatServiceErrorConvert(errorDescription));
() -> NativeTesting.TESTING_ChatServiceErrorConvert(errorDescription));
}
@Test
@ -106,14 +107,17 @@ public class ChatServiceTest {
new ChatService.Request(
expectedMethod, expectedPathAndQuery, EXPECTED_HEADERS, EXPECTED_CONTENT, 5000);
final ChatService.InternalRequest internal = ChatService.buildInternalRequest(request);
assertEquals(expectedMethod, internal.guardedMap(Native::TESTING_ChatRequestGetMethod));
assertEquals(expectedPathAndQuery, internal.guardedMap(Native::TESTING_ChatRequestGetPath));
assertArrayEquals(EXPECTED_CONTENT, internal.guardedMap(Native::TESTING_ChatRequestGetBody));
assertEquals(expectedMethod, internal.guardedMap(NativeTesting::TESTING_ChatRequestGetMethod));
assertEquals(
expectedPathAndQuery, internal.guardedMap(NativeTesting::TESTING_ChatRequestGetPath));
assertArrayEquals(
EXPECTED_CONTENT, internal.guardedMap(NativeTesting::TESTING_ChatRequestGetBody));
EXPECTED_HEADERS.forEach(
(name, value) ->
assertEquals(
value,
internal.guardedMap(h -> Native.TESTING_ChatRequestGetHeaderValue(h, name))));
internal.guardedMap(
h -> NativeTesting.TESTING_ChatRequestGetHeaderValue(h, name))));
}
@Test

View File

@ -7,8 +7,8 @@ Run the following command to update this file after adding or updating a depende
(remove the backslashes before running)
Depending on which dependency you've updated, you may have to run an actual build action instead of
just `help`. You can add `-x android:makeJniLibraries -x android:makeTestJniLibraries` to skip
building the Android native libraries.
just `help`. You can add `-x android:makeJniLibraries` to skip building the Android native
libraries.
For more information, see:
https://docs.gradle.org/current/userguide/dependency_verification.html

View File

@ -397,8 +397,6 @@ public final class Native {
public static native byte[] NumericFingerprintGenerator_GetScannableEncoding(long obj) throws Exception;
public static native long NumericFingerprintGenerator_New(int iterations, int version, byte[] localIdentifier, byte[] localKey, byte[] remoteIdentifier, byte[] remoteKey) throws Exception;
public static native void OtherTestingHandleType_Destroy(long handle);
public static native byte[] PinHash_AccessKey(long ph);
public static native void PinHash_Destroy(long handle);
public static native byte[] PinHash_EncryptionKey(long ph);
@ -648,51 +646,6 @@ public final class Native {
public static native CompletableFuture<byte[]> Svr3Restore(long asyncRuntime, long connectionManager, String password, byte[] shareSet, String username, String enclavePassword);
public static native void TESTING_CdsiLookupErrorConvert(String errorDescription) throws Exception;
public static native CompletableFuture<Object> TESTING_CdsiLookupResponseConvert(long asyncRuntime);
public static native byte[] TESTING_ChatRequestGetBody(long request);
public static native String TESTING_ChatRequestGetHeaderValue(long request, String headerName);
public static native String TESTING_ChatRequestGetMethod(long request);
public static native String TESTING_ChatRequestGetPath(long request);
public static native Object TESTING_ChatServiceDebugInfoConvert() throws Exception;
public static native void TESTING_ChatServiceErrorConvert(String errorDescription) throws Exception;
public static native Object TESTING_ChatServiceResponseAndDebugInfoConvert() throws Exception;
public static native Object TESTING_ChatServiceResponseConvert(boolean bodyPresent) throws Exception;
public static native void TESTING_ChatService_InjectConnectionInterrupted(long chat);
public static native void TESTING_ChatService_InjectRawServerRequest(long chat, byte[] bytes);
public static native void TESTING_ErrorOnBorrowAsync(Object input);
public static native CompletableFuture TESTING_ErrorOnBorrowIo(long asyncRuntime, Object input);
public static native void TESTING_ErrorOnBorrowSync(Object input);
public static native Object TESTING_ErrorOnReturnAsync(Object needsCleanup);
public static native CompletableFuture<Object> TESTING_ErrorOnReturnIo(long asyncRuntime, Object needsCleanup);
public static native Object TESTING_ErrorOnReturnSync(Object needsCleanup);
public static native CompletableFuture<Integer> TESTING_FutureFailure(long asyncRuntime, int input);
public static native CompletableFuture<Long> TESTING_FutureProducesOtherPointerType(long asyncRuntime, String input);
public static native CompletableFuture<Long> TESTING_FutureProducesPointerType(long asyncRuntime, int input);
public static native CompletableFuture<Integer> TESTING_FutureSuccess(long asyncRuntime, int input);
public static native CompletableFuture<Void> TESTING_FutureThrowsCustomErrorType(long asyncRuntime);
public static native byte[] TESTING_InputStreamReadIntoZeroLengthSlice(InputStream capsAlphabetInput);
public static native void TESTING_NonSuspendingBackgroundThreadRuntime_Destroy(long handle);
public static native CompletableFuture TESTING_OnlyCompletesByCancellation(long asyncRuntime);
public static native String TESTING_OtherTestingHandleType_getValue(long handle);
public static native void TESTING_PanicInBodyAsync(Object input);
public static native CompletableFuture TESTING_PanicInBodyIo(long asyncRuntime, Object input);
public static native void TESTING_PanicInBodySync(Object input);
public static native void TESTING_PanicOnBorrowAsync(Object input);
public static native CompletableFuture TESTING_PanicOnBorrowIo(long asyncRuntime, Object input);
public static native void TESTING_PanicOnBorrowSync(Object input);
public static native void TESTING_PanicOnLoadAsync(Object needsCleanup, Object input);
public static native CompletableFuture TESTING_PanicOnLoadIo(long asyncRuntime, Object needsCleanup, Object input);
public static native void TESTING_PanicOnLoadSync(Object needsCleanup, Object input);
public static native Object TESTING_PanicOnReturnAsync(Object needsCleanup);
public static native CompletableFuture<Object> TESTING_PanicOnReturnIo(long asyncRuntime, Object needsCleanup);
public static native Object TESTING_PanicOnReturnSync(Object needsCleanup);
public static native byte[][] TESTING_ProcessBytestringArray(ByteBuffer[] input);
public static native Object[] TESTING_ReturnStringArray();
public static native int TESTING_TestingHandleType_getValue(long handle);
public static native void TestingHandleType_Destroy(long handle);
public static native void TokioAsyncContext_Destroy(long handle);
public static native void TokioAsyncContext_cancel(long context, long rawCancellationId);
public static native long TokioAsyncContext_new();

View File

@ -49,5 +49,52 @@ public final class NativeTesting {
public static native Object[] ComparableBackup_GetUnknownFields(long backup);
public static native long ComparableBackup_ReadUnencrypted(InputStream stream, long len, int purpose) throws Exception;
public static native void OtherTestingHandleType_Destroy(long handle);
public static native void TESTING_CdsiLookupErrorConvert(String errorDescription) throws Exception;
public static native CompletableFuture<Object> TESTING_CdsiLookupResponseConvert(long asyncRuntime);
public static native byte[] TESTING_ChatRequestGetBody(long request);
public static native String TESTING_ChatRequestGetHeaderValue(long request, String headerName);
public static native String TESTING_ChatRequestGetMethod(long request);
public static native String TESTING_ChatRequestGetPath(long request);
public static native Object TESTING_ChatServiceDebugInfoConvert() throws Exception;
public static native void TESTING_ChatServiceErrorConvert(String errorDescription) throws Exception;
public static native Object TESTING_ChatServiceResponseAndDebugInfoConvert() throws Exception;
public static native Object TESTING_ChatServiceResponseConvert(boolean bodyPresent) throws Exception;
public static native void TESTING_ChatService_InjectConnectionInterrupted(long chat);
public static native void TESTING_ChatService_InjectRawServerRequest(long chat, byte[] bytes);
public static native void TESTING_ErrorOnBorrowAsync(Object input);
public static native CompletableFuture TESTING_ErrorOnBorrowIo(long asyncRuntime, Object input);
public static native void TESTING_ErrorOnBorrowSync(Object input);
public static native Object TESTING_ErrorOnReturnAsync(Object needsCleanup);
public static native CompletableFuture<Object> TESTING_ErrorOnReturnIo(long asyncRuntime, Object needsCleanup);
public static native Object TESTING_ErrorOnReturnSync(Object needsCleanup);
public static native CompletableFuture<Integer> TESTING_FutureFailure(long asyncRuntime, int input);
public static native CompletableFuture<Long> TESTING_FutureProducesOtherPointerType(long asyncRuntime, String input);
public static native CompletableFuture<Long> TESTING_FutureProducesPointerType(long asyncRuntime, int input);
public static native CompletableFuture<Integer> TESTING_FutureSuccess(long asyncRuntime, int input);
public static native CompletableFuture<Void> TESTING_FutureThrowsCustomErrorType(long asyncRuntime);
public static native byte[] TESTING_InputStreamReadIntoZeroLengthSlice(InputStream capsAlphabetInput);
public static native void TESTING_NonSuspendingBackgroundThreadRuntime_Destroy(long handle);
public static native CompletableFuture TESTING_OnlyCompletesByCancellation(long asyncRuntime);
public static native String TESTING_OtherTestingHandleType_getValue(long handle);
public static native void TESTING_PanicInBodyAsync(Object input);
public static native CompletableFuture TESTING_PanicInBodyIo(long asyncRuntime, Object input);
public static native void TESTING_PanicInBodySync(Object input);
public static native void TESTING_PanicOnBorrowAsync(Object input);
public static native CompletableFuture TESTING_PanicOnBorrowIo(long asyncRuntime, Object input);
public static native void TESTING_PanicOnBorrowSync(Object input);
public static native void TESTING_PanicOnLoadAsync(Object needsCleanup, Object input);
public static native CompletableFuture TESTING_PanicOnLoadIo(long asyncRuntime, Object needsCleanup, Object input);
public static native void TESTING_PanicOnLoadSync(Object needsCleanup, Object input);
public static native Object TESTING_PanicOnReturnAsync(Object needsCleanup);
public static native CompletableFuture<Object> TESTING_PanicOnReturnIo(long asyncRuntime, Object needsCleanup);
public static native Object TESTING_PanicOnReturnSync(Object needsCleanup);
public static native byte[][] TESTING_ProcessBytestringArray(ByteBuffer[] input);
public static native Object[] TESTING_ReturnStringArray();
public static native int TESTING_TestingHandleType_getValue(long handle);
public static native void TestingHandleType_Destroy(long handle);
public static native int test_only_fn_returns_123();
}

View File

@ -14,62 +14,69 @@ import org.junit.Test;
public class BridgingTest {
@Test
public void testErrorOnBorrow() throws Exception {
assertThrows(IllegalArgumentException.class, () -> Native.TESTING_ErrorOnBorrowSync(null));
assertThrows(IllegalArgumentException.class, () -> Native.TESTING_ErrorOnBorrowAsync(null));
assertThrows(
IllegalArgumentException.class, () -> Native.TESTING_ErrorOnBorrowIo(-1, null).get());
IllegalArgumentException.class, () -> NativeTesting.TESTING_ErrorOnBorrowSync(null));
assertThrows(
IllegalArgumentException.class, () -> NativeTesting.TESTING_ErrorOnBorrowAsync(null));
assertThrows(
IllegalArgumentException.class,
() -> NativeTesting.TESTING_ErrorOnBorrowIo(-1, null).get());
}
@Test
public void testPanicOnBorrow() throws Exception {
assertThrows(AssertionError.class, () -> Native.TESTING_PanicOnBorrowSync(null));
assertThrows(AssertionError.class, () -> Native.TESTING_PanicOnBorrowAsync(null));
assertThrows(AssertionError.class, () -> Native.TESTING_PanicOnBorrowIo(-1, null).get());
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicOnBorrowSync(null));
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicOnBorrowAsync(null));
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicOnBorrowIo(-1, null).get());
}
@Test
public void testPanicOnLoad() throws Exception {
assertThrows(AssertionError.class, () -> Native.TESTING_PanicOnLoadSync(null, null));
assertThrows(AssertionError.class, () -> Native.TESTING_PanicOnLoadAsync(null, null));
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicOnLoadSync(null, null));
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicOnLoadAsync(null, null));
ExecutionException e =
assertThrows(
ExecutionException.class, () -> Native.TESTING_PanicOnLoadIo(-1, null, null).get());
ExecutionException.class,
() -> NativeTesting.TESTING_PanicOnLoadIo(-1, null, null).get());
assertTrue(e.getCause().toString(), e.getCause() instanceof AssertionError);
}
@Test
public void testPanicInBody() throws Exception {
assertThrows(AssertionError.class, () -> Native.TESTING_PanicInBodySync(null));
assertThrows(AssertionError.class, () -> Native.TESTING_PanicInBodyAsync(null));
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicInBodySync(null));
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicInBodyAsync(null));
ExecutionException e =
assertThrows(ExecutionException.class, () -> Native.TESTING_PanicInBodyIo(-1, null).get());
assertThrows(
ExecutionException.class, () -> NativeTesting.TESTING_PanicInBodyIo(-1, null).get());
assertTrue(e.getCause().toString(), e.getCause() instanceof AssertionError);
}
@Test
public void testErrorOnReturn() throws Exception {
assertThrows(IllegalArgumentException.class, () -> Native.TESTING_ErrorOnReturnSync(null));
assertThrows(IllegalArgumentException.class, () -> Native.TESTING_ErrorOnReturnAsync(null));
assertThrows(
IllegalArgumentException.class, () -> NativeTesting.TESTING_ErrorOnReturnSync(null));
assertThrows(
IllegalArgumentException.class, () -> NativeTesting.TESTING_ErrorOnReturnAsync(null));
ExecutionException e =
assertThrows(
ExecutionException.class, () -> Native.TESTING_ErrorOnReturnIo(-1, null).get());
ExecutionException.class, () -> NativeTesting.TESTING_ErrorOnReturnIo(-1, null).get());
assertTrue(e.getCause().toString(), e.getCause() instanceof IllegalArgumentException);
}
@Test
public void testPanicOnReturn() throws Exception {
assertThrows(AssertionError.class, () -> Native.TESTING_PanicOnReturnSync(null));
assertThrows(AssertionError.class, () -> Native.TESTING_PanicOnReturnAsync(null));
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicOnReturnSync(null));
assertThrows(AssertionError.class, () -> NativeTesting.TESTING_PanicOnReturnAsync(null));
ExecutionException e =
assertThrows(
ExecutionException.class, () -> Native.TESTING_PanicOnReturnIo(-1, null).get());
ExecutionException.class, () -> NativeTesting.TESTING_PanicOnReturnIo(-1, null).get());
assertTrue(e.getCause().toString(), e.getCause() instanceof AssertionError);
}
@Test
public void testReturnStringArray() {
assertArrayEquals(
Native.TESTING_ReturnStringArray(), new String[] {"easy", "as", "ABC", "123"});
NativeTesting.TESTING_ReturnStringArray(), new String[] {"easy", "as", "ABC", "123"});
}
@Test
@ -80,12 +87,13 @@ public class BridgingTest {
ByteBuffer second = ByteBuffer.allocateDirect(3);
second.put(new byte[] {4, 5, 6});
byte[][] result =
Native.TESTING_ProcessBytestringArray(new ByteBuffer[] {first, empty, second});
NativeTesting.TESTING_ProcessBytestringArray(new ByteBuffer[] {first, empty, second});
assertArrayEquals(result, new byte[][] {{1, 2, 3, 1, 2, 3}, {}, {4, 5, 6, 4, 5, 6}});
}
@Test
public void testProcessEmptyBytestringArray() {
assertArrayEquals(Native.TESTING_ProcessBytestringArray(new ByteBuffer[] {}), new byte[][] {});
assertArrayEquals(
NativeTesting.TESTING_ProcessBytestringArray(new ByteBuffer[] {}), new byte[][] {});
}
}

View File

@ -14,20 +14,20 @@ import org.junit.Test;
public class FutureTest {
@Test
public void testSuccessFromRust() throws Exception {
Future<Integer> future = Native.TESTING_FutureSuccess(1, 21);
Future<Integer> future = NativeTesting.TESTING_FutureSuccess(1, 21);
assertEquals(42, (int) future.get());
}
@Test
public void testFailureFromRust() throws Exception {
Future<Integer> future = Native.TESTING_FutureFailure(1, 21);
Future<Integer> future = NativeTesting.TESTING_FutureFailure(1, 21);
ExecutionException e = assertThrows(ExecutionException.class, () -> future.get());
assertTrue(e.getCause() instanceof IllegalArgumentException);
}
@Test
public void testFutureThrowsUnloadedException() throws Exception {
Future future = Native.TESTING_FutureThrowsCustomErrorType(1);
Future future = NativeTesting.TESTING_FutureThrowsCustomErrorType(1);
ExecutionException e = assertThrows(ExecutionException.class, () -> future.get());
assertTrue(e.getCause() instanceof org.signal.libsignal.internal.TestingException);
}

View File

@ -93,7 +93,7 @@ def main(args: Optional[List[str]] = None) -> int:
out_dir = options.out_dir.strip('"') or os.path.join('build', configuration_name)
features = ['testing-fns']
features = []
if 'npm_config_libsignal_debug_level_logs' not in os.environ:
features.append('log/release_max_level_info')

View File

@ -18,7 +18,6 @@ crate-type = ["staticlib"]
# Testing the Swift side of this requires compiling with SIGNAL_MEDIA_SUPPORTED enabled for both Swift and C:
# swift test -Xswiftc -DSIGNAL_MEDIA_SUPPORTED -Xcc -DSIGNAL_MEDIA_SUPPORTED
signal-media = ["libsignal-bridge/signal-media"]
testing-fns = ["libsignal-bridge/testing-fns", "dep:libsignal-bridge-testing"]
[dependencies]
libsignal-bridge = { path = "../shared", features = ["ffi"] }

View File

@ -24,7 +24,24 @@ usize_is_size_t = true
prefix_with_name = true
[export]
exclude = ["TAG_SIZE", "NONCE_SIZE"]
exclude = [
# Already in signal_ffi.h
"BorrowedSliceOfc_uchar",
"BorrowedSliceOfBorrowedSliceOfc_uchar",
"BytestringArray",
"CPromisebool",
"CPromiseFfiCdsiLookupResponse",
"FfiCdsiLookupResponse",
"FfiCdsiLookupResponseEntry",
"FfiChatResponse",
"FfiChatServiceDebugInfo",
"FfiInputStreamStruct",
"FfiResponseAndDebugInfo",
"OwnedBufferOfCStringPtr",
"OwnedBufferOfc_uchar",
"OwnedBufferOfFfiCdsiLookupResponseEntry",
"OwnedBufferOfusize",
]
item_types = [
"enums",
"functions",
@ -40,6 +57,14 @@ renaming_overrides_prefixing = true
[export.rename]
"FfiInputStreamStruct" = "SignalInputStream"
"BorrowedSliceOfc_uchar" = "SignalBorrowedBuffer"
"BorrowedSliceOfBorrowedSliceOfc_uchar" = "SignalBorrowedSliceOfBuffers"
"BorrowedMutableSliceOfc_uchar" = "SignalBorrowedMutableBuffer"
"OwnedBufferOfc_uchar" = "SignalOwnedBuffer"
"OwnedBufferOfFfiLookupResponseEntry" = "SignalOwnedLookupResponseEntryList"
"CPromisec_void" = "SignalCPromiseRawPointer"
# Avoid double-prefixing these
"SignalFfiError" = "SignalFfiError"
"SignalErrorCode" = "SignalErrorCode"
@ -53,8 +78,7 @@ args = "horizontal"
[parse]
parse_deps = true
include = []
extra_bindings = ["libsignal-bridge-testing", "libsignal-bridge-types"]
include = ["libsignal-bridge-types"]
[parse.expand]
crates = ["libsignal-bridge-testing"]

View File

@ -62,7 +62,6 @@ renaming_overrides_prefixing = true
"OwnedBufferOfc_uchar" = "SignalOwnedBuffer"
"OwnedBufferOfFfiLookupResponseEntry" = "SignalOwnedLookupResponseEntryList"
"FfiOptionalServiceIdFixedWidthBinaryBytes" = "SignalOptionalServiceIdFixedWidthBinaryBytes"
"CPromisec_void" = "SignalCPromiseRawPointer"
"RawCancellationId" = "SignalCancellationId"
@ -94,8 +93,4 @@ extra_bindings = ["libsignal-bridge", "libsignal-bridge-types", "zkgroup"]
[parse.expand]
crates = ["libsignal-ffi", "libsignal-bridge"]
features = [
"libsignal-bridge/ffi",
"libsignal-bridge/signal-media",
"libsignal-bridge/testing-fns",
]
features = ["libsignal-bridge/ffi", "libsignal-bridge/signal-media"]

View File

@ -8,7 +8,7 @@
use futures_util::FutureExt;
use libsignal_bridge::ffi::*;
#[cfg(feature = "testing-fns")]
#[cfg(feature = "libsignal-bridge-testing")]
#[allow(unused_imports)]
use libsignal_bridge_testing::*;
use libsignal_protocol::*;

View File

@ -24,9 +24,6 @@ jni = { workspace = true }
log = { workspace = true }
log-panics = { workspace = true, features = ["with-backtrace"] }
[features]
testing-fns = ["libsignal-bridge/testing-fns"]
[target.aarch64-linux-android.dependencies]
cpufeatures = "0.2.2" # Make sure 64-bit Android gets optimized crypto

View File

@ -41,7 +41,7 @@ IGNORE_THIS_WARNING = re.compile(
r"WARN: Missing `\[defines\]` entry for `feature = \".*\"` in cbindgen config\.|"
r"WARN: Missing `\[defines\]` entry for `target_os = \"android\"` in cbindgen config\.|"
r"WARN: Missing `\[defines\]` entry for `ios_device_as_detected_in_build_rs` in cbindgen config\.|"
r"WARN: Skip libsignal-bridge::.+ - \(not `(?:pub|no_mangle)`\)\.|"
r"WARN: Skip libsignal-bridge(-testing)?::.+ - \(not `(pub|no_mangle)`\)\.|"
r"WARN: Couldn't find path for Array\(Path\(GenericPath \{ .+ \}\), Name\(\"LEN\"\)\), skipping associated constants|"
r"WARN: Cannot find a mangling for generic path GenericPath { path: Path { name: \"JavaCompletableFuture\" }.+|"
r"WARN: Cannot find a mangling for generic path GenericPath { path: Path { name: \"Throwing\" }.+"

View File

@ -25,8 +25,4 @@ extra_bindings = ["libsignal-bridge"]
[parse.expand]
crates = ["libsignal-jni", "libsignal-bridge"]
features = [
"libsignal-bridge/jni",
"libsignal-bridge/signal-media",
"libsignal-bridge/testing-fns",
]
features = ["libsignal-bridge/jni", "libsignal-bridge/signal-media"]

View File

@ -31,6 +31,3 @@ neon = { version = "1.0.0", default-features = false, features = ["napi-6"] }
# cmake 0.1.49 breaks no-toolchain Windows cross-compilation using Visual Studio
# https://github.com/rust-lang/cmake-rs/pull/158#issuecomment-1544695163
cmake = ">= 0.1, < 0.1.49"
[features]
testing-fns = ["libsignal-bridge/testing-fns"]

View File

@ -277,7 +277,7 @@ def main() -> None:
convert_to_typescript(
rust_crates=[
Crate(path=os.path.join(our_abs_dir, '..')),
Crate(path=os.path.join(our_abs_dir, '..', '..', 'shared'), features=('node', 'signal-media', 'testing-fns')),
Crate(path=os.path.join(our_abs_dir, '..', '..', 'shared'), features=('node', 'signal-media')),
Crate(path=os.path.join(our_abs_dir, '..', '..', 'shared', 'types'), features=('node', 'signal-media')),
Crate(path=os.path.join(our_abs_dir, '..', '..', 'shared', 'testing'), features=('node', 'signal-media')),
],

View File

@ -62,4 +62,3 @@ ffi = ["libsignal-bridge-types/ffi"]
jni = ["dep:jni", "libsignal-bridge-types/jni"]
node = ["neon", "linkme", "libsignal-bridge-types/node"]
signal-media = ["dep:signal-media", "libsignal-bridge-types/signal-media"]
testing-fns = []

View File

@ -62,8 +62,3 @@ pub mod usernames;
#[cfg(feature = "signal-media")]
pub mod media;
// These APIs are only useful for tests. To save on code size, we omit them by default.
// To run tests, build with `--features testing-fns`.
#[cfg(feature = "testing-fns")]
pub mod testing;

View File

@ -3,7 +3,6 @@
// SPDX-License-Identifier: AGPL-3.0-only
//
use std::future;
use std::time::Duration;
use http::uri::InvalidUri;
@ -16,7 +15,6 @@ use libsignal_net::auth::Auth;
use libsignal_net::chat::{
self, ChatServiceError, DebugInfo as ChatServiceDebugInfo, Request, Response as ChatResponse,
};
use libsignal_net::infra::ws::WebSocketServiceError;
use crate::support::*;
use crate::*;
@ -204,32 +202,6 @@ fn ChatService_SetListenerUnauth(
chat.set_listener_unauth(listener, runtime)
}
#[cfg(feature = "testing-fns")]
#[bridge_fn]
fn TESTING_ChatService_InjectRawServerRequest(chat: &Chat, bytes: &[u8]) {
let request_proto = <chat::RequestProto as prost::Message>::decode(bytes)
.expect("invalid protobuf cannot use this endpoint to test");
chat.synthetic_request_tx
.blocking_send(chat::ws::ServerEvent::fake(request_proto))
.expect("not closed");
}
#[cfg(feature = "testing-fns")]
#[bridge_fn]
fn TESTING_ChatService_InjectConnectionInterrupted(chat: &Chat) {
chat.synthetic_request_tx
.blocking_send(chat::ws::ServerEvent::Stopped(ChatServiceError::WebSocket(
WebSocketServiceError::ChannelClosed,
)))
.expect("not closed");
}
#[cfg(feature = "testing-fns")]
#[bridge_fn(jni = false, ffi = false)]
fn TESTING_ServerMessageAck_Create() -> ServerMessageAck {
ServerMessageAck::new(Box::new(|_| Box::pin(future::ready(Ok(())))))
}
bridge_handle_fns!(ServerMessageAck, clone = false);
#[bridge_io(TokioAsyncContext, node = false)]

View File

@ -11,14 +11,22 @@ edition = "2021"
license = "AGPL-3.0-only"
[dependencies]
attest = { path = "../../../attest" }
libsignal-bridge-macros = { path = "../macros" }
libsignal-bridge-types = { path = "../types" }
libsignal-message-backup = { path = "../../../message-backup", features = ["json"] }
libsignal-net = { path = "../../../net" }
libsignal-protocol = { path = "../../../protocol" }
futures-util = { workspace = true }
http = { workspace = true }
nonzero_ext = { workspace = true }
paste = { workspace = true }
prost = { workspace = true }
scopeguard = { workspace = true }
strum = { workspace = true, features = ["derive"] }
tokio = { workspace = true }
uuid = { workspace = true }
jni = { workspace = true, optional = true }
linkme = { workspace = true, optional = true }

View File

@ -1,5 +1,5 @@
//
// Copyright 2023 Signal Messenger, LLC.
// Copyright 2022 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//
@ -12,9 +12,7 @@ use libsignal_protocol::SignalProtocolError;
use std::future::Future;
mod net;
mod types;
use types::*;
use crate::types::*;
pub struct NonSuspendingBackgroundThreadRuntime;
bridge_as_handle!(

View File

@ -18,4 +18,7 @@ pub fn test_only_fn_returns_123() -> u32 {
123
}
pub mod convert;
pub mod message_backup;
pub mod net;
pub mod types;

View File

@ -8,18 +8,20 @@ use std::time::Duration;
use http::{HeaderMap, HeaderName, HeaderValue, StatusCode};
use libsignal_bridge_macros::*;
use libsignal_bridge_types::net::chat::{HttpRequest, ResponseAndDebugInfo};
use libsignal_bridge_types::net::chat::{
Chat, HttpRequest, ResponseAndDebugInfo, ServerMessageAck,
};
use libsignal_bridge_types::net::TokioAsyncContext;
use libsignal_net::cdsi::{LookupError, LookupResponse, LookupResponseEntry, E164};
use libsignal_net::chat::{
ChatServiceError, DebugInfo as ChatServiceDebugInfo, Response as ChatResponse,
self, ChatServiceError, DebugInfo as ChatServiceDebugInfo, Response as ChatResponse,
};
use libsignal_net::infra::ws::WebSocketServiceError;
use libsignal_net::infra::IpType;
use libsignal_protocol::{Aci, Pni};
use nonzero_ext::nonzero;
use uuid::Uuid;
use crate::support::*;
use crate::*;
#[bridge_io(TokioAsyncContext)]
@ -257,3 +259,26 @@ fn TESTING_ChatRequestGetBody(request: &HttpRequest) -> Vec<u8> {
.map(|b| b.into_vec())
.unwrap_or_default()
}
#[bridge_fn]
fn TESTING_ChatService_InjectRawServerRequest(chat: &Chat, bytes: &[u8]) {
let request_proto = <chat::RequestProto as prost::Message>::decode(bytes)
.expect("invalid protobuf cannot use this endpoint to test");
chat.synthetic_request_tx
.blocking_send(chat::ws::ServerEvent::fake(request_proto))
.expect("not closed");
}
#[bridge_fn]
fn TESTING_ChatService_InjectConnectionInterrupted(chat: &Chat) {
chat.synthetic_request_tx
.blocking_send(chat::ws::ServerEvent::Stopped(ChatServiceError::WebSocket(
WebSocketServiceError::ChannelClosed,
)))
.expect("not closed");
}
#[bridge_fn(jni = false, ffi = false)]
fn TESTING_ServerMessageAck_Create() -> ServerMessageAck {
ServerMessageAck::new(Box::new(|_| Box::pin(std::future::ready(Ok(())))))
}

View File

@ -238,10 +238,6 @@ typedef struct SignalMessageBackupKey SignalMessageBackupKey;
typedef struct SignalMessageBackupValidationOutcome SignalMessageBackupValidationOutcome;
typedef struct SignalNonSuspendingBackgroundThreadRuntime SignalNonSuspendingBackgroundThreadRuntime;
typedef struct SignalOtherTestingHandleType SignalOtherTestingHandleType;
typedef struct SignalPinHash SignalPinHash;
typedef struct SignalPlaintextContent SignalPlaintextContent;
@ -302,8 +298,6 @@ typedef struct SignalMessage SignalMessage;
typedef struct SignalSignedPreKeyRecord SignalSignedPreKeyRecord;
typedef struct SignalTestingHandleType SignalTestingHandleType;
typedef struct SignalTokioAsyncContext SignalTokioAsyncContext;
typedef struct SignalUnidentifiedSenderMessageContent SignalUnidentifiedSenderMessageContent;
@ -671,66 +665,6 @@ typedef struct {
typedef SignalInputStream SignalSyncInputStream;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, const int32_t *result, const void *context);
const void *context;
SignalCancellationId cancellation_id;
} SignalCPromisei32;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, SignalTestingHandleType *const *result, const void *context);
const void *context;
SignalCancellationId cancellation_id;
} SignalCPromiseTestingHandleType;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, SignalOtherTestingHandleType *const *result, const void *context);
const void *context;
SignalCancellationId cancellation_id;
} SignalCPromiseOtherTestingHandleType;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, const void *const *result, const void *context);
const void *context;
SignalCancellationId cancellation_id;
} SignalCPromiseRawPointer;
typedef uint8_t SignalRandomnessBytes[SignalRANDOMNESS_LEN];
void signal_print_ptr(const void *p);
@ -1583,10 +1517,6 @@ SignalFfiError *signal_chat_service_set_listener_auth(const SignalTokioAsyncCont
SignalFfiError *signal_chat_service_set_listener_unauth(const SignalTokioAsyncContext *runtime, const SignalChat *chat, const SignalFfiMakeChatListenerStruct *make_listener);
SignalFfiError *signal_testing_chat_service_inject_raw_server_request(const SignalChat *chat, SignalBorrowedBuffer bytes);
SignalFfiError *signal_testing_chat_service_inject_connection_interrupted(const SignalChat *chat);
SignalFfiError *signal_server_message_ack_destroy(SignalServerMessageAck *p);
SignalFfiError *signal_server_message_ack_send(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime, const SignalServerMessageAck *ack);
@ -1691,90 +1621,4 @@ SignalFfiError *signal_sanitized_metadata_get_data_offset(uint64_t *out, const S
SignalFfiError *signal_sanitized_metadata_get_data_len(uint64_t *out, const SignalSanitizedMetadata *sanitized);
#endif
SignalFfiError *signal_testing_NonSuspendingBackgroundThreadRuntime_destroy(SignalNonSuspendingBackgroundThreadRuntime *p);
SignalFfiError *signal_testing_future_success(SignalCPromisei32 *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input);
SignalFfiError *signal_testing_future_failure(SignalCPromisei32 *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t _input);
SignalFfiError *signal_testing_handle_type_destroy(SignalTestingHandleType *p);
SignalFfiError *signal_testing_handle_type_clone(SignalTestingHandleType **new_obj, const SignalTestingHandleType *obj);
SignalFfiError *signal_testing_testing_handle_type_get_value(uint8_t *out, const SignalTestingHandleType *handle);
SignalFfiError *signal_testing_future_produces_pointer_type(SignalCPromiseTestingHandleType *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input);
SignalFfiError *signal_other_testing_handle_type_destroy(SignalOtherTestingHandleType *p);
SignalFfiError *signal_other_testing_handle_type_clone(SignalOtherTestingHandleType **new_obj, const SignalOtherTestingHandleType *obj);
SignalFfiError *signal_testing_other_testing_handle_type_get_value(const char **out, const SignalOtherTestingHandleType *handle);
SignalFfiError *signal_testing_future_produces_other_pointer_type(SignalCPromiseOtherTestingHandleType *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const char *input);
SignalFfiError *signal_testing_panic_on_borrow_sync(const void *_input);
SignalFfiError *signal_testing_panic_on_borrow_async(const void *_input);
SignalFfiError *signal_testing_panic_on_borrow_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input);
SignalFfiError *signal_testing_error_on_borrow_sync(const void *_input);
SignalFfiError *signal_testing_error_on_borrow_async(const void *_input);
SignalFfiError *signal_testing_error_on_borrow_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input);
SignalFfiError *signal_testing_panic_on_load_sync(const void *_needs_cleanup, const void *_input);
SignalFfiError *signal_testing_panic_on_load_async(const void *_needs_cleanup, const void *_input);
SignalFfiError *signal_testing_panic_on_load_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup, const void *_input);
SignalFfiError *signal_testing_panic_in_body_sync(const void *_input);
SignalFfiError *signal_testing_panic_in_body_async(const void *_input);
SignalFfiError *signal_testing_panic_in_body_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input);
SignalFfiError *signal_testing_panic_on_return_sync(const void **out, const void *_needs_cleanup);
SignalFfiError *signal_testing_panic_on_return_async(const void **out, const void *_needs_cleanup);
SignalFfiError *signal_testing_panic_on_return_io(SignalCPromiseRawPointer *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup);
SignalFfiError *signal_testing_error_on_return_sync(const void **out, const void *_needs_cleanup);
SignalFfiError *signal_testing_error_on_return_async(const void **out, const void *_needs_cleanup);
SignalFfiError *signal_testing_error_on_return_io(SignalCPromiseRawPointer *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup);
SignalFfiError *signal_testing_return_string_array(SignalStringArray *out);
SignalFfiError *signal_testing_process_bytestring_array(SignalBytestringArray *out, SignalBorrowedSliceOfBuffers input);
SignalFfiError *signal_testing_input_stream_read_into_zero_length_slice(SignalOwnedBuffer *out, const SignalInputStream *caps_alphabet_input);
SignalFfiError *signal_testing_cdsi_lookup_response_convert(SignalCPromiseFfiCdsiLookupResponse *promise, const SignalTokioAsyncContext *async_runtime);
SignalFfiError *signal_testing_only_completes_by_cancellation(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime);
SignalFfiError *signal_testing_cdsi_lookup_error_convert(const char *error_description);
SignalFfiError *signal_testing_chat_service_error_convert(const char *error_description);
SignalFfiError *signal_testing_chat_service_response_convert(SignalFfiChatResponse *out, bool body_present);
SignalFfiError *signal_testing_chat_service_debug_info_convert(SignalFfiChatServiceDebugInfo *out);
SignalFfiError *signal_testing_chat_service_response_and_debug_info_convert(SignalFfiResponseAndDebugInfo *out);
SignalFfiError *signal_testing_chat_request_get_method(const char **out, const SignalHttpRequest *request);
SignalFfiError *signal_testing_chat_request_get_path(const char **out, const SignalHttpRequest *request);
SignalFfiError *signal_testing_chat_request_get_header_value(const char **out, const SignalHttpRequest *request, const char *header_name);
SignalFfiError *signal_testing_chat_request_get_body(SignalOwnedBuffer *out, const SignalHttpRequest *request);
#endif /* SIGNAL_FFI_H_ */

View File

@ -16,10 +16,160 @@ SPDX-License-Identifier: AGPL-3.0-only
#include <stdlib.h>
#include "signal_ffi.h"
typedef struct SignalChat SignalChat;
typedef struct SignalComparableBackup SignalComparableBackup;
typedef struct SignalHttpRequest SignalHttpRequest;
typedef struct SignalNonSuspendingBackgroundThreadRuntime SignalNonSuspendingBackgroundThreadRuntime;
typedef struct SignalOtherTestingHandleType SignalOtherTestingHandleType;
/**
* The top-level error type (opaquely) returned to C clients when something goes wrong.
*
* Ideally this would use [ThinBox][], and then we wouldn't need an extra level of indirection when
* returning it to C, but unfortunately that isn't stable yet.
*
* [ThinBox]: https://doc.rust-lang.org/std/boxed/struct.ThinBox.html
*/
typedef struct SignalFfiError SignalFfiError;
typedef struct SignalTestingHandleType SignalTestingHandleType;
typedef struct SignalTokioAsyncContext SignalTokioAsyncContext;
typedef uint64_t SignalRawCancellationId;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, const int32_t *result, const void *context);
const void *context;
SignalRawCancellationId cancellation_id;
} SignalCPromisei32;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, SignalTestingHandleType *const *result, const void *context);
const void *context;
SignalRawCancellationId cancellation_id;
} SignalCPromiseTestingHandleType;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, SignalOtherTestingHandleType *const *result, const void *context);
const void *context;
SignalRawCancellationId cancellation_id;
} SignalCPromiseOtherTestingHandleType;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, const void *const *result, const void *context);
const void *context;
SignalRawCancellationId cancellation_id;
} SignalCPromiseRawPointer;
typedef SignalBytestringArray SignalStringArray;
SignalFfiError *signal_test_only_fn_returns_123(uint32_t *out);
SignalFfiError *signal_testing_NonSuspendingBackgroundThreadRuntime_destroy(SignalNonSuspendingBackgroundThreadRuntime *p);
SignalFfiError *signal_testing_future_success(SignalCPromisei32 *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input);
SignalFfiError *signal_testing_future_failure(SignalCPromisei32 *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t _input);
SignalFfiError *signal_testing_handle_type_destroy(SignalTestingHandleType *p);
SignalFfiError *signal_testing_handle_type_clone(SignalTestingHandleType **new_obj, const SignalTestingHandleType *obj);
SignalFfiError *signal_testing_testing_handle_type_get_value(uint8_t *out, const SignalTestingHandleType *handle);
SignalFfiError *signal_testing_future_produces_pointer_type(SignalCPromiseTestingHandleType *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, uint8_t input);
SignalFfiError *signal_other_testing_handle_type_destroy(SignalOtherTestingHandleType *p);
SignalFfiError *signal_other_testing_handle_type_clone(SignalOtherTestingHandleType **new_obj, const SignalOtherTestingHandleType *obj);
SignalFfiError *signal_testing_other_testing_handle_type_get_value(const char **out, const SignalOtherTestingHandleType *handle);
SignalFfiError *signal_testing_future_produces_other_pointer_type(SignalCPromiseOtherTestingHandleType *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const char *input);
SignalFfiError *signal_testing_panic_on_borrow_sync(const void *_input);
SignalFfiError *signal_testing_panic_on_borrow_async(const void *_input);
SignalFfiError *signal_testing_panic_on_borrow_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input);
SignalFfiError *signal_testing_error_on_borrow_sync(const void *_input);
SignalFfiError *signal_testing_error_on_borrow_async(const void *_input);
SignalFfiError *signal_testing_error_on_borrow_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input);
SignalFfiError *signal_testing_panic_on_load_sync(const void *_needs_cleanup, const void *_input);
SignalFfiError *signal_testing_panic_on_load_async(const void *_needs_cleanup, const void *_input);
SignalFfiError *signal_testing_panic_on_load_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup, const void *_input);
SignalFfiError *signal_testing_panic_in_body_sync(const void *_input);
SignalFfiError *signal_testing_panic_in_body_async(const void *_input);
SignalFfiError *signal_testing_panic_in_body_io(SignalCPromisebool *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_input);
SignalFfiError *signal_testing_panic_on_return_sync(const void **out, const void *_needs_cleanup);
SignalFfiError *signal_testing_panic_on_return_async(const void **out, const void *_needs_cleanup);
SignalFfiError *signal_testing_panic_on_return_io(SignalCPromiseRawPointer *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup);
SignalFfiError *signal_testing_error_on_return_sync(const void **out, const void *_needs_cleanup);
SignalFfiError *signal_testing_error_on_return_async(const void **out, const void *_needs_cleanup);
SignalFfiError *signal_testing_error_on_return_io(SignalCPromiseRawPointer *promise, const SignalNonSuspendingBackgroundThreadRuntime *async_runtime, const void *_needs_cleanup);
SignalFfiError *signal_testing_return_string_array(SignalStringArray *out);
SignalFfiError *signal_testing_process_bytestring_array(SignalBytestringArray *out, SignalBorrowedSliceOfBuffers input);
SignalFfiError *signal_testing_input_stream_read_into_zero_length_slice(SignalOwnedBuffer *out, const SignalInputStream *caps_alphabet_input);
SignalFfiError *signal_comparable_backup_destroy(SignalComparableBackup *p);
SignalFfiError *signal_comparable_backup_read_unencrypted(SignalComparableBackup **out, const SignalInputStream *stream, uint64_t len, uint8_t purpose);
@ -28,4 +178,30 @@ SignalFfiError *signal_comparable_backup_get_comparable_string(const char **out,
SignalFfiError *signal_comparable_backup_get_unknown_fields(SignalStringArray *out, const SignalComparableBackup *backup);
SignalFfiError *signal_testing_cdsi_lookup_response_convert(SignalCPromiseFfiCdsiLookupResponse *promise, const SignalTokioAsyncContext *async_runtime);
SignalFfiError *signal_testing_only_completes_by_cancellation(SignalCPromisebool *promise, const SignalTokioAsyncContext *async_runtime);
SignalFfiError *signal_testing_cdsi_lookup_error_convert(const char *error_description);
SignalFfiError *signal_testing_chat_service_error_convert(const char *error_description);
SignalFfiError *signal_testing_chat_service_response_convert(SignalFfiChatResponse *out, bool body_present);
SignalFfiError *signal_testing_chat_service_debug_info_convert(SignalFfiChatServiceDebugInfo *out);
SignalFfiError *signal_testing_chat_service_response_and_debug_info_convert(SignalFfiResponseAndDebugInfo *out);
SignalFfiError *signal_testing_chat_request_get_method(const char **out, const SignalHttpRequest *request);
SignalFfiError *signal_testing_chat_request_get_path(const char **out, const SignalHttpRequest *request);
SignalFfiError *signal_testing_chat_request_get_header_value(const char **out, const SignalHttpRequest *request, const char *header_name);
SignalFfiError *signal_testing_chat_request_get_body(SignalOwnedBuffer *out, const SignalHttpRequest *request);
SignalFfiError *signal_testing_chat_service_inject_raw_server_request(const SignalChat *chat, SignalBorrowedBuffer bytes);
SignalFfiError *signal_testing_chat_service_inject_connection_interrupted(const SignalChat *chat);
#endif /* SIGNAL_FFI_TESTING_H_ */

View File

@ -32,7 +32,7 @@ export CFLAGS_x86_64_apple_ios_macabi="--target=x86_64-apple-ios-macabi ${CFLAGS
FEATURES=()
if [[ "${CARGO_BUILD_TARGET:-}" != "aarch64-apple-ios" ]]; then
FEATURES+=("testing-fns")
FEATURES+=("libsignal-bridge-testing")
fi
usage() {