Loading android/app/tests/unit/src/com/android/bluetooth/mapclient/RequestTest.java +4 −4 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ public class RequestTest { @Before public void setUp() throws IOException { mFakeMapObexServer = new FakeMapObexServer(); mFakeClientSession = new ClientSession(mFakeMapObexServer.mClientObexTransport); mFakeClientSession = mFakeMapObexServer.getClientSession(); mFakeClientSession.connect(new HeaderSet()); } Loading Loading @@ -182,7 +182,7 @@ public class RequestTest { @Override @SuppressWarnings("JavaUtilDate") public int onGetValidator(final Operation op) { public int onGet(final Operation op) { OutputStream outputStream; HeaderSet replyHeaders = new HeaderSet(); BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); Loading Loading @@ -223,7 +223,7 @@ public class RequestTest { } @Override public int onPutValidator(final Operation op) { public int onPut(final Operation op) { try { HeaderSet request = op.getReceivedHeader(); String type = (String) request.getHeader(HeaderSet.TYPE); Loading Loading @@ -263,7 +263,7 @@ public class RequestTest { } @Override public int onSetPathValidator( public int onSetPath( final HeaderSet request, HeaderSet reply, final boolean backup, Loading android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexServer.java +237 −29 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.bluetooth; import com.android.obex.ClientSession; import com.android.obex.HeaderSet; import com.android.obex.ObexTransport; import com.android.obex.Operation; Loading @@ -23,61 +24,266 @@ import com.android.obex.ResponseCodes; import com.android.obex.ServerRequestHandler; import com.android.obex.ServerSession; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; /** A Fake OBEX Server base class for use when testing OBEX clients and client requests. */ public class FakeObexServer { private static final String TAG = FakeObexServer.class.getSimpleName(); // Server streams to talk with client under test private final PipedInputStream mReceiveFromClient; private final PipedOutputStream mSendToClient; // Client streams to talk to server private final PipedInputStream mReceiveFromServer; private final PipedOutputStream mSendToServer; // Transports for either side private final TestObexTransport mServerTransport; private final TestObexTransport mClientTransport; private final TestServiceRequestHandler mRequestHandler; private final ServerSession mServerSession; public FakeObexServer() throws IOException { mSendToServer = new PipedOutputStream(); mReceiveFromServer = new PipedInputStream(); mReceiveFromClient = new PipedInputStream(mSendToServer); mSendToClient = new PipedOutputStream(mReceiveFromServer); // Transports mServerTransport = new TestObexTransport(mReceiveFromClient, mSendToClient, true); mClientTransport = new TestObexTransport(mReceiveFromServer, mSendToServer, true); mRequestHandler = new TestServiceRequestHandler(this); mServerSession = new ServerSession(mServerTransport, mRequestHandler, null); } /** * Get a transport for use with a client. * * <p>You can use the openInputStream() and openOutputStream() to get the underlying stream * objects and inject them into your objects under test. */ public ObexTransport getClientTransport() { return mClientTransport; } /** * A fake obex server for testing obex clients. Test cases should implement *Validator functions to * validate input and return appropriate responses for individual tests. * Directly create a session with this server. * * <p>Note: it is important to not perform any testing Assert operations within the validators as * that would crash the testing framework. * <p>This can be used to quickly test request objects that need a ClientSession */ public abstract class FakeObexServer { public ClientSession getClientSession() throws IOException { return new ClientSession(mClientTransport); } public ObexTransport mClientObexTransport; /** * This will close the underlying transport, which will close the streams given to us. * * <p>By specification, servers themselves cannot issue an OBEX session level disconnect. */ public void close() { mServerSession.close(); } private ObexTransport mServerObexTransport; private Server mFakeServer; private FakeObexTransport mFakeObexTransport; // ********************************************************************************************* // * Server Operations // ********************************************************************************************* public FakeObexServer() throws IOException { mFakeServer = new Server(); mFakeObexTransport = new FakeObexTransport(); mServerObexTransport = mFakeObexTransport.mServerTransport; mClientObexTransport = mFakeObexTransport.mClientTransport; new ServerSession(mServerObexTransport, mFakeServer, null); public int onConnect(final HeaderSet request, HeaderSet reply) { return ResponseCodes.OBEX_HTTP_OK; } public void onDisconnect(final HeaderSet request, HeaderSet reply) {} public int onGet(final Operation op) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; } public int onPut(final Operation op) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; } public int onAbort(final HeaderSet request, HeaderSet reply) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; } public int onSetPath( final HeaderSet request, HeaderSet reply, final boolean backup, final boolean create) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; } public void onClose() {} /** * Send a response to a client with the given headers and payload * * @param op The Operation object representing the ongoing operation with the client * @param replyHeaders The HeaderSet to return to the client * @param bytes The payload to send in the response, if any */ public final int sendResponse(Operation op, HeaderSet replyHeaders, byte[] bytes) { int responseCode = ResponseCodes.OBEX_HTTP_OK; OutputStream outStream = null; int maxChunkSize = 0; int bytesToWrite = 0; int bytesWritten = 0; try { op.sendHeaders(replyHeaders); // Do this before getting chunk size outStream = op.openOutputStream(); if (bytes == null) { op.noBodyHeader(); outStream.flush(); } else { maxChunkSize = op.getMaxPacketSize(); while (bytesWritten < bytes.length) { bytesToWrite = Math.min(maxChunkSize, bytes.length - bytesWritten); outStream.write(bytes, bytesWritten, bytesToWrite); bytesWritten += bytesToWrite; } } } catch (IOException e) { responseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } finally { // Make sure we close if (outStream != null) { try { outStream.close(); } catch (IOException e) { // drop, as we're closing anyways } } } // If we didn't write everything then send the error code if (bytes != null && bytesWritten != bytes.length) { responseCode = ResponseCodes.OBEX_HTTP_BAD_REQUEST; } // Otherwise, success! return responseCode; } // ********************************************************************************************* // * Transport // ********************************************************************************************* public static class TestObexTransport implements ObexTransport { private final InputStream mInput; private final OutputStream mOutput; private boolean mIsSrmSupported; public TestObexTransport(InputStream input, OutputStream output, boolean isSrmSupported) { mInput = input; mOutput = output; setSrmSupported(isSrmSupported); } @Override public DataInputStream openDataInputStream() throws IOException { return new DataInputStream(openInputStream()); } @Override public DataOutputStream openDataOutputStream() throws IOException { return new DataOutputStream(openOutputStream()); } @Override public InputStream openInputStream() throws IOException { return mInput; } @Override public OutputStream openOutputStream() throws IOException { return mOutput; } @Override public int getMaxReceivePacketSize() { return -1; } @Override public int getMaxTransmitPacketSize() { return -1; } @Override public void connect() throws IOException {} @Override public void create() throws IOException {} @Override public void disconnect() throws IOException {} @Override public void listen() throws IOException {} @Override public void close() throws IOException { mInput.close(); mOutput.close(); } public boolean isSrmSupported() { return mIsSrmSupported; } public abstract int onGetValidator(Operation op); public void setSrmSupported(boolean isSrmSupported) { mIsSrmSupported = isSrmSupported; } } public abstract int onPutValidator(Operation op); // ********************************************************************************************* // * Request Handler // ********************************************************************************************* public abstract int onSetPathValidator( HeaderSet request, HeaderSet reply, boolean backup, boolean create); /** * Internal ServerRequestHandler that delegates calls to the FakeObexServer implementation * * <p>This is setup this way for easier test syntax, so one can extend the fake without needing * to care about the framework specifics */ private static class TestServiceRequestHandler extends ServerRequestHandler { private final FakeObexServer mServer; class Server extends ServerRequestHandler { public TestServiceRequestHandler(FakeObexServer server) { mServer = server; } @Override public int onConnect(final HeaderSet request, HeaderSet reply) { return ResponseCodes.OBEX_HTTP_OK; return mServer.onConnect(request, reply); } @Override public void onDisconnect(final HeaderSet request, HeaderSet reply) {} public void onDisconnect(final HeaderSet request, HeaderSet reply) { mServer.onDisconnect(request, reply); } @Override public int onGet(final Operation op) { return onGetValidator(op); return mServer.onGet(op); } @Override public int onPut(final Operation op) { return onPutValidator(op); return mServer.onPut(op); } @Override public int onAbort(final HeaderSet request, HeaderSet reply) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; return mServer.onAbort(request, reply); } @Override Loading @@ -86,10 +292,12 @@ public abstract class FakeObexServer { HeaderSet reply, final boolean backup, final boolean create) { return onSetPathValidator(request, reply, backup, create); return mServer.onSetPath(request, reply, backup, create); } @Override public void onClose() {} public void onClose() { mServer.onClose(); } } } android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexTransport.javadeleted 100644 → 0 +0 −117 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth; import com.android.obex.ObexTransport; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; /** * A fake obex transport used for testing Client/Server connections. The transport uses two pairs of * pipes to route input from the client to the server, and back. The obex transport is of the * simplest form, returning default values for everything. */ public class FakeObexTransport { ObexTransport mClientTransport; ObexTransport mServerTransport; PipedInputStream mClientInputStream; PipedInputStream mServerInputStream; PipedOutputStream mClientOutputStream; PipedOutputStream mServerOutputStream; public FakeObexTransport() throws IOException { mClientInputStream = new PipedInputStream(); mServerOutputStream = new PipedOutputStream(mClientInputStream); mServerInputStream = new PipedInputStream(); mClientOutputStream = new PipedOutputStream(mServerInputStream); mClientTransport = new BiDirectionalTransport(mClientInputStream, mClientOutputStream); mServerTransport = new BiDirectionalTransport(mServerInputStream, mServerOutputStream); } static class BiDirectionalTransport implements ObexTransport { InputStream mInputStream; OutputStream mOutputStream; BiDirectionalTransport(InputStream inputStream, OutputStream outputStream) { mInputStream = inputStream; mOutputStream = outputStream; } @Override public DataInputStream openDataInputStream() throws IOException { return new DataInputStream(openInputStream()); } @Override public DataOutputStream openDataOutputStream() throws IOException { return new DataOutputStream(openOutputStream()); } @Override public InputStream openInputStream() throws IOException { return mInputStream; } @Override public OutputStream openOutputStream() throws IOException { return mOutputStream; } @Override public void connect() throws IOException {} @Override public void create() throws IOException {} @Override public void disconnect() throws IOException {} @Override public void listen() throws IOException {} @Override public void close() throws IOException {} public boolean isConnected() throws IOException { return true; } @Override public int getMaxTransmitPacketSize() { return -1; } @Override public int getMaxReceivePacketSize() { return -1; } @Override public boolean isSrmSupported() { return true; } } } Loading
android/app/tests/unit/src/com/android/bluetooth/mapclient/RequestTest.java +4 −4 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ public class RequestTest { @Before public void setUp() throws IOException { mFakeMapObexServer = new FakeMapObexServer(); mFakeClientSession = new ClientSession(mFakeMapObexServer.mClientObexTransport); mFakeClientSession = mFakeMapObexServer.getClientSession(); mFakeClientSession.connect(new HeaderSet()); } Loading Loading @@ -182,7 +182,7 @@ public class RequestTest { @Override @SuppressWarnings("JavaUtilDate") public int onGetValidator(final Operation op) { public int onGet(final Operation op) { OutputStream outputStream; HeaderSet replyHeaders = new HeaderSet(); BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); Loading Loading @@ -223,7 +223,7 @@ public class RequestTest { } @Override public int onPutValidator(final Operation op) { public int onPut(final Operation op) { try { HeaderSet request = op.getReceivedHeader(); String type = (String) request.getHeader(HeaderSet.TYPE); Loading Loading @@ -263,7 +263,7 @@ public class RequestTest { } @Override public int onSetPathValidator( public int onSetPath( final HeaderSet request, HeaderSet reply, final boolean backup, Loading
android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexServer.java +237 −29 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.bluetooth; import com.android.obex.ClientSession; import com.android.obex.HeaderSet; import com.android.obex.ObexTransport; import com.android.obex.Operation; Loading @@ -23,61 +24,266 @@ import com.android.obex.ResponseCodes; import com.android.obex.ServerRequestHandler; import com.android.obex.ServerSession; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; /** A Fake OBEX Server base class for use when testing OBEX clients and client requests. */ public class FakeObexServer { private static final String TAG = FakeObexServer.class.getSimpleName(); // Server streams to talk with client under test private final PipedInputStream mReceiveFromClient; private final PipedOutputStream mSendToClient; // Client streams to talk to server private final PipedInputStream mReceiveFromServer; private final PipedOutputStream mSendToServer; // Transports for either side private final TestObexTransport mServerTransport; private final TestObexTransport mClientTransport; private final TestServiceRequestHandler mRequestHandler; private final ServerSession mServerSession; public FakeObexServer() throws IOException { mSendToServer = new PipedOutputStream(); mReceiveFromServer = new PipedInputStream(); mReceiveFromClient = new PipedInputStream(mSendToServer); mSendToClient = new PipedOutputStream(mReceiveFromServer); // Transports mServerTransport = new TestObexTransport(mReceiveFromClient, mSendToClient, true); mClientTransport = new TestObexTransport(mReceiveFromServer, mSendToServer, true); mRequestHandler = new TestServiceRequestHandler(this); mServerSession = new ServerSession(mServerTransport, mRequestHandler, null); } /** * Get a transport for use with a client. * * <p>You can use the openInputStream() and openOutputStream() to get the underlying stream * objects and inject them into your objects under test. */ public ObexTransport getClientTransport() { return mClientTransport; } /** * A fake obex server for testing obex clients. Test cases should implement *Validator functions to * validate input and return appropriate responses for individual tests. * Directly create a session with this server. * * <p>Note: it is important to not perform any testing Assert operations within the validators as * that would crash the testing framework. * <p>This can be used to quickly test request objects that need a ClientSession */ public abstract class FakeObexServer { public ClientSession getClientSession() throws IOException { return new ClientSession(mClientTransport); } public ObexTransport mClientObexTransport; /** * This will close the underlying transport, which will close the streams given to us. * * <p>By specification, servers themselves cannot issue an OBEX session level disconnect. */ public void close() { mServerSession.close(); } private ObexTransport mServerObexTransport; private Server mFakeServer; private FakeObexTransport mFakeObexTransport; // ********************************************************************************************* // * Server Operations // ********************************************************************************************* public FakeObexServer() throws IOException { mFakeServer = new Server(); mFakeObexTransport = new FakeObexTransport(); mServerObexTransport = mFakeObexTransport.mServerTransport; mClientObexTransport = mFakeObexTransport.mClientTransport; new ServerSession(mServerObexTransport, mFakeServer, null); public int onConnect(final HeaderSet request, HeaderSet reply) { return ResponseCodes.OBEX_HTTP_OK; } public void onDisconnect(final HeaderSet request, HeaderSet reply) {} public int onGet(final Operation op) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; } public int onPut(final Operation op) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; } public int onAbort(final HeaderSet request, HeaderSet reply) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; } public int onSetPath( final HeaderSet request, HeaderSet reply, final boolean backup, final boolean create) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; } public void onClose() {} /** * Send a response to a client with the given headers and payload * * @param op The Operation object representing the ongoing operation with the client * @param replyHeaders The HeaderSet to return to the client * @param bytes The payload to send in the response, if any */ public final int sendResponse(Operation op, HeaderSet replyHeaders, byte[] bytes) { int responseCode = ResponseCodes.OBEX_HTTP_OK; OutputStream outStream = null; int maxChunkSize = 0; int bytesToWrite = 0; int bytesWritten = 0; try { op.sendHeaders(replyHeaders); // Do this before getting chunk size outStream = op.openOutputStream(); if (bytes == null) { op.noBodyHeader(); outStream.flush(); } else { maxChunkSize = op.getMaxPacketSize(); while (bytesWritten < bytes.length) { bytesToWrite = Math.min(maxChunkSize, bytes.length - bytesWritten); outStream.write(bytes, bytesWritten, bytesToWrite); bytesWritten += bytesToWrite; } } } catch (IOException e) { responseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; } finally { // Make sure we close if (outStream != null) { try { outStream.close(); } catch (IOException e) { // drop, as we're closing anyways } } } // If we didn't write everything then send the error code if (bytes != null && bytesWritten != bytes.length) { responseCode = ResponseCodes.OBEX_HTTP_BAD_REQUEST; } // Otherwise, success! return responseCode; } // ********************************************************************************************* // * Transport // ********************************************************************************************* public static class TestObexTransport implements ObexTransport { private final InputStream mInput; private final OutputStream mOutput; private boolean mIsSrmSupported; public TestObexTransport(InputStream input, OutputStream output, boolean isSrmSupported) { mInput = input; mOutput = output; setSrmSupported(isSrmSupported); } @Override public DataInputStream openDataInputStream() throws IOException { return new DataInputStream(openInputStream()); } @Override public DataOutputStream openDataOutputStream() throws IOException { return new DataOutputStream(openOutputStream()); } @Override public InputStream openInputStream() throws IOException { return mInput; } @Override public OutputStream openOutputStream() throws IOException { return mOutput; } @Override public int getMaxReceivePacketSize() { return -1; } @Override public int getMaxTransmitPacketSize() { return -1; } @Override public void connect() throws IOException {} @Override public void create() throws IOException {} @Override public void disconnect() throws IOException {} @Override public void listen() throws IOException {} @Override public void close() throws IOException { mInput.close(); mOutput.close(); } public boolean isSrmSupported() { return mIsSrmSupported; } public abstract int onGetValidator(Operation op); public void setSrmSupported(boolean isSrmSupported) { mIsSrmSupported = isSrmSupported; } } public abstract int onPutValidator(Operation op); // ********************************************************************************************* // * Request Handler // ********************************************************************************************* public abstract int onSetPathValidator( HeaderSet request, HeaderSet reply, boolean backup, boolean create); /** * Internal ServerRequestHandler that delegates calls to the FakeObexServer implementation * * <p>This is setup this way for easier test syntax, so one can extend the fake without needing * to care about the framework specifics */ private static class TestServiceRequestHandler extends ServerRequestHandler { private final FakeObexServer mServer; class Server extends ServerRequestHandler { public TestServiceRequestHandler(FakeObexServer server) { mServer = server; } @Override public int onConnect(final HeaderSet request, HeaderSet reply) { return ResponseCodes.OBEX_HTTP_OK; return mServer.onConnect(request, reply); } @Override public void onDisconnect(final HeaderSet request, HeaderSet reply) {} public void onDisconnect(final HeaderSet request, HeaderSet reply) { mServer.onDisconnect(request, reply); } @Override public int onGet(final Operation op) { return onGetValidator(op); return mServer.onGet(op); } @Override public int onPut(final Operation op) { return onPutValidator(op); return mServer.onPut(op); } @Override public int onAbort(final HeaderSet request, HeaderSet reply) { return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; return mServer.onAbort(request, reply); } @Override Loading @@ -86,10 +292,12 @@ public abstract class FakeObexServer { HeaderSet reply, final boolean backup, final boolean create) { return onSetPathValidator(request, reply, backup, create); return mServer.onSetPath(request, reply, backup, create); } @Override public void onClose() {} public void onClose() { mServer.onClose(); } } }
android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexTransport.javadeleted 100644 → 0 +0 −117 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth; import com.android.obex.ObexTransport; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; /** * A fake obex transport used for testing Client/Server connections. The transport uses two pairs of * pipes to route input from the client to the server, and back. The obex transport is of the * simplest form, returning default values for everything. */ public class FakeObexTransport { ObexTransport mClientTransport; ObexTransport mServerTransport; PipedInputStream mClientInputStream; PipedInputStream mServerInputStream; PipedOutputStream mClientOutputStream; PipedOutputStream mServerOutputStream; public FakeObexTransport() throws IOException { mClientInputStream = new PipedInputStream(); mServerOutputStream = new PipedOutputStream(mClientInputStream); mServerInputStream = new PipedInputStream(); mClientOutputStream = new PipedOutputStream(mServerInputStream); mClientTransport = new BiDirectionalTransport(mClientInputStream, mClientOutputStream); mServerTransport = new BiDirectionalTransport(mServerInputStream, mServerOutputStream); } static class BiDirectionalTransport implements ObexTransport { InputStream mInputStream; OutputStream mOutputStream; BiDirectionalTransport(InputStream inputStream, OutputStream outputStream) { mInputStream = inputStream; mOutputStream = outputStream; } @Override public DataInputStream openDataInputStream() throws IOException { return new DataInputStream(openInputStream()); } @Override public DataOutputStream openDataOutputStream() throws IOException { return new DataOutputStream(openOutputStream()); } @Override public InputStream openInputStream() throws IOException { return mInputStream; } @Override public OutputStream openOutputStream() throws IOException { return mOutputStream; } @Override public void connect() throws IOException {} @Override public void create() throws IOException {} @Override public void disconnect() throws IOException {} @Override public void listen() throws IOException {} @Override public void close() throws IOException {} public boolean isConnected() throws IOException { return true; } @Override public int getMaxTransmitPacketSize() { return -1; } @Override public int getMaxReceivePacketSize() { return -1; } @Override public boolean isSrmSupported() { return true; } } }