@@ -35,8 +35,8 @@ func (s *BaseCloningSuite) SetupSuite() {
3535}
3636
3737func (s * BaseCloningSuite ) TearDownTest () {
38- s .cloning .clones = make ( map [ string ] * CloneWrapper )
39- s .cloning .snapshotBox = SnapshotBox { items : make (map [string ]* models.Snapshot )}
38+ s .cloning .resetClones ( )
39+ s .cloning .resetSnapshots ( make (map [string ]* models.Snapshot ), nil )
4040}
4141
4242func (s * BaseCloningSuite ) TestFindWrapper () {
@@ -217,3 +217,123 @@ func TestCalculateProtectionTime_EdgeCases(t *testing.T) {
217217func ptrUint (v uint ) * uint {
218218 return & v
219219}
220+
221+ func (s * BaseCloningSuite ) TestGetExpectedCloningTime () {
222+ t := s .T ()
223+
224+ result := s .cloning .getExpectedCloningTime ()
225+ assert .Equal (t , 0.0 , result , "expected zero when no clones exist" )
226+
227+ s .cloning .setWrapper ("clone1" , & CloneWrapper {Clone : & models.Clone {Metadata : models.CloneMetadata {CloningTime : 2.0 }}})
228+ s .cloning .setWrapper ("clone2" , & CloneWrapper {Clone : & models.Clone {Metadata : models.CloneMetadata {CloningTime : 4.0 }}})
229+ s .cloning .setWrapper ("clone3" , & CloneWrapper {Clone : & models.Clone {Metadata : models.CloneMetadata {CloningTime : 6.0 }}})
230+
231+ result = s .cloning .getExpectedCloningTime ()
232+ assert .Equal (t , 4.0 , result , "expected average of 2, 4, 6" )
233+ }
234+
235+ func (s * BaseCloningSuite ) TestGetExpectedCloningTimeSingleClone () {
236+ t := s .T ()
237+
238+ s .cloning .setWrapper ("clone1" , & CloneWrapper {Clone : & models.Clone {Metadata : models.CloneMetadata {CloningTime : 3.5 }}})
239+
240+ result := s .cloning .getExpectedCloningTime ()
241+ assert .Equal (t , 3.5 , result )
242+ }
243+
244+ func (s * BaseCloningSuite ) TestGetExpectedCloningTimeZeroValues () {
245+ t := s .T ()
246+
247+ s .cloning .setWrapper ("clone1" , & CloneWrapper {Clone : & models.Clone {Metadata : models.CloneMetadata {CloningTime : 0.0 }}})
248+ s .cloning .setWrapper ("clone2" , & CloneWrapper {Clone : & models.Clone {Metadata : models.CloneMetadata {CloningTime : 0.0 }}})
249+
250+ result := s .cloning .getExpectedCloningTime ()
251+ assert .Equal (t , 0.0 , result )
252+ }
253+
254+ func (s * BaseCloningSuite ) TestUpdateCloneStatusNotFound () {
255+ t := s .T ()
256+
257+ err := s .cloning .UpdateCloneStatus ("nonexistent" , models.Status {Code : models .StatusOK , Message : models .CloneMessageOK })
258+ assert .Error (t , err )
259+ assert .Contains (t , err .Error (), "not found" )
260+ }
261+
262+ func (s * BaseCloningSuite ) TestUpdateCloneSnapshot () {
263+ t := s .T ()
264+
265+ originalSnapshot := & models.Snapshot {ID : "snap1" }
266+ newSnapshot := & models.Snapshot {ID : "snap2" }
267+
268+ s .cloning .setWrapper ("clone1" , & CloneWrapper {Clone : & models.Clone {ID : "clone1" , Snapshot : originalSnapshot }})
269+
270+ err := s .cloning .UpdateCloneSnapshot ("clone1" , newSnapshot )
271+ require .NoError (t , err )
272+
273+ w , ok := s .cloning .findWrapper ("clone1" )
274+ require .True (t , ok )
275+ assert .Equal (t , "snap2" , w .Clone .Snapshot .ID )
276+ }
277+
278+ func (s * BaseCloningSuite ) TestUpdateCloneSnapshotNotFound () {
279+ t := s .T ()
280+
281+ err := s .cloning .UpdateCloneSnapshot ("nonexistent" , & models.Snapshot {ID : "snap1" })
282+ assert .Error (t , err )
283+ assert .Contains (t , err .Error (), "not found" )
284+ }
285+
286+ func TestConnectionString (t * testing.T ) {
287+ tests := []struct {
288+ name string
289+ host string
290+ port string
291+ username string
292+ dbname string
293+ expected string
294+ }{
295+ {name : "standard values" , host : "localhost" , port : "5432" , username : "postgres" , dbname : "testdb" , expected : "host='localhost' port=5432 user='postgres' database='testdb'" },
296+ {name : "custom host and port" , host : "10.0.0.1" , port : "6000" , username : "admin" , dbname : "mydb" , expected : "host='10.0.0.1' port=6000 user='admin' database='mydb'" },
297+ {name : "socket path host" , host : "/var/run/postgres" , port : "5433" , username : "user1" , dbname : "db1" , expected : "host='/var/run/postgres' port=5433 user='user1' database='db1'" },
298+ {name : "empty dbname" , host : "localhost" , port : "5432" , username : "postgres" , dbname : "" , expected : "host='localhost' port=5432 user='postgres' database=''" },
299+ {name : "dbname with single quote" , host : "localhost" , port : "5432" , username : "postgres" , dbname : "test'db" , expected : "host='localhost' port=5432 user='postgres' database='test''db'" },
300+ {name : "dbname with spaces" , host : "localhost" , port : "5432" , username : "postgres" , dbname : "my database" , expected : "host='localhost' port=5432 user='postgres' database='my database'" },
301+ {name : "dbname with backslash" , host : "localhost" , port : "5432" , username : "postgres" , dbname : `test\db` , expected : `host='localhost' port=5432 user='postgres' database='test\\db'` },
302+ {name : "username with single quote" , host : "localhost" , port : "5432" , username : "user'name" , dbname : "testdb" , expected : `host='localhost' port=5432 user='user''name' database='testdb'` },
303+ {name : "username with backslash" , host : "localhost" , port : "5432" , username : `user\name` , dbname : "testdb" , expected : `host='localhost' port=5432 user='user\\name' database='testdb'` },
304+ {name : "combined quote and backslash in dbname" , host : "localhost" , port : "5432" , username : "postgres" , dbname : `test\'db` , expected : `host='localhost' port=5432 user='postgres' database='test\\''db'` },
305+ {name : "host with single quote" , host : "host'name" , port : "5432" , username : "postgres" , dbname : "testdb" , expected : `host='host''name' port=5432 user='postgres' database='testdb'` },
306+ }
307+
308+ for _ , tt := range tests {
309+ t .Run (tt .name , func (t * testing.T ) {
310+ result := connectionString (tt .host , tt .port , tt .username , tt .dbname )
311+ assert .Equal (t , tt .expected , result )
312+ })
313+ }
314+ }
315+
316+ func TestGetCloningState (t * testing.T ) {
317+ cfg := & Config {ProtectionLeaseDurationMinutes : 60 , ProtectionMaxDurationMinutes : 120 }
318+ base := & Base {
319+ config : cfg ,
320+ clones : make (map [string ]* CloneWrapper ),
321+ snapshotBox : SnapshotBox {items : make (map [string ]* models.Snapshot )},
322+ }
323+
324+ state := base .GetCloningState ()
325+ assert .Equal (t , uint64 (0 ), state .NumClones )
326+ assert .Equal (t , 0.0 , state .ExpectedCloningTime )
327+ assert .Equal (t , uint (60 ), state .ProtectionLeaseDurationMinutes )
328+ assert .Equal (t , uint (120 ), state .ProtectionMaxDurationMinutes )
329+ assert .Empty (t , state .Clones )
330+
331+ base .setWrapper ("c1" , & CloneWrapper {Clone : & models.Clone {
332+ CreatedAt : & models.LocalTime {Time : time .Now ()},
333+ Metadata : models.CloneMetadata {CloningTime : 1.5 },
334+ }})
335+
336+ state = base .GetCloningState ()
337+ assert .Equal (t , uint64 (1 ), state .NumClones )
338+ assert .Equal (t , 1.5 , state .ExpectedCloningTime )
339+ }
0 commit comments