content: package arthas;
  
  import java.io.File;
  import java.lang.ref.WeakReference;
  import java.util.ArrayList;
  import java.util.concurrent.TimeUnit;
  import java.util.concurrent.atomic.AtomicLong;
  
  import org.assertj.core.api.Assertions;
  import org.junit.Assert;
  import org.junit.Test;
  
  import com.taobao.arthas.common.VmToolUtils;
  
  /**
   * 以下本地测试的jvm参数均为：-Xms128m -Xmx128m
   */
  public class VmToolTest {
      private VmTool initVmTool() {
          File path = new File(VmTool.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getParentFile();
  
          String libPath = new File(path, VmToolUtils.detectLibName()).getAbsolutePath();
          return VmTool.getInstance(libPath);
      }
  
      /**
       * macbook上运行结果如下
       * allLoadedClasses->1050
       * arthas.VmTool@5bb21b69 arthas.VmTool@6b9651f3
       * before instances->[arthas.VmTool@5bb21b69, arthas.VmTool@6b9651f3]
       * size->16
       * count->2
       * sum size->32
       * null null
       * after instances->[]
       */
      @Test
      public void testIsSnapshot() {
          try {
              VmTool vmtool = initVmTool();
              //调用native方法，获取已加载的类，不包括小类型(如int)
              Class<?>[] allLoadedClasses = vmtool.getAllLoadedClasses();
              System.out.println("allLoadedClasses->" + allLoadedClasses.length);
  
              //通过下面的例子，可以看到getInstances(Class<T> klass)拿到的是当前存活的所有对象
              WeakReference<VmToolTest> weakReference1 = new WeakReference<VmToolTest>(new VmToolTest());
              WeakReference<VmToolTest> weakReference2 = new WeakReference<VmToolTest>(new VmToolTest());
              System.out.println(weakReference1.get() + " " + weakReference2.get());
              VmTool[] beforeInstances = vmtool.getInstances(VmTool.class);
              System.out.println("before instances->" + beforeInstances);
              System.out.println("size->" + vmtool.getInstanceSize(weakReference1.get()));
              System.out.println("count->" + vmtool.countInstances(VmTool.class));
              System.out.println("sum size->" + vmtool.sumInstanceSize(VmTool.class));
              beforeInstances = null;
  
              vmtool.forceGc();
              Thread.sleep(100);
              System.out.println(weakReference1.get() + " " + weakReference2.get());
              VmTool[] afterInstances = vmtool.getInstances(VmTool.class);
              System.out.println("after instances->" + afterInstances);
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  
      @Test
      public void testGetInstancesMemoryLeak() {
          //这里睡20s是为了方便用jprofiler连接上进程
  //        try {
  //            Thread.sleep(20000);
  //        } catch (InterruptedException e) {
  //            e.printStackTrace();
  //        }
          VmTool vmtool = initVmTool();
          final AtomicLong totalTime = new AtomicLong();
          //本地测试请改成200000
          for (int i = 1; i <= 2; i++) {
              long start = System.currentTimeMillis();
              WeakReference<Object[]> reference = new WeakReference<Object[]>(vmtool.getInstances(Object.class));
              Object[] instances = reference.get();
              long cost = System.currentTimeMillis() - start;
              totalTime.addAndGet(cost);
              System.out.println(i + " instance size:" + (instances == null ? 0 : instances.length) + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
              instances = null;
              vmtool.forceGc();
          }
      }
  
      @Test
      public void testSumInstancesMemoryLeak() {
          //这里睡20s是为了方便用jprofiler连接上进程
  //        try {
  //            Thread.sleep(20000);
  //        } catch (InterruptedException e) {
  //            e.printStackTrace();
  //        }
          VmTool vmtool = initVmTool();
          final AtomicLong totalTime = new AtomicLong();
          //本地测试请改成200000
          for (int i = 1; i <= 2; i++) {
              long start = System.currentTimeMillis();
              long sum = vmtool.sumInstanceSize(Object.class);
              long cost = System.currentTimeMillis() - start;
              totalTime.addAndGet(cost);
              System.out.println(i + " sum:" + sum + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
          }
      }
  
      @Test
      public void testCountInstancesMemoryLeak() {
          //这里睡20s是为了方便用jprofiler连接上进程
  //        try {
  //            Thread.sleep(20000);
  //        } catch (InterruptedException e) {
  //            e.printStackTrace();
  //        }
          VmTool vmtool = initVmTool();
          final AtomicLong totalTime = new AtomicLong();
          //本地测试请改成200000
          for (int i = 1; i <= 2; i++) {
              long start = System.currentTimeMillis();
              long count = vmtool.countInstances(Object.class);
              long cost = System.currentTimeMillis() - start;
              totalTime.addAndGet(cost);
              System.out.println(i + " count:" + count + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
          }
      }
  
      @Test
      public void testGetAllLoadedClassesMemoryLeak() {
          //这里睡20s是为了方便用jprofiler连接上进程
  //        try {
  //            Thread.sleep(20000);
  //        } catch (InterruptedException e) {
  //            e.printStackTrace();
  //        }
          VmTool vmtool = initVmTool();
          final AtomicLong totalTime = new AtomicLong();
          //本地测试请改成200000
          for (int i = 1; i <= 2; i++) {
              long start = System.currentTimeMillis();
              Class<?>[] allLoadedClasses = vmtool.getAllLoadedClasses();
              long cost = System.currentTimeMillis() - start;
              totalTime.addAndGet(cost);
              System.out.println(i + " class size:" + allLoadedClasses.length + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
              allLoadedClasses = null;
          }
      }
  
      class LimitTest {
      }
  
      @Test
      public void test_getInstances_lmiit() {
          VmTool vmtool = initVmTool();
  
          ArrayList<LimitTest> list = new ArrayList<LimitTest>();
          for (int i = 0; i < 10; ++i) {
              list.add(new LimitTest());
          }
          LimitTest[] instances = vmtool.getInstances(LimitTest.class, 5);
          Assertions.assertThat(instances).hasSize(5);
          LimitTest[] instances2 = vmtool.getInstances(LimitTest.class, -1);
          Assertions.assertThat(instances2).hasSize(10);
          LimitTest[] instances3 = vmtool.getInstances(LimitTest.class, 1);
          Assertions.assertThat(instances3).hasSize(1);
      }
  
      interface III {
      }
  
      class AAA implements III {
      }
  
      @Test
      public void test_getInstances_interface() {
          AAA aaa = new AAA();
          VmTool vmtool = initVmTool();
          III[] interfaceInstances = vmtool.getInstances(III.class);
          Assertions.assertThat(interfaceInstances.length).isEqualTo(1);
  
          AAA[] ObjectInstances = vmtool.getInstances(AAA.class);
          Assertions.assertThat(ObjectInstances.length).isEqualTo(1);
  
          Assertions.assertThat(interfaceInstances[0]).isEqualTo(ObjectInstances[0]);
      }
  
      @Test
      public void test_interrupt_thread() throws InterruptedException {
          String threadName = "interruptMe";
          final RuntimeException[] re = new RuntimeException[1];
          Runnable runnable = new Runnable() {
              @Override public void run() {
                  try {
                      System.out.printf("Thread name is: [%s], thread id is: [%d].\n", Thread.currentThread().getName(),Thread.currentThread().getId());
                      TimeUnit.SECONDS.sleep(1000);
                  } catch (InterruptedException e) {
                      re[0] = new RuntimeException("interrupted " + Thread.currentThread().getId() + " thread success.");
                  }
              }
          };
          Thread interruptMe = new Thread(runnable,threadName);
          Thread interruptMe1 = new Thread(runnable,threadName);
  
          interruptMe.start();
          interruptMe1.start();
  
          VmTool tool = initVmTool();
          tool.interruptSpecialThread((int) interruptMe.getId());
          TimeUnit.SECONDS.sleep(5);
          Assert.assertEquals(("interrupted " + interruptMe.getId() + " thread success."), re[0].getMessage());
      }
  
      @Test
      public void testMallocTrim() {
          VmTool vmtool = initVmTool();
          vmtool.mallocTrim();
      }
  
      @Test
      public void testMallocStats() {
          VmTool vmtool = initVmTool();
          vmtool.mallocStats();
      }
  }
  