mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-28 04:37:40 +00:00
refactor: migrate DeviceStats
to Kotlin
This commit is contained in:
parent
0a2080fdcd
commit
66877d6730
@ -371,7 +371,7 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public void onPacketReceived(@NonNull NetworkPacket np) {
|
public void onPacketReceived(@NonNull NetworkPacket np) {
|
||||||
|
|
||||||
DeviceStats.countReceived(getDeviceId(), np.getType());
|
DeviceStats.INSTANCE.countReceived(getDeviceId(), np.getType());
|
||||||
|
|
||||||
if (NetworkPacket.PACKET_TYPE_PAIR.equals(np.getType())) {
|
if (NetworkPacket.PACKET_TYPE_PAIR.equals(np.getType())) {
|
||||||
Log.i("KDE/Device", "Pair packet");
|
Log.i("KDE/Device", "Pair packet");
|
||||||
@ -519,7 +519,7 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
DeviceStats.countSent(getDeviceId(), np.getType(), success);
|
DeviceStats.INSTANCE.countSent(getDeviceId(), np.getType(), success);
|
||||||
if (success) break;
|
if (success) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,198 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kde.kdeconnect;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class DeviceStats {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keep 24 hours of events
|
|
||||||
*/
|
|
||||||
private static final long EVENT_KEEP_WINDOW_MILLIS = 24 * 60 * 60 * 1000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete old (>24 hours, see EVENT_KEEP_WINDOW_MILLIS) events every 6 hours
|
|
||||||
*/
|
|
||||||
private static final long CLEANUP_INTERVAL_MILLIS = EVENT_KEEP_WINDOW_MILLIS/4;
|
|
||||||
|
|
||||||
private final static HashMap<String, PacketStats> eventsByDevice = new HashMap<>();
|
|
||||||
private static long nextCleanup = System.currentTimeMillis() + CLEANUP_INTERVAL_MILLIS;
|
|
||||||
|
|
||||||
static class PacketStats {
|
|
||||||
public long createdAtMillis = System.currentTimeMillis();
|
|
||||||
public HashMap<String, ArrayList<Long>> receivedByType = new HashMap<>();
|
|
||||||
public HashMap<String, ArrayList<Long>> sentSuccessfulByType = new HashMap<>();
|
|
||||||
public HashMap<String, ArrayList<Long>> sentFailedByType = new HashMap<>();
|
|
||||||
|
|
||||||
static class Summary {
|
|
||||||
final @NonNull String packetType;
|
|
||||||
int received = 0;
|
|
||||||
int sentSuccessful = 0;
|
|
||||||
int sentFailed = 0;
|
|
||||||
int total = 0;
|
|
||||||
|
|
||||||
Summary(@NonNull String packetType) {
|
|
||||||
this.packetType = packetType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
|
||||||
public @NonNull Collection<Summary> getSummaries() {
|
|
||||||
HashMap<String, Summary> countsByType = new HashMap<>();
|
|
||||||
for (Map.Entry<String, ArrayList<Long>> entry : receivedByType.entrySet()) {
|
|
||||||
Summary summary = countsByType.computeIfAbsent(entry.getKey(), Summary::new);
|
|
||||||
summary.received += entry.getValue().size();
|
|
||||||
summary.total += entry.getValue().size();
|
|
||||||
}
|
|
||||||
for (Map.Entry<String, ArrayList<Long>> entry : sentSuccessfulByType.entrySet()) {
|
|
||||||
Summary summary = countsByType.computeIfAbsent(entry.getKey(), Summary::new);
|
|
||||||
summary.sentSuccessful += entry.getValue().size();
|
|
||||||
summary.total += entry.getValue().size();
|
|
||||||
}
|
|
||||||
for (Map.Entry<String, ArrayList<Long>> entry : sentFailedByType.entrySet()) {
|
|
||||||
Summary summary = countsByType.computeIfAbsent(entry.getKey(), Summary::new);
|
|
||||||
summary.sentFailed += entry.getValue().size();
|
|
||||||
summary.total += entry.getValue().size();
|
|
||||||
}
|
|
||||||
return countsByType.values();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
|
||||||
public static @NonNull String getStatsForDevice(@NonNull String deviceId) {
|
|
||||||
|
|
||||||
cleanupIfNeeded();
|
|
||||||
|
|
||||||
PacketStats packetStats = eventsByDevice.get(deviceId);
|
|
||||||
if (packetStats == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder ret = new StringBuilder();
|
|
||||||
|
|
||||||
long timeInMillis = System.currentTimeMillis() - packetStats.createdAtMillis;
|
|
||||||
if (timeInMillis > EVENT_KEEP_WINDOW_MILLIS) {
|
|
||||||
timeInMillis = EVENT_KEEP_WINDOW_MILLIS;
|
|
||||||
}
|
|
||||||
long hours = TimeUnit.MILLISECONDS.toHours(timeInMillis);
|
|
||||||
long minutes = TimeUnit.MILLISECONDS.toMinutes(timeInMillis) % 60;
|
|
||||||
ret.append("From last ");
|
|
||||||
ret.append(hours);
|
|
||||||
ret.append("h ");
|
|
||||||
ret.append(minutes);
|
|
||||||
ret.append("m\n\n");
|
|
||||||
|
|
||||||
ArrayList<PacketStats.Summary> counts = new ArrayList<>(packetStats.getSummaries());
|
|
||||||
Collections.sort(counts, (o1, o2) -> Integer.compare(o2.total, o1.total)); // Sort them by total number of events
|
|
||||||
|
|
||||||
for (PacketStats.Summary count : counts) {
|
|
||||||
String name = count.packetType;
|
|
||||||
if (name.startsWith("kdeconnect.")) {
|
|
||||||
name = name.substring("kdeconnect.".length());
|
|
||||||
}
|
|
||||||
ret.append(name);
|
|
||||||
ret.append("\n• ");
|
|
||||||
ret.append(count.received);
|
|
||||||
ret.append(" received\n• ");
|
|
||||||
ret.append(count.sentSuccessful + count.sentFailed);
|
|
||||||
ret.append(" sent (");
|
|
||||||
ret.append(count.sentFailed);
|
|
||||||
ret.append(" failed)\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void countReceived(@NonNull String deviceId, @NonNull String packetType) {
|
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
|
|
||||||
return; // computeIfAbsent not present in API < 24
|
|
||||||
}
|
|
||||||
synchronized (DeviceStats.class) {
|
|
||||||
eventsByDevice
|
|
||||||
.computeIfAbsent(deviceId, key -> new PacketStats())
|
|
||||||
.receivedByType
|
|
||||||
.computeIfAbsent(packetType, key -> new ArrayList<>())
|
|
||||||
.add(System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
cleanupIfNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void countSent(@NonNull String deviceId, @NonNull String packetType, boolean success) {
|
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
|
|
||||||
return; // computeIfAbsent not present in API < 24
|
|
||||||
}
|
|
||||||
if (success) {
|
|
||||||
synchronized (DeviceStats.class) {
|
|
||||||
eventsByDevice
|
|
||||||
.computeIfAbsent(deviceId, key -> new PacketStats())
|
|
||||||
.sentSuccessfulByType
|
|
||||||
.computeIfAbsent(packetType, key -> new ArrayList<>())
|
|
||||||
.add(System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
synchronized (DeviceStats.class) {
|
|
||||||
eventsByDevice
|
|
||||||
.computeIfAbsent(deviceId, key -> new PacketStats())
|
|
||||||
.sentFailedByType
|
|
||||||
.computeIfAbsent(packetType, key -> new ArrayList<>())
|
|
||||||
.add(System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cleanupIfNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void cleanupIfNeeded() {
|
|
||||||
final long cutoutTimestamp = System.currentTimeMillis() - EVENT_KEEP_WINDOW_MILLIS;
|
|
||||||
if (System.currentTimeMillis() > nextCleanup) {
|
|
||||||
synchronized (DeviceStats.class) {
|
|
||||||
Log.i("PacketStats", "Doing periodic cleanup");
|
|
||||||
for (PacketStats de : eventsByDevice.values()) {
|
|
||||||
removeOldEvents(de.receivedByType, cutoutTimestamp);
|
|
||||||
removeOldEvents(de.sentFailedByType, cutoutTimestamp);
|
|
||||||
removeOldEvents(de.sentSuccessfulByType, cutoutTimestamp);
|
|
||||||
}
|
|
||||||
nextCleanup = System.currentTimeMillis() + CLEANUP_INTERVAL_MILLIS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static void removeOldEvents(HashMap<String, ArrayList<Long>> eventsByType, final long cutoutTimestamp) {
|
|
||||||
|
|
||||||
Iterator<Map.Entry<String, ArrayList<Long>>> iterator = eventsByType.entrySet().iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Map.Entry<String, ArrayList<Long>> entry = iterator.next();
|
|
||||||
ArrayList<Long> events = entry.getValue();
|
|
||||||
|
|
||||||
int index = Collections.binarySearch(events, cutoutTimestamp);
|
|
||||||
if (index < 0) {
|
|
||||||
index = -(index + 1); // Convert the negative index to insertion point
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < events.size()) {
|
|
||||||
events.subList(0, index).clear();
|
|
||||||
} else {
|
|
||||||
iterator.remove(); // No element greater than the threshold
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
167
src/org/kde/kdeconnect/DeviceStats.kt
Normal file
167
src/org/kde/kdeconnect/DeviceStats.kt
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
*/
|
||||||
|
package org.kde.kdeconnect
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
object DeviceStats {
|
||||||
|
/**
|
||||||
|
* Keep 24 hours of events
|
||||||
|
*/
|
||||||
|
private const val EVENT_KEEP_WINDOW_MILLIS: Long = 24 * 60 * 60 * 1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete old (>24 hours, see EVENT_KEEP_WINDOW_MILLIS) events every 6 hours
|
||||||
|
*/
|
||||||
|
private const val CLEANUP_INTERVAL_MILLIS = EVENT_KEEP_WINDOW_MILLIS / 4
|
||||||
|
|
||||||
|
private val eventsByDevice: MutableMap<String, PacketStats> = HashMap<String, PacketStats>()
|
||||||
|
private var nextCleanup = System.currentTimeMillis() + CLEANUP_INTERVAL_MILLIS
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||||
|
fun getStatsForDevice(deviceId: String): String {
|
||||||
|
cleanupIfNeeded()
|
||||||
|
|
||||||
|
val packetStats = eventsByDevice[deviceId] ?: return ""
|
||||||
|
|
||||||
|
return buildString {
|
||||||
|
val timeInMillis =
|
||||||
|
minOf((System.currentTimeMillis() - packetStats.createdAtMillis), EVENT_KEEP_WINDOW_MILLIS)
|
||||||
|
val hours = TimeUnit.MILLISECONDS.toHours(timeInMillis)
|
||||||
|
val minutes = TimeUnit.MILLISECONDS.toMinutes(timeInMillis) % 60
|
||||||
|
append("From last ")
|
||||||
|
append(hours)
|
||||||
|
append("h ")
|
||||||
|
append(minutes)
|
||||||
|
append("m\n\n")
|
||||||
|
|
||||||
|
packetStats.summaries.stream().sorted { o1, o2 ->
|
||||||
|
o2.total compareTo o1.total // Sort them by total number of events
|
||||||
|
}.forEach { count ->
|
||||||
|
append(count.packetType.removePrefix("kdeconnect."))
|
||||||
|
append("\n• ")
|
||||||
|
append(count.received)
|
||||||
|
append(" received\n• ")
|
||||||
|
append(count.sentSuccessful + count.sentFailed)
|
||||||
|
append(" sent (")
|
||||||
|
append(count.sentFailed)
|
||||||
|
append(" failed)\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi") // We use core library desugar
|
||||||
|
fun countReceived(deviceId: String, packetType: String) {
|
||||||
|
synchronized(DeviceStats::class.java) {
|
||||||
|
eventsByDevice
|
||||||
|
.computeIfAbsent(deviceId) { PacketStats() }
|
||||||
|
.receivedByType
|
||||||
|
.computeIfAbsent(packetType) { ArrayList() }
|
||||||
|
.add(System.currentTimeMillis())
|
||||||
|
}
|
||||||
|
cleanupIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi") // We use core library desugar
|
||||||
|
fun countSent(deviceId: String, packetType: String, success: Boolean) {
|
||||||
|
if (success) {
|
||||||
|
synchronized(DeviceStats::class.java) {
|
||||||
|
eventsByDevice
|
||||||
|
.computeIfAbsent(deviceId) { PacketStats() }
|
||||||
|
.sentSuccessfulByType
|
||||||
|
.computeIfAbsent(packetType) { ArrayList() }
|
||||||
|
.add(System.currentTimeMillis())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
synchronized(DeviceStats::class.java) {
|
||||||
|
eventsByDevice
|
||||||
|
.computeIfAbsent(deviceId) { PacketStats() }
|
||||||
|
.sentFailedByType
|
||||||
|
.computeIfAbsent(packetType) { ArrayList() }
|
||||||
|
.add(System.currentTimeMillis())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cleanupIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cleanupIfNeeded() {
|
||||||
|
val cutoutTimestamp = System.currentTimeMillis() - EVENT_KEEP_WINDOW_MILLIS
|
||||||
|
if (System.currentTimeMillis() > nextCleanup) {
|
||||||
|
synchronized(DeviceStats::class.java) {
|
||||||
|
Log.i("PacketStats", "Doing periodic cleanup")
|
||||||
|
for (de in eventsByDevice.values) {
|
||||||
|
removeOldEvents(de.receivedByType, cutoutTimestamp)
|
||||||
|
removeOldEvents(de.sentFailedByType, cutoutTimestamp)
|
||||||
|
removeOldEvents(de.sentSuccessfulByType, cutoutTimestamp)
|
||||||
|
}
|
||||||
|
nextCleanup = System.currentTimeMillis() + CLEANUP_INTERVAL_MILLIS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
fun removeOldEvents(eventsByType: HashMap<String, ArrayList<Long>>, cutoutTimestamp: Long) {
|
||||||
|
val iterator = eventsByType.entries.iterator()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val entry = iterator.next()
|
||||||
|
val events = entry.value
|
||||||
|
|
||||||
|
var index = Collections.binarySearch(events, cutoutTimestamp)
|
||||||
|
if (index < 0) {
|
||||||
|
index = -(index + 1) // Convert the negative index to insertion point
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < events.size) {
|
||||||
|
events.subList(0, index).clear()
|
||||||
|
} else {
|
||||||
|
iterator.remove() // No element greater than the threshold
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class PacketStats {
|
||||||
|
val createdAtMillis: Long = System.currentTimeMillis()
|
||||||
|
val receivedByType: HashMap<String, ArrayList<Long>> = HashMap()
|
||||||
|
val sentSuccessfulByType: HashMap<String, ArrayList<Long>> = HashMap()
|
||||||
|
val sentFailedByType: HashMap<String, ArrayList<Long>> = HashMap()
|
||||||
|
|
||||||
|
internal data class Summary(
|
||||||
|
val packetType: String,
|
||||||
|
var received: Int = 0,
|
||||||
|
var sentSuccessful: Int = 0,
|
||||||
|
var sentFailed: Int = 0,
|
||||||
|
var total: Int = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
@get:SuppressLint("NewApi") // We use core library desugar
|
||||||
|
val summaries: Collection<Summary>
|
||||||
|
get() {
|
||||||
|
val countsByType: MutableMap<String, Summary> = HashMap()
|
||||||
|
for ((key, value) in receivedByType) {
|
||||||
|
val summary = countsByType.computeIfAbsent(key) { packetType -> Summary(packetType) }
|
||||||
|
summary.received += value.size
|
||||||
|
summary.total += value.size
|
||||||
|
}
|
||||||
|
for ((key, value) in sentSuccessfulByType) {
|
||||||
|
val summary = countsByType.computeIfAbsent(key) { packetType -> Summary(packetType) }
|
||||||
|
summary.sentSuccessful += value.size
|
||||||
|
summary.total += value.size
|
||||||
|
}
|
||||||
|
for ((key, value) in sentFailedByType) {
|
||||||
|
val summary = countsByType.computeIfAbsent(key) { packetType -> Summary(packetType) }
|
||||||
|
summary.sentFailed += value.size
|
||||||
|
summary.total += value.size
|
||||||
|
}
|
||||||
|
return countsByType.values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -104,7 +104,7 @@ public class PluginSettingsActivity
|
|||||||
return false; // PacketStats not working in API < 24
|
return false; // PacketStats not working in API < 24
|
||||||
}
|
}
|
||||||
menu.add(R.string.plugin_stats).setOnMenuItemClickListener(item -> {
|
menu.add(R.string.plugin_stats).setOnMenuItemClickListener(item -> {
|
||||||
String stats = DeviceStats.getStatsForDevice(deviceId);
|
String stats = DeviceStats.INSTANCE.getStatsForDevice(deviceId);
|
||||||
AlertDialog alertDialog = new MaterialAlertDialogBuilder(PluginSettingsActivity.this)
|
AlertDialog alertDialog = new MaterialAlertDialogBuilder(PluginSettingsActivity.this)
|
||||||
.setTitle(R.string.plugin_stats)
|
.setTitle(R.string.plugin_stats)
|
||||||
.setPositiveButton(R.string.ok, (dialog, which) -> dialog.dismiss())
|
.setPositiveButton(R.string.ok, (dialog, which) -> dialog.dismiss())
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
package org.kde.kdeconnect;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
public class DeviceStatsTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void removeOldEvents_cutoutExists() {
|
|
||||||
final String key = "kdeconnect.ping";
|
|
||||||
HashMap<String, ArrayList<Long>> eventsByType = new HashMap<>();
|
|
||||||
ArrayList<Long> events = new ArrayList<>();
|
|
||||||
eventsByType.put(key, events);
|
|
||||||
events.add(10L);
|
|
||||||
events.add(20L);
|
|
||||||
events.add(30L);
|
|
||||||
final long cutout = 20L;
|
|
||||||
DeviceStats.removeOldEvents(eventsByType, cutout);
|
|
||||||
ArrayList<Long> eventsAfter = eventsByType.get(key);
|
|
||||||
Assert.assertNotNull(eventsAfter);
|
|
||||||
Assert.assertEquals(2, eventsAfter.size());
|
|
||||||
Assert.assertEquals(eventsAfter.get(0).longValue(), 20L);
|
|
||||||
Assert.assertEquals(eventsAfter.get(1).longValue(), 30L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void removeOldEvents_cutoutDoesntExist() {
|
|
||||||
final String key = "kdeconnect.ping";
|
|
||||||
HashMap<String, ArrayList<Long>> eventsByType = new HashMap<>();
|
|
||||||
ArrayList<Long> events = new ArrayList<>();
|
|
||||||
eventsByType.put(key, events);
|
|
||||||
events.add(10L);
|
|
||||||
events.add(20L);
|
|
||||||
events.add(30L);
|
|
||||||
final long cutout = 25L;
|
|
||||||
DeviceStats.removeOldEvents(eventsByType, cutout);
|
|
||||||
ArrayList<Long> eventsAfter = eventsByType.get(key);
|
|
||||||
Assert.assertNotNull(eventsAfter);
|
|
||||||
Assert.assertEquals(1, eventsAfter.size());
|
|
||||||
Assert.assertEquals(eventsAfter.get(0).longValue(), 30L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void removeOldEvents_OnlyOldEvents() {
|
|
||||||
final String key = "kdeconnect.ping";
|
|
||||||
HashMap<String, ArrayList<Long>> eventsByType = new HashMap<>();
|
|
||||||
ArrayList<Long> events = new ArrayList<>();
|
|
||||||
eventsByType.put(key, events);
|
|
||||||
events.add(10L);
|
|
||||||
events.add(20L);
|
|
||||||
final long cutout = 25L;
|
|
||||||
DeviceStats.removeOldEvents(eventsByType, cutout);
|
|
||||||
ArrayList<Long> eventsAfter = eventsByType.get(key);
|
|
||||||
Assert.assertNull(eventsAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void removeOldEvents_OnlyNewEvents() {
|
|
||||||
final String key = "kdeconnect.ping";
|
|
||||||
HashMap<String, ArrayList<Long>> eventsByType = new HashMap<>();
|
|
||||||
ArrayList<Long> events = new ArrayList<>();
|
|
||||||
eventsByType.put(key, events);
|
|
||||||
events.add(10L);
|
|
||||||
final long cutout = 5L;
|
|
||||||
DeviceStats.removeOldEvents(eventsByType, cutout);
|
|
||||||
ArrayList<Long> eventsAfter = eventsByType.get(key);
|
|
||||||
Assert.assertNotNull(eventsAfter);
|
|
||||||
Assert.assertEquals(1, eventsAfter.size());
|
|
||||||
Assert.assertEquals(eventsAfter.get(0).longValue(), 10L);
|
|
||||||
}
|
|
||||||
}
|
|
66
tests/org/kde/kdeconnect/DeviceStatsTest.kt
Normal file
66
tests/org/kde/kdeconnect/DeviceStatsTest.kt
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package org.kde.kdeconnect
|
||||||
|
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Test
|
||||||
|
import org.kde.kdeconnect.DeviceStats.removeOldEvents
|
||||||
|
|
||||||
|
class DeviceStatsTest {
|
||||||
|
@Test
|
||||||
|
fun removeOldEvents_cutoutExists() {
|
||||||
|
val key = "kdeconnect.ping"
|
||||||
|
val eventsByType = HashMap<String, ArrayList<Long>>().apply {
|
||||||
|
val events = arrayListOf(10L, 20L, 30L)
|
||||||
|
put(key, events)
|
||||||
|
}
|
||||||
|
val cutout = 20L
|
||||||
|
removeOldEvents(eventsByType, cutout)
|
||||||
|
val eventsAfter = eventsByType[key]!!
|
||||||
|
Assert.assertNotNull(eventsAfter)
|
||||||
|
Assert.assertEquals(2, eventsAfter.size.toLong())
|
||||||
|
Assert.assertEquals(eventsAfter[0], 20L)
|
||||||
|
Assert.assertEquals(eventsAfter[1], 30L)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun removeOldEvents_cutoutDoesntExist() {
|
||||||
|
val key = "kdeconnect.ping"
|
||||||
|
val eventsByType = HashMap<String, ArrayList<Long>>().apply {
|
||||||
|
val events = arrayListOf(10L, 20L, 30L)
|
||||||
|
put(key, events)
|
||||||
|
}
|
||||||
|
val cutout = 25L
|
||||||
|
removeOldEvents(eventsByType, cutout)
|
||||||
|
val eventsAfter = eventsByType[key]!!
|
||||||
|
Assert.assertNotNull(eventsAfter)
|
||||||
|
Assert.assertEquals(1, eventsAfter.size.toLong())
|
||||||
|
Assert.assertEquals(eventsAfter[0], 30L)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun removeOldEvents_OnlyOldEvents() {
|
||||||
|
val key = "kdeconnect.ping"
|
||||||
|
val eventsByType = HashMap<String, ArrayList<Long>>().apply {
|
||||||
|
val events = arrayListOf(10L, 20L)
|
||||||
|
put(key, events)
|
||||||
|
}
|
||||||
|
val cutout = 25L
|
||||||
|
removeOldEvents(eventsByType, cutout)
|
||||||
|
val eventsAfter = eventsByType[key]
|
||||||
|
Assert.assertNull(eventsAfter)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun removeOldEvents_OnlyNewEvents() {
|
||||||
|
val key = "kdeconnect.ping"
|
||||||
|
val eventsByType = HashMap<String, ArrayList<Long>>().apply {
|
||||||
|
val events = arrayListOf(10L)
|
||||||
|
put(key, events)
|
||||||
|
}
|
||||||
|
val cutout = 5L
|
||||||
|
removeOldEvents(eventsByType, cutout)
|
||||||
|
val eventsAfter = eventsByType[key]!!
|
||||||
|
Assert.assertNotNull(eventsAfter)
|
||||||
|
Assert.assertEquals(1, eventsAfter.size.toLong())
|
||||||
|
Assert.assertEquals(eventsAfter[0], 10L)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user