280 lines
10 KiB
Kotlin
280 lines
10 KiB
Kotlin
/*
|
||
* Copyright 2020 dorkbox, llc
|
||
*
|
||
* 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.
|
||
*
|
||
* Copyright (c) 2008, Nathan Sweet
|
||
* All rights reserved.
|
||
*
|
||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
|
||
* conditions are met:
|
||
*
|
||
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
||
* disclaimer in the documentation and/or other materials provided with the distribution.
|
||
* - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
|
||
* from this software without specific prior written permission.
|
||
*
|
||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
*/
|
||
package dorkboxTest.network
|
||
|
||
import dorkbox.network.Client
|
||
import dorkbox.network.Server
|
||
import dorkbox.network.connection.Connection
|
||
import dorkbox.network.serialization.Serialization
|
||
import org.junit.Assert
|
||
import org.junit.Test
|
||
import java.util.concurrent.atomic.*
|
||
|
||
class PingPongTest : BaseTest() {
|
||
@Volatile
|
||
private var fail: String? = null
|
||
var tries = 1000
|
||
|
||
@Test
|
||
fun pingPong() {
|
||
fail = "Data not received."
|
||
val data = Data()
|
||
populateData(data)
|
||
|
||
run {
|
||
val config = serverConfig()
|
||
register(config.serialization)
|
||
|
||
|
||
val server: Server<Connection> = Server(config)
|
||
addEndPoint(server)
|
||
server.bind()
|
||
|
||
server.onError { throwable ->
|
||
fail = "Error during processing. $throwable"
|
||
}
|
||
|
||
server.onConnect {
|
||
this.logger.error("server connection: $this")
|
||
}
|
||
|
||
server.onMessage<Data> { message ->
|
||
send(message)
|
||
}
|
||
}
|
||
|
||
|
||
run {
|
||
val config = clientConfig()
|
||
|
||
val client: Client<Connection> = Client(config)
|
||
addEndPoint(client)
|
||
|
||
|
||
client.onConnect {
|
||
logger.error("client connection: $this")
|
||
|
||
fail = null
|
||
send(data)
|
||
}
|
||
|
||
client.onError { throwable ->
|
||
fail = "Error during processing. $throwable"
|
||
throwable.printStackTrace()
|
||
}
|
||
|
||
val counter = AtomicInteger(0)
|
||
client.onMessage<Data> { _ ->
|
||
if (counter.getAndIncrement() <= tries) {
|
||
send(data)
|
||
} else {
|
||
logger.error("done.")
|
||
logger.error("Ran $tries times")
|
||
stopEndPoints()
|
||
}
|
||
}
|
||
|
||
client.connect(LOCALHOST)
|
||
}
|
||
|
||
|
||
waitForThreads()
|
||
|
||
|
||
if (fail != null) {
|
||
Assert.fail(fail)
|
||
}
|
||
}
|
||
|
||
private fun register(manager: Serialization<*>) {
|
||
manager.register(Data::class.java)
|
||
}
|
||
|
||
class Data {
|
||
var string: String? = null
|
||
var strings = arrayOf<String>()
|
||
|
||
var ints = IntArray(0)
|
||
var shorts = ShortArray(0)
|
||
var floats = FloatArray(0)
|
||
var doubles = DoubleArray(0)
|
||
var longs = LongArray(0)
|
||
var bytes = ByteArray(0)
|
||
var chars = CharArray(0)
|
||
var booleans = BooleanArray(0)
|
||
|
||
var Ints = Array(0) { 0 }
|
||
var Shorts = Array(0) { 0.toShort() }
|
||
var Floats = Array(0) { 0F }
|
||
var Doubles = Array(0) { 0.0 }
|
||
var Longs = Array(0) { 0L }
|
||
var Bytes = Array(0) { 0.toByte() }
|
||
var Chars = Array(0) { 'a' }
|
||
var Booleans = Array(0) { false }
|
||
|
||
override fun hashCode(): Int {
|
||
val prime = 31
|
||
var result = 1
|
||
result = prime * result + Booleans.contentHashCode()
|
||
result = prime * result + Bytes.contentHashCode()
|
||
result = prime * result + Chars.contentHashCode()
|
||
result = prime * result + Doubles.contentHashCode()
|
||
result = prime * result + Floats.contentHashCode()
|
||
result = prime * result + Ints.contentHashCode()
|
||
result = prime * result + Longs.contentHashCode()
|
||
result = prime * result + Shorts.contentHashCode()
|
||
result = prime * result + booleans.contentHashCode()
|
||
result = prime * result + bytes.contentHashCode()
|
||
result = prime * result + chars.contentHashCode()
|
||
result = prime * result + doubles.contentHashCode()
|
||
result = prime * result + floats.contentHashCode()
|
||
result = prime * result + ints.contentHashCode()
|
||
result = prime * result + longs.contentHashCode()
|
||
result = prime * result + shorts.contentHashCode()
|
||
result = prime * result + if (string == null) 0 else string.hashCode()
|
||
result = prime * result + strings.contentHashCode()
|
||
return result
|
||
}
|
||
|
||
override fun equals(other: Any?): Boolean {
|
||
if (this === other) {
|
||
return true
|
||
}
|
||
|
||
if (other == null) {
|
||
return false
|
||
}
|
||
|
||
if (javaClass != other.javaClass) {
|
||
return false
|
||
}
|
||
|
||
other as Data
|
||
if (!Booleans.contentEquals(other.Booleans)) {
|
||
return false
|
||
}
|
||
if (!Bytes.contentEquals(other.Bytes)) {
|
||
return false
|
||
}
|
||
if (!Chars.contentEquals(other.Chars)) {
|
||
return false
|
||
}
|
||
if (!Doubles.contentEquals(other.Doubles)) {
|
||
return false
|
||
}
|
||
if (!Floats.contentEquals(other.Floats)) {
|
||
return false
|
||
}
|
||
if (!Ints.contentEquals(other.Ints)) {
|
||
return false
|
||
}
|
||
if (!Longs.contentEquals(other.Longs)) {
|
||
return false
|
||
}
|
||
if (!Shorts.contentEquals(other.Shorts)) {
|
||
return false
|
||
}
|
||
if (!booleans.contentEquals(other.booleans)) {
|
||
return false
|
||
}
|
||
if (!bytes.contentEquals(other.bytes)) {
|
||
return false
|
||
}
|
||
if (!chars.contentEquals(other.chars)) {
|
||
return false
|
||
}
|
||
if (!doubles.contentEquals(other.doubles)) {
|
||
return false
|
||
}
|
||
if (!floats.contentEquals(other.floats)) {
|
||
return false
|
||
}
|
||
if (!ints.contentEquals(other.ints)) {
|
||
return false
|
||
}
|
||
if (!longs.contentEquals(other.longs)) {
|
||
return false
|
||
}
|
||
if (!shorts.contentEquals(other.shorts)) {
|
||
return false
|
||
}
|
||
if (string == null) {
|
||
if (other.string != null) {
|
||
return false
|
||
}
|
||
} else if (string != other.string) {
|
||
return false
|
||
}
|
||
|
||
if (!strings.contentEquals(other.strings)) {
|
||
return false
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
override fun toString(): String {
|
||
return "Data"
|
||
}
|
||
}
|
||
|
||
companion object {
|
||
private fun populateData(data: Data) {
|
||
val buffer = StringBuilder(3001)
|
||
for (i in 0..2999) {
|
||
buffer.append('a')
|
||
}
|
||
data.string = buffer.toString()
|
||
data.strings = arrayOf("abcdefghijklmnopqrstuvwxyz0123456789", "", "!@#$", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")
|
||
data.ints = intArrayOf(-1234567, 1234567, -1, 0, 1, Int.MAX_VALUE, Int.MIN_VALUE)
|
||
data.shorts = shortArrayOf(-12345, 12345, -1, 0, 1, Short.MAX_VALUE, Short.MIN_VALUE)
|
||
data.floats = floatArrayOf(0f, -0f, 1f, -1f, 123456f, -123456f, 0.1f, 0.2f, -0.3f, Math.PI.toFloat(), Float.MAX_VALUE, Float.MIN_VALUE)
|
||
data.doubles = doubleArrayOf(0.0, -0.0, 1.0, -1.0, 123456.0, -123456.0, 0.1, 0.2, -0.3, Math.PI, Double.MAX_VALUE, Double.MIN_VALUE)
|
||
data.longs = longArrayOf(0, -0, 1, -1, 123456, -123456, 99999999999L, -99999999999L, Long.MAX_VALUE, Long.MIN_VALUE)
|
||
data.bytes = byteArrayOf(-123, 123, -1, 0, 1, Byte.MAX_VALUE, Byte.MIN_VALUE)
|
||
data.chars = charArrayOf(32345.toChar(), 12345.toChar(), 0.toChar(), 1.toChar(), 63.toChar(), Character.MAX_VALUE, Character.MIN_VALUE)
|
||
data.booleans = booleanArrayOf(true, false)
|
||
data.Ints = arrayOf(-1234567, 1234567, -1, 0, 1, Int.MAX_VALUE, Int.MIN_VALUE)
|
||
data.Shorts = arrayOf(-12345, 12345, -1, 0, 1, Short.MAX_VALUE, Short.MIN_VALUE)
|
||
data.Floats = arrayOf(0f, -0f, 1.0f, -1f, 123456f, -123456f, 0.1f, 0.2f, -0.3f, Math.PI.toFloat(), Float.MAX_VALUE, Float.MIN_VALUE)
|
||
data.Doubles = arrayOf(0.0, -0.0, 1.0, -1.0, 123456.0, -123456.0, 0.1, 0.2, -0.3, Math.PI, Double.MAX_VALUE, Double.MIN_VALUE)
|
||
data.Longs = arrayOf(0L, -0L, 1L, -1L, 123456L, -123456L, 99999999999L, -99999999999L, Long.MAX_VALUE, Long.MIN_VALUE)
|
||
data.Bytes = arrayOf(-123, 123, -1, 0, 1, Byte.MAX_VALUE, Byte.MIN_VALUE)
|
||
data.Chars = arrayOf(32345.toChar(), 12345.toChar(), 0.toChar(), 1.toChar(), 63.toChar(), Character.MAX_VALUE, Character.MIN_VALUE)
|
||
data.Booleans = arrayOf(true, false)
|
||
}
|
||
}
|
||
}
|