diff --git a/common/build.gradle b/common/build.gradle index bce2aea..19a1ef1 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -4,6 +4,8 @@ apply from: '../dependencies.gradle' dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin" + testImplementation "org.junit.jupiter:junit-jupiter:$versions.junit5" + testImplementation "com.google.truth:truth:$versions.truth" } repositories { diff --git a/common/src/main/java/com/kaspresky/test_server/log/LoggerEmptyImpl.kt b/common/src/main/java/com/kaspresky/test_server/log/LoggerEmptyImpl.kt deleted file mode 100644 index 5597e3f..0000000 --- a/common/src/main/java/com/kaspresky/test_server/log/LoggerEmptyImpl.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.kaspresky.test_server.log - -import java.lang.Exception - -internal class LoggerEmptyImpl : Logger { - - override fun i(tag: String, text: String) = Unit - - override fun i(tag: String, method: String, text: String) = Unit - - override fun d(tag: String, text: String) = Unit - - override fun d(tag: String, method: String, text: String) = Unit - - override fun e(tag: String, exception: Exception) = Unit - - override fun e(tag: String, method: String, exception: Exception) = Unit -} \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/LoggerFactory.kt b/common/src/main/java/com/kaspresky/test_server/log/LoggerFactory.kt index 898ce91..7630754 100644 --- a/common/src/main/java/com/kaspresky/test_server/log/LoggerFactory.kt +++ b/common/src/main/java/com/kaspresky/test_server/log/LoggerFactory.kt @@ -1,11 +1,18 @@ package com.kaspresky.test_server.log +import com.kaspresky.test_server.log.full_logger.FullLogger +import com.kaspresky.test_server.log.full_logger.FullLoggerFilteringByDeviceProvider +import com.kaspresky.test_server.log.logger.Logger +import com.kaspresky.test_server.log.logger.LoggerImpl + /** * The singleton to provide Logger interface and to hide an implementation */ object LoggerFactory { - fun emptyLogger(): Logger = LoggerEmptyImpl() + private val fullLogger: FullLogger = + FullLoggerFilteringByDeviceProvider() - fun systemLogger(): Logger = LoggerSystemImpl() + fun getLogger(tag: String, deviceName: String? = null): Logger = + LoggerImpl(tag, deviceName, fullLogger) } \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/LoggerSystemImpl.kt b/common/src/main/java/com/kaspresky/test_server/log/LoggerSystemImpl.kt deleted file mode 100644 index 316f9c1..0000000 --- a/common/src/main/java/com/kaspresky/test_server/log/LoggerSystemImpl.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.kaspresky.test_server.log - -import java.lang.Exception - -/** - * Presents logs in next form: - * INFO:_____tag=ConnectionMaker_________________________method=connect()_______________________________message => start - * INFO:_____tag=ConnectionMaker_________________________method=connect()_______________________________message => current state=DISCONNECTED - */ -internal class LoggerSystemImpl : Logger { - - companion object { - private const val COMMON_FIELD_LENGTH = 40 - private const val TAG = "tag=" - private const val METHOD = "method=" - private const val MESSAGE = "message => " - } - - override fun i(tag: String, text: String) { - System.out.println("INFO:_____${getShortMessage(tag, text)}") - } - - override fun i(tag: String, method: String, text: String) { - System.out.println("INFO:_____${getLongMessage(tag, method, text)}") - } - - override fun d(tag: String, text: String) { - System.out.println("DEBUG:____${getShortMessage(tag, text)}") - } - - override fun d(tag: String, method: String, text: String) { - System.out.println("DEBUG:____${getLongMessage(tag, method, text)}") - } - - override fun e(tag: String, exception: Exception) { - System.err.println("ERROR:____${getShortMessage(tag, exception)}") - } - - override fun e(tag: String, method: String, exception: Exception) { - System.err.println("ERROR:____${getLongMessage(tag, method, exception)}") - } - - private fun getShortMessage(tag: String, message: Any): String = - "$TAG${getFieldString(tag)}$MESSAGE$message" - - private fun getLongMessage(tag: String, method: String, message: Any) = - "$TAG${getFieldString(tag)}$METHOD${getFieldString(method)}$MESSAGE$message" - - private fun getFieldString(text: String): String { - if (text.length > COMMON_FIELD_LENGTH) { - return text + "_" - } - return text + "_".repeat(COMMON_FIELD_LENGTH - text.length) - } -} \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/filter_log/FullLoggerOptimiser.kt b/common/src/main/java/com/kaspresky/test_server/log/filter_log/FullLoggerOptimiser.kt new file mode 100644 index 0000000..d50f992 --- /dev/null +++ b/common/src/main/java/com/kaspresky/test_server/log/filter_log/FullLoggerOptimiser.kt @@ -0,0 +1,73 @@ +package com.kaspresky.test_server.log.filter_log + +import com.kaspresky.test_server.log.full_logger.FullLogger +import java.util.ArrayDeque +import java.util.Deque + +internal class FullLoggerOptimiser( + private val originalFullLogger: FullLogger, + recordingStackMaxSize: Int = DEFAULT_RECORDING_STACK_MAX_SIZE +) : FullLogger { + + private companion object { + private const val SLASH_AT_THE_BEGINNING: Int = 40 + private const val SLASH_AT_THE_END: Int = 100 + private const val DEFAULT_RECORDING_STACK_MAX_SIZE: Int = 200 + } + + private val logStack: Deque = ArrayDeque() + private var logRecorder: LogRecorder = LogRecorder(recordingStackMaxSize) + + override fun log( + logType: FullLogger.LogType?, + deviceName: String?, + tag: String?, + method: String?, + text: String? + ) { + handleLog( + key = "$logType$deviceName$tag$method$text", + action = { originalFullLogger.log(logType, deviceName, tag, method, text) } + ) + } + + private fun handleLog(key: String, action: () -> Unit) { + val logData = LogData(key, action) + val position = logStack.indexOf(logData) + val answer = logRecorder.put(position, LogData(key, action)) + when (answer) { + is RecordInProgress -> { return } + is ReadyRecord -> { + outputRecord(answer) + updateState(answer) + } + } + } + + private fun outputRecord(readyRecord: ReadyRecord) { + // prepare the first and the last log for recorded Fragment if it's needed + var fragmentStartString: String? = null + var fragmentEndString: String? = null + if (readyRecord.countOfRecordingStack > 0) { + fragmentStartString = "/".repeat(SLASH_AT_THE_BEGINNING) + + "FRAGMENT IS REPEATED ${readyRecord.countOfRecordingStack} TIMES" + + "/".repeat(SLASH_AT_THE_BEGINNING) + fragmentEndString = "/".repeat(SLASH_AT_THE_END) + } + // output record + fragmentStartString?.let { originalFullLogger.log(text = fragmentStartString) } + readyRecord.recordingStack.descendingIterator().forEach { it.logOutput.invoke() } + fragmentEndString?.let { originalFullLogger.log(text = fragmentEndString) } + // output remained part + readyRecord.remainedStack.descendingIterator().forEach { it.logOutput.invoke() } + } + + private fun updateState(readyRecord: ReadyRecord) { + if (readyRecord.recordingStack.isNotEmpty()) { + logStack.clear() + } + readyRecord.remainedStack.descendingIterator().forEach { + logStack.addFirst(it) + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/filter_log/LogData.kt b/common/src/main/java/com/kaspresky/test_server/log/filter_log/LogData.kt new file mode 100644 index 0000000..821563e --- /dev/null +++ b/common/src/main/java/com/kaspresky/test_server/log/filter_log/LogData.kt @@ -0,0 +1,24 @@ +package com.kaspresky.test_server.log.filter_log + +internal class LogData( + val logMessage: String, + val logOutput: () -> Unit +) { + + override fun equals(other: Any?): Boolean { + if (other == null) { + return false + } + if (this === other) { + return true + } + if (other is LogData) { + return this.logMessage == other.logMessage + } + return false + } + + override fun hashCode(): Int { + return logMessage.hashCode() + } +} \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/filter_log/LogRecorder.kt b/common/src/main/java/com/kaspresky/test_server/log/filter_log/LogRecorder.kt new file mode 100644 index 0000000..4c9a506 --- /dev/null +++ b/common/src/main/java/com/kaspresky/test_server/log/filter_log/LogRecorder.kt @@ -0,0 +1,101 @@ +package com.kaspresky.test_server.log.filter_log + +import java.util.ArrayDeque +import java.util.Deque + +internal class LogRecorder( + private val recordingStackMaxSize: Int +) { + + companion object { + private const val UNBOUND_INDEX: Int = -1 + } + + private var forecastedPositionAtInitialStack: Int = UNBOUND_INDEX + private var recordingStackSize: Int = 0 + // last log is at the first position + private val recordingStack: Deque = ArrayDeque() + private var countOfRecordingStack: Int = 0 + private var state: State = State.NO_RECORDING + + /** + * @param foundPosition index of last found logData + * @param logData found LogData + */ + @SuppressWarnings("detekt.ReturnCount") + fun put(foundPosition: Int, logData: LogData): RecordAnswer { + if (state == State.NO_RECORDING && foundPosition == UNBOUND_INDEX) { + return getSingleUniqueRecord(logData) + } + if (state == State.NO_RECORDING) { + startRecording(foundPosition) + } + if (foundPosition != forecastedPositionAtInitialStack) { + val record = getRecord(logData) + resetState() + return record + } + addNewLogToStack(logData) + if (countOfRecordingStack >= recordingStackMaxSize) { + val record = getRecord(null) + resetState() + return record + } + return RecordInProgress() + } + + private fun getSingleUniqueRecord(logData: LogData): ReadyRecord { + val remainedStack: Deque = ArrayDeque() + remainedStack.addFirst(logData) + return ReadyRecord( + recordingStack = ArrayDeque(), + countOfRecordingStack = 0, + remainedStack = remainedStack + ) + } + + private fun startRecording(foundPosition: Int) { + state = State.RECORDING + recordingStackSize = foundPosition + 1 + forecastedPositionAtInitialStack = recordingStackSize - 1 + } + + private fun getRecord(newLog: LogData? = null): RecordAnswer { + val remainedStack: Deque = ArrayDeque() + newLog?.let { remainedStack.addFirst(newLog) } + if (forecastedPositionAtInitialStack > UNBOUND_INDEX) { + recordingStack + .filterIndexed { index, _ -> index > forecastedPositionAtInitialStack } + .forEachIndexed { _, logData -> remainedStack.addLast(logData) } + } + return ReadyRecord( + recordingStack = ArrayDeque(recordingStack), + countOfRecordingStack = countOfRecordingStack, + remainedStack = remainedStack + ) + } + + private fun resetState() { + forecastedPositionAtInitialStack = UNBOUND_INDEX + recordingStackSize = 0 + recordingStack.clear() + countOfRecordingStack = 0 + state = State.NO_RECORDING + } + + private fun addNewLogToStack(logData: LogData) { + if (countOfRecordingStack == 0) { + recordingStack.addFirst(logData) + } + forecastedPositionAtInitialStack-- + if (forecastedPositionAtInitialStack == UNBOUND_INDEX) { + countOfRecordingStack++ + forecastedPositionAtInitialStack = recordingStackSize - 1 + } + } + + private enum class State { + RECORDING, + NO_RECORDING + } +} \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/filter_log/RecordAnswers.kt b/common/src/main/java/com/kaspresky/test_server/log/filter_log/RecordAnswers.kt new file mode 100644 index 0000000..1ceca16 --- /dev/null +++ b/common/src/main/java/com/kaspresky/test_server/log/filter_log/RecordAnswers.kt @@ -0,0 +1,22 @@ +package com.kaspresky.test_server.log.filter_log + +import java.util.Deque + +internal interface RecordAnswer + +internal class RecordInProgress : RecordAnswer + +internal data class ReadyRecord( + /** + * last log is at the first position + */ + val recordingStack: Deque, + /** + * The count of recordingStack + */ + val countOfRecordingStack: Int = 0, + /** + * last log is at the first position + */ + val remainedStack: Deque +) : RecordAnswer \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLogger.kt b/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLogger.kt new file mode 100644 index 0000000..f41851d --- /dev/null +++ b/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLogger.kt @@ -0,0 +1,18 @@ +package com.kaspresky.test_server.log.full_logger + +internal interface FullLogger { + + fun log( + logType: LogType? = null, + deviceName: String? = null, + tag: String? = null, + method: String? = null, + text: String? = null + ) + + enum class LogType { + INFO, + DEBUG, + ERROR + } +} diff --git a/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLoggerFilteringByDeviceProvider.kt b/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLoggerFilteringByDeviceProvider.kt new file mode 100644 index 0000000..b4e7f11 --- /dev/null +++ b/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLoggerFilteringByDeviceProvider.kt @@ -0,0 +1,29 @@ +package com.kaspresky.test_server.log.full_logger + +import com.kaspresky.test_server.log.filter_log.FullLoggerOptimiser + +internal class FullLoggerFilteringByDeviceProvider : FullLogger { + + private val loggersMap: MutableMap = hashMapOf() + + override fun log( + logType: FullLogger.LogType?, + deviceName: String?, + tag: String?, + method: String?, + text: String? + ) { + getFullLogger(deviceName).log(logType, deviceName, tag, method, text) + } + + private fun getFullLogger(deviceName: String?): FullLogger { + if (loggersMap.containsKey(deviceName)) { + return loggersMap[deviceName] ?: throw RuntimeException("It's unbelievable!") + } + val fullLogger = FullLoggerOptimiser( + FullLoggerSystemImpl() + ) + loggersMap[deviceName] = fullLogger + return fullLogger + } +} \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLoggerSystemImpl.kt b/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLoggerSystemImpl.kt new file mode 100644 index 0000000..03815d6 --- /dev/null +++ b/common/src/main/java/com/kaspresky/test_server/log/full_logger/FullLoggerSystemImpl.kt @@ -0,0 +1,56 @@ +package com.kaspresky.test_server.log.full_logger + +/** + * Presents logs in the form like: + * INFO:_____tag=ConnectionMaker____________method=connect()_________________message => start + * INFO:_____tag=ConnectionMaker____________method=connect()_________________message => current state=DISCONNECTED + */ +internal class FullLoggerSystemImpl : FullLogger { + + companion object { + private const val COMMON_FIELD_LENGTH = 43 + private const val TAG_FIELD_LENGTH = 5 + private const val DEVICE = "device=" + private const val TAG = "tag=" + private const val METHOD = "method=" + private const val MESSAGE = "message => " + } + + override fun log( + logType: FullLogger.LogType?, + deviceName: String?, + tag: String?, + method: String?, + text: String? + ) { + val fullLog = "${getLogType(logType)}${getDevice(deviceName)}${getTag(tag)}" + + "${getMethod(method)}${getText(text)}" + if (logType == FullLogger.LogType.ERROR) { + System.err.println(fullLog) + return + } + println(fullLog) + } + + private fun getLogType(logType: FullLogger.LogType?): String = + if (logType != null) { "${getFieldString(logType.name, TAG_FIELD_LENGTH)}____" } else { "" } + + private fun getDevice(deviceName: String?): String = + if (deviceName != null) { "$DEVICE${deviceName}____" } else { "" } + + private fun getTag(tag: String?): String = + if (tag != null) { "$TAG${getFieldString(tag)}" } else "" + + private fun getMethod(method: String?): String = + if (method != null) { "$METHOD${getFieldString(method)}" } else "" + + private fun getText(text: String?): String = + if (text != null) { "$MESSAGE$text" } else "" + + private fun getFieldString(text: String, length: Int = COMMON_FIELD_LENGTH): String { + if (text.length >= length) { + return text + "_" + } + return text + "_".repeat(length - text.length) + } +} \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/Logger.kt b/common/src/main/java/com/kaspresky/test_server/log/logger/Logger.kt similarity index 57% rename from common/src/main/java/com/kaspresky/test_server/log/Logger.kt rename to common/src/main/java/com/kaspresky/test_server/log/logger/Logger.kt index 0d89cb9..7d820ec 100644 --- a/common/src/main/java/com/kaspresky/test_server/log/Logger.kt +++ b/common/src/main/java/com/kaspresky/test_server/log/logger/Logger.kt @@ -1,4 +1,4 @@ -package com.kaspresky.test_server.log +package com.kaspresky.test_server.log.logger import java.lang.Exception @@ -10,30 +10,30 @@ interface Logger { /** * Info level of logging with tag. */ - fun i(tag: String, text: String) + fun i(text: String) /** * Info level of logging with tag. */ - fun i(tag: String, method: String, text: String) + fun i(method: String, text: String) /** * Debug level of logging with tag. */ - fun d(tag: String, text: String) + fun d(text: String) /** * Debug level of logging with tag. */ - fun d(tag: String, method: String, text: String) + fun d(method: String, text: String) /** * Error level of logging with tag. */ - fun e(tag: String, exception: Exception) + fun e(exception: Exception) /** * Error level of logging with tag. */ - fun e(tag: String, method: String, exception: Exception) + fun e(method: String, exception: Exception) } \ No newline at end of file diff --git a/common/src/main/java/com/kaspresky/test_server/log/logger/LoggerImpl.kt b/common/src/main/java/com/kaspresky/test_server/log/logger/LoggerImpl.kt new file mode 100644 index 0000000..a1debda --- /dev/null +++ b/common/src/main/java/com/kaspresky/test_server/log/logger/LoggerImpl.kt @@ -0,0 +1,68 @@ +package com.kaspresky.test_server.log.logger + +import com.kaspresky.test_server.log.full_logger.FullLogger +import java.lang.Exception + +internal class LoggerImpl( + private val tag: String?, + private val deviceName: String? = null, + private val fullLogger: FullLogger +) : Logger { + + override fun i(text: String) { + fullLogger.log( + logType = FullLogger.LogType.INFO, + deviceName = deviceName, + tag = tag, + text = text + ) + } + + override fun i(method: String, text: String) { + fullLogger.log( + logType = FullLogger.LogType.INFO, + deviceName = deviceName, + tag = tag, + method = method, + text = text + ) + } + + override fun d(text: String) { + fullLogger.log( + logType = FullLogger.LogType.DEBUG, + deviceName = deviceName, + tag = tag, + text = text + ) + } + + override fun d(method: String, text: String) { + fullLogger.log( + logType = FullLogger.LogType.DEBUG, + deviceName = deviceName, + tag = tag, + method = method, + text = text + ) + } + + override fun e(exception: Exception) { + fullLogger.log( + logType = FullLogger.LogType.ERROR, + deviceName = deviceName, + tag = tag, + text = exception.toString() + ) + } + + override fun e(method: String, exception: Exception) { + fullLogger.log( + logType = FullLogger.LogType.ERROR, + deviceName = deviceName, + tag = tag, + method = method, + text = exception.toString() + ) + } +} \ No newline at end of file diff --git a/common/src/test/java/com/kaspresky/test_server/log/filter_log/FullLoggerForTest.kt b/common/src/test/java/com/kaspresky/test_server/log/filter_log/FullLoggerForTest.kt new file mode 100644 index 0000000..1541eed --- /dev/null +++ b/common/src/test/java/com/kaspresky/test_server/log/filter_log/FullLoggerForTest.kt @@ -0,0 +1,19 @@ +package com.kaspresky.test_server.log.filter_log + +import com.kaspresky.test_server.log.full_logger.FullLogger + +internal class FullLoggerForTest : FullLogger { + + val list: MutableList = mutableListOf() + + override fun log( + logType: FullLogger.LogType?, + deviceName: String?, + tag: String?, + method: String?, + text: String? + ) { + val entry = "${logType ?: ""}${deviceName ?: ""}${tag ?: ""}${method ?: ""}${text ?: ""}" + list.add(entry) + } +} \ No newline at end of file diff --git a/common/src/test/java/com/kaspresky/test_server/log/filter_log/LoggerAnalyzerTest.kt b/common/src/test/java/com/kaspresky/test_server/log/filter_log/LoggerAnalyzerTest.kt new file mode 100644 index 0000000..8b3ef03 --- /dev/null +++ b/common/src/test/java/com/kaspresky/test_server/log/filter_log/LoggerAnalyzerTest.kt @@ -0,0 +1,165 @@ +package com.kaspresky.test_server.log.filter_log + +import com.google.common.truth.Truth.assertThat +import com.kaspresky.test_server.log.full_logger.FullLogger +import org.junit.jupiter.api.Test + +class LoggerAnalyzerTest { + + private val fullLoggerTest = FullLoggerForTest() + private val loggerAnalyzer = FullLoggerOptimiser( + originalFullLogger = fullLoggerTest, + recordingStackMaxSize = 5 + ) + + @Test + fun check_common_case_and_brake_of_sequence() { + fullLoggerTest.list.clear() + // start + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text2") + loggerAnalyzer.log(text = "text3") + loggerAnalyzer.log(tag = "tag1", text = "text4") + loggerAnalyzer.log(tag = "tag2", text = "text5") + loggerAnalyzer.log(tag = "tag1", text = "text5") + // repeated part + loggerAnalyzer.log(text = "text6") + loggerAnalyzer.log(text = "text7") + loggerAnalyzer.log(text = "text8") + loggerAnalyzer.log(text = "text6") + loggerAnalyzer.log(text = "text7") + loggerAnalyzer.log(text = "text8") + loggerAnalyzer.log(text = "text6") + loggerAnalyzer.log(text = "text7") + // end + loggerAnalyzer.log(tag = "tag2", text = "text8") + loggerAnalyzer.log(tag = "tag2", text = "text7") + // verify + val outputLogs = fullLoggerTest.list + assertThat(outputLogs[0]).isEqualTo("text1") + assertThat(outputLogs[1]).isEqualTo("text2") + assertThat(outputLogs[2]).isEqualTo("text3") + assertThat(outputLogs[3]).isEqualTo("tag1text4") + assertThat(outputLogs[4]).isEqualTo("tag2text5") + assertThat(outputLogs[5]).isEqualTo("tag1text5") + assertThat(outputLogs[6]).isEqualTo("text6") + assertThat(outputLogs[7]).isEqualTo("text7") + assertThat(outputLogs[8]).isEqualTo("text8") + assertThat(outputLogs[9]).contains("REPEATED 1 TIMES") + assertThat(outputLogs[10]).isEqualTo("text6") + assertThat(outputLogs[11]).isEqualTo("text7") + assertThat(outputLogs[12]).isEqualTo("text8") + assertThat(outputLogs[13]).contains("/") + assertThat(outputLogs[14]).isEqualTo("text6") + assertThat(outputLogs[15]).isEqualTo("text7") + assertThat(outputLogs[16]).isEqualTo("tag2text8") + assertThat(outputLogs[17]).isEqualTo("tag2text7") + assertThat(outputLogs).hasSize(18) + } + + @Test + fun check_recording_of_one_line() { + fullLoggerTest.list.clear() + // logs + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text4") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text6") + // verify + val outputLogs = fullLoggerTest.list + assertThat(outputLogs[0]).isEqualTo("text1") + assertThat(outputLogs[1]).contains("REPEATED 2 TIMES") + assertThat(outputLogs[2]).isEqualTo("text1") + assertThat(outputLogs[3]).contains("/") + assertThat(outputLogs[4]).isEqualTo("text4") + assertThat(outputLogs[5]).isEqualTo("text1") + assertThat(outputLogs[6]).contains("REPEATED 1 TIMES") + assertThat(outputLogs[7]).isEqualTo("text1") + assertThat(outputLogs[8]).contains("/") + assertThat(outputLogs[9]).isEqualTo("text6") + assertThat(outputLogs).hasSize(10) + } + + @Test + fun check_no_recordings_and_all_params() { + fullLoggerTest.list.clear() + // logs + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(logType = FullLogger.LogType.INFO, text = "text1") + loggerAnalyzer.log(logType = FullLogger.LogType.DEBUG, text = "text1") + loggerAnalyzer.log(logType = FullLogger.LogType.INFO, deviceName = "device1", text = "text1") + loggerAnalyzer.log(logType = FullLogger.LogType.INFO, deviceName = "device1", tag = "tag1", text = "text1") + loggerAnalyzer.log(logType = FullLogger.LogType.INFO, deviceName = "device1", tag = "tag1", method = "method1", text = "text1") + loggerAnalyzer.log(logType = FullLogger.LogType.INFO, deviceName = "device1", tag = "tag2", method = "method1", text = "text1") + loggerAnalyzer.log(logType = FullLogger.LogType.INFO, deviceName = "device1", tag = "tag1", method = "method2", text = "text1") + // verify + val outputLogs = fullLoggerTest.list + assertThat(outputLogs[0]).isEqualTo("text1") + assertThat(outputLogs[1]).isEqualTo("INFOtext1") + assertThat(outputLogs[2]).isEqualTo("DEBUGtext1") + assertThat(outputLogs[3]).isEqualTo("INFOdevice1text1") + assertThat(outputLogs[4]).isEqualTo("INFOdevice1tag1text1") + assertThat(outputLogs[5]).isEqualTo("INFOdevice1tag1method1text1") + assertThat(outputLogs[6]).isEqualTo("INFOdevice1tag2method1text1") + assertThat(outputLogs[7]).isEqualTo("INFOdevice1tag1method2text1") + assertThat(outputLogs).hasSize(8) + } + + @Test + fun check_continuous_recording() { + fullLoggerTest.list.clear() + // logs + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text2") + loggerAnalyzer.log(text = "text2") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text2") + loggerAnalyzer.log(text = "text2") + loggerAnalyzer.log(text = "text2") + // verify + val outputLogs = fullLoggerTest.list + assertThat(outputLogs[0]).isEqualTo("text1") + assertThat(outputLogs[1]).isEqualTo("text2") + assertThat(outputLogs[2]).contains("REPEATED 1 TIMES") + assertThat(outputLogs[3]).isEqualTo("text2") + assertThat(outputLogs[4]).contains("/") + assertThat(outputLogs[5]).isEqualTo("text1") + assertThat(outputLogs[6]).isEqualTo("text2") + assertThat(outputLogs).hasSize(7) + // we are waiting for the end of "text2" sequence that's why last logs has not been outputted yet + } + + @Test + fun check_recording_with_max_size() { + fullLoggerTest.list.clear() + // logs + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text2") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + loggerAnalyzer.log(text = "text1") + // verify + val outputLogs = fullLoggerTest.list + assertThat(outputLogs[0]).isEqualTo("text1") + assertThat(outputLogs[1]).contains("REPEATED 5 TIMES") + assertThat(outputLogs[2]).isEqualTo("text1") + assertThat(outputLogs[3]).contains("/") + assertThat(outputLogs[4]).isEqualTo("text2") + assertThat(outputLogs[5]).isEqualTo("text1") + assertThat(outputLogs[6]).contains("REPEATED 5 TIMES") + assertThat(outputLogs[7]).isEqualTo("text1") + assertThat(outputLogs[8]).contains("/") + assertThat(outputLogs).hasSize(9) + } +} \ No newline at end of file diff --git a/connection/src/main/java/com/kaspersky/test_server/api/ConnectionFactory.kt b/connection/src/main/java/com/kaspersky/test_server/api/ConnectionFactory.kt index ce41738..63c1245 100644 --- a/connection/src/main/java/com/kaspersky/test_server/api/ConnectionFactory.kt +++ b/connection/src/main/java/com/kaspersky/test_server/api/ConnectionFactory.kt @@ -2,7 +2,6 @@ package com.kaspersky.test_server.api import com.kaspersky.test_server.implementation.ConnectionClientImplBySocket import com.kaspersky.test_server.implementation.ConnectionServerImplBySocket -import com.kaspresky.test_server.log.Logger import java.net.Socket /** @@ -13,13 +12,12 @@ object ConnectionFactory { fun createServer( socketCreation: () -> Socket, commandExecutor: CommandExecutor, - logger: Logger + deviceName: String ): ConnectionServer = - ConnectionServerImplBySocket(socketCreation, commandExecutor, logger) + ConnectionServerImplBySocket(socketCreation, commandExecutor, deviceName) fun createClient( - socketCreation: () -> Socket, - logger: Logger + socketCreation: () -> Socket ): ConnectionClient = - ConnectionClientImplBySocket(socketCreation, logger) + ConnectionClientImplBySocket(socketCreation) } \ No newline at end of file diff --git a/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionClientImplBySocket.kt b/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionClientImplBySocket.kt index ccacf5f..fd6225f 100644 --- a/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionClientImplBySocket.kt +++ b/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionClientImplBySocket.kt @@ -8,21 +8,20 @@ import com.kaspersky.test_server.implementation.light_socket.LightSocketWrapperI import com.kaspersky.test_server.implementation.transferring.ResultMessage import com.kaspersky.test_server.implementation.transferring.SocketMessagesTransferring import com.kaspersky.test_server.implementation.transferring.TaskMessage -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory import java.net.Socket import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.TimeUnit internal class ConnectionClientImplBySocket( - private val socketCreation: () -> Socket, - private val logger: Logger + private val socketCreation: () -> Socket ) : ConnectionClient { companion object { private val COMMAND_TIMEOUT_MIN = TimeUnit.MINUTES.toSeconds(3) } - private val tag = javaClass.simpleName + private val logger = LoggerFactory.getLogger(tag = javaClass.simpleName) private var _socket: Socket? = null private val socket: Socket @@ -32,47 +31,46 @@ internal class ConnectionClientImplBySocket( private val socketMessagesTransferring: SocketMessagesTransferring, TaskMessage> get() = _socketMessagesTransferring ?: throw IllegalStateException("tryConnect must be called first") - private var connectionMaker: ConnectionMaker = ConnectionMaker(logger) + private var connectionMaker: ConnectionMaker = ConnectionMaker() private val commandsInProgress = ConcurrentHashMap>>() override fun tryConnect() { - logger.i(tag, "tryConnect", "start") + logger.i("tryConnect", "start") connectionMaker.connect( connectAction = { _socket = socketCreation.invoke() }, successConnectAction = { - logger.i(tag, "tryConnect", "start handleMessages") + logger.i("tryConnect", "start handleMessages") handleMessages() } ) - logger.i(tag, "tryConnect", "attempt completed") + logger.i("tryConnect", "attempt completed") } private fun handleMessages() { _socketMessagesTransferring = SocketMessagesTransferring.createTransferring( lightSocketWrapper = LightSocketWrapperImpl(socket), - logger = logger, disruptAction = { tryDisconnect() } ) socketMessagesTransferring.startListening { resultMessage -> - logger.i(tag, "handleMessages", "received resultMessage=$resultMessage") + logger.i("handleMessages", "received resultMessage=$resultMessage") commandsInProgress[resultMessage.command]?.latchResult(resultMessage) } } override fun tryDisconnect() { - logger.i(tag, "tryDisconnect", "start") + logger.i("tryDisconnect", "start") connectionMaker.disconnect { socketMessagesTransferring.stopListening() socket.close() resetCommandsInProgress() } - logger.i(tag, "tryDisconnect", "attempt completed") + logger.i("tryDisconnect", "attempt completed") } private fun resetCommandsInProgress() { for ((adbCommand, resultWaiter) in commandsInProgress) { val commandResult = CommandResult(ExecutorResultStatus.FAILED, "tryDisconnect was called") - logger.i(tag, "resetCommandsInProgress", "command=$adbCommand was failed because of disconnecting. " + + logger.i("resetCommandsInProgress", "command=$adbCommand was failed because of disconnecting. " + "result=$commandResult" ) resultWaiter.latchResult( @@ -87,7 +85,7 @@ internal class ConnectionClientImplBySocket( @Suppress("ReturnCount") override fun executeCommand(command: Command): CommandResult { - logger.i(tag, "executeAdbCommand", "started command=$command") + logger.i("executeAdbCommand", "started command=$command") val resultWaiter = ResultWaiter>() commandsInProgress[command] = resultWaiter @@ -100,7 +98,7 @@ internal class ConnectionClientImplBySocket( resultMessage = resultWaiter.waitResult(COMMAND_TIMEOUT_MIN, TimeUnit.SECONDS) } catch (exception: InterruptedException) { val failedCommandResult = CommandResult(ExecutorResultStatus.FAILED, "Waiting thread was interrupted") - logger.i(tag, "executeAdbCommand", "command=$command failed with commandResult=$failedCommandResult") + logger.i("executeAdbCommand", "command=$command failed with commandResult=$failedCommandResult") return failedCommandResult } finally { commandsInProgress.remove(command) @@ -108,10 +106,10 @@ internal class ConnectionClientImplBySocket( if (resultMessage == null) { val failedCommandResult = CommandResult(ExecutorResultStatus.FAILED, "Waiting result timeout was expired") - logger.i(tag, "executeAdbCommand", "command=$command failed with commandResult=$failedCommandResult") + logger.i("executeAdbCommand", "command=$command failed with commandResult=$failedCommandResult") return failedCommandResult } - logger.i(tag, "executeAdbCommand", "command=$command completed with commandResult=${resultMessage.data}") + logger.i("executeAdbCommand", "command=$command completed with commandResult=${resultMessage.data}") return resultMessage.data } diff --git a/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionMaker.kt b/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionMaker.kt index 2f6a843..2727f8f 100644 --- a/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionMaker.kt +++ b/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionMaker.kt @@ -1,24 +1,22 @@ package com.kaspersky.test_server.implementation -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory /** * The helper to establish a connection correctly according to all possible states and multithread's environment */ -internal class ConnectionMaker( - private val logger: Logger -) { +internal class ConnectionMaker(deviceName: String? = null) { - private val tag = javaClass.simpleName + private val logger = LoggerFactory.getLogger(tag = javaClass.simpleName, deviceName = deviceName) @Volatile private var connectionState: ConnectionState = ConnectionState.DISCONNECTED @Synchronized fun connect(connectAction: () -> Unit, successConnectAction: () -> Unit) { - logger.i(tag, "connect", "start") - logger.i(tag, "connect", "current state=$connectionState") + logger.i("connect", "start") + logger.i("connect", "current state=$connectionState") if (connectionState == ConnectionState.CONNECTING || connectionState == ConnectionState.DISCONNECTING) { - logger.i(tag, "connect", "Unexpected connection state appeared during connect") + logger.i("connect", "Unexpected connection state appeared during connect") return } if (connectionState == ConnectionState.CONNECTED) { @@ -28,20 +26,20 @@ internal class ConnectionMaker( try { connectAction.invoke() connectionState = ConnectionState.CONNECTED - logger.i(tag, "connect", "updated state=$connectionState") + logger.i("connect", "updated state=$connectionState") successConnectAction.invoke() } catch (exception: Exception) { - logger.e(tag, "connect", exception) + logger.e("connect", exception) connectionState = ConnectionState.DISCONNECTED } } @Synchronized fun disconnect(connectAction: () -> Unit) { - logger.i(tag, "disconnect", "start") - logger.i(tag, "disconnect", "current state=$connectionState") + logger.i("disconnect", "start") + logger.i("disconnect", "current state=$connectionState") if (connectionState == ConnectionState.CONNECTING || connectionState == ConnectionState.DISCONNECTING) { - logger.i(tag, "disconnect", "Unexpected connection state appeared during disconnect") + logger.i("disconnect", "Unexpected connection state appeared during disconnect") return } if (connectionState == ConnectionState.DISCONNECTED) { @@ -49,11 +47,11 @@ internal class ConnectionMaker( } try { connectionState = ConnectionState.DISCONNECTING - logger.i(tag, "disconnect", "updated state=$connectionState") + logger.i("disconnect", "updated state=$connectionState") connectAction.invoke() } finally { connectionState = ConnectionState.DISCONNECTED - logger.i(tag, "disconnect", "updated state=$connectionState") + logger.i("disconnect", "updated state=$connectionState") } } diff --git a/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionServerImplBySocket.kt b/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionServerImplBySocket.kt index 6fe5c5a..9942b60 100644 --- a/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionServerImplBySocket.kt +++ b/connection/src/main/java/com/kaspersky/test_server/implementation/ConnectionServerImplBySocket.kt @@ -7,19 +7,18 @@ import com.kaspersky.test_server.implementation.light_socket.LightSocketWrapperI import com.kaspersky.test_server.implementation.transferring.ResultMessage import com.kaspersky.test_server.implementation.transferring.SocketMessagesTransferring import com.kaspersky.test_server.implementation.transferring.TaskMessage -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory import java.net.Socket import java.util.concurrent.Executors internal class ConnectionServerImplBySocket( private val socketCreation: () -> Socket, private val commandExecutor: CommandExecutor, - private val logger: Logger + private val deviceName: String ) : ConnectionServer { - private val tag = javaClass.simpleName - - private var connectionMaker: ConnectionMaker = ConnectionMaker(logger) + private val logger = LoggerFactory.getLogger(tag = javaClass.simpleName, deviceName = deviceName) + private var connectionMaker: ConnectionMaker = ConnectionMaker(deviceName) private lateinit var socketMessagesTransferring: SocketMessagesTransferring> private var _socket: Socket? = null @@ -29,28 +28,28 @@ internal class ConnectionServerImplBySocket( private val backgroundExecutor = Executors.newCachedThreadPool() override fun tryConnect() { - logger.i(tag, "tryConnect", "start") + logger.i("tryConnect", "start") connectionMaker.connect( connectAction = { _socket = socketCreation.invoke() }, successConnectAction = { - logger.i(tag, "tryConnect", "start handleMessages") + logger.i("tryConnect", "start handleMessages") handleMessages() } ) - logger.i(tag, "tryConnect", "attempt completed") + logger.i("tryConnect", "attempt completed") } private fun handleMessages() { socketMessagesTransferring = SocketMessagesTransferring.createTransferring( lightSocketWrapper = LightSocketWrapperImpl(socket), - logger = logger, - disruptAction = { tryDisconnect() } + disruptAction = { tryDisconnect() }, + deviceName = deviceName ) socketMessagesTransferring.startListening { taskMessage -> - logger.i(tag, "handleMessages", "received taskMessage=$taskMessage") + logger.i("handleMessages", "received taskMessage=$taskMessage") backgroundExecutor.execute { val result = commandExecutor.execute(taskMessage.command) - logger.i(tag, "handleMessages.backgroundExecutor", "result of taskMessage=$taskMessage => result=$result") + logger.i("handleMessages.backgroundExecutor", "result of taskMessage=$taskMessage => result=$result") socketMessagesTransferring.sendMessage( ResultMessage(taskMessage.command, result) ) @@ -59,12 +58,12 @@ internal class ConnectionServerImplBySocket( } override fun tryDisconnect() { - logger.i(tag, "tryDisconnect", "start") + logger.i("tryDisconnect", "start") connectionMaker.disconnect { socketMessagesTransferring.stopListening() socket.close() } - logger.i(tag, "tryDisconnect", "attempt completed") + logger.i("tryDisconnect", "attempt completed") } override fun isConnected(): Boolean = diff --git a/connection/src/main/java/com/kaspersky/test_server/implementation/transferring/SocketMessagesTransferring.kt b/connection/src/main/java/com/kaspersky/test_server/implementation/transferring/SocketMessagesTransferring.kt index 64bc860..ded822e 100644 --- a/connection/src/main/java/com/kaspersky/test_server/implementation/transferring/SocketMessagesTransferring.kt +++ b/connection/src/main/java/com/kaspersky/test_server/implementation/transferring/SocketMessagesTransferring.kt @@ -1,7 +1,7 @@ package com.kaspersky.test_server.implementation.transferring import com.kaspersky.test_server.implementation.light_socket.LightSocketWrapper -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory import java.io.ObjectInputStream import java.io.ObjectOutputStream import java.util.concurrent.atomic.AtomicBoolean @@ -10,27 +10,27 @@ internal class SocketMessagesTransferring private const private val lightSocketWrapper: LightSocketWrapper, private val receiveModelClass: Class, private val sendModelClass: Class, - private val logger: Logger, - private val disruptAction: () -> Unit + private val disruptAction: () -> Unit, + deviceName: String? ) { companion object { inline fun createTransferring( lightSocketWrapper: LightSocketWrapper, - logger: Logger, - noinline disruptAction: () -> Unit + noinline disruptAction: () -> Unit, + deviceName: String? = null ): SocketMessagesTransferring { return SocketMessagesTransferring( lightSocketWrapper, Receive::class.java, Send::class.java, - logger, - disruptAction + disruptAction, + deviceName ) } } - private val tag = javaClass.simpleName + private val logger = LoggerFactory.getLogger(tag = javaClass.simpleName, deviceName = deviceName) private lateinit var inputStream: ObjectInputStream private lateinit var outputStream: ObjectOutputStream @@ -39,14 +39,14 @@ internal class SocketMessagesTransferring private const private val isRunning: AtomicBoolean = AtomicBoolean(false) fun startListening(listener: (ReceiveModel) -> Unit) { - logger.i(tag, "startListening", "start") + logger.i("startListening", "start") messagesListener = listener try { outputStream = ObjectOutputStream(lightSocketWrapper.getOutputStream()) inputStream = ObjectInputStream(lightSocketWrapper.getInputStream()) - logger.i(tag, "startListening", "IO Streams were created") + logger.i("startListening", "IO Streams were created") } catch (exception: Exception) { - logger.e(tag, "startListening", exception) + logger.e("startListening", exception) disruptAction.invoke() return } @@ -59,12 +59,12 @@ internal class SocketMessagesTransferring private const } fun sendMessage(sendModel: SendModel) { - logger.i(tag, "sendMessage", "where sendModel=$sendModel") + logger.i("sendMessage", "where sendModel=$sendModel") try { outputStream.writeObject(sendModel) outputStream.flush() } catch (exception: Exception) { - logger.e(tag, "sendMessage", exception) + logger.e("sendMessage", exception) } } @@ -74,7 +74,7 @@ internal class SocketMessagesTransferring private const private inner class MessagesListeningThread : Thread() { override fun run() { - logger.i("$tag.MessagesListeningThread", "run", "start to work") + logger.i("MessagesListeningThread.run", "start to work") while (isRunning.get()) { peekNextMessage() } @@ -86,16 +86,16 @@ internal class SocketMessagesTransferring private const try { obj = inputStream.readObject() if (obj.javaClass == receiveModelClass) { - logger.i("$tag.MessagesListeningThread", "peekNextMessage", "with message=$obj") + logger.i("MessagesListeningThread.peekNextMessage", "with message=$obj") messagesListener.invoke(obj as ReceiveModel) } else { - logger.i("$tag.MessagesListeningThread", "peekNextMessage", "with message=$obj" + + logger.i("MessagesListeningThread.peekNextMessage", "with message=$obj" + " but this message type is not $receiveModelClass" ) disruptAction.invoke() } } catch (exception: Exception) { - logger.e("$tag.MessagesListeningThread", "peekNextMessage", exception) + logger.e("MessagesListeningThread.peekNextMessage", exception) disruptAction.invoke() } } diff --git a/dependencies.gradle b/dependencies.gradle index 26ba74f..88ecef9 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,4 +7,7 @@ ext.versions = [ androidPlugin : "3.2.1", androidSupport : "1.0.2", bintrayPlugin : "1.8.4", + + junit5 : "5.5.2", + truth : "1.0" ] diff --git a/desktop/src/main/java/com/kaspersky/test_server/CommandExecutorImpl.kt b/desktop/src/main/java/com/kaspersky/test_server/CommandExecutorImpl.kt index 0e7fcd6..7892ed9 100644 --- a/desktop/src/main/java/com/kaspersky/test_server/CommandExecutorImpl.kt +++ b/desktop/src/main/java/com/kaspersky/test_server/CommandExecutorImpl.kt @@ -3,22 +3,23 @@ package com.kaspersky.test_server import com.kaspersky.test_server.api.Command import com.kaspersky.test_server.api.CommandExecutor import com.kaspersky.test_server.api.CommandResult -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory import java.lang.UnsupportedOperationException internal class CommandExecutorImpl( private val cmdCommandPerformer: CmdCommandPerformer, private val deviceName: String, - private val adbServerPort: String?, - private val logger: Logger + private val adbServerPort: String? ) : CommandExecutor { + private val logger = LoggerFactory.getLogger(tag = javaClass.simpleName, deviceName = deviceName) + override fun execute(command: Command): CommandResult { return when (command) { is CmdCommand -> cmdCommandPerformer.perform(command.body) is AdbCommand -> { val adbCommand = "adb ${ adbServerPort?.let { "-P $adbServerPort " } ?: "" }-s $deviceName ${command.body}" - logger.i("CommandExecutorImpl", "execute", "adbCommand=$adbCommand") + logger.i("execute", "adbCommand=$adbCommand") cmdCommandPerformer.perform(adbCommand) } else -> throw UnsupportedOperationException("The command=$command is unsupported command") diff --git a/desktop/src/main/java/com/kaspersky/test_server/Desktop.kt b/desktop/src/main/java/com/kaspersky/test_server/Desktop.kt index 630dc20..b4f0031 100644 --- a/desktop/src/main/java/com/kaspersky/test_server/Desktop.kt +++ b/desktop/src/main/java/com/kaspersky/test_server/Desktop.kt @@ -1,36 +1,34 @@ package com.kaspersky.test_server import com.kaspersky.test_server.api.ExecutorResultStatus -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory import java.util.regex.Pattern internal class Desktop( private val cmdCommandPerformer: CmdCommandPerformer, private val presetEmulators: List, - private val adbServerPort: String?, - private val logger: Logger + private val adbServerPort: String? ) { companion object { private const val PAUSE_MS = 500L } - private val tag = javaClass.simpleName + private val logger = LoggerFactory.getLogger(tag = javaClass.simpleName) private val devices: MutableCollection = mutableListOf() fun startDevicesObserving() { - logger.i(tag, "startDevicesObserving", "start") + logger.i("startDevicesObserving", "start") while (true) { val namesOfAttachedDevicesByAdb = getAttachedDevicesByAdb() namesOfAttachedDevicesByAdb.forEach { deviceName -> if (devices.find { client -> client.deviceName == deviceName } == null) { logger.i( - tag, "startDevicesObserving", "New device has been found: $deviceName. Initialize connection to it..." ) val deviceMirror = DeviceMirror.create( - deviceName, adbServerPort, cmdCommandPerformer, logger + deviceName, adbServerPort, cmdCommandPerformer ) deviceMirror.startConnectionToDevice() devices += deviceMirror @@ -39,7 +37,7 @@ internal class Desktop( devices.removeIf { client -> if (client.deviceName !in namesOfAttachedDevicesByAdb) { logger.i( - tag, + "startDevicesObserving", "Adb connection to ${client.deviceName} has been missed. Stop connection." ) diff --git a/desktop/src/main/java/com/kaspersky/test_server/DeviceMirror.kt b/desktop/src/main/java/com/kaspersky/test_server/DeviceMirror.kt index 10d07b1..9082b9e 100644 --- a/desktop/src/main/java/com/kaspersky/test_server/DeviceMirror.kt +++ b/desktop/src/main/java/com/kaspersky/test_server/DeviceMirror.kt @@ -2,13 +2,12 @@ package com.kaspersky.test_server import com.kaspersky.test_server.api.ConnectionFactory import com.kaspersky.test_server.api.ConnectionServer -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory import java.util.concurrent.atomic.AtomicReference internal class DeviceMirror private constructor( val deviceName: String, - private val connectionServer: ConnectionServer, - private val logger: Logger + private val connectionServer: ConnectionServer ) { companion object { @@ -17,51 +16,50 @@ internal class DeviceMirror private constructor( fun create( deviceName: String, adbServerPort: String?, - cmdCommandPerformer: CmdCommandPerformer, - logger: Logger + cmdCommandPerformer: CmdCommandPerformer ): DeviceMirror { val desktopDeviceSocketConnection = DesktopDeviceSocketConnectionFactory.getSockets( DesktopDeviceSocketConnectionType.FORWARD, - logger + deviceName ) val commandExecutor = CommandExecutorImpl( - cmdCommandPerformer, deviceName, adbServerPort, logger + cmdCommandPerformer, deviceName, adbServerPort ) val connectionServer = ConnectionFactory.createServer( desktopDeviceSocketConnection.getDesktopSocketLoad(commandExecutor), commandExecutor, - logger + deviceName ) - return DeviceMirror(deviceName, connectionServer, logger) + return DeviceMirror(deviceName, connectionServer) } } - private val tag = javaClass.simpleName + private val logger = LoggerFactory.getLogger(tag = javaClass.simpleName, deviceName = deviceName) private val isRunning = AtomicReference() fun startConnectionToDevice() { - logger.i(tag, "startConnectionToDevice", "connect to device=$deviceName start") + logger.i("startConnectionToDevice", "connect to device=$deviceName start") isRunning.set(true) WatchdogThread().start() } fun stopConnectionToDevice() { - logger.i(tag, "stopConnectionToDevice", "connection to device=$deviceName was stopped") + logger.i("stopConnectionToDevice", "connection to device=$deviceName was stopped") isRunning.set(false) connectionServer.tryDisconnect() } private inner class WatchdogThread : Thread() { override fun run() { - logger.i("$tag.WatchdogThread", "run", "WatchdogThread is started from Desktop to Device=$deviceName") + logger.i("WatchdogThread.run", "WatchdogThread is started from Desktop to Device=$deviceName") while (isRunning.get()) { if (!connectionServer.isConnected()) { try { - logger.i("$tag.WatchdogThread", "run", "Try to connect to Device=$deviceName...") + logger.i("WatchdogThread.run", "Try to connect to Device=$deviceName...") connectionServer.tryConnect() } catch (exception: Exception) { - logger.i("$tag.WatchdogThread", "run", "The attempt to connect to Device=$deviceName was with exception: $exception") + logger.i("WatchdogThread,run", "The attempt to connect to Device=$deviceName was with exception: $exception") } } sleep(CONNECTION_WAIT_MS) diff --git a/desktop/src/main/java/com/kaspersky/test_server/Main.kt b/desktop/src/main/java/com/kaspersky/test_server/Main.kt index ab07581..9a4e4bb 100644 --- a/desktop/src/main/java/com/kaspersky/test_server/Main.kt +++ b/desktop/src/main/java/com/kaspersky/test_server/Main.kt @@ -18,15 +18,14 @@ internal fun main(args: Array) { ?.replace("=", "") ?.trim() - val logger = LoggerFactory.systemLogger() + val logger = LoggerFactory.getLogger(tag = "Desktop") logger.i("MAIN", "arguments: emulators=$emulators, adbServerPort=$adbServerPort") val cmdCommandPerformer = CmdCommandPerformer() val desktop = Desktop( cmdCommandPerformer = cmdCommandPerformer, presetEmulators = emulators, - adbServerPort = adbServerPort, - logger = logger + adbServerPort = adbServerPort ) desktop.startDevicesObserving() } \ No newline at end of file diff --git a/desktop_device_connection/src/main/java/com/kaspersky/test_server/DesktopDeviceSocketConnectionFactory.kt b/desktop_device_connection/src/main/java/com/kaspersky/test_server/DesktopDeviceSocketConnectionFactory.kt index cc3fdbf..2d3b1c7 100644 --- a/desktop_device_connection/src/main/java/com/kaspersky/test_server/DesktopDeviceSocketConnectionFactory.kt +++ b/desktop_device_connection/src/main/java/com/kaspersky/test_server/DesktopDeviceSocketConnectionFactory.kt @@ -1,15 +1,13 @@ package com.kaspersky.test_server -import com.kaspresky.test_server.log.Logger - object DesktopDeviceSocketConnectionFactory { fun getSockets( desktopDeviceSocketConnectionType: DesktopDeviceSocketConnectionType, - logger: Logger + deviceName: String? = null ): DesktopDeviceSocketConnection { return when (desktopDeviceSocketConnectionType) { - DesktopDeviceSocketConnectionType.FORWARD -> DesktopDeviceSocketConnectionForwardImpl(logger) + DesktopDeviceSocketConnectionType.FORWARD -> DesktopDeviceSocketConnectionForwardImpl(deviceName) DesktopDeviceSocketConnectionType.REVERSE -> throw UnsupportedOperationException("Please implement REVERSE DesktopDeviceSocketConnection") } } diff --git a/desktop_device_connection/src/main/java/com/kaspersky/test_server/DesktopDeviceSocketConnectionForwardImpl.kt b/desktop_device_connection/src/main/java/com/kaspersky/test_server/DesktopDeviceSocketConnectionForwardImpl.kt index 47ddd93..25a6df9 100644 --- a/desktop_device_connection/src/main/java/com/kaspersky/test_server/DesktopDeviceSocketConnectionForwardImpl.kt +++ b/desktop_device_connection/src/main/java/com/kaspersky/test_server/DesktopDeviceSocketConnectionForwardImpl.kt @@ -1,13 +1,13 @@ package com.kaspersky.test_server import com.kaspersky.test_server.api.CommandExecutor -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory import java.net.ServerSocket import java.net.Socket import kotlin.random.Random internal class DesktopDeviceSocketConnectionForwardImpl( - private val logger: Logger + deviceName: String? ) : DesktopDeviceSocketConnection { companion object { @@ -17,18 +17,19 @@ internal class DesktopDeviceSocketConnectionForwardImpl( private const val LOCAL_HOST: String = "127.0.0.1" } - private val tag = javaClass.simpleName + private val desktopLogger = LoggerFactory.getLogger(tag = javaClass.simpleName, deviceName = deviceName) + private val deviceLogger = LoggerFactory.getLogger(tag = javaClass.simpleName) private val clientPortsList: MutableList = mutableListOf() override fun getDesktopSocketLoad(executor: CommandExecutor): () -> Socket { val clientPort = getFreePort() - logger.i(tag, "getDesktopSocketLoad", "calculated desktop client port=$clientPort") + desktopLogger.i("getDesktopSocketLoad", "calculated desktop client port=$clientPort") forwardPorts(executor, clientPort, DEVICE_PORT) - logger.i(tag, "getDesktopSocketLoad", "desktop client port=$clientPort is forwarding with device server port=$DEVICE_PORT") + desktopLogger.i("getDesktopSocketLoad", "desktop client port=$clientPort is forwarding with device server port=$DEVICE_PORT") return { - logger.i(tag, "getDesktopSocketLoad", "started with ip=$LOCAL_HOST, port=$clientPort") + desktopLogger.i("getDesktopSocketLoad", "started with ip=$LOCAL_HOST, port=$clientPort") val readyClientSocket = Socket(LOCAL_HOST, clientPort) - logger.i(tag, "getDesktopSocketLoad", "completed with ip=$LOCAL_HOST, port=$clientPort") + desktopLogger.i("getDesktopSocketLoad", "completed with ip=$LOCAL_HOST, port=$clientPort") readyClientSocket } } @@ -46,16 +47,16 @@ internal class DesktopDeviceSocketConnectionForwardImpl( } private fun forwardPorts(executor: CommandExecutor, fromPort: Int, toPort: Int) { - logger.i(tag, "forwardPorts(fromPort=$fromPort, toPort=$toPort)", "started") + desktopLogger.i("forwardPorts(fromPort=$fromPort, toPort=$toPort)", "started") val result = executor.execute(AdbCommand("forward tcp:$fromPort tcp:$toPort")) - logger.i(tag, "forwardPorts(fromPort=$fromPort, toPort=$toPort)", "result=$result") + desktopLogger.i("forwardPorts(fromPort=$fromPort, toPort=$toPort)", "result=$result") } override fun getDeviceSocketLoad(): () -> Socket = { - logger.i(tag, "getDeviceSocketLoad", "started") + deviceLogger.i("getDeviceSocketLoad", "started") val serverSocket = ServerSocket(DEVICE_PORT) val readyServerSocket = serverSocket.accept() - logger.i(tag, "getDeviceSocketLoad", "completed") + deviceLogger.i("getDeviceSocketLoad", "completed") readyServerSocket } } \ No newline at end of file diff --git a/device/src/main/java/com/kaspersky/test_server/AdbTerminal.kt b/device/src/main/java/com/kaspersky/test_server/AdbTerminal.kt index e595f91..2e7ee86 100644 --- a/device/src/main/java/com/kaspersky/test_server/AdbTerminal.kt +++ b/device/src/main/java/com/kaspersky/test_server/AdbTerminal.kt @@ -1,13 +1,10 @@ package com.kaspersky.test_server import com.kaspersky.test_server.api.CommandResult -import com.kaspresky.test_server.log.LoggerFactory object AdbTerminal { - private val device = Device.create( - LoggerFactory.systemLogger() - ) + private val device = Device.create() fun connect() { device.startConnectionToDesktop() diff --git a/device/src/main/java/com/kaspersky/test_server/Device.kt b/device/src/main/java/com/kaspersky/test_server/Device.kt index 43e92a9..4f5701e 100644 --- a/device/src/main/java/com/kaspersky/test_server/Device.kt +++ b/device/src/main/java/com/kaspersky/test_server/Device.kt @@ -5,46 +5,43 @@ import com.kaspersky.test_server.api.CommandResult import com.kaspersky.test_server.api.ConnectionClient import com.kaspersky.test_server.api.ConnectionFactory import com.kaspersky.test_server.api.ExecutorResultStatus -import com.kaspresky.test_server.log.Logger +import com.kaspresky.test_server.log.LoggerFactory import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean internal class Device private constructor( - private val connectionClient: ConnectionClient, - private val logger: Logger + private val connectionClient: ConnectionClient ) { companion object { private const val CONNECTION_ESTABLISH_TIMEOUT_SEC = 5L private const val CONNECTION_WAIT_MS = 200L - fun create(logger: Logger): Device { + fun create(): Device { val desktopDeviceSocketConnection = DesktopDeviceSocketConnectionFactory.getSockets( - DesktopDeviceSocketConnectionType.FORWARD, - logger + DesktopDeviceSocketConnectionType.FORWARD ) val connectionClient = ConnectionFactory.createClient( - desktopDeviceSocketConnection.getDeviceSocketLoad(), - logger + desktopDeviceSocketConnection.getDeviceSocketLoad() ) - return Device(connectionClient, logger) + return Device(connectionClient) } } - private val tag = javaClass.simpleName + private val logger = LoggerFactory.getLogger(tag = javaClass.simpleName) private val isRunning = AtomicBoolean(false) fun startConnectionToDesktop() { if (isRunning.compareAndSet(false, true)) { - logger.i(tag, "start", "start") + logger.i("start", "start") WatchdogThread().start() } } fun stopConnectionToDesktop() { if (isRunning.compareAndSet(true, false)) { - logger.i(tag, "stop", "stop") + logger.i("stop", "stop") connectionClient.tryDisconnect() } } @@ -57,7 +54,7 @@ internal class Device private constructor( * 2. the adb command execution time */ fun fulfill(command: Command): CommandResult { - logger.i(tag, "execute", "Start to execute the command=$command") + logger.i("execute", "Start to execute the command=$command") val commandResult = try { awaitConnectionEstablished(CONNECTION_ESTABLISH_TIMEOUT_SEC, TimeUnit.SECONDS) connectionClient.executeCommand(command) @@ -67,7 +64,7 @@ internal class Device private constructor( "The time for the connection establishment is over" ) } - logger.i(tag, "execute", "The result of command=$command => $commandResult") + logger.i("execute", "The result of command=$command => $commandResult") return commandResult } @@ -89,14 +86,14 @@ internal class Device private constructor( // todo get name of the device? private inner class WatchdogThread : Thread("Connection watchdog thread from Device to Desktop") { override fun run() { - logger.i("$tag.WatchdogThread", "run", "WatchdogThread starts from Device to Desktop") + logger.i("WatchdogThread.run", "WatchdogThread starts from Device to Desktop") while (isRunning.get()) { if (!connectionClient.isConnected()) { try { - logger.i("$tag.WatchdogThread", "run", "Try to connect to Desktop...") + logger.i("WatchdogThread.run", "Try to connect to Desktop...") connectionClient.tryConnect() } catch (exception: Exception) { - logger.i("$tag.WatchdogThread", "run", "The attempt to connect to Desktop was with exception: $exception") + logger.i("WatchdogThread.run", "The attempt to connect to Desktop was with exception: $exception") } } }