workflow-pr: more unit tests
This commit is contained in:
parent
b96c4d26ca
commit
e56f444960
@ -65,8 +65,6 @@ func updateOrCreatePRBranch(req *common.PullRequestWebhookEvent, git *common.Git
|
|||||||
}
|
}
|
||||||
|
|
||||||
var DebugMode bool
|
var DebugMode bool
|
||||||
var checkOnStart bool
|
|
||||||
var checkInterval time.Duration
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := common.RequireGiteaSecretToken(); err != nil {
|
if err := common.RequireGiteaSecretToken(); err != nil {
|
||||||
@ -80,12 +78,10 @@ func main() {
|
|||||||
giteaHost := flag.String("gitea", "src.opensuse.org", "Gitea instance")
|
giteaHost := flag.String("gitea", "src.opensuse.org", "Gitea instance")
|
||||||
rabbitUrl := flag.String("url", "amqps://rabbit.opensuse.org", "URL for RabbitMQ instance")
|
rabbitUrl := flag.String("url", "amqps://rabbit.opensuse.org", "URL for RabbitMQ instance")
|
||||||
flag.BoolVar(&DebugMode, "debug", false, "Extra debugging information")
|
flag.BoolVar(&DebugMode, "debug", false, "Extra debugging information")
|
||||||
flag.BoolVar(&checkOnStart, "check-on-start", false, "Check all repositories for consistency on start, without delays")
|
checkOnStart := flag.Bool("check-on-start", false, "Check all repositories for consistency on start, without delays")
|
||||||
checkIntervalHours := flag.Float64("check-interval", 5, "Check interval (+-random delay) for repositories for consitency, in hours")
|
checkIntervalHours := flag.Float64("check-interval", 5, "Check interval (+-random delay) for repositories for consitency, in hours")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
checkInterval = time.Duration(*checkIntervalHours) * time.Hour
|
|
||||||
|
|
||||||
if len(*workflowConfig) == 0 {
|
if len(*workflowConfig) == 0 {
|
||||||
log.Fatalln("No configuratio file specified. Aborting")
|
log.Fatalln("No configuratio file specified. Aborting")
|
||||||
}
|
}
|
||||||
@ -115,23 +111,20 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gitea := common.AllocateGiteaTransport(*giteaHost)
|
||||||
|
|
||||||
|
|
||||||
checker := &DefaultStateChecker {
|
|
||||||
gitea: common.AllocateGiteaTransport(*giteaHost),
|
|
||||||
git: &common.GitHandlerImpl{},
|
|
||||||
}
|
|
||||||
req.Synced = &PullRequestSynced{
|
req.Synced = &PullRequestSynced{
|
||||||
gitea: checker.gitea,
|
gitea: gitea,
|
||||||
}
|
}
|
||||||
req.Opened = &PullRequestOpened{
|
req.Opened = &PullRequestOpened{
|
||||||
gitea: checker.gitea,
|
gitea: gitea,
|
||||||
}
|
}
|
||||||
req.Closed = &PullRequestClosed{
|
req.Closed = &PullRequestClosed{
|
||||||
gitea: checker.gitea,
|
gitea: gitea,
|
||||||
}
|
}
|
||||||
|
|
||||||
go checker.consistencyCheckProcess(req)
|
checker := CreateDefaultStateChecker(*checkOnStart, req, gitea, time.Duration(*checkIntervalHours)*time.Hour)
|
||||||
|
go checker.ConsistencyCheckProcess()
|
||||||
|
|
||||||
var defs common.ListenDefinitions
|
var defs common.ListenDefinitions
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -11,20 +12,48 @@ import (
|
|||||||
"src.opensuse.org/autogits/common"
|
"src.opensuse.org/autogits/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:generate mockgen -source=repo_check.go -destination=mock/repo_check.go -typed
|
||||||
|
|
||||||
type StateChecker interface {
|
type StateChecker interface {
|
||||||
|
VerifyProjectState(orgName string, configs []*common.AutogitConfig, idx int) error
|
||||||
|
CheckRepos() error
|
||||||
|
ConsistencyCheckProcess() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultStateChecker struct {
|
type DefaultStateChecker struct {
|
||||||
processor *RequestProcessor
|
exitCheckLoop bool
|
||||||
|
checkOnStart bool
|
||||||
|
checkInterval time.Duration
|
||||||
|
|
||||||
gitea common.Gitea
|
gitea common.Gitea
|
||||||
git common.GitHandlerGenerator
|
git common.GitHandlerGenerator
|
||||||
|
processor *RequestProcessor
|
||||||
|
i StateChecker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultStateChecker) verifyProjectState(processor *RequestProcessor, git *common.GitHandler, orgName string, config *common.AutogitConfig, configs []*common.AutogitConfig) error {
|
func CreateDefaultStateChecker(checkOnStart bool, processor *RequestProcessor, gitea common.Gitea, interval time.Duration) *DefaultStateChecker {
|
||||||
|
var s = &DefaultStateChecker{
|
||||||
|
git: &common.GitHandlerImpl{},
|
||||||
|
gitea: gitea,
|
||||||
|
checkInterval: interval,
|
||||||
|
checkOnStart: checkOnStart,
|
||||||
|
processor: processor,
|
||||||
|
}
|
||||||
|
s.i = s
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultStateChecker) VerifyProjectState(orgName string, configs []*common.AutogitConfig, idx int) error {
|
||||||
org := common.Organization{
|
org := common.Organization{
|
||||||
Username: orgName,
|
Username: orgName,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
git, err := s.git.CreateGitHandler(GitAuthor, GitEmail, AppName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Cannot create git handler: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := configs[idx]
|
||||||
repo, err := s.gitea.CreateRepositoryIfNotExist(git, org, config.GitProjectName)
|
repo, err := s.gitea.CreateRepositoryIfNotExist(git, org, config.GitProjectName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error fetching or creating '%s/%s' -- aborting verifyProjectState(). Err: %w", orgName, config.GitProjectName, err)
|
return fmt.Errorf("Error fetching or creating '%s/%s' -- aborting verifyProjectState(). Err: %w", orgName, config.GitProjectName, err)
|
||||||
@ -120,43 +149,45 @@ nextSubmodule:
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultStateChecker) checkRepos(processor *RequestProcessor) {
|
func (s *DefaultStateChecker) CheckRepos() error {
|
||||||
for org, configs := range processor.configuredRepos {
|
errorList := make([]error, 0, 10)
|
||||||
for _, config := range configs {
|
|
||||||
if checkInterval > 0 {
|
for org, configs := range s.processor.configuredRepos {
|
||||||
sleepInterval := checkInterval - checkInterval/2 + time.Duration(rand.Int63n(int64(checkInterval)))
|
for configIdx, config := range configs {
|
||||||
|
if s.checkInterval > 0 {
|
||||||
|
sleepInterval := (s.checkInterval - s.checkInterval/2) + time.Duration(rand.Int63n(int64(s.checkInterval)))
|
||||||
log.Println(" - sleep interval", sleepInterval, "until next check")
|
log.Println(" - sleep interval", sleepInterval, "until next check")
|
||||||
time.Sleep(sleepInterval)
|
time.Sleep(sleepInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf(" ++ starting verification, org: `%s` config: `%s`\n", org, config.GitProjectName)
|
log.Printf(" ++ starting verification, org: `%s` config: `%s`\n", org, config.GitProjectName)
|
||||||
git, err := s.git.CreateGitHandler(GitAuthor, GitEmail, AppName)
|
if err := s.i.VerifyProjectState(org, configs, configIdx); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Println("Faield to allocate GitHandler:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !DebugMode {
|
|
||||||
defer git.Close()
|
|
||||||
}
|
|
||||||
if err := s.verifyProjectState(processor, git, org, config, configs); err != nil {
|
|
||||||
log.Printf(" *** verification failed, org: `%s`, err: %#v\n", org, err)
|
log.Printf(" *** verification failed, org: `%s`, err: %#v\n", org, err)
|
||||||
|
errorList = append(errorList, err)
|
||||||
}
|
}
|
||||||
log.Printf(" ++ verification complete, org: `%s` config: `%s`\n", org, config.GitProjectName)
|
log.Printf(" ++ verification complete, org: `%s` config: `%s`\n", org, config.GitProjectName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return errors.Join(errorList...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultStateChecker) consistencyCheckProcess(processor *RequestProcessor) {
|
func (s *DefaultStateChecker) ConsistencyCheckProcess() error {
|
||||||
if checkOnStart {
|
if s.checkOnStart {
|
||||||
savedCheckInterval := checkInterval
|
savedCheckInterval := s.checkInterval
|
||||||
checkInterval = 0
|
s.checkInterval = 0
|
||||||
log.Println("== Startup consistency check begin...")
|
log.Println("== Startup consistency check begin...")
|
||||||
s.checkRepos(processor)
|
s.i.CheckRepos()
|
||||||
log.Println("== Startup consistency check done...")
|
log.Println("== Startup consistency check done...")
|
||||||
checkInterval = savedCheckInterval
|
s.checkInterval = savedCheckInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
s.checkRepos(processor)
|
if s.exitCheckLoop {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s.i.CheckRepos()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
137
workflow-pr/repo_check_test.go
Normal file
137
workflow-pr/repo_check_test.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
"src.opensuse.org/autogits/common"
|
||||||
|
mock_common "src.opensuse.org/autogits/common/mock"
|
||||||
|
mock_main "src.opensuse.org/workflow-pr/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRepoCheck(t *testing.T) {
|
||||||
|
var logBuf bytes.Buffer
|
||||||
|
oldOut := log.Writer()
|
||||||
|
log.SetOutput(&logBuf)
|
||||||
|
defer log.SetOutput(oldOut)
|
||||||
|
|
||||||
|
t.Run("Consistency Check On Start", func(t *testing.T) {
|
||||||
|
c := CreateDefaultStateChecker(true, nil, nil, 100)
|
||||||
|
ctl := gomock.NewController(t)
|
||||||
|
state := mock_main.NewMockStateChecker(ctl)
|
||||||
|
c.i = state
|
||||||
|
state.EXPECT().CheckRepos().Do(func() error {
|
||||||
|
// only checkOnStart has checkInterval = 0
|
||||||
|
if c.checkInterval != 0 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.exitCheckLoop = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
c.ConsistencyCheckProcess()
|
||||||
|
if c.checkInterval != 100 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("No consistency Check On Start", func(t *testing.T) {
|
||||||
|
c := CreateDefaultStateChecker(true, nil, nil, 100)
|
||||||
|
ctl := gomock.NewController(t)
|
||||||
|
state := mock_main.NewMockStateChecker(ctl)
|
||||||
|
c.i = state
|
||||||
|
|
||||||
|
nCalls := 10
|
||||||
|
state.EXPECT().CheckRepos().Do(func() error {
|
||||||
|
// only checkOnStart has checkInterval = 0
|
||||||
|
if c.checkInterval != 100 {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
nCalls--
|
||||||
|
if nCalls == 0 {
|
||||||
|
c.exitCheckLoop = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}).Times(nCalls)
|
||||||
|
c.checkOnStart = false
|
||||||
|
|
||||||
|
c.ConsistencyCheckProcess()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("CheckRepos() calls CheckProjectState() for each project", func(t *testing.T) {
|
||||||
|
ctl := gomock.NewController(t)
|
||||||
|
state := mock_main.NewMockStateChecker(ctl)
|
||||||
|
gitea := mock_common.NewMockGitea(ctl)
|
||||||
|
|
||||||
|
config1 := &common.AutogitConfig{
|
||||||
|
GitProjectName: "git_repo1",
|
||||||
|
Organization: "repo1_org",
|
||||||
|
}
|
||||||
|
config2 := &common.AutogitConfig{
|
||||||
|
GitProjectName: "git_repo2",
|
||||||
|
Organization: "repo2_org",
|
||||||
|
}
|
||||||
|
config3 := &common.AutogitConfig{
|
||||||
|
GitProjectName: "git_repo3",
|
||||||
|
Organization: "repo3_org",
|
||||||
|
}
|
||||||
|
|
||||||
|
configs := &RequestProcessor{
|
||||||
|
configuredRepos: map[string][]*common.AutogitConfig{
|
||||||
|
"repo1_org": []*common.AutogitConfig{config1},
|
||||||
|
"repo2_org": []*common.AutogitConfig{config2},
|
||||||
|
"repo3_org": []*common.AutogitConfig{config3},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
r := configs.configuredRepos
|
||||||
|
|
||||||
|
c := CreateDefaultStateChecker(true, configs, gitea, 100)
|
||||||
|
c.i = state
|
||||||
|
|
||||||
|
state.EXPECT().VerifyProjectState("repo1_org", r["repo1_org"], 0)
|
||||||
|
state.EXPECT().VerifyProjectState("repo2_org", r["repo2_org"], 0)
|
||||||
|
state.EXPECT().VerifyProjectState("repo3_org", r["repo3_org"], 0)
|
||||||
|
|
||||||
|
if err := c.CheckRepos(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("CheckRepos errors", func(t *testing.T) {
|
||||||
|
ctl := gomock.NewController(t)
|
||||||
|
state := mock_main.NewMockStateChecker(ctl)
|
||||||
|
gitea := mock_common.NewMockGitea(ctl)
|
||||||
|
git := mock_common.NewMockGitHandlerGenerator(ctl)
|
||||||
|
|
||||||
|
config1 := &common.AutogitConfig{
|
||||||
|
GitProjectName: "git_repo1",
|
||||||
|
Organization: "repo1_org",
|
||||||
|
}
|
||||||
|
|
||||||
|
configs := &RequestProcessor{
|
||||||
|
configuredRepos: map[string][]*common.AutogitConfig{
|
||||||
|
"repo1_org": []*common.AutogitConfig{config1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
//r := configs.configuredRepos
|
||||||
|
|
||||||
|
c := CreateDefaultStateChecker(true, configs, gitea, 100)
|
||||||
|
c.i = state
|
||||||
|
c.git = git
|
||||||
|
|
||||||
|
err := errors.New("test error")
|
||||||
|
state.EXPECT().VerifyProjectState("repo1_org", gomock.Any(), 0).Return(err)
|
||||||
|
|
||||||
|
r := c.CheckRepos()
|
||||||
|
|
||||||
|
if !errors.Is(r, err) {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user