mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-27 04:35:16 +01:00
add immutable tag middleware
Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
parent
b231814533
commit
da02b820ad
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/core/middlewares/chart"
|
"github.com/goharbor/harbor/src/core/middlewares/chart"
|
||||||
"github.com/goharbor/harbor/src/core/middlewares/contenttrust"
|
"github.com/goharbor/harbor/src/core/middlewares/contenttrust"
|
||||||
"github.com/goharbor/harbor/src/core/middlewares/countquota"
|
"github.com/goharbor/harbor/src/core/middlewares/countquota"
|
||||||
|
"github.com/goharbor/harbor/src/core/middlewares/immutable"
|
||||||
"github.com/goharbor/harbor/src/core/middlewares/listrepo"
|
"github.com/goharbor/harbor/src/core/middlewares/listrepo"
|
||||||
"github.com/goharbor/harbor/src/core/middlewares/multiplmanifest"
|
"github.com/goharbor/harbor/src/core/middlewares/multiplmanifest"
|
||||||
"github.com/goharbor/harbor/src/core/middlewares/readonly"
|
"github.com/goharbor/harbor/src/core/middlewares/readonly"
|
||||||
@ -70,6 +71,7 @@ func (b *DefaultCreator) geMiddleware(mName string) alice.Constructor {
|
|||||||
VULNERABLE: func(next http.Handler) http.Handler { return vulnerable.New(next) },
|
VULNERABLE: func(next http.Handler) http.Handler { return vulnerable.New(next) },
|
||||||
SIZEQUOTA: func(next http.Handler) http.Handler { return sizequota.New(next) },
|
SIZEQUOTA: func(next http.Handler) http.Handler { return sizequota.New(next) },
|
||||||
COUNTQUOTA: func(next http.Handler) http.Handler { return countquota.New(next) },
|
COUNTQUOTA: func(next http.Handler) http.Handler { return countquota.New(next) },
|
||||||
|
IMMUTABLE: func(next http.Handler) http.Handler { return immutable.New(next) },
|
||||||
}
|
}
|
||||||
return middlewares[mName]
|
return middlewares[mName]
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,14 @@ const (
|
|||||||
VULNERABLE = "vulnerable"
|
VULNERABLE = "vulnerable"
|
||||||
SIZEQUOTA = "sizequota"
|
SIZEQUOTA = "sizequota"
|
||||||
COUNTQUOTA = "countquota"
|
COUNTQUOTA = "countquota"
|
||||||
|
IMMUTABLE = "immutable"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChartMiddlewares middlewares for chart server
|
// ChartMiddlewares middlewares for chart server
|
||||||
var ChartMiddlewares = []string{CHART}
|
var ChartMiddlewares = []string{CHART}
|
||||||
|
|
||||||
// Middlewares with sequential organization
|
// Middlewares with sequential organization
|
||||||
var Middlewares = []string{READONLY, URL, MUITIPLEMANIFEST, LISTREPO, CONTENTTRUST, VULNERABLE, SIZEQUOTA, COUNTQUOTA}
|
var Middlewares = []string{READONLY, URL, MUITIPLEMANIFEST, LISTREPO, CONTENTTRUST, VULNERABLE, SIZEQUOTA, IMMUTABLE, COUNTQUOTA}
|
||||||
|
|
||||||
// MiddlewaresLocal ...
|
// MiddlewaresLocal ...
|
||||||
var MiddlewaresLocal = []string{SIZEQUOTA, COUNTQUOTA}
|
var MiddlewaresLocal = []string{SIZEQUOTA, COUNTQUOTA}
|
||||||
|
93
src/core/middlewares/immutable/handler.go
Normal file
93
src/core/middlewares/immutable/handler.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Copyright Project Harbor 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 immutable
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/goharbor/harbor/src/common/dao"
|
||||||
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
|
common_util "github.com/goharbor/harbor/src/common/utils"
|
||||||
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
|
"github.com/goharbor/harbor/src/core/middlewares/util"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/art"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/immutabletag/match/rule"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type immutableHandler struct {
|
||||||
|
next http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// New ...
|
||||||
|
func New(next http.Handler) http.Handler {
|
||||||
|
return &immutableHandler{
|
||||||
|
next: next,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServeHTTP ...
|
||||||
|
func (rh immutableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
if match, _, _ := util.MatchPushManifest(req); !match {
|
||||||
|
rh.next.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
info, ok := util.ManifestInfoFromContext(req.Context())
|
||||||
|
if !ok {
|
||||||
|
var err error
|
||||||
|
info, err = util.ParseManifestInfoFromPath(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
rh.next.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, repoName := common_util.ParseRepository(info.Repository)
|
||||||
|
matched, err := rule.NewRuleMatcher(info.ProjectID).Match(art.Candidate{
|
||||||
|
Repository: repoName,
|
||||||
|
Tag: info.Tag,
|
||||||
|
NamespaceID: info.ProjectID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
rh.next.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !matched {
|
||||||
|
rh.next.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
artifactQuery := &models.ArtifactQuery{
|
||||||
|
PID: info.ProjectID,
|
||||||
|
Repo: info.Repository,
|
||||||
|
Tag: info.Tag,
|
||||||
|
}
|
||||||
|
afs, err := dao.ListArtifacts(artifactQuery)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
rh.next.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(afs) == 0 {
|
||||||
|
rh.next.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// rule matched and non-existent is a immutable tag
|
||||||
|
http.Error(rw, util.MarshalError("DENIED",
|
||||||
|
fmt.Sprintf("The tag:%s:%s is immutable, cannot be overwrite.", info.Repository, info.Tag)), http.StatusPreconditionFailed)
|
||||||
|
return
|
||||||
|
}
|
151
src/core/middlewares/immutable/handler_test.go
Normal file
151
src/core/middlewares/immutable/handler_test.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package immutable
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/distribution"
|
||||||
|
"github.com/goharbor/harbor/src/core/middlewares/util"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"github.com/goharbor/harbor/src/common/dao"
|
||||||
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||||
|
immu_model "github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HandlerSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func doPutManifestRequest(projectID int64, projectName, name, tag, dgt string, next ...http.HandlerFunc) int {
|
||||||
|
repository := fmt.Sprintf("%s/%s", projectName, name)
|
||||||
|
|
||||||
|
url := fmt.Sprintf("/v2/%s/manifests/%s", repository, tag)
|
||||||
|
req, _ := http.NewRequest("PUT", url, nil)
|
||||||
|
|
||||||
|
mfInfo := &util.ManifestInfo{
|
||||||
|
ProjectID: projectID,
|
||||||
|
Repository: repository,
|
||||||
|
Tag: tag,
|
||||||
|
Digest: dgt,
|
||||||
|
References: []distribution.Descriptor{
|
||||||
|
{Digest: digest.FromString(randomString(15))},
|
||||||
|
{Digest: digest.FromString(randomString(15))},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctx := util.NewManifestInfoContext(req.Context(), mfInfo)
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
|
||||||
|
var n http.HandlerFunc
|
||||||
|
if len(next) > 0 {
|
||||||
|
n = next[0]
|
||||||
|
} else {
|
||||||
|
n = func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h := New(http.HandlerFunc(n))
|
||||||
|
h.ServeHTTP(util.NewCustomResponseWriter(rr), req.WithContext(ctx))
|
||||||
|
|
||||||
|
return rr.Code
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomString(n int) string {
|
||||||
|
const letterBytes = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
b := make([]byte, n)
|
||||||
|
for i := range b {
|
||||||
|
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *HandlerSuite) addProject(projectName string) int64 {
|
||||||
|
projectID, err := dao.AddProject(models.Project{
|
||||||
|
Name: projectName,
|
||||||
|
OwnerID: 1,
|
||||||
|
})
|
||||||
|
suite.Nil(err, fmt.Sprintf("Add project failed for %s", projectName))
|
||||||
|
return projectID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *HandlerSuite) addArt(pid int64, repo string, tag string) int64 {
|
||||||
|
afid, err := dao.AddArtifact(&models.Artifact{
|
||||||
|
PID: pid,
|
||||||
|
Repo: repo,
|
||||||
|
Tag: tag,
|
||||||
|
Digest: digest.FromString(randomString(15)).String(),
|
||||||
|
Kind: "Docker-Image",
|
||||||
|
})
|
||||||
|
suite.Nil(err, fmt.Sprintf("Add artifact failed for %s", repo))
|
||||||
|
return afid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *HandlerSuite) addImmutableRule(pid int64) int64 {
|
||||||
|
metadata := &immu_model.Metadata{
|
||||||
|
ProjectID: pid,
|
||||||
|
Priority: 1,
|
||||||
|
Action: "immutable",
|
||||||
|
Template: "immutable_template",
|
||||||
|
TagSelectors: []*immu_model.Selector{
|
||||||
|
{
|
||||||
|
Kind: "doublestar",
|
||||||
|
Decoration: "matches",
|
||||||
|
Pattern: "release-**",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ScopeSelectors: map[string][]*immu_model.Selector{
|
||||||
|
"repository": {
|
||||||
|
{
|
||||||
|
Kind: "doublestar",
|
||||||
|
Decoration: "repoMatches",
|
||||||
|
Pattern: "**",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
id, err := immutabletag.ImmuCtr.CreateImmutableRule(metadata)
|
||||||
|
require.NoError(suite.T(), err, "nil error expected but got %s", err)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *HandlerSuite) TestPutManifestCreated() {
|
||||||
|
projectName := randomString(5)
|
||||||
|
|
||||||
|
projectID := suite.addProject(projectName)
|
||||||
|
immuRuleID := suite.addImmutableRule(projectID)
|
||||||
|
afID := suite.addArt(projectID, projectName+"/photon", "release-1.10")
|
||||||
|
defer func() {
|
||||||
|
dao.DeleteProject(projectID)
|
||||||
|
dao.DeleteArtifact(afID)
|
||||||
|
immutabletag.ImmuCtr.DeleteImmutableRule(immuRuleID)
|
||||||
|
}()
|
||||||
|
|
||||||
|
dgt := digest.FromString(randomString(15)).String()
|
||||||
|
code1 := doPutManifestRequest(projectID, projectName, "photon", "release-1.10", dgt)
|
||||||
|
suite.Equal(http.StatusPreconditionFailed, code1)
|
||||||
|
|
||||||
|
code2 := doPutManifestRequest(projectID, projectName, "photon", "latest", dgt)
|
||||||
|
suite.Equal(http.StatusCreated, code2)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
dao.PrepareTestForPostgresSQL()
|
||||||
|
|
||||||
|
if result := m.Run(); result != 0 {
|
||||||
|
os.Exit(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunHandlerSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(HandlerSuite))
|
||||||
|
}
|
@ -1,15 +1,15 @@
|
|||||||
package rule
|
package rule
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/common/utils/test"
|
"github.com/goharbor/harbor/src/common/dao"
|
||||||
"github.com/goharbor/harbor/src/pkg/art"
|
"github.com/goharbor/harbor/src/pkg/art"
|
||||||
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
"github.com/goharbor/harbor/src/pkg/immutabletag"
|
||||||
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
"github.com/goharbor/harbor/src/pkg/immutabletag/model"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MatchTestSuite ...
|
// MatchTestSuite ...
|
||||||
@ -25,7 +25,6 @@ type MatchTestSuite struct {
|
|||||||
|
|
||||||
// SetupSuite ...
|
// SetupSuite ...
|
||||||
func (s *MatchTestSuite) SetupSuite() {
|
func (s *MatchTestSuite) SetupSuite() {
|
||||||
test.InitDatabaseFromEnv()
|
|
||||||
s.t = s.T()
|
s.t = s.T()
|
||||||
s.assert = assert.New(s.t)
|
s.assert = assert.New(s.t)
|
||||||
s.require = require.New(s.t)
|
s.require = require.New(s.t)
|
||||||
@ -34,34 +33,31 @@ func (s *MatchTestSuite) SetupSuite() {
|
|||||||
|
|
||||||
func (s *MatchTestSuite) TestImmuMatch() {
|
func (s *MatchTestSuite) TestImmuMatch() {
|
||||||
rule := &model.Metadata{
|
rule := &model.Metadata{
|
||||||
ID: 1,
|
ProjectID: 1,
|
||||||
ProjectID: 2,
|
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
Template: "latestPushedK",
|
Action: "immutable",
|
||||||
Action: "immuablity",
|
Template: "immutable_template",
|
||||||
TagSelectors: []*model.Selector{
|
TagSelectors: []*model.Selector{
|
||||||
{
|
{
|
||||||
Kind: "doublestar",
|
Kind: "doublestar",
|
||||||
Decoration: "matches",
|
Decoration: "matches",
|
||||||
Pattern: "release-[\\d\\.]+",
|
Pattern: "release-**",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ScopeSelectors: map[string][]*model.Selector{
|
ScopeSelectors: map[string][]*model.Selector{
|
||||||
"repository": {
|
"repository": {
|
||||||
{
|
{
|
||||||
Kind: "doublestar",
|
Kind: "doublestar",
|
||||||
Decoration: "matches",
|
Decoration: "repoMatches",
|
||||||
Pattern: "redis",
|
Pattern: "redis",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
rule2 := &model.Metadata{
|
rule2 := &model.Metadata{
|
||||||
ID: 1,
|
ProjectID: 1,
|
||||||
ProjectID: 2,
|
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
Template: "latestPushedK",
|
Template: "immutable_template",
|
||||||
Action: "immuablity",
|
Action: "immuablity",
|
||||||
TagSelectors: []*model.Selector{
|
TagSelectors: []*model.Selector{
|
||||||
{
|
{
|
||||||
@ -74,7 +70,7 @@ func (s *MatchTestSuite) TestImmuMatch() {
|
|||||||
"repository": {
|
"repository": {
|
||||||
{
|
{
|
||||||
Kind: "doublestar",
|
Kind: "doublestar",
|
||||||
Decoration: "matches",
|
Decoration: "repoMatches",
|
||||||
Pattern: "mysql",
|
Pattern: "mysql",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -83,69 +79,52 @@ func (s *MatchTestSuite) TestImmuMatch() {
|
|||||||
|
|
||||||
id, err := s.ctr.CreateImmutableRule(rule)
|
id, err := s.ctr.CreateImmutableRule(rule)
|
||||||
s.ruleID = id
|
s.ruleID = id
|
||||||
s.require.NotNil(err)
|
s.require.Nil(err)
|
||||||
|
|
||||||
id, err = s.ctr.CreateImmutableRule(rule2)
|
id, err = s.ctr.CreateImmutableRule(rule2)
|
||||||
s.ruleID2 = id
|
s.ruleID2 = id
|
||||||
s.require.NotNil(err)
|
s.require.Nil(err)
|
||||||
|
|
||||||
match := NewRuleMatcher(2)
|
match := NewRuleMatcher(1)
|
||||||
|
|
||||||
c1 := art.Candidate{
|
c1 := art.Candidate{
|
||||||
NamespaceID: 2,
|
NamespaceID: 1,
|
||||||
Namespace: "immutable",
|
Namespace: "library",
|
||||||
Repository: "redis",
|
Repository: "redis",
|
||||||
Tag: "release-1.10",
|
Tag: "release-1.10",
|
||||||
Kind: art.Image,
|
|
||||||
PushedTime: time.Now().Unix() - 3600,
|
|
||||||
PulledTime: time.Now().Unix(),
|
|
||||||
CreationTime: time.Now().Unix() - 7200,
|
|
||||||
Labels: []string{"label1", "label4", "label5"},
|
|
||||||
}
|
}
|
||||||
isMatch, err := match.Match(c1)
|
isMatch, err := match.Match(c1)
|
||||||
s.require.Equal(isMatch, true)
|
s.require.Equal(isMatch, true)
|
||||||
s.require.Nil(err)
|
s.require.Nil(err)
|
||||||
|
|
||||||
c2 := art.Candidate{
|
c2 := art.Candidate{
|
||||||
NamespaceID: 2,
|
NamespaceID: 1,
|
||||||
Namespace: "immutable",
|
Namespace: "library",
|
||||||
Repository: "redis",
|
Repository: "redis",
|
||||||
Tag: "1.10",
|
Tag: "1.10",
|
||||||
Kind: art.Image,
|
Kind: art.Image,
|
||||||
PushedTime: time.Now().Unix() - 3600,
|
|
||||||
PulledTime: time.Now().Unix(),
|
|
||||||
CreationTime: time.Now().Unix() - 7200,
|
|
||||||
Labels: []string{"label1", "label4", "label5"},
|
|
||||||
}
|
}
|
||||||
isMatch, err = match.Match(c2)
|
isMatch, err = match.Match(c2)
|
||||||
s.require.Equal(isMatch, false)
|
s.require.Equal(isMatch, false)
|
||||||
s.require.Nil(err)
|
s.require.Nil(err)
|
||||||
|
|
||||||
c3 := art.Candidate{
|
c3 := art.Candidate{
|
||||||
NamespaceID: 2,
|
NamespaceID: 1,
|
||||||
Namespace: "immutable",
|
Namespace: "immutable",
|
||||||
Repository: "mysql",
|
Repository: "mysql",
|
||||||
Tag: "9.4.8",
|
Tag: "9.4.8",
|
||||||
Kind: art.Image,
|
Kind: art.Image,
|
||||||
PushedTime: time.Now().Unix() - 3600,
|
|
||||||
PulledTime: time.Now().Unix(),
|
|
||||||
CreationTime: time.Now().Unix() - 7200,
|
|
||||||
Labels: []string{"label1"},
|
|
||||||
}
|
}
|
||||||
isMatch, err = match.Match(c3)
|
isMatch, err = match.Match(c3)
|
||||||
s.require.Equal(isMatch, true)
|
s.require.Equal(isMatch, true)
|
||||||
s.require.Nil(err)
|
s.require.Nil(err)
|
||||||
|
|
||||||
c4 := art.Candidate{
|
c4 := art.Candidate{
|
||||||
NamespaceID: 2,
|
NamespaceID: 1,
|
||||||
Namespace: "immutable",
|
Namespace: "immutable",
|
||||||
Repository: "hello",
|
Repository: "hello",
|
||||||
Tag: "world",
|
Tag: "world",
|
||||||
Kind: art.Image,
|
Kind: art.Image,
|
||||||
PushedTime: time.Now().Unix() - 3600,
|
|
||||||
PulledTime: time.Now().Unix(),
|
|
||||||
CreationTime: time.Now().Unix() - 7200,
|
|
||||||
Labels: []string{"label1"},
|
|
||||||
}
|
}
|
||||||
isMatch, err = match.Match(c4)
|
isMatch, err = match.Match(c4)
|
||||||
s.require.Equal(isMatch, false)
|
s.require.Equal(isMatch, false)
|
||||||
@ -160,3 +139,15 @@ func (s *MatchTestSuite) TearDownSuite() {
|
|||||||
err = s.ctr.DeleteImmutableRule(s.ruleID2)
|
err = s.ctr.DeleteImmutableRule(s.ruleID2)
|
||||||
require.NoError(s.T(), err, "delete immutable")
|
require.NoError(s.T(), err, "delete immutable")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
dao.PrepareTestForPostgresSQL()
|
||||||
|
|
||||||
|
if result := m.Run(); result != 0 {
|
||||||
|
os.Exit(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunHandlerSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(MatchTestSuite))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user