@@ -488,9 +488,8 @@ func TestStacksPlanStackChanges(t *testing.T) {
488488 }
489489}
490490
491- func TestStackChangeProgressDuringPlan (t * testing.T ) {
491+ func TestStackChangeProgressDuringPlanNormal (t * testing.T ) {
492492 tcs := map [string ]struct {
493- mode stacks.PlanMode
494493 source string
495494 store * stacks_testing_provider.ResourceStore
496495 state []stackstate.AppliedChange
@@ -499,7 +498,6 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
499498 diagnostics []* terraform1.Diagnostic
500499 }{
501500 "deferred_changes" : {
502- mode : stacks .PlanMode_NORMAL ,
503501 source : "git::https://example.com/bar.git" ,
504502 want : []* stacks.StackChangeProgress {
505503 {
@@ -569,7 +567,6 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
569567 },
570568 },
571569 "moved" : {
572- mode : stacks .PlanMode_NORMAL ,
573570 source : "git::https://example.com/moved.git" ,
574571 store : stacks_testing_provider .NewResourceStoreBuilder ().
575572 AddResource ("before" , cty .ObjectVal (map [string ]cty.Value {
@@ -631,7 +628,6 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
631628 },
632629 },
633630 "import" : {
634- mode : stacks .PlanMode_NORMAL ,
635631 source : "git::https://example.com/import.git" ,
636632 store : stacks_testing_provider .NewResourceStoreBuilder ().
637633 AddResource ("self" , cty .ObjectVal (map [string ]cty.Value {
@@ -753,7 +749,6 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
753749 },
754750 },
755751 "removed" : {
756- mode : stacks .PlanMode_NORMAL ,
757752 source : "git::https://example.com/removed.git" ,
758753 store : stacks_testing_provider .NewResourceStoreBuilder ().
759754 AddResource ("resource" , cty .ObjectVal (map [string ]cty.Value {
@@ -816,7 +811,6 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
816811 },
817812 },
818813 "invalid - update" : {
819- mode : stacks .PlanMode_NORMAL ,
820814 source : "git::https://example.com/invalid.git" ,
821815 store : stacks_testing_provider .NewResourceStoreBuilder ().
822816 AddResource ("resource" , cty .ObjectVal (map [string ]cty.Value {
@@ -881,7 +875,6 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
881875 },
882876 },
883877 "invalid - create" : {
884- mode : stacks .PlanMode_NORMAL ,
885878 source : "git::https://example.com/invalid.git" ,
886879 store : stacks_testing_provider .NewResourceStoreBuilder ().
887880 AddResource ("resource" , cty .ObjectVal (map [string ]cty.Value {
@@ -927,8 +920,7 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
927920 },
928921 },
929922 },
930- "destroy plan" : {
931- mode : stacks .PlanMode_DESTROY ,
923+ "no-op plan" : {
932924 source : "git::https://example.com/simple.git" ,
933925 store : stacks_testing_provider .NewResourceStoreBuilder ().
934926 AddResource ("resource" , cty .ObjectVal (map [string ]cty.Value {
@@ -956,35 +948,213 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
956948 },
957949 want : []* stacks.StackChangeProgress {
958950 {
959- Event : & stacks.StackChangeProgress_ResourceInstancePlannedChange_ {
960- ResourceInstancePlannedChange : & stacks.StackChangeProgress_ResourceInstancePlannedChange {
961- Addr : & stacks.ResourceInstanceObjectInStackAddr {
951+ Event : & stacks.StackChangeProgress_ComponentInstanceStatus_ {
952+ ComponentInstanceStatus : & stacks.StackChangeProgress_ComponentInstanceStatus {
953+ Addr : & stacks.ComponentInstanceInStackAddr {
954+ ComponentAddr : "component.self" ,
962955 ComponentInstanceAddr : "component.self" ,
963- ResourceInstanceAddr : "testing_resource.resource" ,
964- },
965- Actions : []stacks.ChangeType {
966- stacks .ChangeType_DELETE ,
967956 },
968- ProviderAddr : "registry.terraform.io/hashicorp/testing" ,
957+ Status : stacks . StackChangeProgress_ComponentInstanceStatus_PLANNED ,
969958 },
970959 },
971960 },
961+ },
962+ },
963+ "empty plan" : {
964+ source : "git::https://example.com/empty.git" ,
965+ state : []stackstate.AppliedChange {
966+ & stackstate.AppliedChangeComponentInstance {
967+ ComponentAddr : mustAbsComponent (t , "component.self" ),
968+ ComponentInstanceAddr : mustAbsComponentInstance (t , "component.self" ),
969+ },
970+ },
971+ want : []* stacks.StackChangeProgress {
972972 {
973- Event : & stacks.StackChangeProgress_ComponentInstanceChanges_ {
974- ComponentInstanceChanges : & stacks.StackChangeProgress_ComponentInstanceChanges {
973+ Event : & stacks.StackChangeProgress_ComponentInstanceStatus_ {
974+ ComponentInstanceStatus : & stacks.StackChangeProgress_ComponentInstanceStatus {
975975 Addr : & stacks.ComponentInstanceInStackAddr {
976976 ComponentAddr : "component.self" ,
977977 ComponentInstanceAddr : "component.self" ,
978978 },
979- Total : 1 ,
980- Remove : 1 ,
979+ Status : stacks .StackChangeProgress_ComponentInstanceStatus_PLANNED ,
981980 },
982981 },
983982 },
984983 },
985984 },
986- "no-op plan" : {
987- mode : stacks .PlanMode_NORMAL ,
985+ }
986+
987+ for name , tc := range tcs {
988+ t .Run (name , func (t * testing.T ) {
989+ ctx := context .Background ()
990+ handles := newHandleTable ()
991+ stacksServer := newStacksServer (newStopper (), handles , disco .New (), & serviceOpts {})
992+
993+ // For this test, we do actually want to use a "real" provider. We'll
994+ // use the providerCacheOverride to side-load the testing provider.
995+ stacksServer .providerCacheOverride = make (map [addrs.Provider ]providers.Factory )
996+ stacksServer .providerCacheOverride [addrs .NewDefaultProvider ("testing" )] = func () (providers.Interface , error ) {
997+ return stacks_testing_provider .NewProviderWithData (t , tc .store ), nil
998+ }
999+ lock := depsfile .NewLocks ()
1000+ lock .SetProvider (
1001+ addrs .NewDefaultProvider ("testing" ),
1002+ providerreqs .MustParseVersion ("0.0.0" ),
1003+ providerreqs .MustParseVersionConstraints ("=0.0.0" ),
1004+ providerreqs .PreferredHashes ([]providerreqs.Hash {}),
1005+ )
1006+ stacksServer .providerDependencyLockOverride = lock
1007+
1008+ sb , err := sourcebundle .OpenDir ("testdata/sourcebundle" )
1009+ if err != nil {
1010+ t .Fatal (err )
1011+ }
1012+ hnd := handles .NewSourceBundle (sb )
1013+
1014+ client , close := grpcClientForTesting (ctx , t , func (srv * grpc.Server ) {
1015+ stacks .RegisterStacksServer (srv , stacksServer )
1016+ })
1017+ defer close ()
1018+
1019+ stacksClient := stacks .NewStacksClient (client )
1020+
1021+ open , err := stacksClient .OpenStackConfiguration (ctx , & stacks.OpenStackConfiguration_Request {
1022+ SourceBundleHandle : hnd .ForProtobuf (),
1023+ SourceAddress : & terraform1.SourceAddress {
1024+ Source : tc .source ,
1025+ },
1026+ })
1027+ if err != nil {
1028+ t .Fatalf ("unexpected error: %s" , err )
1029+ }
1030+ defer stacksClient .CloseStackConfiguration (ctx , & stacks.CloseStackConfiguration_Request {
1031+ StackConfigHandle : open .StackConfigHandle ,
1032+ })
1033+
1034+ resp , err := stacksClient .PlanStackChanges (ctx , & stacks.PlanStackChanges_Request {
1035+ PlanMode : stacks .PlanMode_NORMAL ,
1036+ StackConfigHandle : open .StackConfigHandle ,
1037+ PreviousState : appliedChangeToRawState (t , tc .state ),
1038+ InputValues : func () map [string ]* stacks.DynamicValueWithSource {
1039+ values := make (map [string ]* stacks.DynamicValueWithSource )
1040+ for name , value := range tc .inputs {
1041+ values [name ] = & stacks.DynamicValueWithSource {
1042+ Value : & stacks.DynamicValue {
1043+ Msgpack : mustMsgpack (t , value , value .Type ()),
1044+ },
1045+ SourceRange : & terraform1.SourceRange {
1046+ Start : & terraform1.SourcePos {},
1047+ End : & terraform1.SourcePos {},
1048+ },
1049+ }
1050+ }
1051+ return values
1052+ }(),
1053+ })
1054+ if err != nil {
1055+ t .Fatalf ("unexpected error: %s" , err )
1056+ }
1057+
1058+ wantEvents := splitStackOperationEvents (func () []* stacks.PlanStackChanges_Event {
1059+ events := make ([]* stacks.PlanStackChanges_Event , 0 , len (tc .want ))
1060+ for _ , want := range tc .want {
1061+ events = append (events , & stacks.PlanStackChanges_Event {
1062+ Event : & stacks.PlanStackChanges_Event_Progress {
1063+ Progress : want ,
1064+ },
1065+ })
1066+ }
1067+ return events
1068+ }())
1069+
1070+ gotEvents := splitStackOperationEvents (func () []* stacks.PlanStackChanges_Event {
1071+ var events []* stacks.PlanStackChanges_Event
1072+ for {
1073+ event , err := resp .Recv ()
1074+ if err == io .EOF {
1075+ break
1076+ }
1077+ if err != nil {
1078+ t .Fatalf ("unexpected error: %s" , err )
1079+ }
1080+ events = append (events , event )
1081+ }
1082+ return events
1083+ }())
1084+
1085+ // First, validate the diagnostics. Most of the tests are either
1086+ // expecting a specific single diagnostic so we do actually check
1087+ // everything.
1088+ // We don't care about the ordering since it's not guaranteed.
1089+
1090+ if len (tc .diagnostics ) != len (gotEvents .Diagnostics ) {
1091+ t .Fatalf ("expected %d diagnostics, got %d" , len (tc .diagnostics ), len (gotEvents .Diagnostics ))
1092+ }
1093+
1094+ DIAGS:
1095+ for _ , expectedDiag := range tc .diagnostics {
1096+ for _ , gotDiagEvent := range gotEvents .Diagnostics {
1097+ gotDiag := gotDiagEvent .Event .(* stacks.PlanStackChanges_Event_Diagnostic ).Diagnostic
1098+
1099+ if diff := cmp .Diff (expectedDiag , gotDiag , protocmp .Transform ()); diff == "" {
1100+ continue DIAGS // Found it
1101+ }
1102+ }
1103+
1104+ // If we reach this point we did not find the diag
1105+ t .Errorf ("missing expected diagnostic: %v, got %v" , expectedDiag , gotEvents .Diagnostics )
1106+ }
1107+
1108+ // Now we're going to manually verify the existence of some key events.
1109+ // We're not looking for every event because (a) the exact ordering of
1110+ // events is not guaranteed and (b) we don't want to start failing every
1111+ // time a new event is added.
1112+
1113+ WantPlannedChange:
1114+ for _ , want := range wantEvents .PlannedChanges {
1115+ for _ , got := range gotEvents .PlannedChanges {
1116+ if len (cmp .Diff (want , got , protocmp .Transform ())) == 0 {
1117+ continue WantPlannedChange
1118+ }
1119+ }
1120+ t .Errorf ("missing expected planned change: %v" , want )
1121+ }
1122+
1123+ WantMiscHook:
1124+ for _ , want := range wantEvents .MiscHooks {
1125+ for _ , got := range gotEvents .MiscHooks {
1126+ if len (cmp .Diff (want , got , protocmp .Transform ())) == 0 {
1127+ continue WantMiscHook
1128+ }
1129+ }
1130+ t .Errorf ("missing expected event: %v" , want )
1131+ }
1132+
1133+ if t .Failed () {
1134+ // if the test failed, let's print out all the events we got to help
1135+ // with debugging.
1136+ for _ , evt := range gotEvents .MiscHooks {
1137+ t .Logf (" returned event: %s" , evt .String ())
1138+ }
1139+
1140+ for _ , evt := range gotEvents .PlannedChanges {
1141+ t .Logf (" returned event: %s" , evt .String ())
1142+ }
1143+ }
1144+ })
1145+ }
1146+ }
1147+
1148+ func TestStackChangeProgressDuringPlanDestroy (t * testing.T ) {
1149+ tcs := map [string ]struct {
1150+ source string
1151+ store * stacks_testing_provider.ResourceStore
1152+ state []stackstate.AppliedChange
1153+ inputs map [string ]cty.Value
1154+ want []* stacks.StackChangeProgress
1155+ diagnostics []* terraform1.Diagnostic
1156+ }{
1157+ "destroy plan" : {
9881158 source : "git::https://example.com/simple.git" ,
9891159 store : stacks_testing_provider .NewResourceStoreBuilder ().
9901160 AddResource ("resource" , cty .ObjectVal (map [string ]cty.Value {
@@ -1012,36 +1182,28 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
10121182 },
10131183 want : []* stacks.StackChangeProgress {
10141184 {
1015- Event : & stacks.StackChangeProgress_ComponentInstanceStatus_ {
1016- ComponentInstanceStatus : & stacks.StackChangeProgress_ComponentInstanceStatus {
1017- Addr : & stacks.ComponentInstanceInStackAddr {
1018- ComponentAddr : "component.self" ,
1185+ Event : & stacks.StackChangeProgress_ResourceInstancePlannedChange_ {
1186+ ResourceInstancePlannedChange : & stacks.StackChangeProgress_ResourceInstancePlannedChange {
1187+ Addr : & stacks.ResourceInstanceObjectInStackAddr {
10191188 ComponentInstanceAddr : "component.self" ,
1189+ ResourceInstanceAddr : "testing_resource.resource" ,
10201190 },
1021- Status : stacks .StackChangeProgress_ComponentInstanceStatus_PLANNED ,
1191+ Actions : []stacks.ChangeType {
1192+ stacks .ChangeType_DELETE ,
1193+ },
1194+ ProviderAddr : "registry.terraform.io/hashicorp/testing" ,
10221195 },
10231196 },
10241197 },
1025- },
1026- },
1027- "empty plan" : {
1028- mode : stacks .PlanMode_NORMAL ,
1029- source : "git::https://example.com/empty.git" ,
1030- state : []stackstate.AppliedChange {
1031- & stackstate.AppliedChangeComponentInstance {
1032- ComponentAddr : mustAbsComponent (t , "component.self" ),
1033- ComponentInstanceAddr : mustAbsComponentInstance (t , "component.self" ),
1034- },
1035- },
1036- want : []* stacks.StackChangeProgress {
10371198 {
1038- Event : & stacks.StackChangeProgress_ComponentInstanceStatus_ {
1039- ComponentInstanceStatus : & stacks.StackChangeProgress_ComponentInstanceStatus {
1199+ Event : & stacks.StackChangeProgress_ComponentInstanceChanges_ {
1200+ ComponentInstanceChanges : & stacks.StackChangeProgress_ComponentInstanceChanges {
10401201 Addr : & stacks.ComponentInstanceInStackAddr {
10411202 ComponentAddr : "component.self" ,
10421203 ComponentInstanceAddr : "component.self" ,
10431204 },
1044- Status : stacks .StackChangeProgress_ComponentInstanceStatus_PLANNED ,
1205+ Total : 1 ,
1206+ Remove : 1 ,
10451207 },
10461208 },
10471209 },
@@ -1097,7 +1259,7 @@ func TestStackChangeProgressDuringPlan(t *testing.T) {
10971259 })
10981260
10991261 resp , err := stacksClient .PlanStackChanges (ctx , & stacks.PlanStackChanges_Request {
1100- PlanMode : tc . mode ,
1262+ PlanMode : stacks . PlanMode_DESTROY ,
11011263 StackConfigHandle : open .StackConfigHandle ,
11021264 PreviousState : appliedChangeToRawState (t , tc .state ),
11031265 InputValues : func () map [string ]* stacks.DynamicValueWithSource {
0 commit comments