@@ -646,3 +646,205 @@ func TestAllowedIPRangesAllRulesAreDisabled(t *testing.T) {
646646 require .False (t , actual )
647647 })
648648}
649+
650+ func TestPodProbeOverridesValue (t * testing.T ) {
651+ t .Run ("nil PodProbeOverrides" , func (t * testing.T ) {
652+ var probeOverrides * PodProbeOverrides
653+ value , err := probeOverrides .Value ()
654+ assert .NoError (t , err )
655+ assert .Nil (t , value )
656+ })
657+
658+ t .Run ("empty PodProbeOverrides" , func (t * testing.T ) {
659+ probeOverrides := & PodProbeOverrides {}
660+ value , err := probeOverrides .Value ()
661+ assert .NoError (t , err )
662+ assert .NotNil (t , value )
663+
664+ expected := `{}`
665+ assert .JSONEq (t , expected , string (value .([]byte )))
666+ })
667+
668+ t .Run ("PodProbeOverrides with values" , func (t * testing.T ) {
669+ probeOverrides := & PodProbeOverrides {
670+ LivenessProbeOverride : & corev1.Probe {
671+ FailureThreshold : 5 ,
672+ InitialDelaySeconds : 30 ,
673+ TimeoutSeconds : 10 ,
674+ },
675+ ReadinessProbeOverride : & corev1.Probe {
676+ FailureThreshold : 3 ,
677+ InitialDelaySeconds : 15 ,
678+ TimeoutSeconds : 5 ,
679+ },
680+ }
681+ value , err := probeOverrides .Value ()
682+ assert .NoError (t , err )
683+ assert .NotNil (t , value )
684+
685+ // Unmarshal to verify JSON structure
686+ var result PodProbeOverrides
687+ err = json .Unmarshal (value .([]byte ), & result )
688+ assert .NoError (t , err )
689+ assert .Equal (t , int32 (5 ), result .LivenessProbeOverride .FailureThreshold )
690+ assert .Equal (t , int32 (30 ), result .LivenessProbeOverride .InitialDelaySeconds )
691+ assert .Equal (t , int32 (10 ), result .LivenessProbeOverride .TimeoutSeconds )
692+ assert .Equal (t , int32 (3 ), result .ReadinessProbeOverride .FailureThreshold )
693+ assert .Equal (t , int32 (15 ), result .ReadinessProbeOverride .InitialDelaySeconds )
694+ assert .Equal (t , int32 (5 ), result .ReadinessProbeOverride .TimeoutSeconds )
695+ })
696+ }
697+
698+ func TestPodProbeOverridesScan (t * testing.T ) {
699+ t .Run ("nil source" , func (t * testing.T ) {
700+ var probeOverrides PodProbeOverrides
701+ err := probeOverrides .Scan (nil )
702+ assert .NoError (t , err )
703+ })
704+
705+ t .Run ("invalid source type" , func (t * testing.T ) {
706+ var probeOverrides PodProbeOverrides
707+ err := probeOverrides .Scan ("invalid" )
708+ assert .Error (t , err )
709+ assert .Contains (t , err .Error (), "could not assert type of PodProbeOverrides" )
710+ })
711+
712+ t .Run ("invalid JSON" , func (t * testing.T ) {
713+ var probeOverrides PodProbeOverrides
714+ err := probeOverrides .Scan ([]byte ("invalid json" ))
715+ assert .Error (t , err )
716+ })
717+
718+ t .Run ("empty JSON object" , func (t * testing.T ) {
719+ var probeOverrides PodProbeOverrides
720+ err := probeOverrides .Scan ([]byte (`{}` ))
721+ assert .NoError (t , err )
722+ assert .Nil (t , probeOverrides .LivenessProbeOverride )
723+ assert .Nil (t , probeOverrides .ReadinessProbeOverride )
724+ })
725+
726+ t .Run ("valid JSON with probe overrides" , func (t * testing.T ) {
727+ jsonData := `{
728+ "LivenessProbeOverride": {
729+ "failureThreshold": 8,
730+ "initialDelaySeconds": 45,
731+ "timeoutSeconds": 15
732+ },
733+ "ReadinessProbeOverride": {
734+ "failureThreshold": 6,
735+ "initialDelaySeconds": 20,
736+ "timeoutSeconds": 8
737+ }
738+ }`
739+
740+ var probeOverrides PodProbeOverrides
741+ err := probeOverrides .Scan ([]byte (jsonData ))
742+ assert .NoError (t , err )
743+
744+ assert .NotNil (t , probeOverrides .LivenessProbeOverride )
745+ assert .Equal (t , int32 (8 ), probeOverrides .LivenessProbeOverride .FailureThreshold )
746+ assert .Equal (t , int32 (45 ), probeOverrides .LivenessProbeOverride .InitialDelaySeconds )
747+ assert .Equal (t , int32 (15 ), probeOverrides .LivenessProbeOverride .TimeoutSeconds )
748+
749+ assert .NotNil (t , probeOverrides .ReadinessProbeOverride )
750+ assert .Equal (t , int32 (6 ), probeOverrides .ReadinessProbeOverride .FailureThreshold )
751+ assert .Equal (t , int32 (20 ), probeOverrides .ReadinessProbeOverride .InitialDelaySeconds )
752+ assert .Equal (t , int32 (8 ), probeOverrides .ReadinessProbeOverride .TimeoutSeconds )
753+ })
754+ }
755+
756+ func TestPodProbeOverridesRoundTrip (t * testing.T ) {
757+ t .Run ("round trip serialization" , func (t * testing.T ) {
758+ original := & PodProbeOverrides {
759+ LivenessProbeOverride : & corev1.Probe {
760+ FailureThreshold : 10 ,
761+ SuccessThreshold : 2 ,
762+ InitialDelaySeconds : 60 ,
763+ PeriodSeconds : 20 ,
764+ TimeoutSeconds : 15 ,
765+ },
766+ ReadinessProbeOverride : & corev1.Probe {
767+ FailureThreshold : 7 ,
768+ SuccessThreshold : 3 ,
769+ InitialDelaySeconds : 30 ,
770+ PeriodSeconds : 10 ,
771+ TimeoutSeconds : 12 ,
772+ },
773+ }
774+
775+ // Serialize using Value()
776+ value , err := original .Value ()
777+ assert .NoError (t , err )
778+ assert .NotNil (t , value )
779+
780+ // Deserialize using Scan()
781+ var result PodProbeOverrides
782+ err = result .Scan (value )
783+ assert .NoError (t , err )
784+
785+ // Verify the round trip preserved all values
786+ assert .Equal (t , original .LivenessProbeOverride .FailureThreshold , result .LivenessProbeOverride .FailureThreshold )
787+ assert .Equal (t , original .LivenessProbeOverride .SuccessThreshold , result .LivenessProbeOverride .SuccessThreshold )
788+ assert .Equal (t , original .LivenessProbeOverride .InitialDelaySeconds , result .LivenessProbeOverride .InitialDelaySeconds )
789+ assert .Equal (t , original .LivenessProbeOverride .PeriodSeconds , result .LivenessProbeOverride .PeriodSeconds )
790+ assert .Equal (t , original .LivenessProbeOverride .TimeoutSeconds , result .LivenessProbeOverride .TimeoutSeconds )
791+
792+ assert .Equal (t , original .ReadinessProbeOverride .FailureThreshold , result .ReadinessProbeOverride .FailureThreshold )
793+ assert .Equal (t , original .ReadinessProbeOverride .SuccessThreshold , result .ReadinessProbeOverride .SuccessThreshold )
794+ assert .Equal (t , original .ReadinessProbeOverride .InitialDelaySeconds , result .ReadinessProbeOverride .InitialDelaySeconds )
795+ assert .Equal (t , original .ReadinessProbeOverride .PeriodSeconds , result .ReadinessProbeOverride .PeriodSeconds )
796+ assert .Equal (t , original .ReadinessProbeOverride .TimeoutSeconds , result .ReadinessProbeOverride .TimeoutSeconds )
797+ })
798+ }
799+
800+ func TestPodProbeOverridesSimulatedDatabaseScenario (t * testing.T ) {
801+ t .Run ("simulates the original database error scenario" , func (t * testing.T ) {
802+ // This test simulates what happens when trying to store an installation
803+ // with both liveness and readiness probe overrides in the database.
804+ // Before our fix, this would fail with:
805+ // "sql: converting argument $21 type: unsupported type model.PodProbeOverrides, a struct"
806+
807+ installation := & Installation {
808+ PodProbeOverrides : & PodProbeOverrides {
809+ LivenessProbeOverride : & corev1.Probe {
810+ FailureThreshold : 10 ,
811+ InitialDelaySeconds : 60 ,
812+ TimeoutSeconds : 15 ,
813+ },
814+ ReadinessProbeOverride : & corev1.Probe {
815+ FailureThreshold : 5 ,
816+ InitialDelaySeconds : 30 ,
817+ TimeoutSeconds : 8 ,
818+ },
819+ },
820+ }
821+
822+ // Simulate what the SQL driver would do when trying to store this value
823+ value , err := installation .PodProbeOverrides .Value ()
824+ assert .NoError (t , err , "PodProbeOverrides should be serializable to database value" )
825+ assert .NotNil (t , value , "Database value should not be nil" )
826+
827+ // Verify the value is valid JSON
828+ var result PodProbeOverrides
829+ err = json .Unmarshal (value .([]byte ), & result )
830+ assert .NoError (t , err , "Database value should be valid JSON" )
831+
832+ // Verify we can read it back correctly
833+ var scannedOverrides PodProbeOverrides
834+ err = scannedOverrides .Scan (value )
835+ assert .NoError (t , err , "Should be able to scan value back from database" )
836+
837+ // Verify the round trip preserves data
838+ assert .Equal (t , installation .PodProbeOverrides .LivenessProbeOverride .FailureThreshold , scannedOverrides .LivenessProbeOverride .FailureThreshold )
839+ assert .Equal (t , installation .PodProbeOverrides .LivenessProbeOverride .InitialDelaySeconds , scannedOverrides .LivenessProbeOverride .InitialDelaySeconds )
840+ assert .Equal (t , installation .PodProbeOverrides .LivenessProbeOverride .TimeoutSeconds , scannedOverrides .LivenessProbeOverride .TimeoutSeconds )
841+
842+ assert .Equal (t , installation .PodProbeOverrides .ReadinessProbeOverride .FailureThreshold , scannedOverrides .ReadinessProbeOverride .FailureThreshold )
843+ assert .Equal (t , installation .PodProbeOverrides .ReadinessProbeOverride .InitialDelaySeconds , scannedOverrides .ReadinessProbeOverride .InitialDelaySeconds )
844+ assert .Equal (t , installation .PodProbeOverrides .ReadinessProbeOverride .TimeoutSeconds , scannedOverrides .ReadinessProbeOverride .TimeoutSeconds )
845+
846+ // This test passing means the original error:
847+ // "sql: converting argument $21 type: unsupported type model.PodProbeOverrides, a struct"
848+ // should no longer occur because PodProbeOverrides now implements driver.Valuer
849+ })
850+ }
0 commit comments