github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/rollout-service/pkg/revolution/revolution_test.go (about) 1 /*This file is part of kuberpult. 2 3 Kuberpult is free software: you can redistribute it and/or modify 4 it under the terms of the Expat(MIT) License as published by 5 the Free Software Foundation. 6 7 Kuberpult is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 MIT License for more details. 11 12 You should have received a copy of the MIT License 13 along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>. 14 15 Copyright 2023 freiheit.com*/ 16 /* 17 This file is part of kuberpult. 18 19 Kuberpult is free software: you can redistribute it and/or modify 20 it under the terms of the Expat(MIT) License as published by 21 the Free Software Foundation. 22 23 Kuberpult is distributed in the hope that it will be useful, 24 but WITHOUT ANY WARRANTY; without even the implied warranty of 25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 MIT License for more details. 27 28 You should have received a copy of the MIT License 29 along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>. 30 31 Copyright 2023 freiheit.com 32 */ 33 package revolution 34 35 import ( 36 "context" 37 "io" 38 "net/http" 39 "net/http/httptest" 40 "testing" 41 "time" 42 43 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" 44 "github.com/argoproj/gitops-engine/pkg/health" 45 "github.com/freiheit-com/kuberpult/services/rollout-service/pkg/service" 46 "github.com/freiheit-com/kuberpult/services/rollout-service/pkg/versions" 47 "github.com/google/go-cmp/cmp" 48 ) 49 50 func TestRevolution(t *testing.T) { 51 type request struct { 52 Url string 53 Header http.Header 54 Body string 55 } 56 type step struct { 57 ArgoEvent *service.ArgoEvent 58 KuberpultEvent *versions.KuberpultEvent 59 ExpectedRequest *request 60 } 61 tcs := []struct { 62 Name string 63 Steps []step 64 Now time.Time 65 }{ 66 { 67 Name: "send out deployment events with timestamp once", 68 Now: time.Unix(123456789, 0).UTC(), 69 Steps: []step{ 70 { 71 ArgoEvent: &service.ArgoEvent{ 72 Environment: "foo", 73 Application: "bar", 74 SyncStatusCode: v1alpha1.SyncStatusCodeSynced, 75 HealthStatusCode: health.HealthStatusHealthy, 76 Version: &versions.VersionInfo{ 77 Version: 1, 78 SourceCommitId: "123456", 79 DeployedAt: time.Unix(123456789, 0).UTC(), 80 }, 81 }, 82 KuberpultEvent: &versions.KuberpultEvent{ 83 Environment: "foo", 84 Application: "bar", 85 IsProduction: true, 86 Version: &versions.VersionInfo{ 87 Version: 1, 88 SourceCommitId: "123456", 89 DeployedAt: time.Unix(123456789, 0).UTC(), 90 }, 91 }, 92 93 ExpectedRequest: &request{ 94 Url: "/", 95 Header: http.Header{ 96 "Content-Type": []string{"application/json"}, 97 "User-Agent": []string{"kuberpult"}, 98 "X-Hub-Signature-256": []string{"sha256=c227a4f702ce00368a15bd00c3678dd20c76ed7275d82c5a2d48009beb78b5ee"}, 99 }, 100 Body: `{"id":"0ee3e568-0f9d-5be9-b75c-caa9025599c2","commitHash":"123456","eventTime":"1973-11-29T21:33:09Z","serviceName":"bar"}`, 101 }, 102 }, 103 { 104 ArgoEvent: &service.ArgoEvent{ 105 Environment: "foo", 106 Application: "bar", 107 SyncStatusCode: v1alpha1.SyncStatusCodeSynced, 108 HealthStatusCode: health.HealthStatusDegraded, 109 Version: &versions.VersionInfo{ 110 Version: 1, 111 SourceCommitId: "123456", 112 DeployedAt: time.Unix(123456789, 0).UTC(), 113 }, 114 }, 115 116 ExpectedRequest: nil, 117 }, 118 }, 119 }, 120 { 121 Name: "ignore old events", 122 Now: time.Date(2024, 2, 15, 12, 15, 0, 0, time.UTC), 123 Steps: []step{ 124 { 125 ArgoEvent: &service.ArgoEvent{ 126 Environment: "foo", 127 Application: "bar", 128 SyncStatusCode: v1alpha1.SyncStatusCodeSynced, 129 HealthStatusCode: health.HealthStatusDegraded, 130 Version: &versions.VersionInfo{ 131 Version: 1, 132 SourceCommitId: "123456", 133 DeployedAt: time.Date(2024, 2, 14, 12, 15, 0, 0, time.UTC), 134 }, 135 }, 136 ExpectedRequest: nil, 137 }, 138 }, 139 }, 140 } 141 for _, tc := range tcs { 142 tc := tc 143 t.Run(tc.Name, func(t *testing.T) { 144 reqCh := make(chan *request) 145 revolution := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 146 body, _ := io.ReadAll(r.Body) 147 hdr := r.Header.Clone() 148 hdr.Del("Accept-Encoding") 149 hdr.Del("Content-Length") 150 reqCh <- &request{ 151 Url: r.URL.String(), 152 Header: hdr, 153 Body: string(body), 154 } 155 w.WriteHeader(http.StatusOK) 156 })) 157 readyCh := make(chan struct{}, 1) 158 bc := service.New() 159 errCh := make(chan error, 1) 160 cs := New(Config{ 161 URL: revolution.URL, 162 Token: []byte("revolution"), 163 Concurrency: 100, 164 MaxEventAge: time.Second, 165 }) 166 cs.ready = func() { readyCh <- struct{}{} } 167 cs.now = func() time.Time { return tc.Now } 168 ctx, cancel := context.WithCancel(context.Background()) 169 go func() { 170 errCh <- cs.Subscribe(ctx, bc) 171 }() 172 <-readyCh 173 for i, s := range tc.Steps { 174 if s.ArgoEvent != nil { 175 bc.ProcessArgoEvent(context.Background(), *s.ArgoEvent) 176 } 177 if s.KuberpultEvent != nil { 178 bc.ProcessKuberpultEvent(context.Background(), *s.KuberpultEvent) 179 } 180 if s.ExpectedRequest != nil { 181 select { 182 case <-time.After(5 * time.Second): 183 t.Fatalf("expexted request in step %d, but didn't receive any", i) 184 case req := <-reqCh: 185 d := cmp.Diff(req, s.ExpectedRequest) 186 if d != "" { 187 t.Errorf("unexpected requests diff in step %d: %s", i, d) 188 } 189 } 190 191 } else { 192 select { 193 case req := <-reqCh: 194 t.Errorf("unexpected requests in step %d: %#v", i, req) 195 default: 196 } 197 } 198 } 199 cancel() 200 err := <-errCh 201 if err != nil { 202 t.Errorf("expected no error but got %q", err) 203 } 204 }) 205 } 206 }