@@ -127,6 +127,50 @@ func (d *readDriver) AdoptionRef(spec interfaces.ResourceSpec) (interfaces.Resou
127127 return interfaces.ResourceRef {Name : spec .Name , Type : spec .Type , ProviderID : providerID }, true , nil
128128}
129129
130+ type configAdoptDriver struct {
131+ readOut * interfaces.ResourceOutput
132+ readErr error
133+ reads []interfaces.ResourceRef
134+ expectedProviderID string
135+ supportsConfigAdoption bool
136+ }
137+
138+ func (d * configAdoptDriver ) Create (_ context.Context , spec interfaces.ResourceSpec ) (* interfaces.ResourceOutput , error ) {
139+ return & interfaces.ResourceOutput {Name : spec .Name , Type : spec .Type }, nil
140+ }
141+
142+ func (d * configAdoptDriver ) Read (_ context.Context , ref interfaces.ResourceRef ) (* interfaces.ResourceOutput , error ) {
143+ d .reads = append (d .reads , ref )
144+ if d .expectedProviderID != "" && ref .ProviderID != d .expectedProviderID {
145+ return nil , interfaces .ErrResourceNotFound
146+ }
147+ return d .readOut , d .readErr
148+ }
149+
150+ func (d * configAdoptDriver ) Update (_ context.Context , ref interfaces.ResourceRef , spec interfaces.ResourceSpec ) (* interfaces.ResourceOutput , error ) {
151+ return & interfaces.ResourceOutput {Name : spec .Name , Type : spec .Type , ProviderID : ref .ProviderID }, nil
152+ }
153+
154+ func (d * configAdoptDriver ) Delete (_ context.Context , _ interfaces.ResourceRef ) error { return nil }
155+
156+ func (d * configAdoptDriver ) Diff (_ context.Context , _ interfaces.ResourceSpec , _ * interfaces.ResourceOutput ) (* interfaces.DiffResult , error ) {
157+ return & interfaces.DiffResult {NeedsUpdate : true }, nil
158+ }
159+
160+ func (d * configAdoptDriver ) HealthCheck (_ context.Context , _ interfaces.ResourceRef ) (* interfaces.HealthResult , error ) {
161+ return nil , nil
162+ }
163+
164+ func (d * configAdoptDriver ) Scale (_ context.Context , ref interfaces.ResourceRef , _ int ) (* interfaces.ResourceOutput , error ) {
165+ return & interfaces.ResourceOutput {Name : ref .Name , Type : ref .Type , ProviderID : ref .ProviderID }, nil
166+ }
167+
168+ func (d * configAdoptDriver ) SensitiveKeys () []string { return nil }
169+
170+ func (d * configAdoptDriver ) SupportsConfigAdoption () bool {
171+ return d .supportsConfigAdoption
172+ }
173+
130174type readBackedProvider struct {
131175 applyCapture
132176 driver interfaces.ResourceDriver
@@ -955,6 +999,133 @@ func TestApplyWithProvider_AdoptsResourceThroughDriverLocator(t *testing.T) {
955999 }
9561000}
9571001
1002+ func TestApplyWithProvider_AdoptsResourceWhenConfigAdoptExistingTrue (t * testing.T ) {
1003+ spec := interfaces.ResourceSpec {
1004+ Name : "wfcompute-stg-db" ,
1005+ Type : "infra.database" ,
1006+ Config : map [string ]any {
1007+ "adopt_existing" : true ,
1008+ "engine" : "pg" ,
1009+ "version" : "18" ,
1010+ },
1011+ }
1012+ driver := & configAdoptDriver {
1013+ supportsConfigAdoption : true ,
1014+ readOut : & interfaces.ResourceOutput {
1015+ Name : "wfcompute-stg-db" ,
1016+ Type : "infra.database" ,
1017+ ProviderID : "db-123" ,
1018+ Outputs : map [string ]any {
1019+ "name" : "wfcompute-stg-db" ,
1020+ "engine" : "pg" ,
1021+ },
1022+ },
1023+ }
1024+ provider := & readBackedProvider {driver : driver }
1025+ store := & fakeStateStore {}
1026+
1027+ if err := applyWithProviderAndStore (t .Context (), provider , "digitalocean" , []interfaces.ResourceSpec {spec }, nil , store , io .Discard , "" , "" , nil ); err != nil {
1028+ t .Fatalf ("applyWithProviderAndStore: %v" , err )
1029+ }
1030+ if len (driver .reads ) != 1 {
1031+ t .Fatalf ("driver reads = %d, want 1" , len (driver .reads ))
1032+ }
1033+ if driver .reads [0 ] != (interfaces.ResourceRef {Name : "wfcompute-stg-db" , Type : "infra.database" }) {
1034+ t .Fatalf ("read ref = %+v, want name/type only" , driver .reads [0 ])
1035+ }
1036+ store .mu .Lock ()
1037+ defer store .mu .Unlock ()
1038+ if len (store .saved ) != 1 || store .saved [0 ].ProviderID != "db-123" {
1039+ t .Fatalf ("saved states = %+v, want adopted db-123" , store .saved )
1040+ }
1041+ provider .mu .Lock ()
1042+ appliedPlan := provider .appliedPlan
1043+ provider .mu .Unlock ()
1044+ if appliedPlan == nil || len (appliedPlan .Actions ) != 1 || appliedPlan .Actions [0 ].Action != "update" {
1045+ t .Fatalf ("applied plan = %#v, want update after adoption" , appliedPlan )
1046+ }
1047+ }
1048+
1049+ func TestApplyWithProvider_ConfigAdoptionRejectsUnsupportedDriver (t * testing.T ) {
1050+ spec := interfaces.ResourceSpec {
1051+ Name : "wfcompute-stg-db" ,
1052+ Type : "infra.database" ,
1053+ Config : map [string ]any {
1054+ "adopt_existing" : true ,
1055+ },
1056+ }
1057+ driver := & configAdoptDriver {}
1058+ provider := & readBackedProvider {driver : driver }
1059+
1060+ err := applyWithProviderAndStore (t .Context (), provider , "digitalocean" , []interfaces.ResourceSpec {spec }, nil , & fakeStateStore {}, io .Discard , "" , "" , nil )
1061+ if err == nil {
1062+ t .Fatal ("expected unsupported config adoption error" )
1063+ }
1064+ if ! strings .Contains (err .Error (), "adopt_existing requires a driver that supports name-based adoption" ) {
1065+ t .Fatalf ("error = %v, want unsupported config adoption failure" , err )
1066+ }
1067+ if len (driver .reads ) != 0 {
1068+ t .Fatalf ("driver reads = %d, want 0" , len (driver .reads ))
1069+ }
1070+ }
1071+
1072+ func TestApplyWithProvider_ConfigAdoptionRejectsNilDriver (t * testing.T ) {
1073+ spec := interfaces.ResourceSpec {
1074+ Name : "wfcompute-stg-db" ,
1075+ Type : "infra.database" ,
1076+ Config : map [string ]any {
1077+ "adopt_existing" : true ,
1078+ },
1079+ }
1080+ provider := & readBackedProvider {}
1081+
1082+ err := applyWithProviderAndStore (t .Context (), provider , "digitalocean" , []interfaces.ResourceSpec {spec }, nil , & fakeStateStore {}, io .Discard , "" , "" , nil )
1083+ if err == nil {
1084+ t .Fatal ("expected nil driver resolution error" )
1085+ }
1086+ if ! strings .Contains (err .Error (), "resolve resource driver: driver returned nil" ) {
1087+ t .Fatalf ("error = %v, want nil driver resolution failure" , err )
1088+ }
1089+ provider .mu .Lock ()
1090+ defer provider .mu .Unlock ()
1091+ if provider .applyCalled {
1092+ t .Fatal ("Apply should not be called when explicit adoption driver resolution fails" )
1093+ }
1094+ }
1095+
1096+ func TestApplyWithProvider_DNSAdoptionPreservesBuiltInRefWithAdoptExisting (t * testing.T ) {
1097+ spec := interfaces.ResourceSpec {
1098+ Name : "site-dns" ,
1099+ Type : "infra.dns" ,
1100+ Config : map [string ]any {
1101+ "adopt_existing" : true ,
1102+ "domain" : "example.com" ,
1103+ },
1104+ }
1105+ driver := & configAdoptDriver {
1106+ expectedProviderID : "example.com" ,
1107+ readOut : & interfaces.ResourceOutput {
1108+ Name : "site-dns" ,
1109+ Type : "infra.dns" ,
1110+ ProviderID : "do-domain-123" ,
1111+ Outputs : map [string ]any {
1112+ "domain" : "example.com" ,
1113+ },
1114+ },
1115+ }
1116+ provider := & readBackedProvider {driver : driver }
1117+
1118+ if err := applyWithProviderAndStore (t .Context (), provider , "digitalocean" , []interfaces.ResourceSpec {spec }, nil , & fakeStateStore {}, io .Discard , "" , "" , nil ); err != nil {
1119+ t .Fatalf ("applyWithProviderAndStore: %v" , err )
1120+ }
1121+ if len (driver .reads ) != 1 {
1122+ t .Fatalf ("driver reads = %d, want 1" , len (driver .reads ))
1123+ }
1124+ if driver .reads [0 ] != (interfaces.ResourceRef {Name : "site-dns" , Type : "infra.dns" , ProviderID : "example.com" }) {
1125+ t .Fatalf ("read ref = %+v, want built-in DNS domain ref" , driver .reads [0 ])
1126+ }
1127+ }
1128+
9581129func TestApplyWithProvider_SkipsAdoptionWhenAppDriverHasNoLocator (t * testing.T ) {
9591130 spec := interfaces.ResourceSpec {
9601131 Name : "site-app" ,
0 commit comments