github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/cd-service/pkg/service/version_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 package service 18 19 import ( 20 "context" 21 "crypto/md5" 22 "fmt" 23 "testing" 24 "time" 25 26 "github.com/freiheit-com/kuberpult/services/cd-service/pkg/repository/testutil" 27 "github.com/google/go-cmp/cmp" 28 "github.com/google/go-cmp/cmp/cmpopts" 29 "google.golang.org/grpc/codes" 30 "google.golang.org/grpc/status" 31 "google.golang.org/protobuf/testing/protocmp" 32 33 api "github.com/freiheit-com/kuberpult/pkg/api/v1" 34 "github.com/freiheit-com/kuberpult/services/cd-service/pkg/config" 35 "github.com/freiheit-com/kuberpult/services/cd-service/pkg/repository" 36 ) 37 38 func TestVersion(t *testing.T) { 39 type expectedVersion struct { 40 Environment string 41 Application string 42 ExpectedVersion uint64 43 ExpectedDeployedAt time.Time 44 ExpectedSourceCommitId string 45 } 46 tcs := []struct { 47 Name string 48 Setup []repository.Transformer 49 ExpectedVersions []expectedVersion 50 }{ 51 { 52 Name: "simple-tests", 53 Setup: []repository.Transformer{ 54 &repository.CreateEnvironment{ 55 Environment: "development", 56 Config: config.EnvironmentConfig{ 57 Upstream: &config.EnvironmentConfigUpstream{ 58 Latest: true, 59 }, 60 }, 61 }, 62 &repository.CreateEnvironment{ 63 Environment: "staging", 64 Config: config.EnvironmentConfig{ 65 Upstream: &config.EnvironmentConfigUpstream{ 66 Latest: true, 67 }, 68 }, 69 }, 70 &repository.CreateApplicationVersion{ 71 Application: "test", 72 Version: 1, 73 Manifests: map[string]string{ 74 "development": "dev", 75 }, 76 }, 77 }, 78 ExpectedVersions: []expectedVersion{ 79 { 80 Environment: "development", 81 Application: "test", 82 ExpectedVersion: 1, 83 ExpectedDeployedAt: time.Unix(2, 0), 84 }, 85 { 86 Environment: "staging", 87 Application: "test", 88 ExpectedVersion: 0, 89 }, 90 }, 91 }, 92 { 93 Name: "with source commits", 94 Setup: []repository.Transformer{ 95 &repository.CreateEnvironment{ 96 Environment: "development", 97 Config: config.EnvironmentConfig{ 98 Upstream: &config.EnvironmentConfigUpstream{ 99 Latest: true, 100 }, 101 }, 102 }, 103 &repository.CreateEnvironment{ 104 Environment: "staging", 105 Config: config.EnvironmentConfig{ 106 Upstream: &config.EnvironmentConfigUpstream{ 107 Latest: true, 108 }, 109 }, 110 }, 111 &repository.CreateApplicationVersion{ 112 Application: "test", 113 Version: 1, 114 Manifests: map[string]string{ 115 "development": "dev", 116 }, 117 SourceCommitId: "deadbeef", 118 }, 119 }, 120 ExpectedVersions: []expectedVersion{ 121 { 122 Environment: "development", 123 Application: "test", 124 ExpectedVersion: 1, 125 ExpectedDeployedAt: time.Unix(2, 0), 126 ExpectedSourceCommitId: "deadbeef", 127 }, 128 }, 129 }, 130 } 131 for _, tc := range tcs { 132 tc := tc 133 t.Run(tc.Name, func(t *testing.T) { 134 repo, err := setupRepositoryTest(t) 135 if err != nil { 136 t.Fatalf("error setting up repository test: %v", err) 137 } 138 sv := &VersionServiceServer{Repository: repo} 139 140 for i, transformer := range tc.Setup { 141 now := time.Unix(int64(i), 0) 142 ctx := repository.WithTimeNow(testutil.MakeTestContext(), now) 143 err := repo.Apply(ctx, transformer) 144 if err != nil { 145 t.Fatal(err) 146 } 147 } 148 cid := repo.State().Commit.Id().String() 149 for _, ev := range tc.ExpectedVersions { 150 res, err := sv.GetVersion(context.Background(), &api.GetVersionRequest{ 151 GitRevision: cid, 152 Application: ev.Application, 153 Environment: ev.Environment, 154 }) 155 if err != nil { 156 t.Fatal(err) 157 } 158 if res.Version != ev.ExpectedVersion { 159 t.Errorf("got wrong version for %s/%s: expected %d but got %d", ev.Application, ev.Environment, ev.ExpectedVersion, res.Version) 160 } 161 if ev.ExpectedDeployedAt.IsZero() { 162 if res.DeployedAt != nil { 163 t.Errorf("got wrong deployed at for %s/%s: expected <nil> but got %q", ev.Application, ev.Environment, res.DeployedAt) 164 } 165 } else { 166 if !res.DeployedAt.AsTime().Equal(ev.ExpectedDeployedAt) { 167 t.Errorf("got wrong deployed at for %s/%s: expected %q but got %q", ev.Application, ev.Environment, ev.ExpectedDeployedAt, res.DeployedAt.AsTime()) 168 } 169 } 170 if ev.ExpectedSourceCommitId != res.SourceCommitId { 171 t.Errorf("go wrong source commit id, expected %q, got %q", ev.ExpectedSourceCommitId, res.SourceCommitId) 172 } 173 } 174 }) 175 } 176 } 177 178 func TestGetManifests(t *testing.T) { 179 type testCase struct { 180 name string 181 setup []repository.Transformer 182 req *api.GetManifestsRequest 183 want *api.GetManifestsResponse 184 wantErr error 185 } 186 187 appName := "app-default" 188 appNameOther := "app-other" 189 fixtureRequest := func(mods ...func(*api.GetManifestsRequest)) *api.GetManifestsRequest { 190 req := &api.GetManifestsRequest{ 191 Application: appName, 192 Release: "latest", 193 } 194 for _, m := range mods { 195 m(req) 196 } 197 return req 198 } 199 fixtureSetupEnv := func() []repository.Transformer { 200 return []repository.Transformer{ 201 &repository.CreateEnvironment{ 202 Environment: "development", 203 Config: config.EnvironmentConfig{ 204 Upstream: &config.EnvironmentConfigUpstream{ 205 Latest: true, 206 }, 207 }, 208 }, 209 &repository.CreateEnvironment{ 210 Environment: "staging", 211 Config: config.EnvironmentConfig{ 212 Upstream: &config.EnvironmentConfigUpstream{ 213 Latest: true, 214 }, 215 }, 216 }, 217 } 218 } 219 fixtureRelease := func(application string, release uint64) *repository.CreateApplicationVersion { 220 return &repository.CreateApplicationVersion{ 221 Application: application, 222 Version: release, 223 Manifests: map[string]string{ 224 "development": fmt.Sprintf("dev-manifest for %s in release %d", application, release), 225 "staging": fmt.Sprintf("staging-manifest for %s in release %d", application, release), 226 }, 227 SourceCommitId: fmt.Sprintf("%x", 228 md5.Sum( 229 []byte( 230 fmt.Sprintf("source commit id for app %s and release %d", application, release), 231 ), 232 ), 233 ), 234 } 235 } 236 237 fixtureReleaseToManifests := func(release *repository.CreateApplicationVersion) *api.GetManifestsResponse { 238 return &api.GetManifestsResponse{ 239 Release: &api.Release{ 240 Version: release.Version, 241 SourceCommitId: release.SourceCommitId, 242 }, 243 Manifests: map[string]*api.Manifest{ 244 "development": { 245 Environment: "development", 246 Content: release.Manifests["development"], 247 }, 248 "staging": { 249 Environment: "staging", 250 Content: release.Manifests["staging"], 251 }, 252 }, 253 } 254 } 255 256 for _, tc := range []*testCase{ 257 func() *testCase { 258 release := fixtureRelease(appName, 3) 259 260 return &testCase{ 261 name: "happy path", 262 setup: append(fixtureSetupEnv(), 263 fixtureRelease(appNameOther, 1), 264 fixtureRelease(appNameOther, 2), 265 fixtureRelease(appName, 1), 266 fixtureRelease(appName, 2), 267 release, 268 ), 269 req: fixtureRequest(), 270 want: fixtureReleaseToManifests(release), 271 } 272 }(), 273 func() *testCase { 274 release := fixtureRelease(appName, 2) 275 276 return &testCase{ 277 name: "request specific release", 278 setup: append(fixtureSetupEnv(), 279 fixtureRelease(appName, 1), 280 fixtureRelease(appNameOther, 1), 281 release, 282 fixtureRelease(appName, 3), 283 fixtureRelease(appNameOther, 2), 284 ), 285 req: fixtureRequest(func(req *api.GetManifestsRequest) { req.Release = "2" }), 286 want: fixtureReleaseToManifests(release), 287 } 288 }(), 289 { 290 name: "no release specified", 291 setup: append(fixtureSetupEnv(), 292 fixtureRelease(appName, 1), 293 fixtureRelease(appName, 2), 294 fixtureRelease(appName, 3), 295 ), 296 req: fixtureRequest(func(req *api.GetManifestsRequest) { req.Release = "" }), 297 wantErr: status.Error(codes.InvalidArgument, "invalid release number, expected uint or 'latest'"), 298 }, 299 { 300 name: "no application specified", 301 setup: append(fixtureSetupEnv(), 302 fixtureRelease(appName, 1), 303 fixtureRelease(appName, 2), 304 fixtureRelease(appName, 3), 305 ), 306 req: fixtureRequest(func(req *api.GetManifestsRequest) { req.Application = "" }), 307 wantErr: status.Error(codes.InvalidArgument, "no application specified"), 308 }, 309 { 310 name: "no releases for application", 311 setup: append(fixtureSetupEnv(), 312 fixtureRelease(appNameOther, 1), 313 fixtureRelease(appNameOther, 2), 314 fixtureRelease(appNameOther, 3), 315 ), 316 req: fixtureRequest(), 317 wantErr: status.Errorf(codes.NotFound, "no releases found for application %s", appName), 318 }, 319 } { 320 tc := tc // TODO SRX-SRRONB: Remove after switching to go v1.22 321 t.Run(tc.name, func(t *testing.T) { 322 repo, err := setupRepositoryTest(t) 323 if err != nil { 324 t.Fatalf("error setting up repository test: %v", err) 325 } 326 sv := &VersionServiceServer{Repository: repo} 327 328 for i, transformer := range tc.setup { 329 now := time.Unix(int64(i), 0) 330 ctx := repository.WithTimeNow(testutil.MakeTestContext(), now) 331 err := repo.Apply(ctx, transformer) 332 if err != nil { 333 t.Fatal(err) 334 } 335 } 336 337 got, err := sv.GetManifests(context.Background(), tc.req) 338 if diff := cmp.Diff(tc.wantErr, err, cmpopts.EquateErrors()); diff != "" { 339 t.Errorf("error mismatch (-want, +got):\n%s", diff) 340 } 341 if diff := cmp.Diff(tc.want, got, protocmp.Transform(), protocmp.IgnoreFields(&api.Release{}, "created_at")); diff != "" { 342 t.Errorf("response mismatch (-want, +got):\n%s", diff) 343 } 344 }) 345 } 346 }