diff --git a/modules/AcShop/pom.xml b/modules/AcShop/pom.xml index b929296..1b86d4e 100644 --- a/modules/AcShop/pom.xml +++ b/modules/AcShop/pom.xml @@ -86,6 +86,18 @@ jar 1.0.0 + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + 5.11.0 + test + diff --git a/modules/AcShop/src/main/java/com/mcatk/acshop/FileOperation.java b/modules/AcShop/src/main/java/com/mcatk/acshop/FileOperation.java index 5bc8638..8bb3931 100644 --- a/modules/AcShop/src/main/java/com/mcatk/acshop/FileOperation.java +++ b/modules/AcShop/src/main/java/com/mcatk/acshop/FileOperation.java @@ -11,23 +11,35 @@ public class FileOperation { + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); private final File shopsFile; - private final Gson gson; public FileOperation() { - shopsFile = new File(AcShop.getPlugin().getDataFolder(), "shopsFile.json"); - gson = new GsonBuilder().setPrettyPrinting().create(); + this(AcShop.getPlugin().getDataFolder()); + } + + public FileOperation(File dataFolder) { + this.shopsFile = new File(dataFolder, "shopsFile.json"); } public void saveShops(Shops shops) { - try { - FileWriter writer = new FileWriter(shopsFile); + try (FileWriter writer = new FileWriter(shopsFile)) { gson.toJson(shops, writer); - writer.flush(); } catch (IOException e) { e.printStackTrace(); } } + + public void saveShopsAsync(Shops shops) { + final String json = gson.toJson(shops); + org.bukkit.Bukkit.getScheduler().runTaskAsynchronously(AcShop.getPlugin(), () -> { + try (FileWriter writer = new FileWriter(shopsFile)) { + writer.write(json); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } public Shops loadShops() { Shops shops = null; diff --git a/modules/AcShop/src/main/java/com/mcatk/acshop/command/AdminCommand.java b/modules/AcShop/src/main/java/com/mcatk/acshop/command/AdminCommand.java index ee8c7e1..1b1d97d 100644 --- a/modules/AcShop/src/main/java/com/mcatk/acshop/command/AdminCommand.java +++ b/modules/AcShop/src/main/java/com/mcatk/acshop/command/AdminCommand.java @@ -47,7 +47,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St break; default: } - new FileOperation().saveShops(AcShop.getShops()); + new FileOperation().saveShopsAsync(AcShop.getShops()); return true; } diff --git a/modules/AcShop/src/test/java/com/mcatk/acshop/BenchmarkTest.java b/modules/AcShop/src/test/java/com/mcatk/acshop/BenchmarkTest.java new file mode 100644 index 0000000..3390eab --- /dev/null +++ b/modules/AcShop/src/test/java/com/mcatk/acshop/BenchmarkTest.java @@ -0,0 +1,70 @@ +package com.mcatk.acshop; + +import com.mcatk.acshop.commodity.Item; +import com.mcatk.acshop.commodity.ItemType; +import com.mcatk.acshop.shop.Shop; +import com.mcatk.acshop.shop.Shops; +import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.plugin.Plugin; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class BenchmarkTest { + + @Test + public void benchmarkSaveShops() throws IOException { + // Setup data + Shops shops = new Shops(); + for (int i = 0; i < 50; i++) { + Shop shop = new Shop("Shop" + i); + for (int j = 0; j < 50; j++) { + shop.getItemHashMap().put("Item" + j, new Item(ItemType.ITEM_STACK, "Item" + j, 100, "sort", "id")); + } + shops.getShopsHashMap().put(shop.getId(), shop); + } + + // Mock AcShop + File tempDir = Files.createTempDirectory("acshop_test").toFile(); + tempDir.deleteOnExit(); + + AcShop mockPlugin = mock(AcShop.class); + when(mockPlugin.getDataFolder()).thenReturn(tempDir); + + BukkitScheduler mockScheduler = mock(BukkitScheduler.class); + when(mockScheduler.runTaskAsynchronously(any(Plugin.class), any(Runnable.class))).thenReturn(null); + + try (MockedStatic mockedAcShop = Mockito.mockStatic(AcShop.class); + MockedStatic mockedBukkit = Mockito.mockStatic(Bukkit.class)) { + + mockedAcShop.when(AcShop::getPlugin).thenReturn(mockPlugin); + mockedBukkit.when(Bukkit::getScheduler).thenReturn(mockScheduler); + + // Warmup + new FileOperation().saveShopsAsync(shops); + + // Benchmark + long startTime = System.nanoTime(); + int iterations = 20; + for (int i = 0; i < iterations; i++) { + new FileOperation().saveShopsAsync(shops); + } + long endTime = System.nanoTime(); + double avgTime = (endTime - startTime) / (double) iterations / 1_000_000.0; + System.out.println("Average save time (Async offload): " + avgTime + " ms"); + } + } +}