20
20
21
21
import static org .mockito .Mockito .when ;
22
22
23
+ import java .lang .reflect .Field ;
23
24
import java .net .URI ;
24
25
import java .net .URISyntaxException ;
26
+ import java .text .SimpleDateFormat ;
25
27
import java .util .ArrayList ;
26
28
import java .util .Arrays ;
27
29
import java .util .Date ;
33
35
import java .util .concurrent .ConcurrentHashMap ;
34
36
import java .util .concurrent .TimeUnit ;
35
37
38
+ import com .cloud .utils .DateUtil ;
39
+ import com .google .gson .JsonSyntaxException ;
36
40
import org .apache .cloudstack .framework .config .ConfigKey ;
37
41
import org .apache .cloudstack .storage .datastore .db .StoragePoolVO ;
38
42
import org .apache .commons .collections .CollectionUtils ;
@@ -116,6 +120,8 @@ public class StatsCollectorTest {
116
120
117
121
private static Gson gson = new Gson ();
118
122
123
+ private Gson msStatsGson ;
124
+
119
125
private MockedStatic <InfluxDBFactory > influxDBFactoryMocked ;
120
126
121
127
private AutoCloseable closeable ;
@@ -125,6 +131,9 @@ public void setUp() throws Exception {
125
131
closeable = MockitoAnnotations .openMocks (this );
126
132
statsCollector .vmStatsDao = vmStatsDaoMock ;
127
133
statsCollector .volumeStatsDao = volumeStatsDao ;
134
+ Field msStatsGsonField = StatsCollector .class .getDeclaredField ("msStatsGson" );
135
+ msStatsGsonField .setAccessible (true );
136
+ msStatsGson = (Gson ) msStatsGsonField .get (null );
128
137
}
129
138
130
139
@ After
@@ -612,4 +621,107 @@ public void testPoolNeedsIopsStatsUpdating_NullIops() {
612
621
Mockito .verify (mockPool , Mockito .never ()).setCapacityIops (Mockito .anyLong ());
613
622
Mockito .verify (mockPool , Mockito .never ()).setUsedIops (Mockito .anyLong ());
614
623
}
624
+
625
+ @ Test
626
+ public void testGsonDateFormatSerialization () {
627
+ Date now = new Date ();
628
+ TestClass testObj = new TestClass ("TestString" , 999 , now );
629
+ String json = msStatsGson .toJson (testObj );
630
+
631
+ Assert .assertTrue (json .contains ("TestString" ));
632
+ Assert .assertTrue (json .contains ("999" ));
633
+ String expectedDate = new SimpleDateFormat (DateUtil .ZONED_DATETIME_FORMAT ).format (now );
634
+ Assert .assertTrue (json .contains (expectedDate ));
635
+ }
636
+
637
+ @ Test
638
+ public void testGsonDateFormatDeserializationWithSameDateFormat () throws Exception {
639
+ String json = "{\" str\" :\" TestString\" ,\" num\" :999,\" date\" :\" 2025-08-22T15:39:43+0000\" }" ;
640
+ TestClass testObj = msStatsGson .fromJson (json , TestClass .class );
641
+
642
+ Assert .assertEquals ("TestString" , testObj .getStr ());
643
+ Assert .assertEquals (999 , testObj .getNum ());
644
+ Date expectedDate = new SimpleDateFormat (DateUtil .ZONED_DATETIME_FORMAT ).parse ("2025-08-22T15:39:43+0000" );
645
+ Assert .assertEquals (expectedDate , testObj .getDate ());
646
+ }
647
+
648
+ @ Test (expected = JsonSyntaxException .class )
649
+ public void testGsonDateFormatDeserializationWithDifferentDateFormat () throws Exception {
650
+ String json = "{\" str\" :\" TestString\" ,\" num\" :999,\" date\" :\" 22/08/2025T15:39:43+0000\" }" ;
651
+ msStatsGson .fromJson (json , TestClass .class );
652
+ /* Deserialization throws the below exception:
653
+ com.google.gson.JsonSyntaxException: 22/08/2025T15:39:43+0000
654
+ at com.google.gson.DefaultTypeAdapters$DefaultDateTypeAdapter.deserializeToDate(DefaultTypeAdapters.java:376)
655
+ at com.google.gson.DefaultTypeAdapters$DefaultDateTypeAdapter.deserialize(DefaultTypeAdapters.java:351)
656
+ at com.google.gson.DefaultTypeAdapters$DefaultDateTypeAdapter.deserialize(DefaultTypeAdapters.java:307)
657
+ at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:92)
658
+ at com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler(JsonObjectDeserializationVisitor.java:117)
659
+ at com.google.gson.ReflectingFieldNavigator.visitFieldsReflectively(ReflectingFieldNavigator.java:63)
660
+ at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:120)
661
+ at com.google.gson.JsonDeserializationContextDefault.fromJsonObject(JsonDeserializationContextDefault.java:76)
662
+ at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:54)
663
+ at com.google.gson.Gson.fromJson(Gson.java:551)
664
+ at com.google.gson.Gson.fromJson(Gson.java:498)
665
+ at com.google.gson.Gson.fromJson(Gson.java:467)
666
+ at com.google.gson.Gson.fromJson(Gson.java:417)
667
+ at com.google.gson.Gson.fromJson(Gson.java:389)
668
+ at com.cloud.serializer.GsonHelperTest.testGsonDateFormatDeserializationWithDifferentDateFormat(GsonHelperTest.java:113)
669
+ at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
670
+ at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
671
+ at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
672
+ at java.base/java.lang.reflect.Method.invoke(Method.java:566)
673
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
674
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
675
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
676
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
677
+ at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
678
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
679
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
680
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
681
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
682
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
683
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
684
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
685
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
686
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
687
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
688
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
689
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
690
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
691
+ at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
692
+ at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
693
+ at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
694
+ at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
695
+ at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:231)
696
+ at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
697
+ Caused by: java.text.ParseException: Unparseable date: "22/08/2025T15:39:43+0000"
698
+ at java.base/java.text.DateFormat.parse(DateFormat.java:395)
699
+ at com.google.gson.DefaultTypeAdapters$DefaultDateTypeAdapter.deserializeToDate(DefaultTypeAdapters.java:374)
700
+ ... 42 more
701
+ */
702
+ }
703
+
704
+ private static class TestClass {
705
+ private String str ;
706
+ private int num ;
707
+ private Date date ;
708
+
709
+ public TestClass (String str , int num , Date date ) {
710
+ this .str = str ;
711
+ this .num = num ;
712
+ this .date = date ;
713
+ }
714
+
715
+ public String getStr () {
716
+ return str ;
717
+ }
718
+
719
+ public int getNum () {
720
+ return num ;
721
+ }
722
+
723
+ public Date getDate () {
724
+ return date ;
725
+ }
726
+ }
615
727
}
0 commit comments