From 3d0b0a55e996d2872674a3835b3dcd64a6506377 Mon Sep 17 00:00:00 2001 From: ayushsarode Date: Thu, 23 Jul 2026 13:19:16 +0530 Subject: [PATCH 1/4] add firestore integration test Signed-off-by: ayushsarode --- .../datastore/firestore/application_test.go | 193 ++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 test/integration/datastore/firestore/application_test.go diff --git a/test/integration/datastore/firestore/application_test.go b/test/integration/datastore/firestore/application_test.go new file mode 100644 index 0000000000..cf1f09cdcc --- /dev/null +++ b/test/integration/datastore/firestore/application_test.go @@ -0,0 +1,193 @@ +// Copyright 2026 The PipeCD Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package firestore + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pipe-cd/pipecd/pkg/datastore" + "github.com/pipe-cd/pipecd/pkg/model" +) + +func TestGetApplication(t *testing.T) { + col := &collection{kind: "Application"} + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "get-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + } + err := store.Create(ctx, col, "get-id", fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + want *model.Application + wantErr error + }{ + { + name: "entity found", + id: "get-id", + want: fakeApplication, + wantErr: nil, + }, + { + name: "not found", + id: "id-wrong", + want: &model.Application{}, + wantErr: datastore.ErrNotFound, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + got := &model.Application{} + err := store.Get(ctx, col, tc.id, got) + assert.Equal(t, tc.wantErr, err) + assert.Equal(t, tc.want, got) + }) + } +} + +func TestCreateApplication(t *testing.T) { + col := &collection{kind: "Application"} + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "create-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + } + err := store.Create(ctx, col, "create-id", fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + wantErr error + }{ + { + name: "already exists", + id: "create-id", + wantErr: datastore.ErrAlreadyExists, + }, + { + name: "successful create", + id: "id-new", + wantErr: nil, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + err := store.Create(ctx, col, tc.id, fakeApplication) + assert.Equal(t, tc.wantErr, err) + }) + } +} + +func TestUpdateApplication(t *testing.T) { + col := &collection{ + kind: "Application", + factory: func() interface{} { + return &model.Application{} + }, + } + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "update-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + } + err := store.Create(ctx, col, "update-id", fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + updater func(interface{}) error + wantErr error + }{ + { + name: "not found", + id: "id-wrong", + wantErr: datastore.ErrNotFound, + }, + { + name: "unable to update", + id: "update-id", + updater: func(interface{}) error { + return fmt.Errorf("error") + }, + wantErr: fmt.Errorf("error"), + }, + { + name: "successful update", + id: "update-id", + updater: func(e interface{}) error { + v := e.(*model.Application) + v.Name = "new-name" + return nil + }, + wantErr: nil, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + err := store.Update(ctx, col, tc.id, tc.updater) + assert.Equal(t, tc.wantErr, err) + }) + } +} From 03ae8f69d21d6933d08a25378ba3f1c611710b53 Mon Sep 17 00:00:00 2001 From: ayushsarode Date: Tue, 15 Sep 2026 22:20:36 +0530 Subject: [PATCH 2/4] test(firestore): add TestFindApplication integration test Replace redundant Application CRUD tests with Find coverage matching the MySQL integration test, since generic CRUD is already covered in firestore_test.go. Signed-off-by: ayushsarode --- .../datastore/firestore/application_test.go | 175 ++++++------------ 1 file changed, 55 insertions(+), 120 deletions(-) diff --git a/test/integration/datastore/firestore/application_test.go b/test/integration/datastore/firestore/application_test.go index cf1f09cdcc..eee3568d4c 100644 --- a/test/integration/datastore/firestore/application_test.go +++ b/test/integration/datastore/firestore/application_test.go @@ -16,7 +16,7 @@ package firestore import ( "context" - "fmt" + "errors" "testing" "time" @@ -27,15 +27,15 @@ import ( "github.com/pipe-cd/pipecd/pkg/model" ) -func TestGetApplication(t *testing.T) { +func TestFindApplication(t *testing.T) { col := &collection{kind: "Application"} ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() fakeApplication := &model.Application{ - Id: "get-id", - Name: "name", + Id: "find-id-1", + Name: "name-1", PipedId: "piped-id", ProjectId: "project-id", Kind: model.ApplicationKind_KUBERNETES, @@ -47,47 +47,9 @@ func TestGetApplication(t *testing.T) { CreatedAt: 1, UpdatedAt: 1, } - err := store.Create(ctx, col, "get-id", fakeApplication) - require.NoError(t, err) - - testcases := []struct { - name string - id string - want *model.Application - wantErr error - }{ - { - name: "entity found", - id: "get-id", - want: fakeApplication, - wantErr: nil, - }, - { - name: "not found", - id: "id-wrong", - want: &model.Application{}, - wantErr: datastore.ErrNotFound, - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - got := &model.Application{} - err := store.Get(ctx, col, tc.id, got) - assert.Equal(t, tc.wantErr, err) - assert.Equal(t, tc.want, got) - }) - } -} - -func TestCreateApplication(t *testing.T) { - col := &collection{kind: "Application"} - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - fakeApplication := &model.Application{ - Id: "create-id", - Name: "name", + fakeApplication2 := &model.Application{ + Id: "find-id-2", + Name: "name-2", PipedId: "piped-id", ProjectId: "project-id", Kind: model.ApplicationKind_KUBERNETES, @@ -96,98 +58,71 @@ func TestCreateApplication(t *testing.T) { Path: "path", }, CloudProvider: "cloud-provider", - CreatedAt: 1, - UpdatedAt: 1, + CreatedAt: 2, + UpdatedAt: 2, } - err := store.Create(ctx, col, "create-id", fakeApplication) + err := store.Create(ctx, col, "find-id-1", fakeApplication) + require.NoError(t, err) + err = store.Create(ctx, col, "find-id-2", fakeApplication2) require.NoError(t, err) testcases := []struct { name string - id string - wantErr error + opts datastore.ListOptions + want []*model.Application + wantErr bool }{ { - name: "already exists", - id: "create-id", - wantErr: datastore.ErrAlreadyExists, + name: "fetch by name", + opts: datastore.ListOptions{ + Filters: []datastore.ListFilter{ + { + Field: "Name", + Operator: datastore.OperatorEqual, + Value: "name-1", + }, + }, + }, + want: []*model.Application{ + fakeApplication, + }, + wantErr: false, }, { - name: "successful create", - id: "id-new", - wantErr: nil, + name: "only cursor given", + opts: datastore.ListOptions{ + Cursor: "cursor", + }, + want: []*model.Application{}, + wantErr: true, }, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { - err := store.Create(ctx, col, tc.id, fakeApplication) - assert.Equal(t, tc.wantErr, err) + it, err := store.Find(ctx, col, tc.opts) + assert.Equal(t, tc.wantErr, err != nil) + got, err := listApplications(it) + require.NoError(t, err) + assert.Equal(t, tc.want, got) }) } } -func TestUpdateApplication(t *testing.T) { - col := &collection{ - kind: "Application", - factory: func() interface{} { - return &model.Application{} - }, - } - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - fakeApplication := &model.Application{ - Id: "update-id", - Name: "name", - PipedId: "piped-id", - ProjectId: "project-id", - Kind: model.ApplicationKind_KUBERNETES, - GitPath: &model.ApplicationGitPath{ - Repo: &model.ApplicationGitRepository{Id: "id"}, - Path: "path", - }, - CloudProvider: "cloud-provider", - CreatedAt: 1, - UpdatedAt: 1, - } - err := store.Create(ctx, col, "update-id", fakeApplication) - require.NoError(t, err) - - testcases := []struct { - name string - id string - updater func(interface{}) error - wantErr error - }{ - { - name: "not found", - id: "id-wrong", - wantErr: datastore.ErrNotFound, - }, - { - name: "unable to update", - id: "update-id", - updater: func(interface{}) error { - return fmt.Errorf("error") - }, - wantErr: fmt.Errorf("error"), - }, - { - name: "successful update", - id: "update-id", - updater: func(e interface{}) error { - v := e.(*model.Application) - v.Name = "new-name" - return nil - }, - wantErr: nil, - }, +func listApplications(it datastore.Iterator) ([]*model.Application, error) { + ret := make([]*model.Application, 0) + if it == nil { + return ret, nil } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - err := store.Update(ctx, col, tc.id, tc.updater) - assert.Equal(t, tc.wantErr, err) - }) + for { + var v model.Application + err := it.Next(&v) + if errors.Is(err, datastore.ErrIteratorDone) { + break + } + if err != nil { + return nil, err + } + ret = append(ret, &v) } + return ret, nil } From f77a201bb95781b960b015a7881f42294ada53a2 Mon Sep 17 00:00:00 2001 From: ayushsarode Date: Thu, 17 Sep 2026 20:38:47 +0530 Subject: [PATCH 3/4] test(firestore): restore accidentally deleted Get, Create, Update tests Signed-off-by: ayushsarode --- .../datastore/firestore/application_test.go | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/test/integration/datastore/firestore/application_test.go b/test/integration/datastore/firestore/application_test.go index eee3568d4c..dc90727ad8 100644 --- a/test/integration/datastore/firestore/application_test.go +++ b/test/integration/datastore/firestore/application_test.go @@ -17,6 +17,7 @@ package firestore import ( "context" "errors" + "fmt" "testing" "time" @@ -126,3 +127,168 @@ func listApplications(it datastore.Iterator) ([]*model.Application, error) { } return ret, nil } + +func TestGetApplication(t *testing.T) { + col := &collection{kind: "Application"} + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "get-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + } + err := store.Create(ctx, col, "get-id", fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + want *model.Application + wantErr error + }{ + { + name: "entity found", + id: "get-id", + want: fakeApplication, + wantErr: nil, + }, + { + name: "not found", + id: "id-wrong", + want: &model.Application{}, + wantErr: datastore.ErrNotFound, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + got := &model.Application{} + err := store.Get(ctx, col, tc.id, got) + assert.Equal(t, tc.wantErr, err) + assert.Equal(t, tc.want, got) + }) + } +} + +func TestCreateApplication(t *testing.T) { + col := &collection{kind: "Application"} + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "create-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + } + err := store.Create(ctx, col, "create-id", fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + wantErr error + }{ + { + name: "already exists", + id: "create-id", + wantErr: datastore.ErrAlreadyExists, + }, + { + name: "successful create", + id: "id-new", + wantErr: nil, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + err := store.Create(ctx, col, tc.id, fakeApplication) + assert.Equal(t, tc.wantErr, err) + }) + } +} + +func TestUpdateApplication(t *testing.T) { + col := &collection{ + kind: "Application", + factory: func() interface{} { + return &model.Application{} + }, + } + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "update-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + } + err := store.Create(ctx, col, "update-id", fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + updater func(interface{}) error + wantErr error + }{ + { + name: "not found", + id: "id-wrong", + wantErr: datastore.ErrNotFound, + }, + { + name: "unable to update", + id: "update-id", + updater: func(interface{}) error { + return fmt.Errorf("error") + }, + wantErr: fmt.Errorf("error"), + }, + { + name: "successful update", + id: "update-id", + updater: func(e interface{}) error { + v := e.(*model.Application) + v.Name = "new-name" + return nil + }, + wantErr: nil, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + err := store.Update(ctx, col, tc.id, tc.updater) + assert.Equal(t, tc.wantErr, err) + }) + } +} From db6c82249c522453ccf314c7a177df38b13f7bad Mon Sep 17 00:00:00 2001 From: ayushsarode Date: Mon, 21 Sep 2026 21:22:30 +0530 Subject: [PATCH 4/4] added delete, enable and disable Signed-off-by: ayushsarode --- .../datastore/firestore/application_test.go | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/test/integration/datastore/firestore/application_test.go b/test/integration/datastore/firestore/application_test.go index dc90727ad8..07c9a74a5c 100644 --- a/test/integration/datastore/firestore/application_test.go +++ b/test/integration/datastore/firestore/application_test.go @@ -292,3 +292,146 @@ func TestUpdateApplication(t *testing.T) { }) } } + +func TestDeleteApplication(t *testing.T) { + appStore := datastore.NewApplicationStore(store) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "delete-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + } + err := appStore.Add(ctx, fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + wantErr error + }{ + { + name: "successful delete", + id: "delete-id", + wantErr: nil, + }, + { + name: "not found", + id: "id-wrong", + wantErr: datastore.ErrNotFound, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + err := appStore.Delete(ctx, tc.id) + assert.Equal(t, tc.wantErr, err) + }) + } +} + +func TestEnableApplication(t *testing.T) { + appStore := datastore.NewApplicationStore(store) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "enable-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + Disabled: true, + } + err := appStore.Add(ctx, fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + wantErr error + }{ + { + name: "successful enable", + id: "enable-id", + wantErr: nil, + }, + { + name: "not found", + id: "id-wrong", + wantErr: datastore.ErrNotFound, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + err := appStore.Enable(ctx, tc.id) + assert.Equal(t, tc.wantErr, err) + }) + } +} + +func TestDisableApplication(t *testing.T) { + appStore := datastore.NewApplicationStore(store) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + fakeApplication := &model.Application{ + Id: "disable-id", + Name: "name", + PipedId: "piped-id", + ProjectId: "project-id", + Kind: model.ApplicationKind_KUBERNETES, + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{Id: "id"}, + Path: "path", + }, + CloudProvider: "cloud-provider", + CreatedAt: 1, + UpdatedAt: 1, + Disabled: false, + } + err := appStore.Add(ctx, fakeApplication) + require.NoError(t, err) + + testcases := []struct { + name string + id string + wantErr error + }{ + { + name: "successful disable", + id: "disable-id", + wantErr: nil, + }, + { + name: "not found", + id: "id-wrong", + wantErr: datastore.ErrNotFound, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + err := appStore.Disable(ctx, tc.id) + assert.Equal(t, tc.wantErr, err) + }) + } +}