Merge changes I0f8e6590,I61a1bb91
* changes: Add MdnsAnyRecord Add constructors to MDNS records
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.server.connectivity.mdns;
|
||||||
|
|
||||||
|
import android.net.DnsResolver;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mDNS "ANY" record, used in mDNS questions to query for any record type.
|
||||||
|
*/
|
||||||
|
public class MdnsAnyRecord extends MdnsRecord {
|
||||||
|
|
||||||
|
protected MdnsAnyRecord(String[] name, MdnsPacketReader reader) throws IOException {
|
||||||
|
super(name, TYPE_ANY, reader, true /* isQuestion */);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MdnsAnyRecord(String[] name, boolean unicast) {
|
||||||
|
super(name, TYPE_ANY, DnsResolver.CLASS_IN /* cls */,
|
||||||
|
0L /* receiptTimeMillis */, unicast /* cacheFlush */, 0L /* ttlMillis */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readData(MdnsPacketReader reader) throws IOException {
|
||||||
|
// No data to read
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeData(MdnsPacketWriter writer) throws IOException {
|
||||||
|
// No data to write
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,32 @@ public class MdnsInetAddressRecord extends MdnsRecord {
|
|||||||
*/
|
*/
|
||||||
public MdnsInetAddressRecord(String[] name, int type, MdnsPacketReader reader)
|
public MdnsInetAddressRecord(String[] name, int type, MdnsPacketReader reader)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
super(name, type, reader);
|
this(name, type, reader, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the {@link MdnsRecord}
|
||||||
|
*
|
||||||
|
* @param name the service host name
|
||||||
|
* @param type the type of record (either Type 'AAAA' or Type 'A')
|
||||||
|
* @param reader the reader to read the record from.
|
||||||
|
* @param isQuestion whether the record is in the question section
|
||||||
|
*/
|
||||||
|
public MdnsInetAddressRecord(String[] name, int type, MdnsPacketReader reader,
|
||||||
|
boolean isQuestion)
|
||||||
|
throws IOException {
|
||||||
|
super(name, type, reader, isQuestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MdnsInetAddressRecord(String[] name, long receiptTimeMillis, boolean cacheFlush,
|
||||||
|
long ttlMillis, InetAddress address) {
|
||||||
|
super(name, address instanceof Inet4Address ? TYPE_A : TYPE_AAAA,
|
||||||
|
MdnsConstants.QCLASS_INTERNET, receiptTimeMillis, cacheFlush, ttlMillis);
|
||||||
|
if (address instanceof Inet4Address) {
|
||||||
|
inet4Address = (Inet4Address) address;
|
||||||
|
} else {
|
||||||
|
inet6Address = (Inet6Address) address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the IPv6 address. */
|
/** Returns the IPv6 address. */
|
||||||
@@ -127,4 +152,4 @@ public class MdnsInetAddressRecord extends MdnsRecord {
|
|||||||
&& Objects.equals(inet4Address, ((MdnsInetAddressRecord) other).inet4Address)
|
&& Objects.equals(inet4Address, ((MdnsInetAddressRecord) other).inet4Address)
|
||||||
&& Objects.equals(inet6Address, ((MdnsInetAddressRecord) other).inet6Address);
|
&& Objects.equals(inet6Address, ((MdnsInetAddressRecord) other).inet6Address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,19 @@ public class MdnsPointerRecord extends MdnsRecord {
|
|||||||
private String[] pointer;
|
private String[] pointer;
|
||||||
|
|
||||||
public MdnsPointerRecord(String[] name, MdnsPacketReader reader) throws IOException {
|
public MdnsPointerRecord(String[] name, MdnsPacketReader reader) throws IOException {
|
||||||
super(name, TYPE_PTR, reader);
|
this(name, reader, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MdnsPointerRecord(String[] name, MdnsPacketReader reader, boolean isQuestion)
|
||||||
|
throws IOException {
|
||||||
|
super(name, TYPE_PTR, reader, isQuestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MdnsPointerRecord(String[] name, long receiptTimeMillis, boolean cacheFlush,
|
||||||
|
long ttlMillis, String[] pointer) {
|
||||||
|
super(name, TYPE_PTR, MdnsConstants.QCLASS_INTERNET, receiptTimeMillis, cacheFlush,
|
||||||
|
ttlMillis);
|
||||||
|
this.pointer = pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the pointer as an array of labels. */
|
/** Returns the pointer as an array of labels. */
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ public abstract class MdnsRecord {
|
|||||||
public static final int TYPE_PTR = 0x000C;
|
public static final int TYPE_PTR = 0x000C;
|
||||||
public static final int TYPE_SRV = 0x0021;
|
public static final int TYPE_SRV = 0x0021;
|
||||||
public static final int TYPE_TXT = 0x0010;
|
public static final int TYPE_TXT = 0x0010;
|
||||||
|
public static final int TYPE_ANY = 0x00ff;
|
||||||
|
|
||||||
|
private static final int FLAG_CACHE_FLUSH = 0x8000;
|
||||||
|
|
||||||
|
public static final long RECEIPT_TIME_NOT_SENT = 0L;
|
||||||
|
|
||||||
/** Status indicating that the record is current. */
|
/** Status indicating that the record is current. */
|
||||||
public static final int STATUS_OK = 0;
|
public static final int STATUS_OK = 0;
|
||||||
@@ -54,6 +59,33 @@ public abstract class MdnsRecord {
|
|||||||
private final long ttlMillis;
|
private final long ttlMillis;
|
||||||
private Object key;
|
private Object key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new record with the given name and type.
|
||||||
|
*
|
||||||
|
* @param reader The reader to read the record from.
|
||||||
|
* @param isQuestion Whether the record was included in the questions part of the message.
|
||||||
|
* @throws IOException If an error occurs while reading the packet.
|
||||||
|
*/
|
||||||
|
protected MdnsRecord(String[] name, int type, MdnsPacketReader reader, boolean isQuestion)
|
||||||
|
throws IOException {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
cls = reader.readUInt16();
|
||||||
|
receiptTimeMillis = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
|
if (isQuestion) {
|
||||||
|
// Questions do not have TTL or data
|
||||||
|
ttlMillis = 0L;
|
||||||
|
} else {
|
||||||
|
ttlMillis = SECONDS.toMillis(reader.readUInt32());
|
||||||
|
int dataLength = reader.readUInt16();
|
||||||
|
|
||||||
|
reader.setLimit(dataLength);
|
||||||
|
readData(reader);
|
||||||
|
reader.clearLimit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new record with the given name and type.
|
* Constructs a new record with the given name and type.
|
||||||
*
|
*
|
||||||
@@ -64,17 +96,19 @@ public abstract class MdnsRecord {
|
|||||||
// receiver.
|
// receiver.
|
||||||
@SuppressWarnings("nullness:method.invocation.invalid")
|
@SuppressWarnings("nullness:method.invocation.invalid")
|
||||||
protected MdnsRecord(String[] name, int type, MdnsPacketReader reader) throws IOException {
|
protected MdnsRecord(String[] name, int type, MdnsPacketReader reader) throws IOException {
|
||||||
|
this(name, type, reader, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new record with the given properties.
|
||||||
|
*/
|
||||||
|
protected MdnsRecord(String[] name, int type, int cls, long receiptTimeMillis,
|
||||||
|
boolean cacheFlush, long ttlMillis) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
cls = reader.readUInt16();
|
this.cls = cls | (cacheFlush ? FLAG_CACHE_FLUSH : 0);
|
||||||
ttlMillis = SECONDS.toMillis(reader.readUInt32());
|
this.receiptTimeMillis = receiptTimeMillis;
|
||||||
int dataLength = reader.readUInt16();
|
this.ttlMillis = ttlMillis;
|
||||||
|
|
||||||
receiptTimeMillis = SystemClock.elapsedRealtime();
|
|
||||||
|
|
||||||
reader.setLimit(dataLength);
|
|
||||||
readData(reader);
|
|
||||||
reader.clearLimit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,13 +160,29 @@ public abstract class MdnsRecord {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return the record's class. */
|
||||||
|
public final int getRecordClass() {
|
||||||
|
return cls & ~FLAG_CACHE_FLUSH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return whether the cache flush flag is set. */
|
||||||
|
public final boolean getCacheFlush() {
|
||||||
|
return (cls & FLAG_CACHE_FLUSH) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the record's remaining TTL.
|
* Returns the record's remaining TTL.
|
||||||
*
|
*
|
||||||
|
* If the record was not sent yet (receipt time {@link #RECEIPT_TIME_NOT_SENT}), this is the
|
||||||
|
* original TTL of the record.
|
||||||
* @param now The current system time.
|
* @param now The current system time.
|
||||||
* @return The remaning TTL, in milliseconds.
|
* @return The remaning TTL, in milliseconds.
|
||||||
*/
|
*/
|
||||||
public long getRemainingTTL(final long now) {
|
public long getRemainingTTL(final long now) {
|
||||||
|
if (receiptTimeMillis == RECEIPT_TIME_NOT_SENT) {
|
||||||
|
return ttlMillis;
|
||||||
|
}
|
||||||
|
|
||||||
long age = now - receiptTimeMillis;
|
long age = now - receiptTimeMillis;
|
||||||
if (age > ttlMillis) {
|
if (age > ttlMillis) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -187,6 +237,9 @@ public abstract class MdnsRecord {
|
|||||||
|
|
||||||
/** Gets the status of the record. */
|
/** Gets the status of the record. */
|
||||||
public int getStatus(final long now) {
|
public int getStatus(final long now) {
|
||||||
|
if (receiptTimeMillis == RECEIPT_TIME_NOT_SENT) {
|
||||||
|
return STATUS_OK;
|
||||||
|
}
|
||||||
final long age = now - receiptTimeMillis;
|
final long age = now - receiptTimeMillis;
|
||||||
if (age > ttlMillis) {
|
if (age > ttlMillis) {
|
||||||
return STATUS_EXPIRED;
|
return STATUS_EXPIRED;
|
||||||
|
|||||||
@@ -39,7 +39,23 @@ public class MdnsServiceRecord extends MdnsRecord {
|
|||||||
private String[] serviceHost;
|
private String[] serviceHost;
|
||||||
|
|
||||||
public MdnsServiceRecord(String[] name, MdnsPacketReader reader) throws IOException {
|
public MdnsServiceRecord(String[] name, MdnsPacketReader reader) throws IOException {
|
||||||
super(name, TYPE_SRV, reader);
|
this(name, reader, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MdnsServiceRecord(String[] name, MdnsPacketReader reader, boolean isQuestion)
|
||||||
|
throws IOException {
|
||||||
|
super(name, TYPE_SRV, reader, isQuestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MdnsServiceRecord(String[] name, long receiptTimeMillis, boolean cacheFlush,
|
||||||
|
long ttlMillis, int servicePriority, int serviceWeight, int servicePort,
|
||||||
|
String[] serviceHost) {
|
||||||
|
super(name, TYPE_SRV, MdnsConstants.QCLASS_INTERNET, receiptTimeMillis, cacheFlush,
|
||||||
|
ttlMillis);
|
||||||
|
this.servicePriority = servicePriority;
|
||||||
|
this.serviceWeight = serviceWeight;
|
||||||
|
this.servicePort = servicePort;
|
||||||
|
this.serviceHost = serviceHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the service's port number. */
|
/** Returns the service's port number. */
|
||||||
|
|||||||
@@ -33,7 +33,19 @@ public class MdnsTextRecord extends MdnsRecord {
|
|||||||
private List<TextEntry> entries;
|
private List<TextEntry> entries;
|
||||||
|
|
||||||
public MdnsTextRecord(String[] name, MdnsPacketReader reader) throws IOException {
|
public MdnsTextRecord(String[] name, MdnsPacketReader reader) throws IOException {
|
||||||
super(name, TYPE_TXT, reader);
|
this(name, reader, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MdnsTextRecord(String[] name, MdnsPacketReader reader, boolean isQuestion)
|
||||||
|
throws IOException {
|
||||||
|
super(name, TYPE_TXT, reader, isQuestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MdnsTextRecord(String[] name, long receiptTimeMillis, boolean cacheFlush, long ttlMillis,
|
||||||
|
List<TextEntry> entries) {
|
||||||
|
super(name, TYPE_TXT, MdnsConstants.QCLASS_INTERNET, receiptTimeMillis, cacheFlush,
|
||||||
|
ttlMillis);
|
||||||
|
this.entries = entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the list of strings. */
|
/** Returns the list of strings. */
|
||||||
|
|||||||
@@ -79,14 +79,7 @@ public class MdnsRecordTests {
|
|||||||
Inet4Address addr = record.getInet4Address();
|
Inet4Address addr = record.getInet4Address();
|
||||||
assertEquals("/10.1.2.3", addr.toString());
|
assertEquals("/10.1.2.3", addr.toString());
|
||||||
|
|
||||||
// Encode
|
String dataOutText = toHex(record);
|
||||||
MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
|
|
||||||
record.write(writer, record.getReceiptTime());
|
|
||||||
|
|
||||||
packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
|
|
||||||
byte[] dataOut = packet.getData();
|
|
||||||
|
|
||||||
String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
|
|
||||||
Log.d(TAG, dataOutText);
|
Log.d(TAG, dataOutText);
|
||||||
|
|
||||||
assertEquals(dataInText, dataOutText);
|
assertEquals(dataInText, dataOutText);
|
||||||
@@ -123,14 +116,7 @@ public class MdnsRecordTests {
|
|||||||
Inet6Address addr = record.getInet6Address();
|
Inet6Address addr = record.getInet6Address();
|
||||||
assertEquals("/aabb:ccdd:1122:3344:a0b0:c0d0:1020:3040", addr.toString());
|
assertEquals("/aabb:ccdd:1122:3344:a0b0:c0d0:1020:3040", addr.toString());
|
||||||
|
|
||||||
// Encode
|
String dataOutText = toHex(record);
|
||||||
MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
|
|
||||||
record.write(writer, record.getReceiptTime());
|
|
||||||
|
|
||||||
packet = writer.getPacket(MULTICAST_IPV6_ADDRESS);
|
|
||||||
byte[] dataOut = packet.getData();
|
|
||||||
|
|
||||||
String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
|
|
||||||
Log.d(TAG, dataOutText);
|
Log.d(TAG, dataOutText);
|
||||||
|
|
||||||
assertEquals(dataInText, dataOutText);
|
assertEquals(dataInText, dataOutText);
|
||||||
@@ -167,14 +153,7 @@ public class MdnsRecordTests {
|
|||||||
Inet4Address addr = record.getInet4Address();
|
Inet4Address addr = record.getInet4Address();
|
||||||
assertEquals("/16.32.48.64", addr.toString());
|
assertEquals("/16.32.48.64", addr.toString());
|
||||||
|
|
||||||
// Encode
|
String dataOutText = toHex(record);
|
||||||
MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
|
|
||||||
record.write(writer, record.getReceiptTime());
|
|
||||||
|
|
||||||
packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
|
|
||||||
byte[] dataOut = packet.getData();
|
|
||||||
|
|
||||||
String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
|
|
||||||
Log.d(TAG, dataOutText);
|
Log.d(TAG, dataOutText);
|
||||||
|
|
||||||
final byte[] expectedDataIn =
|
final byte[] expectedDataIn =
|
||||||
@@ -215,14 +194,7 @@ public class MdnsRecordTests {
|
|||||||
assertFalse(record.hasSubtype());
|
assertFalse(record.hasSubtype());
|
||||||
assertNull(record.getSubtype());
|
assertNull(record.getSubtype());
|
||||||
|
|
||||||
// Encode
|
String dataOutText = toHex(record);
|
||||||
MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
|
|
||||||
record.write(writer, record.getReceiptTime());
|
|
||||||
|
|
||||||
packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
|
|
||||||
byte[] dataOut = packet.getData();
|
|
||||||
|
|
||||||
String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
|
|
||||||
Log.d(TAG, dataOutText);
|
Log.d(TAG, dataOutText);
|
||||||
|
|
||||||
assertEquals(dataInText, dataOutText);
|
assertEquals(dataInText, dataOutText);
|
||||||
@@ -263,14 +235,35 @@ public class MdnsRecordTests {
|
|||||||
assertEquals(1, record.getServicePriority());
|
assertEquals(1, record.getServicePriority());
|
||||||
assertEquals(255, record.getServiceWeight());
|
assertEquals(255, record.getServiceWeight());
|
||||||
|
|
||||||
// Encode
|
String dataOutText = toHex(record);
|
||||||
MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
|
Log.d(TAG, dataOutText);
|
||||||
record.write(writer, record.getReceiptTime());
|
|
||||||
|
|
||||||
packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
|
assertEquals(dataInText, dataOutText);
|
||||||
byte[] dataOut = packet.getData();
|
}
|
||||||
|
|
||||||
String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
|
@Test
|
||||||
|
public void testAnyRecord() throws IOException {
|
||||||
|
final byte[] dataIn = HexDump.hexStringToByteArray(
|
||||||
|
"047465737407616E64726F696403636F6D0000FF0001000000000000");
|
||||||
|
assertNotNull(dataIn);
|
||||||
|
String dataInText = HexDump.dumpHexString(dataIn, 0, dataIn.length);
|
||||||
|
|
||||||
|
// Decode
|
||||||
|
DatagramPacket packet = new DatagramPacket(dataIn, dataIn.length);
|
||||||
|
MdnsPacketReader reader = new MdnsPacketReader(packet);
|
||||||
|
|
||||||
|
String[] name = reader.readLabels();
|
||||||
|
assertNotNull(name);
|
||||||
|
assertEquals(3, name.length);
|
||||||
|
String fqdn = MdnsRecord.labelsToString(name);
|
||||||
|
assertEquals("test.android.com", fqdn);
|
||||||
|
|
||||||
|
int type = reader.readUInt16();
|
||||||
|
assertEquals(MdnsRecord.TYPE_ANY, type);
|
||||||
|
|
||||||
|
MdnsAnyRecord record = new MdnsAnyRecord(name, reader);
|
||||||
|
|
||||||
|
String dataOutText = toHex(record);
|
||||||
Log.d(TAG, dataOutText);
|
Log.d(TAG, dataOutText);
|
||||||
|
|
||||||
assertEquals(dataInText, dataOutText);
|
assertEquals(dataInText, dataOutText);
|
||||||
@@ -320,19 +313,23 @@ public class MdnsRecordTests {
|
|||||||
assertEquals(new TextEntry("b", "1234567890"), entries.get(1));
|
assertEquals(new TextEntry("b", "1234567890"), entries.get(1));
|
||||||
assertEquals(new TextEntry("xyz", "!@#$"), entries.get(2));
|
assertEquals(new TextEntry("xyz", "!@#$"), entries.get(2));
|
||||||
|
|
||||||
// Encode
|
String dataOutText = toHex(record);
|
||||||
MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
|
|
||||||
record.write(writer, record.getReceiptTime());
|
|
||||||
|
|
||||||
packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
|
|
||||||
byte[] dataOut = packet.getData();
|
|
||||||
|
|
||||||
String dataOutText = HexDump.dumpHexString(dataOut, 0, packet.getLength());
|
|
||||||
Log.d(TAG, dataOutText);
|
Log.d(TAG, dataOutText);
|
||||||
|
|
||||||
assertEquals(dataInText, dataOutText);
|
assertEquals(dataInText, dataOutText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String toHex(MdnsRecord record) throws IOException {
|
||||||
|
MdnsPacketWriter writer = new MdnsPacketWriter(MAX_PACKET_SIZE);
|
||||||
|
record.write(writer, record.getReceiptTime());
|
||||||
|
|
||||||
|
// The address does not matter as only the data is used
|
||||||
|
final DatagramPacket packet = writer.getPacket(MULTICAST_IPV4_ADDRESS);
|
||||||
|
final byte[] dataOut = packet.getData();
|
||||||
|
|
||||||
|
return HexDump.dumpHexString(dataOut, 0, packet.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void textRecord_recordDoesNotHaveDataOfGivenLength_throwsEOFException()
|
public void textRecord_recordDoesNotHaveDataOfGivenLength_throwsEOFException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user