mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 14:19:49 +08:00
Merge pull request #7802 from rainzm/scheduler/failInfo
Optimization of the scheduler
This commit is contained in:
@@ -56,6 +56,7 @@ require (
|
||||
github.com/golang-plus/errors v1.0.0
|
||||
github.com/golang-plus/testing v1.0.0 // indirect
|
||||
github.com/golang-plus/uuid v1.0.0
|
||||
github.com/golang/mock v1.3.1
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/google/gopacket v1.1.17
|
||||
github.com/googleapis/gnostic v0.2.0 // indirect
|
||||
|
||||
@@ -361,6 +361,7 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
||||
@@ -258,14 +258,17 @@ type ForecastFilter struct {
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type ForecastResult struct {
|
||||
Candidate string `json:"candidate"`
|
||||
Count int64 `json:"count"`
|
||||
Capacity int64 `json:"capacity"`
|
||||
type FilteredCandidate struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
FilterName string `json:"filter_name"`
|
||||
Reasons []string `json:"reasons"`
|
||||
}
|
||||
|
||||
type SchedForecastResult struct {
|
||||
CanCreate bool `json:"can_create"`
|
||||
Filters []*ForecastFilter `json:"filters"`
|
||||
Results []*api.CandidateResource `json:"results"`
|
||||
CanCreate bool `json:"can_create"`
|
||||
ReqCount int64 `json:"req_count"`
|
||||
AllowCount int64 `json:"allow_count"`
|
||||
NotAllowReasons []string `json:"not_allow_reasons"`
|
||||
FilteredCandidates []FilteredCandidate `json:"filtered_candidates"`
|
||||
}
|
||||
|
||||
+7
-3
@@ -30,11 +30,10 @@ import (
|
||||
computemodels "yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/data_manager/sku"
|
||||
schedmodels "yunion.io/x/onecloud/pkg/scheduler/models"
|
||||
)
|
||||
|
||||
var ErrInstanceGroupNotFound = errors.Error("InstanceGroupNotFound")
|
||||
|
||||
type BaseHostDesc struct {
|
||||
*computemodels.SHost
|
||||
Region *computemodels.SCloudregion `json:"region"`
|
||||
@@ -126,6 +125,11 @@ func (b baseHostGetter) HostSchedtags() []computemodels.SSchedtag {
|
||||
return b.h.HostSchedtags
|
||||
}
|
||||
|
||||
func (b baseHostGetter) Sku(instanceType string) *sku.ServerSku {
|
||||
zone := b.Zone()
|
||||
return sku.GetByZone(instanceType, zone.GetId())
|
||||
}
|
||||
|
||||
func (b baseHostGetter) Storages() []*api.CandidateStorage {
|
||||
return b.h.Storages
|
||||
}
|
||||
@@ -138,7 +142,7 @@ func (b baseHostGetter) GetFreeGroupCount(groupId string) (int, error) {
|
||||
// Must Be
|
||||
scg, ok := b.h.InstanceGroups[groupId]
|
||||
if !ok {
|
||||
return 0, errors.Wrap(ErrInstanceGroupNotFound, groupId)
|
||||
return 0, errors.Wrap(core.ErrInstanceGroupNotFound, groupId)
|
||||
}
|
||||
free := scg.Granularity - scg.ReferCount
|
||||
if free < 1 {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -29,9 +28,6 @@ import (
|
||||
utiltrace "yunion.io/x/pkg/util/trace"
|
||||
"yunion.io/x/pkg/util/workqueue"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
o "yunion.io/x/onecloud/pkg/scheduler/options"
|
||||
)
|
||||
|
||||
@@ -104,7 +100,7 @@ func NewGenericScheduler(s Scheduler) (*GenericScheduler, error) {
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *GenericScheduler) Schedule(unit *Unit, candidates []Candidater) (*SchedResultItemList, error) {
|
||||
func (g *GenericScheduler) Schedule(unit *Unit, candidates []Candidater, helper IResultHelper) (*ScheduleResult, error) {
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
log.V(4).Infof("Schedule cost time: %v", time.Since(startTime))
|
||||
@@ -171,7 +167,8 @@ func (g *GenericScheduler) Schedule(unit *Unit, candidates []Candidater) (*Sched
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SchedResultItemList{Unit: unit, Data: resultItems}, nil
|
||||
itemList := &SchedResultItemList{Unit: unit, Data: resultItems}
|
||||
return helper.ResultHelp(itemList, unit.SchedInfo), nil
|
||||
}
|
||||
|
||||
func newSchedResultByCtx(u *Unit, count int64, c Candidater) *SchedResultItem {
|
||||
@@ -238,24 +235,6 @@ func generateScheduleResult(u *Unit, scs []*SelectedCandidate, cs []Candidater)
|
||||
return results, nil
|
||||
}
|
||||
|
||||
type SchedResultItem struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Count int64 `json:"count"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
Capacity int64 `json:"capacity"`
|
||||
Score Score `json:"score"`
|
||||
|
||||
CapacityDetails map[string]int64 `json:"capacity_details"`
|
||||
ScoreDetails string `json:"score_details"`
|
||||
|
||||
Candidater Candidater `json:"-"`
|
||||
|
||||
*AllocatedResource
|
||||
|
||||
SchedData *api.SchedInfo
|
||||
}
|
||||
|
||||
type StorageUsed struct {
|
||||
used map[string]int64
|
||||
}
|
||||
@@ -285,27 +264,6 @@ func (s *StorageUsed) Add(storageId string, used int64) {
|
||||
}
|
||||
}
|
||||
|
||||
func (item *SchedResultItem) ToCandidateResource(storageUsed *StorageUsed) *schedapi.CandidateResource {
|
||||
return &schedapi.CandidateResource{
|
||||
HostId: item.ID,
|
||||
Name: item.Name,
|
||||
Disks: item.getDisks(storageUsed),
|
||||
Nets: item.Nets,
|
||||
}
|
||||
}
|
||||
|
||||
func (item *SchedResultItem) getDisks(used *StorageUsed) []*schedapi.CandidateDisk {
|
||||
inputs := item.SchedData.Disks
|
||||
ret := make([]*schedapi.CandidateDisk, 0)
|
||||
for idx, disk := range item.Disks {
|
||||
ret = append(ret, &schedapi.CandidateDisk{
|
||||
Index: idx,
|
||||
StorageIds: item.getSortStorageIds(used, inputs[idx], disk.Storages),
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type sortStorage struct {
|
||||
Id string
|
||||
FeeSize int64
|
||||
@@ -335,31 +293,6 @@ func (s sortStorages) getIds() []string {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (item *SchedResultItem) getSortStorageIds(
|
||||
used *StorageUsed,
|
||||
disk *compute.DiskConfig,
|
||||
storages []*schedapi.CandidateStorage) []string {
|
||||
reqSize := disk.SizeMb
|
||||
ss := make([]sortStorage, 0)
|
||||
for _, s := range storages {
|
||||
ss = append(ss, sortStorage{
|
||||
Id: s.Id,
|
||||
FeeSize: s.FreeCapacity - used.Get(s.Id),
|
||||
})
|
||||
}
|
||||
toSort := sortStorages(ss)
|
||||
sort.Sort(toSort)
|
||||
sortedStorages := toSort.getIds()
|
||||
ret := make([]string, 0)
|
||||
for idx, id := range sortedStorages {
|
||||
if idx == 0 {
|
||||
used.Add(id, int64(reqSize))
|
||||
}
|
||||
ret = append(ret, id)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetCapacities(u *Unit, id string) (res map[string]int64) {
|
||||
res = make(map[string]int64)
|
||||
capacities := u.GetCapacities(id)
|
||||
@@ -371,51 +304,6 @@ func GetCapacities(u *Unit, id string) (res map[string]int64) {
|
||||
return
|
||||
}
|
||||
|
||||
type SchedResultItems []*SchedResultItem
|
||||
|
||||
func (its SchedResultItems) Len() int {
|
||||
return len(its)
|
||||
}
|
||||
|
||||
func (its SchedResultItems) Swap(i, j int) {
|
||||
its[i], its[j] = its[j], its[i]
|
||||
}
|
||||
|
||||
func (its SchedResultItems) Less(i, j int) bool {
|
||||
it1, it2 := its[i], its[j]
|
||||
return it1.Capacity < it2.Capacity
|
||||
/*
|
||||
ctx := its.Unit
|
||||
|
||||
m := func(c int64) int64 {
|
||||
if c > 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
v := func(count, capacity, score int64) int64 {
|
||||
return (m(count) << 42) | (m(capacity) << 21) | score
|
||||
}
|
||||
|
||||
count1, count2 := it1.Count, it2.Count
|
||||
capacity1, capacity2 := ctx.GetCapacity(it1.ID), ctx.GetCapacity(it2.ID)
|
||||
score1, score2 := int64(ctx.GetScore(it1.ID)), int64(ctx.GetScore(it2.ID))
|
||||
|
||||
return v(count1, capacity1, score1) < v(count2, capacity2, score2)
|
||||
*/
|
||||
}
|
||||
|
||||
type SchedResultItemList struct {
|
||||
Unit *Unit
|
||||
Data SchedResultItems
|
||||
}
|
||||
|
||||
func (its SchedResultItemList) String() string {
|
||||
bytes, _ := json.Marshal(its.Data)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
type SelectedCandidate struct {
|
||||
Count int64
|
||||
Candidate Candidater
|
||||
@@ -536,7 +424,11 @@ func findCandidatesThatFit(unit *Unit, candidates []Candidater, predicates map[s
|
||||
unit.AppendFailedCandidates(fcs)
|
||||
}
|
||||
}
|
||||
workqueue.Parallelize(o.GetOptions().PredicateParallelizeSize, len(candidates), checkUnit)
|
||||
workerSize := o.GetOptions().PredicateParallelizeSize
|
||||
if workerSize == 0 {
|
||||
workerSize = 1
|
||||
}
|
||||
workqueue.Parallelize(workerSize, len(candidates), checkUnit)
|
||||
filtered = filtered[:filteredLen]
|
||||
if len(errsChannel) > 0 {
|
||||
errs := make([]error, 0)
|
||||
|
||||
+9
-10
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package manager
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -26,12 +26,10 @@ import (
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/cache/candidate"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core/score"
|
||||
)
|
||||
|
||||
func transToInstanceGroupSchedResult(result *core.SchedResultItemList, schedInfo *api.SchedInfo) *schedapi.ScheduleOutput {
|
||||
func transToInstanceGroupSchedResult(result *SchedResultItemList, schedInfo *api.SchedInfo) *schedapi.ScheduleOutput {
|
||||
for _, item := range result.Data {
|
||||
item.Count = 0
|
||||
}
|
||||
@@ -50,7 +48,7 @@ type sGuestInfo struct {
|
||||
}
|
||||
|
||||
type sSchedResultItem struct {
|
||||
*core.SchedResultItem
|
||||
*SchedResultItem
|
||||
instanceGroupCapacity map[string]int64
|
||||
masterCount int64
|
||||
backupCount int64
|
||||
@@ -69,7 +67,7 @@ func (item *sSchedResultItem) minInstanceGroupCapacity(groupSet map[string]*mode
|
||||
return mincapa
|
||||
}
|
||||
|
||||
func buildHosts(result *core.SchedResultItemList, groups map[string]*models.SGroup) []*sSchedResultItem {
|
||||
func buildHosts(result *SchedResultItemList, groups map[string]*models.SGroup) []*sSchedResultItem {
|
||||
hosts := make([]*sSchedResultItem, result.Data.Len())
|
||||
for i := 0; i < len(result.Data); i++ {
|
||||
getter := result.Data[i].Candidater.Getter()
|
||||
@@ -77,7 +75,7 @@ func buildHosts(result *core.SchedResultItemList, groups map[string]*models.SGro
|
||||
for id, group := range groups {
|
||||
c, err := getter.GetFreeGroupCount(id)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == candidate.ErrInstanceGroupNotFound {
|
||||
if errors.Cause(err) == ErrInstanceGroupNotFound {
|
||||
igCapacity[id] = int64(group.Granularity)
|
||||
} else {
|
||||
igCapacity[id] = 0
|
||||
@@ -124,7 +122,7 @@ func sortHosts(hosts []*sSchedResultItem, guestInfo *sGuestInfo, isBackup *bool)
|
||||
|
||||
// scoreNormalization compare the value of s1 and s2.
|
||||
// If s1 is less than s2, return 1, 0 which means s2 is better than s1.
|
||||
func scoreNormalization(s1, s2 core.Score) (int64, int64) {
|
||||
func scoreNormalization(s1, s2 Score) (int64, int64) {
|
||||
sb1, sb2 := s1.ScoreBucket, s2.ScoreBucket
|
||||
preferLess := score.PreferLess(sb1, sb2)
|
||||
avoidLess := score.AvoidLess(sb1, sb2)
|
||||
@@ -213,7 +211,8 @@ func hostsIndex(hostId string, hosts []*sSchedResultItem) int {
|
||||
// getBackupSchedResult return the ScheduleOutput for guest without backup
|
||||
func getSchedResult(hosts []*sSchedResultItem, guestInfos []sGuestInfo, sid string) *schedapi.ScheduleOutput {
|
||||
apiResults := make([]*schedapi.CandidateResource, 0)
|
||||
storageUsed := core.NewStorageUsed()
|
||||
storageUsed :=
|
||||
NewStorageUsed()
|
||||
var i int = 0
|
||||
for ; i < len(guestInfos); i++ {
|
||||
host := selectHost(hosts, guestInfos[i], nil, true)
|
||||
@@ -244,7 +243,7 @@ func getBackupSchedResult(hosts []*sSchedResultItem, guestInfos, backGuestInfos
|
||||
wireHostMap := buildWireHosts(hosts)
|
||||
apiResults := make([]*schedapi.CandidateResource, 0, len(guestInfos))
|
||||
nowireIds := sets.NewString()
|
||||
storageUsed := core.NewStorageUsed()
|
||||
storageUsed := NewStorageUsed()
|
||||
isBackup := true
|
||||
isMaster := false
|
||||
for i := 0; i < len(guestInfos); i++ {
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
)
|
||||
|
||||
type ScheduleResult struct {
|
||||
// Result is sync schedule result
|
||||
Result *schedapi.ScheduleOutput
|
||||
// ForecastResult is forecast schedule result
|
||||
ForecastResult *api.SchedForecastResult
|
||||
// TestResult is test schedule result
|
||||
TestResult interface{}
|
||||
}
|
||||
|
||||
type SchedResultItem struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Count int64 `json:"count"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
Capacity int64 `json:"capacity"`
|
||||
Score Score `json:"score"`
|
||||
|
||||
CapacityDetails map[string]int64 `json:"capacity_details"`
|
||||
ScoreDetails string `json:"score_details"`
|
||||
|
||||
Candidater Candidater `json:"-"`
|
||||
|
||||
*AllocatedResource
|
||||
|
||||
SchedData *api.SchedInfo
|
||||
}
|
||||
|
||||
type SchedResultItemList struct {
|
||||
Unit *Unit
|
||||
Data SchedResultItems
|
||||
}
|
||||
|
||||
func (its SchedResultItemList) String() string {
|
||||
bytes, _ := json.Marshal(its.Data)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
type SchedResultItems []*SchedResultItem
|
||||
|
||||
func (its SchedResultItems) Len() int {
|
||||
return len(its)
|
||||
}
|
||||
|
||||
func (its SchedResultItems) Swap(i, j int) {
|
||||
its[i], its[j] = its[j], its[i]
|
||||
}
|
||||
|
||||
func (its SchedResultItems) Less(i, j int) bool {
|
||||
it1, it2 := its[i], its[j]
|
||||
return it1.Capacity < it2.Capacity
|
||||
}
|
||||
|
||||
func (item *SchedResultItem) ToCandidateResource(storageUsed *StorageUsed) *schedapi.CandidateResource {
|
||||
return &schedapi.CandidateResource{
|
||||
HostId: item.ID,
|
||||
Name: item.Name,
|
||||
Disks: item.getDisks(storageUsed),
|
||||
Nets: item.Nets,
|
||||
}
|
||||
}
|
||||
|
||||
func (item *SchedResultItem) getDisks(used *StorageUsed) []*schedapi.CandidateDisk {
|
||||
inputs := item.SchedData.Disks
|
||||
ret := make([]*schedapi.CandidateDisk, 0)
|
||||
for idx, disk := range item.Disks {
|
||||
ret = append(ret, &schedapi.CandidateDisk{
|
||||
Index: idx,
|
||||
StorageIds: item.getSortStorageIds(used, inputs[idx], disk.Storages),
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (item *SchedResultItem) getSortStorageIds(
|
||||
used *StorageUsed,
|
||||
disk *compute.DiskConfig,
|
||||
storages []*schedapi.CandidateStorage) []string {
|
||||
reqSize := disk.SizeMb
|
||||
ss := make([]sortStorage, 0)
|
||||
for _, s := range storages {
|
||||
ss = append(ss, sortStorage{
|
||||
Id: s.Id,
|
||||
FeeSize: s.FreeCapacity - used.Get(s.Id),
|
||||
})
|
||||
}
|
||||
toSort := sortStorages(ss)
|
||||
sort.Sort(toSort)
|
||||
sortedStorages := toSort.getIds()
|
||||
ret := make([]string, 0)
|
||||
for idx, id := range sortedStorages {
|
||||
if idx == 0 {
|
||||
used.Add(id, int64(reqSize))
|
||||
}
|
||||
ret = append(ret, id)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
)
|
||||
|
||||
func ResultHelp(result *SchedResultItemList, schedInfo *api.SchedInfo) *ScheduleResult {
|
||||
out := new(ScheduleResult)
|
||||
out.Result = transToSchedResult(result, schedInfo)
|
||||
return out
|
||||
}
|
||||
|
||||
func ResultHelpForForcast(result *SchedResultItemList, _ *api.SchedInfo) *ScheduleResult {
|
||||
out := new(ScheduleResult)
|
||||
out.ForecastResult = transToSchedForecastResult(result)
|
||||
return out
|
||||
}
|
||||
|
||||
func ResultHelpForTest(result *SchedResultItemList, schedInfo *api.SchedInfo) *ScheduleResult {
|
||||
out := new(ScheduleResult)
|
||||
out.TestResult = transToSchedTestResult(result, schedInfo.SuggestionLimit)
|
||||
return out
|
||||
}
|
||||
|
||||
type IResultHelper interface {
|
||||
ResultHelp(result *SchedResultItemList, schedInfo *api.SchedInfo) *ScheduleResult
|
||||
}
|
||||
|
||||
// ResultHelperFunc type is an adapter to allwo the use of ordinary functions as a ResultHelper.
|
||||
// If f is a function with the appropriate signature, ResultHelperFunc(f) is a ResultHelper that calls f.
|
||||
type SResultHelperFunc func(result *SchedResultItemList, schedInfo *api.SchedInfo) *ScheduleResult
|
||||
|
||||
func (r SResultHelperFunc) ResultHelp(result *SchedResultItemList, schedInfo *api.SchedInfo) *ScheduleResult {
|
||||
return r(result, schedInfo)
|
||||
}
|
||||
|
||||
func transToSchedResult(result *SchedResultItemList, schedInfo *api.SchedInfo) *schedapi.ScheduleOutput {
|
||||
if schedInfo.Backup || len(schedInfo.InstanceGroupsDetail) > 0 {
|
||||
return transToInstanceGroupSchedResult(result, schedInfo)
|
||||
} else {
|
||||
return transToRegionSchedResult(result.Data, int64(schedInfo.Count), schedInfo.SessionId)
|
||||
}
|
||||
}
|
||||
|
||||
func transToRegionSchedResult(result SchedResultItems, count int64, sid string) *schedapi.ScheduleOutput {
|
||||
apiResults := make([]*schedapi.CandidateResource, 0)
|
||||
succCount := 0
|
||||
storageUsed := NewStorageUsed()
|
||||
for _, nr := range result {
|
||||
for {
|
||||
if nr.Count <= 0 {
|
||||
break
|
||||
}
|
||||
tr := nr.ToCandidateResource(storageUsed)
|
||||
tr.SessionId = sid
|
||||
apiResults = append(apiResults, tr)
|
||||
nr.Count--
|
||||
succCount++
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
if int64(succCount) >= count {
|
||||
break
|
||||
}
|
||||
er := &schedapi.CandidateResource{Error: "Out of resource"}
|
||||
apiResults = append(apiResults, er)
|
||||
succCount++
|
||||
}
|
||||
|
||||
return &schedapi.ScheduleOutput{
|
||||
Candidates: apiResults,
|
||||
}
|
||||
}
|
||||
|
||||
func hostInResultItemsIndex(hostId string, hosts SchedResultItems) int {
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
if hosts[i].ID == hostId {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func transToSchedTestResult(result *SchedResultItemList, limit int64) interface{} {
|
||||
return &api.SchedTestResult{
|
||||
Data: result.Data,
|
||||
Total: int64(result.Data.Len()),
|
||||
Limit: limit,
|
||||
Offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func transToSchedForecastResult(result *SchedResultItemList) *api.SchedForecastResult {
|
||||
unit := result.Unit
|
||||
schedData := unit.SchedData()
|
||||
filteredCandidates := make([]api.FilteredCandidate, 0)
|
||||
ret := &api.SchedForecastResult{
|
||||
ReqCount: int64(schedData.Count),
|
||||
}
|
||||
|
||||
// build filteredCandidates
|
||||
failedLogs := unit.LogManager.FailedLogs()
|
||||
logIndex := func(item *SchedResultItem) string {
|
||||
getter := item.Candidater.Getter()
|
||||
name := getter.Name()
|
||||
id := getter.Id()
|
||||
return fmt.Sprintf("%s:%s", name, id)
|
||||
}
|
||||
for _, item := range result.Data {
|
||||
if item.Capacity > 0 {
|
||||
continue
|
||||
}
|
||||
filteredCandidate := api.FilteredCandidate{
|
||||
ID: item.ID,
|
||||
Name: item.Name,
|
||||
}
|
||||
for preName, capa := range item.CapacityDetails {
|
||||
if capa > 0 {
|
||||
continue
|
||||
}
|
||||
filteredCandidate.FilterName = preName
|
||||
}
|
||||
failedLog := failedLogs.Get(logIndex(item))
|
||||
if failedLog == nil {
|
||||
log.Errorf("candidate %q capacity is 0 but no failedLog found", item.Name)
|
||||
continue
|
||||
}
|
||||
for _, msg := range failedLog.Messages {
|
||||
filteredCandidate.Reasons = append(filteredCandidate.Reasons, msg.Info)
|
||||
}
|
||||
filteredCandidates = append(filteredCandidates, filteredCandidate)
|
||||
}
|
||||
ret.FilteredCandidates = filteredCandidates
|
||||
|
||||
var (
|
||||
output = transToSchedResult(result, schedData)
|
||||
readyCount int64
|
||||
)
|
||||
for _, candi := range output.Candidates {
|
||||
if len(candi.Error) == 0 {
|
||||
readyCount++
|
||||
continue
|
||||
}
|
||||
ret.NotAllowReasons = append(ret.NotAllowReasons, candi.Error)
|
||||
}
|
||||
|
||||
ret.AllowCount = readyCount
|
||||
if ret.AllowCount < ret.ReqCount {
|
||||
ret.CanCreate = false
|
||||
} else {
|
||||
ret.CanCreate = true
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
computemodels "yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core/score"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/data_manager/sku"
|
||||
schedmodels "yunion.io/x/onecloud/pkg/scheduler/models"
|
||||
)
|
||||
|
||||
@@ -34,6 +36,8 @@ const (
|
||||
PriorityStep int = 1
|
||||
)
|
||||
|
||||
var ErrInstanceGroupNotFound = errors.Error("InstanceGroupNotFound")
|
||||
|
||||
type FailedCandidate struct {
|
||||
Stage string
|
||||
Candidate Candidater
|
||||
@@ -71,6 +75,7 @@ type CandidatePropertyGetter interface {
|
||||
Region() *computemodels.SCloudregion
|
||||
HostType() string
|
||||
HostSchedtags() []computemodels.SSchedtag
|
||||
Sku(string) *sku.ServerSku
|
||||
Storages() []*api.CandidateStorage
|
||||
Networks() []*api.CandidateNetwork
|
||||
OvnCapable() bool
|
||||
|
||||
@@ -96,7 +96,7 @@ func (sm *SchedulerManager) start() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SchedulerManager) schedule(info *api.SchedInfo) (*ScheduleResult, error) {
|
||||
func (sm *SchedulerManager) schedule(info *api.SchedInfo) (*core.ScheduleResult, error) {
|
||||
log.V(10).Infof("SchedulerManager do schedule, input: %#v", info)
|
||||
task, err := sm.TaskManager.AddTask(sm, info)
|
||||
if err != nil {
|
||||
@@ -121,7 +121,7 @@ func NewSessionID() string {
|
||||
|
||||
// Schedule process the request data that is scheduled for dispatch and complements
|
||||
// the session information.
|
||||
func Schedule(info *api.SchedInfo) (*ScheduleResult, error) {
|
||||
func Schedule(info *api.SchedInfo) (*core.ScheduleResult, error) {
|
||||
if len(info.SessionId) == 0 {
|
||||
info.SessionId = NewSessionID()
|
||||
}
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
computemodels "yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
schedmodels "yunion.io/x/onecloud/pkg/scheduler/models"
|
||||
)
|
||||
|
||||
func transToSchedResult(result *core.SchedResultItemList, schedInfo *api.SchedInfo) *schedapi.ScheduleOutput {
|
||||
if schedInfo.Backup || len(schedInfo.InstanceGroupsDetail) > 0 {
|
||||
return transToInstanceGroupSchedResult(result, schedInfo)
|
||||
} else {
|
||||
return transToRegionSchedResult(result.Data, int64(schedInfo.Count), schedInfo.SessionId)
|
||||
}
|
||||
}
|
||||
|
||||
func setSchedPendingUsage(driver computemodels.IGuestDriver, req *api.SchedInfo, resp *schedapi.ScheduleOutput) error {
|
||||
if req.IsSuggestion || IsDriverSkipScheduleDirtyMark(driver) || req.SkipDirtyMarkHost() {
|
||||
return nil
|
||||
}
|
||||
for _, item := range resp.Candidates {
|
||||
schedmodels.HostPendingUsageManager.AddPendingUsage(req, item)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsDriverSkipScheduleDirtyMark(driver computemodels.IGuestDriver) bool {
|
||||
return !(driver.DoScheduleCPUFilter() && driver.DoScheduleMemoryFilter() && driver.DoScheduleStorageFilter())
|
||||
}
|
||||
|
||||
func transToRegionSchedResult(result core.SchedResultItems, count int64, sid string) *schedapi.ScheduleOutput {
|
||||
apiResults := make([]*schedapi.CandidateResource, 0)
|
||||
succCount := 0
|
||||
storageUsed := core.NewStorageUsed()
|
||||
for _, nr := range result {
|
||||
for {
|
||||
if nr.Count <= 0 {
|
||||
break
|
||||
}
|
||||
tr := nr.ToCandidateResource(storageUsed)
|
||||
tr.SessionId = sid
|
||||
apiResults = append(apiResults, tr)
|
||||
nr.Count--
|
||||
succCount++
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
if int64(succCount) >= count {
|
||||
break
|
||||
}
|
||||
er := &schedapi.CandidateResource{Error: "Out of resource"}
|
||||
apiResults = append(apiResults, er)
|
||||
succCount++
|
||||
}
|
||||
|
||||
return &schedapi.ScheduleOutput{
|
||||
Candidates: apiResults,
|
||||
}
|
||||
}
|
||||
|
||||
func hostInResultItemsIndex(hostId string, hosts core.SchedResultItems) int {
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
if hosts[i].ID == hostId {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func transToSchedTestResult(result *core.SchedResultItemList, limit int64) interface{} {
|
||||
return &api.SchedTestResult{
|
||||
Data: result.Data,
|
||||
Total: int64(result.Data.Len()),
|
||||
Limit: limit,
|
||||
Offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func transToSchedForecastResult(result *core.SchedResultItemList) interface{} {
|
||||
unit := result.Unit
|
||||
schedData := unit.SchedData()
|
||||
reqCount := int64(schedData.Count)
|
||||
filters := make([]*api.ForecastFilter, 0)
|
||||
|
||||
filtersMap := make(map[string]*api.ForecastFilter)
|
||||
getOrNewFilter := func(preName string) (*api.ForecastFilter, bool) {
|
||||
if info, ok := filtersMap[preName]; !ok {
|
||||
i := &api.ForecastFilter{
|
||||
Filter: preName,
|
||||
Count: 0,
|
||||
Messages: make([]string, 0),
|
||||
}
|
||||
filtersMap[preName] = i
|
||||
return i, false
|
||||
} else {
|
||||
return info, true
|
||||
}
|
||||
}
|
||||
|
||||
logIndex := func(item *core.SchedResultItem) string {
|
||||
getter := item.Candidater.Getter()
|
||||
name := getter.Name()
|
||||
id := getter.Id()
|
||||
return fmt.Sprintf("%s:%s", name, id)
|
||||
}
|
||||
addInfos := func(logs core.SchedLogList, item *core.SchedResultItem) {
|
||||
for preName, cnt := range item.CapacityDetails {
|
||||
if cnt > 0 {
|
||||
continue
|
||||
}
|
||||
failedLog := logs.Get(logIndex(item))
|
||||
if failedLog == nil {
|
||||
log.Errorf("predicate %q count is 0, but not found failed log", preName)
|
||||
continue
|
||||
}
|
||||
for _, msg := range failedLog.Messages {
|
||||
info, exist := getOrNewFilter(msg.Type)
|
||||
info.Count++
|
||||
info.Messages = append(info.Messages, msg.Info)
|
||||
if !exist {
|
||||
filters = append(filters, info)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items := make(core.SchedResultItems, 0)
|
||||
for _, item := range result.Data {
|
||||
hostType := item.Candidater.Getter().HostType()
|
||||
if schedData.Hypervisor == hostType {
|
||||
items = append(items, item)
|
||||
}
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
addInfos(result.Unit.LogManager.FailedLogs(), item)
|
||||
}
|
||||
|
||||
var (
|
||||
output = transToSchedResult(result, schedData)
|
||||
readyCount int64
|
||||
)
|
||||
|
||||
for _, candi := range output.Candidates {
|
||||
if len(candi.Error) != 0 {
|
||||
info, exist := getOrNewFilter("select_candidate")
|
||||
msg := candi.Error
|
||||
info.Messages = append(info.Messages, msg)
|
||||
if !exist {
|
||||
filters = append(filters, info)
|
||||
}
|
||||
} else {
|
||||
readyCount++
|
||||
}
|
||||
}
|
||||
|
||||
canCreate := true
|
||||
if readyCount < reqCount {
|
||||
canCreate = false
|
||||
filters = append(filters, &api.ForecastFilter{
|
||||
Messages: []string{
|
||||
fmt.Sprintf("No enough resources: %d/%d(free/request)", readyCount, reqCount),
|
||||
},
|
||||
})
|
||||
}
|
||||
return &api.SchedForecastResult{
|
||||
CanCreate: canCreate,
|
||||
Filters: filters,
|
||||
Results: output.Candidates,
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,10 @@ import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
computemodels "yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
schedmodels "yunion.io/x/onecloud/pkg/scheduler/models"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -47,7 +49,7 @@ type TaskExecutor struct {
|
||||
callback TaskExecuteCallback
|
||||
unit *core.Unit
|
||||
|
||||
resultItems *ScheduleResult
|
||||
resultItems *core.ScheduleResult
|
||||
resultError error
|
||||
logs []string
|
||||
capacityMap interface{}
|
||||
@@ -81,16 +83,7 @@ func (te *TaskExecutor) Execute() {
|
||||
}
|
||||
}
|
||||
|
||||
type ScheduleResult struct {
|
||||
// Result is sync schedule result
|
||||
Result *schedapi.ScheduleOutput
|
||||
// ForecastResult is forecast schedule result
|
||||
ForecastResult interface{}
|
||||
// TestResult is test schedule result
|
||||
TestResult interface{}
|
||||
}
|
||||
|
||||
func (te *TaskExecutor) execute() (*ScheduleResult, error) {
|
||||
func (te *TaskExecutor) execute() (*core.ScheduleResult, error) {
|
||||
scheduler := te.scheduler
|
||||
genericScheduler, err := core.NewGenericScheduler(scheduler.(core.Scheduler))
|
||||
if err != nil {
|
||||
@@ -105,25 +98,43 @@ func (te *TaskExecutor) execute() (*ScheduleResult, error) {
|
||||
|
||||
te.unit = scheduler.Unit()
|
||||
schedInfo := te.unit.SchedInfo
|
||||
result, err := genericScheduler.Schedule(te.unit, candidates)
|
||||
helper := GenerateResultHelper(schedInfo)
|
||||
result, err := genericScheduler.Schedule(te.unit, candidates, helper)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "genericScheduler.Schedule")
|
||||
}
|
||||
out := new(ScheduleResult)
|
||||
if schedInfo.IsSuggestion {
|
||||
if schedInfo.ShowSuggestionDetails && schedInfo.SuggestionAll {
|
||||
out.ForecastResult = transToSchedForecastResult(result)
|
||||
} else {
|
||||
out.TestResult = transToSchedTestResult(result, schedInfo.SuggestionLimit)
|
||||
}
|
||||
} else {
|
||||
out.Result = transToSchedResult(result, schedInfo)
|
||||
driver := te.unit.GetHypervisorDriver()
|
||||
if err := setSchedPendingUsage(driver, schedInfo, out.Result); err != nil {
|
||||
return nil, errors.Wrap(err, "setSchedPendingUsage")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return out, nil
|
||||
driver := te.unit.GetHypervisorDriver()
|
||||
if err := setSchedPendingUsage(driver, schedInfo, result.Result); err != nil {
|
||||
return nil, errors.Wrap(err, "setSchedPendingUsage")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GenerateResultHelper(schedInfo *api.SchedInfo) core.IResultHelper {
|
||||
if !schedInfo.IsSuggestion {
|
||||
return core.SResultHelperFunc(core.ResultHelp)
|
||||
}
|
||||
if schedInfo.ShowSuggestionDetails && schedInfo.SuggestionAll {
|
||||
return core.SResultHelperFunc(core.ResultHelpForForcast)
|
||||
}
|
||||
return core.SResultHelperFunc(core.ResultHelpForTest)
|
||||
}
|
||||
|
||||
func setSchedPendingUsage(driver computemodels.IGuestDriver, req *api.SchedInfo, resp *schedapi.ScheduleOutput) error {
|
||||
if req.IsSuggestion || IsDriverSkipScheduleDirtyMark(driver) || req.SkipDirtyMarkHost() {
|
||||
return nil
|
||||
}
|
||||
for _, item := range resp.Candidates {
|
||||
schedmodels.HostPendingUsageManager.AddPendingUsage(req, item)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsDriverSkipScheduleDirtyMark(driver computemodels.IGuestDriver) bool {
|
||||
return !(driver.DoScheduleCPUFilter() && driver.DoScheduleMemoryFilter() && driver.DoScheduleStorageFilter())
|
||||
}
|
||||
|
||||
func (te *TaskExecutor) cleanup() {
|
||||
@@ -138,7 +149,7 @@ func (te *TaskExecutor) Kill() {
|
||||
}
|
||||
}
|
||||
|
||||
func (te *TaskExecutor) GetResult() (*ScheduleResult, error) {
|
||||
func (te *TaskExecutor) GetResult() (*core.ScheduleResult, error) {
|
||||
return te.resultItems, te.resultError
|
||||
}
|
||||
|
||||
@@ -299,7 +310,7 @@ type Task struct {
|
||||
waitCh chan struct{}
|
||||
|
||||
completedCount int
|
||||
resultItems *ScheduleResult
|
||||
resultItems *core.ScheduleResult
|
||||
resultError error
|
||||
}
|
||||
|
||||
@@ -393,12 +404,12 @@ func (t *Task) onCompleted() {
|
||||
close(t.waitCh)
|
||||
}
|
||||
|
||||
func (t *Task) Wait() (*ScheduleResult, error) {
|
||||
func (t *Task) Wait() (*core.ScheduleResult, error) {
|
||||
log.V(10).Infof("Task wait...")
|
||||
<-t.waitCh
|
||||
return t.GetResult()
|
||||
}
|
||||
|
||||
func (t *Task) GetResult() (*ScheduleResult, error) {
|
||||
func (t *Task) GetResult() (*core.ScheduleResult, error) {
|
||||
return t.resultItems, t.resultError
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 test // import "yunion.io/x/onecloud/pkg/scheduler/test"
|
||||
@@ -0,0 +1,191 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
apisdu "yunion.io/x/onecloud/pkg/apis/scheduler"
|
||||
_ "yunion.io/x/onecloud/pkg/compute/guestdrivers"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
)
|
||||
|
||||
func TestGenericSchedulerSchedule(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
scheduler, err := core.NewGenericScheduler(buildScheduler(ctrl, basePredicateNames...))
|
||||
if err != nil {
|
||||
t.Errorf("NewGenericScheduler: %s", err.Error())
|
||||
return
|
||||
}
|
||||
commonInfo := &api.SchedInfo{
|
||||
ScheduleInput: &apisdu.ScheduleInput{
|
||||
ServerConfig: apisdu.ServerConfig{
|
||||
ServerConfigs: &compute.ServerConfigs{
|
||||
PreferRegion: GlobalCloudregion.GetId(),
|
||||
PreferZone: GlobalZone.GetId(),
|
||||
PreferHost: "host01",
|
||||
Hypervisor: "hypervisor",
|
||||
ResourceType: "shared",
|
||||
InstanceType: "ecs.g1.c1m1",
|
||||
Sku: "ecs.g1.c1m1",
|
||||
Backup: false,
|
||||
Count: 1,
|
||||
Disks: []*compute.DiskConfig{
|
||||
{
|
||||
Backend: "local",
|
||||
DiskType: "sys",
|
||||
ImageId: "CentOS7.6",
|
||||
Index: 0,
|
||||
SizeMb: 30720,
|
||||
},
|
||||
{
|
||||
Backend: "local",
|
||||
DiskType: "data",
|
||||
Index: 1,
|
||||
SizeMb: 10240,
|
||||
},
|
||||
},
|
||||
Networks: []*compute.NetworkConfig{
|
||||
{
|
||||
Index: 0,
|
||||
Network: "network01",
|
||||
Domain: GlobalDoamin,
|
||||
},
|
||||
},
|
||||
BaremetalDiskConfigs: []*compute.BaremetalDiskConfig{
|
||||
{
|
||||
Type: "hybrid",
|
||||
Conf: "none",
|
||||
Count: 0,
|
||||
},
|
||||
},
|
||||
InstanceGroupIds: []string{
|
||||
"instancegroup01",
|
||||
},
|
||||
},
|
||||
Memory: 1024,
|
||||
Ncpu: 1,
|
||||
Project: GlobalProject,
|
||||
Domain: GlobalDoamin,
|
||||
},
|
||||
},
|
||||
PreferCandidates: []string{
|
||||
"host01",
|
||||
},
|
||||
RequiredCandidates: 1,
|
||||
InstanceGroupsDetail: map[string]*models.SGroup{
|
||||
"instancegroup01": buildInstanceGroup("instancegroup01", 1, true),
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("Base test", func(t *testing.T) {
|
||||
info := deepCopy(commonInfo)
|
||||
getterParam := sGetterParams{
|
||||
HostId: "host01",
|
||||
HostName: "host01name",
|
||||
Domain: "default",
|
||||
PublicScope: "system",
|
||||
Zone: buildZone("zone01", ""),
|
||||
CloudRegion: buildCloudregion("default", "", ""),
|
||||
HostType: api.HostHypervisorForKvm,
|
||||
Storages: []*api.CandidateStorage{buildStorage("storage01", "", 201330)},
|
||||
Networks: []*api.CandidateNetwork{buildNetwork("network01", "", "192.168.1.0/24")},
|
||||
TotalCPUCount: 8,
|
||||
FreeCPUCount: 8,
|
||||
TotalMemorySize: 10240,
|
||||
FreeMemorySize: 10240,
|
||||
FreeStorageSizeAnyType: 201330,
|
||||
FreePort: 10,
|
||||
FreeGroupCount: 1,
|
||||
Skus: []string{"ecs.g1.c1m1"},
|
||||
}
|
||||
candidate := buildCandidate(ctrl, getterParam)
|
||||
_, err := scheduler.Schedule(preSchedule(info, []core.Candidater{candidate}, false))
|
||||
if err != nil {
|
||||
t.Errorf("genericScheduler.Schedule error: %s", err.Error())
|
||||
}
|
||||
})
|
||||
t.Run("Forcast schedule: no match specified network", func(t *testing.T) {
|
||||
info := deepCopy(commonInfo)
|
||||
info.PreferHost = ""
|
||||
info.PreferCandidates = []string{}
|
||||
info.InstanceGroupIds = []string{}
|
||||
info.InstanceGroupsDetail = make(map[string]*models.SGroup)
|
||||
info.Count = 2
|
||||
getterParam1 := sGetterParams{
|
||||
HostId: "host01",
|
||||
HostName: "host01name",
|
||||
Domain: "default",
|
||||
PublicScope: "system",
|
||||
Zone: buildZone("zone01", ""),
|
||||
CloudRegion: buildCloudregion("default", "", ""),
|
||||
HostType: api.HostHypervisorForKvm,
|
||||
Storages: []*api.CandidateStorage{buildStorage("storage01", "", 201330)},
|
||||
Networks: []*api.CandidateNetwork{
|
||||
buildNetwork("network01", "nework01name", "192.168.1.0/24"),
|
||||
buildNetwork("network02", "nework02name", "192.168.2.0/24"),
|
||||
},
|
||||
TotalCPUCount: 8,
|
||||
FreeCPUCount: 8,
|
||||
TotalMemorySize: 10240,
|
||||
FreeMemorySize: 10240,
|
||||
FreeStorageSizeAnyType: 201330,
|
||||
FreePort: 1,
|
||||
Skus: []string{"ecs.g1.c1m1"},
|
||||
}
|
||||
getterParam2 := getterParam1
|
||||
getterParam2.HostId = "host02"
|
||||
getterParam2.HostName = "host02name"
|
||||
getterParam2.Networks = []*api.CandidateNetwork{
|
||||
buildNetwork("network03", "nework03name", "192.168.3.0/24"),
|
||||
buildNetwork("network04", "nework04name", "192.168.4.0/24"),
|
||||
}
|
||||
candidates := []core.Candidater{
|
||||
buildCandidate(ctrl, getterParam1),
|
||||
buildCandidate(ctrl, getterParam2),
|
||||
}
|
||||
res, err := scheduler.Schedule(preSchedule(info, candidates, true))
|
||||
if err != nil {
|
||||
t.Errorf("genericScheduler.Schedule error: %s", err.Error())
|
||||
}
|
||||
forcastResult := &api.SchedForecastResult{
|
||||
CanCreate: false,
|
||||
AllowCount: 1,
|
||||
ReqCount: 2,
|
||||
NotAllowReasons: []string{"Out of resource"},
|
||||
FilteredCandidates: []api.FilteredCandidate{
|
||||
{
|
||||
FilterName: "host_network",
|
||||
ID: "host02",
|
||||
Name: "host02name",
|
||||
Reasons: []string{
|
||||
"nework03name(network03): id/name not matched",
|
||||
"nework04name(network04): id/name not matched",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(res.ForecastResult, forcastResult) {
|
||||
t.Errorf("want: %v, real: %v", forcastResult, res.ForecastResult)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,871 @@
|
||||
// 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 mock
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
|
||||
jsonutils "yunion.io/x/jsonutils"
|
||||
|
||||
types "yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
baremetal "yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
models "yunion.io/x/onecloud/pkg/compute/models"
|
||||
api "yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
core "yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
sku "yunion.io/x/onecloud/pkg/scheduler/data_manager/sku"
|
||||
models0 "yunion.io/x/onecloud/pkg/scheduler/models"
|
||||
)
|
||||
|
||||
// MockCandidatePropertyGetter is a mock of CandidatePropertyGetter interface
|
||||
type MockCandidatePropertyGetter struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCandidatePropertyGetterMockRecorder
|
||||
}
|
||||
|
||||
// MockCandidatePropertyGetterMockRecorder is the mock recorder for MockCandidatePropertyGetter
|
||||
type MockCandidatePropertyGetterMockRecorder struct {
|
||||
mock *MockCandidatePropertyGetter
|
||||
}
|
||||
|
||||
// NewMockCandidatePropertyGetter creates a new mock instance
|
||||
func NewMockCandidatePropertyGetter(ctrl *gomock.Controller) *MockCandidatePropertyGetter {
|
||||
mock := &MockCandidatePropertyGetter{ctrl: ctrl}
|
||||
mock.recorder = &MockCandidatePropertyGetterMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockCandidatePropertyGetter) EXPECT() *MockCandidatePropertyGetterMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Cloudprovider mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Cloudprovider() *models.SCloudprovider {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Cloudprovider")
|
||||
ret0, _ := ret[0].(*models.SCloudprovider)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Cloudprovider indicates an expected call of Cloudprovider
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Cloudprovider() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cloudprovider", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Cloudprovider))
|
||||
}
|
||||
|
||||
// CreatingGuestCount mocks base method
|
||||
func (m *MockCandidatePropertyGetter) CreatingGuestCount() int {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreatingGuestCount")
|
||||
ret0, _ := ret[0].(int)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreatingGuestCount indicates an expected call of CreatingGuestCount
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) CreatingGuestCount() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatingGuestCount", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).CreatingGuestCount))
|
||||
}
|
||||
|
||||
// DomainId mocks base method
|
||||
func (m *MockCandidatePropertyGetter) DomainId() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DomainId")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DomainId indicates an expected call of DomainId
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) DomainId() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DomainId", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).DomainId))
|
||||
}
|
||||
|
||||
// Enabled mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Enabled() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Enabled")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Enabled indicates an expected call of Enabled
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Enabled() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Enabled", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Enabled))
|
||||
}
|
||||
|
||||
// FreeCPUCount mocks base method
|
||||
func (m *MockCandidatePropertyGetter) FreeCPUCount(arg0 bool) int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FreeCPUCount", arg0)
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// FreeCPUCount indicates an expected call of FreeCPUCount
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) FreeCPUCount(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FreeCPUCount", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).FreeCPUCount), arg0)
|
||||
}
|
||||
|
||||
// FreeMemorySize mocks base method
|
||||
func (m *MockCandidatePropertyGetter) FreeMemorySize(arg0 bool) int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FreeMemorySize", arg0)
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// FreeMemorySize indicates an expected call of FreeMemorySize
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) FreeMemorySize(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FreeMemorySize", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).FreeMemorySize), arg0)
|
||||
}
|
||||
|
||||
// GetFreeGroupCount mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetFreeGroupCount(arg0 string) (int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFreeGroupCount", arg0)
|
||||
ret0, _ := ret[0].(int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetFreeGroupCount indicates an expected call of GetFreeGroupCount
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetFreeGroupCount(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFreeGroupCount", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetFreeGroupCount), arg0)
|
||||
}
|
||||
|
||||
// GetFreePort mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetFreePort(arg0 string) int {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFreePort", arg0)
|
||||
ret0, _ := ret[0].(int)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetFreePort indicates an expected call of GetFreePort
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetFreePort(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFreePort", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetFreePort), arg0)
|
||||
}
|
||||
|
||||
// GetFreeStorageSizeOfType mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetFreeStorageSizeOfType(arg0 string, arg1 bool) int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFreeStorageSizeOfType", arg0, arg1)
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetFreeStorageSizeOfType indicates an expected call of GetFreeStorageSizeOfType
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetFreeStorageSizeOfType(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFreeStorageSizeOfType", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetFreeStorageSizeOfType), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetIpmiInfo mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetIpmiInfo() types.SIPMIInfo {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetIpmiInfo")
|
||||
ret0, _ := ret[0].(types.SIPMIInfo)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetIpmiInfo indicates an expected call of GetIpmiInfo
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetIpmiInfo() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIpmiInfo", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetIpmiInfo))
|
||||
}
|
||||
|
||||
// GetIsolatedDevice mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetIsolatedDevice(arg0 string) *core.IsolatedDeviceDesc {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetIsolatedDevice", arg0)
|
||||
ret0, _ := ret[0].(*core.IsolatedDeviceDesc)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetIsolatedDevice indicates an expected call of GetIsolatedDevice
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetIsolatedDevice(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIsolatedDevice", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetIsolatedDevice), arg0)
|
||||
}
|
||||
|
||||
// GetIsolatedDevices mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetIsolatedDevices() []*core.IsolatedDeviceDesc {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetIsolatedDevices")
|
||||
ret0, _ := ret[0].([]*core.IsolatedDeviceDesc)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetIsolatedDevices indicates an expected call of GetIsolatedDevices
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetIsolatedDevices() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIsolatedDevices", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetIsolatedDevices))
|
||||
}
|
||||
|
||||
// GetPendingUsage mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetPendingUsage() *models0.SPendingUsage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetPendingUsage")
|
||||
ret0, _ := ret[0].(*models0.SPendingUsage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetPendingUsage indicates an expected call of GetPendingUsage
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetPendingUsage() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPendingUsage", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetPendingUsage))
|
||||
}
|
||||
|
||||
// GetQuotaKeys mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetQuotaKeys(arg0 *api.SchedInfo) models.SComputeResourceKeys {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetQuotaKeys", arg0)
|
||||
ret0, _ := ret[0].(models.SComputeResourceKeys)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetQuotaKeys indicates an expected call of GetQuotaKeys
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetQuotaKeys(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQuotaKeys", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetQuotaKeys), arg0)
|
||||
}
|
||||
|
||||
// Host mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Host() *models.SHost {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Host")
|
||||
ret0, _ := ret[0].(*models.SHost)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Host indicates an expected call of Host
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Host() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Host", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Host))
|
||||
}
|
||||
|
||||
// HostSchedtags mocks base method
|
||||
func (m *MockCandidatePropertyGetter) HostSchedtags() []models.SSchedtag {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HostSchedtags")
|
||||
ret0, _ := ret[0].([]models.SSchedtag)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HostSchedtags indicates an expected call of HostSchedtags
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) HostSchedtags() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HostSchedtags", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).HostSchedtags))
|
||||
}
|
||||
|
||||
// HostStatus mocks base method
|
||||
func (m *MockCandidatePropertyGetter) HostStatus() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HostStatus")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HostStatus indicates an expected call of HostStatus
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) HostStatus() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HostStatus", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).HostStatus))
|
||||
}
|
||||
|
||||
// HostType mocks base method
|
||||
func (m *MockCandidatePropertyGetter) HostType() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HostType")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HostType indicates an expected call of HostType
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) HostType() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HostType", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).HostType))
|
||||
}
|
||||
|
||||
// Id mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Id() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Id")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Id indicates an expected call of Id
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Id() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Id))
|
||||
}
|
||||
|
||||
// InstanceGroups mocks base method
|
||||
func (m *MockCandidatePropertyGetter) InstanceGroups() map[string]*api.CandidateGroup {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InstanceGroups")
|
||||
ret0, _ := ret[0].(map[string]*api.CandidateGroup)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InstanceGroups indicates an expected call of InstanceGroups
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) InstanceGroups() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceGroups", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).InstanceGroups))
|
||||
}
|
||||
|
||||
// IsEmpty mocks base method
|
||||
func (m *MockCandidatePropertyGetter) IsEmpty() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsEmpty")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsEmpty indicates an expected call of IsEmpty
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) IsEmpty() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsEmpty", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).IsEmpty))
|
||||
}
|
||||
|
||||
// IsPublic mocks base method
|
||||
func (m *MockCandidatePropertyGetter) IsPublic() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsPublic")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsPublic indicates an expected call of IsPublic
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) IsPublic() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsPublic", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).IsPublic))
|
||||
}
|
||||
|
||||
// KeywordPlural mocks base method
|
||||
func (m *MockCandidatePropertyGetter) KeywordPlural() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "KeywordPlural")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// KeywordPlural indicates an expected call of KeywordPlural
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) KeywordPlural() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeywordPlural", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).KeywordPlural))
|
||||
}
|
||||
|
||||
// Name mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Name() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Name")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Name indicates an expected call of Name
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Name() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Name))
|
||||
}
|
||||
|
||||
// NetInterfaces mocks base method
|
||||
func (m *MockCandidatePropertyGetter) NetInterfaces() map[string][]models.SNetInterface {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NetInterfaces")
|
||||
ret0, _ := ret[0].(map[string][]models.SNetInterface)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// NetInterfaces indicates an expected call of NetInterfaces
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) NetInterfaces() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetInterfaces", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).NetInterfaces))
|
||||
}
|
||||
|
||||
// Networks mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Networks() []*api.CandidateNetwork {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Networks")
|
||||
ret0, _ := ret[0].([]*api.CandidateNetwork)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Networks indicates an expected call of Networks
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Networks() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Networks", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Networks))
|
||||
}
|
||||
|
||||
// OvnCapable mocks base method
|
||||
func (m *MockCandidatePropertyGetter) OvnCapable() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "OvnCapable")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// OvnCapable indicates an expected call of OvnCapable
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) OvnCapable() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OvnCapable", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).OvnCapable))
|
||||
}
|
||||
|
||||
// ProjectGuests mocks base method
|
||||
func (m *MockCandidatePropertyGetter) ProjectGuests() map[string]int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ProjectGuests")
|
||||
ret0, _ := ret[0].(map[string]int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ProjectGuests indicates an expected call of ProjectGuests
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) ProjectGuests() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProjectGuests", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).ProjectGuests))
|
||||
}
|
||||
|
||||
// PublicScope mocks base method
|
||||
func (m *MockCandidatePropertyGetter) PublicScope() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PublicScope")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PublicScope indicates an expected call of PublicScope
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) PublicScope() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublicScope", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).PublicScope))
|
||||
}
|
||||
|
||||
// Region mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Region() *models.SCloudregion {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Region")
|
||||
ret0, _ := ret[0].(*models.SCloudregion)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Region indicates an expected call of Region
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Region() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Region", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Region))
|
||||
}
|
||||
|
||||
// ResourceType mocks base method
|
||||
func (m *MockCandidatePropertyGetter) ResourceType() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ResourceType")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ResourceType indicates an expected call of ResourceType
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) ResourceType() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResourceType", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).ResourceType))
|
||||
}
|
||||
|
||||
// RunningCPUCount mocks base method
|
||||
func (m *MockCandidatePropertyGetter) RunningCPUCount() int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RunningCPUCount")
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RunningCPUCount indicates an expected call of RunningCPUCount
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) RunningCPUCount() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunningCPUCount", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).RunningCPUCount))
|
||||
}
|
||||
|
||||
// RunningMemorySize mocks base method
|
||||
func (m *MockCandidatePropertyGetter) RunningMemorySize() int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RunningMemorySize")
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RunningMemorySize indicates an expected call of RunningMemorySize
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) RunningMemorySize() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunningMemorySize", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).RunningMemorySize))
|
||||
}
|
||||
|
||||
// SharedDomains mocks base method
|
||||
func (m *MockCandidatePropertyGetter) SharedDomains() []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SharedDomains")
|
||||
ret0, _ := ret[0].([]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SharedDomains indicates an expected call of SharedDomains
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) SharedDomains() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SharedDomains", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).SharedDomains))
|
||||
}
|
||||
|
||||
// Sku mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Sku(arg0 string) *sku.ServerSku {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Sku", arg0)
|
||||
ret0, _ := ret[0].(*sku.ServerSku)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Sku indicates an expected call of Sku
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Sku(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sku", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Sku), arg0)
|
||||
}
|
||||
|
||||
// Status mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Status() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Status")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Status indicates an expected call of Status
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Status() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Status))
|
||||
}
|
||||
|
||||
// StorageInfo mocks base method
|
||||
func (m *MockCandidatePropertyGetter) StorageInfo() []*baremetal.BaremetalStorage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StorageInfo")
|
||||
ret0, _ := ret[0].([]*baremetal.BaremetalStorage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// StorageInfo indicates an expected call of StorageInfo
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) StorageInfo() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageInfo", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).StorageInfo))
|
||||
}
|
||||
|
||||
// Storages mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Storages() []*api.CandidateStorage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Storages")
|
||||
ret0, _ := ret[0].([]*api.CandidateStorage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Storages indicates an expected call of Storages
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Storages() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Storages", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Storages))
|
||||
}
|
||||
|
||||
// TotalCPUCount mocks base method
|
||||
func (m *MockCandidatePropertyGetter) TotalCPUCount(arg0 bool) int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TotalCPUCount", arg0)
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// TotalCPUCount indicates an expected call of TotalCPUCount
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) TotalCPUCount(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalCPUCount", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).TotalCPUCount), arg0)
|
||||
}
|
||||
|
||||
// TotalMemorySize mocks base method
|
||||
func (m *MockCandidatePropertyGetter) TotalMemorySize(arg0 bool) int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TotalMemorySize", arg0)
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// TotalMemorySize indicates an expected call of TotalMemorySize
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) TotalMemorySize(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalMemorySize", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).TotalMemorySize), arg0)
|
||||
}
|
||||
|
||||
// UnusedGpuDevices mocks base method
|
||||
func (m *MockCandidatePropertyGetter) UnusedGpuDevices() []*core.IsolatedDeviceDesc {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UnusedGpuDevices")
|
||||
ret0, _ := ret[0].([]*core.IsolatedDeviceDesc)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UnusedGpuDevices indicates an expected call of UnusedGpuDevices
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) UnusedGpuDevices() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnusedGpuDevices", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).UnusedGpuDevices))
|
||||
}
|
||||
|
||||
// UnusedIsolatedDevices mocks base method
|
||||
func (m *MockCandidatePropertyGetter) UnusedIsolatedDevices() []*core.IsolatedDeviceDesc {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UnusedIsolatedDevices")
|
||||
ret0, _ := ret[0].([]*core.IsolatedDeviceDesc)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UnusedIsolatedDevices indicates an expected call of UnusedIsolatedDevices
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) UnusedIsolatedDevices() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnusedIsolatedDevices", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).UnusedIsolatedDevices))
|
||||
}
|
||||
|
||||
// UnusedIsolatedDevicesByModel mocks base method
|
||||
func (m *MockCandidatePropertyGetter) UnusedIsolatedDevicesByModel(arg0 string) []*core.IsolatedDeviceDesc {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UnusedIsolatedDevicesByModel", arg0)
|
||||
ret0, _ := ret[0].([]*core.IsolatedDeviceDesc)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UnusedIsolatedDevicesByModel indicates an expected call of UnusedIsolatedDevicesByModel
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) UnusedIsolatedDevicesByModel(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnusedIsolatedDevicesByModel", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).UnusedIsolatedDevicesByModel), arg0)
|
||||
}
|
||||
|
||||
// UnusedIsolatedDevicesByType mocks base method
|
||||
func (m *MockCandidatePropertyGetter) UnusedIsolatedDevicesByType(arg0 string) []*core.IsolatedDeviceDesc {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UnusedIsolatedDevicesByType", arg0)
|
||||
ret0, _ := ret[0].([]*core.IsolatedDeviceDesc)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UnusedIsolatedDevicesByType indicates an expected call of UnusedIsolatedDevicesByType
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) UnusedIsolatedDevicesByType(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnusedIsolatedDevicesByType", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).UnusedIsolatedDevicesByType), arg0)
|
||||
}
|
||||
|
||||
// UnusedIsolatedDevicesByVendorModel mocks base method
|
||||
func (m *MockCandidatePropertyGetter) UnusedIsolatedDevicesByVendorModel(arg0 string) []*core.IsolatedDeviceDesc {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UnusedIsolatedDevicesByVendorModel", arg0)
|
||||
ret0, _ := ret[0].([]*core.IsolatedDeviceDesc)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UnusedIsolatedDevicesByVendorModel indicates an expected call of UnusedIsolatedDevicesByVendorModel
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) UnusedIsolatedDevicesByVendorModel(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnusedIsolatedDevicesByVendorModel", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).UnusedIsolatedDevicesByVendorModel), arg0)
|
||||
}
|
||||
|
||||
// Zone mocks base method
|
||||
func (m *MockCandidatePropertyGetter) Zone() *models.SZone {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Zone")
|
||||
ret0, _ := ret[0].(*models.SZone)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Zone indicates an expected call of Zone
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) Zone() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Zone", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).Zone))
|
||||
}
|
||||
|
||||
// MockCandidater is a mock of Candidater interface
|
||||
type MockCandidater struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCandidaterMockRecorder
|
||||
}
|
||||
|
||||
// MockCandidaterMockRecorder is the mock recorder for MockCandidater
|
||||
type MockCandidaterMockRecorder struct {
|
||||
mock *MockCandidater
|
||||
}
|
||||
|
||||
// NewMockCandidater creates a new mock instance
|
||||
func NewMockCandidater(ctrl *gomock.Controller) *MockCandidater {
|
||||
mock := &MockCandidater{ctrl: ctrl}
|
||||
mock.recorder = &MockCandidaterMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockCandidater) EXPECT() *MockCandidaterMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetGuestCount mocks base method
|
||||
func (m *MockCandidater) GetGuestCount() int64 {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetGuestCount")
|
||||
ret0, _ := ret[0].(int64)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetGuestCount indicates an expected call of GetGuestCount
|
||||
func (mr *MockCandidaterMockRecorder) GetGuestCount() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGuestCount", reflect.TypeOf((*MockCandidater)(nil).GetGuestCount))
|
||||
}
|
||||
|
||||
// GetResourceType mocks base method
|
||||
func (m *MockCandidater) GetResourceType() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetResourceType")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetResourceType indicates an expected call of GetResourceType
|
||||
func (mr *MockCandidaterMockRecorder) GetResourceType() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResourceType", reflect.TypeOf((*MockCandidater)(nil).GetResourceType))
|
||||
}
|
||||
|
||||
// GetSchedDesc mocks base method
|
||||
func (m *MockCandidater) GetSchedDesc() *jsonutils.JSONDict {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetSchedDesc")
|
||||
ret0, _ := ret[0].(*jsonutils.JSONDict)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetSchedDesc indicates an expected call of GetSchedDesc
|
||||
func (mr *MockCandidaterMockRecorder) GetSchedDesc() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSchedDesc", reflect.TypeOf((*MockCandidater)(nil).GetSchedDesc))
|
||||
}
|
||||
|
||||
// Getter mocks base method
|
||||
func (m *MockCandidater) Getter() core.CandidatePropertyGetter {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Getter")
|
||||
ret0, _ := ret[0].(core.CandidatePropertyGetter)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Getter indicates an expected call of Getter
|
||||
func (mr *MockCandidaterMockRecorder) Getter() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Getter", reflect.TypeOf((*MockCandidater)(nil).Getter))
|
||||
}
|
||||
|
||||
// IndexKey mocks base method
|
||||
func (m *MockCandidater) IndexKey() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IndexKey")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IndexKey indicates an expected call of IndexKey
|
||||
func (mr *MockCandidaterMockRecorder) IndexKey() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IndexKey", reflect.TypeOf((*MockCandidater)(nil).IndexKey))
|
||||
}
|
||||
|
||||
// Type mocks base method
|
||||
func (m *MockCandidater) Type() int {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Type")
|
||||
ret0, _ := ret[0].(int)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Type indicates an expected call of Type
|
||||
func (mr *MockCandidaterMockRecorder) Type() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Type", reflect.TypeOf((*MockCandidater)(nil).Type))
|
||||
}
|
||||
|
||||
// MockScheduler is a mock of Scheduler interface
|
||||
type MockScheduler struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSchedulerMockRecorder
|
||||
}
|
||||
|
||||
// MockSchedulerMockRecorder is the mock recorder for MockScheduler
|
||||
type MockSchedulerMockRecorder struct {
|
||||
mock *MockScheduler
|
||||
}
|
||||
|
||||
// NewMockScheduler creates a new mock instance
|
||||
func NewMockScheduler(ctrl *gomock.Controller) *MockScheduler {
|
||||
mock := &MockScheduler{ctrl: ctrl}
|
||||
mock.recorder = &MockSchedulerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockScheduler) EXPECT() *MockSchedulerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// BeforePredicate mocks base method
|
||||
func (m *MockScheduler) BeforePredicate() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BeforePredicate")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BeforePredicate indicates an expected call of BeforePredicate
|
||||
func (mr *MockSchedulerMockRecorder) BeforePredicate() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforePredicate", reflect.TypeOf((*MockScheduler)(nil).BeforePredicate))
|
||||
}
|
||||
|
||||
// Predicates mocks base method
|
||||
func (m *MockScheduler) Predicates() (map[string]core.FitPredicate, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Predicates")
|
||||
ret0, _ := ret[0].(map[string]core.FitPredicate)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Predicates indicates an expected call of Predicates
|
||||
func (mr *MockSchedulerMockRecorder) Predicates() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Predicates", reflect.TypeOf((*MockScheduler)(nil).Predicates))
|
||||
}
|
||||
|
||||
// PriorityConfigs mocks base method
|
||||
func (m *MockScheduler) PriorityConfigs() ([]core.PriorityConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PriorityConfigs")
|
||||
ret0, _ := ret[0].([]core.PriorityConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// PriorityConfigs indicates an expected call of PriorityConfigs
|
||||
func (mr *MockSchedulerMockRecorder) PriorityConfigs() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PriorityConfigs", reflect.TypeOf((*MockScheduler)(nil).PriorityConfigs))
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 mock // import "yunion.io/x/onecloud/pkg/scheduler/test/mock"
|
||||
@@ -0,0 +1,343 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
_ "yunion.io/x/onecloud/pkg/scheduler/algorithmprovider"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/api"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/data_manager/sku"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/factory"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/test/mock"
|
||||
)
|
||||
|
||||
type sPredicateName string
|
||||
|
||||
var (
|
||||
HostStatus sPredicateName = "a-GuestHostStatusFilter"
|
||||
Hypervisor sPredicateName = "b-GuestHypervisorFilter"
|
||||
Migrate sPredicateName = "d-GuestMigrateFilter"
|
||||
Domain sPredicateName = "e-GuestDomainFilter"
|
||||
Image sPredicateName = "e-GuestImageFilter"
|
||||
CPU sPredicateName = "g-GuestCPUFilter"
|
||||
Memory sPredicateName = "h-GuestMemoryFilter"
|
||||
Storage sPredicateName = "i-GuestStorageFilter"
|
||||
Network sPredicateName = "j-GuestNetworkFilter"
|
||||
IsolateDevice sPredicateName = "k-GuestIsolatedDeviceFilter"
|
||||
ResourceType sPredicateName = "l-GuestResourceTypeFilter"
|
||||
ServerSku sPredicateName = "n-ServerSkuFilter"
|
||||
|
||||
// scheudle tag predicate, need db operator for now
|
||||
HostSchedtag sPredicateName = "c-GuestAggregateFilter"
|
||||
DiskSchedtag sPredicateName = "m-GuestDiskschedtagFilter"
|
||||
NetworkSchedtag sPredicateName = "o-GuestNetschedtagFilter"
|
||||
|
||||
// quota
|
||||
Quota sPredicateName = "z-QuotaFilter"
|
||||
|
||||
basePredicateNames = []sPredicateName{
|
||||
HostStatus, Hypervisor, Migrate, Domain, Image, CPU, Memory, Storage, Network,
|
||||
IsolateDevice, ResourceType, ServerSku,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
GlobalDoamin = "default"
|
||||
GlobalProject = "default"
|
||||
GlobalZone = buildZone("default", "Default")
|
||||
GlobalCloudregion = buildCloudregion("default", "Default", "")
|
||||
GlobalWire = "default"
|
||||
GlobaleVPC = "default"
|
||||
)
|
||||
|
||||
func buildCandidate(ctrl *gomock.Controller, param sGetterParams) *mock.MockCandidater {
|
||||
cn := mock.NewMockCandidater(ctrl)
|
||||
getter := buildGetter(ctrl, param)
|
||||
cn.EXPECT().Getter().AnyTimes().Return(getter)
|
||||
cn.EXPECT().IndexKey().AnyTimes().Return(getter.Id())
|
||||
cn.EXPECT().GetResourceType().AnyTimes().Return(getter.ResourceType())
|
||||
return cn
|
||||
}
|
||||
|
||||
type sGetterParams struct {
|
||||
HostId string
|
||||
HostName string
|
||||
IsPublic *bool
|
||||
Domain string
|
||||
PublicScope string
|
||||
Zone *models.SZone
|
||||
CloudRegion *models.SCloudregion
|
||||
CloudProvider *models.SCloudprovider
|
||||
HostType string
|
||||
Storages []*api.CandidateStorage
|
||||
Networks []*api.CandidateNetwork
|
||||
OvnCapable *bool
|
||||
Status string
|
||||
HostStatus string
|
||||
Enabled *bool
|
||||
ResourceType string
|
||||
TotalCPUCount int64
|
||||
FreeCPUCount int64
|
||||
TotalMemorySize int64
|
||||
FreeMemorySize int64
|
||||
FreeStorageSizeAnyType int64
|
||||
FreePort int
|
||||
QuotaKeys *models.SComputeResourceKeys
|
||||
FreeGroupCount int
|
||||
Skus []string
|
||||
}
|
||||
|
||||
func buildGetter(ctrl *gomock.Controller, param sGetterParams) *mock.MockCandidatePropertyGetter {
|
||||
cg := mock.NewMockCandidatePropertyGetter(ctrl)
|
||||
cg.EXPECT().Id().AnyTimes().Return(param.HostId)
|
||||
cg.EXPECT().Name().AnyTimes().Return(param.HostName)
|
||||
cg.EXPECT().Zone().AnyTimes().Return(param.Zone)
|
||||
if param.IsPublic == nil {
|
||||
cg.EXPECT().IsPublic().AnyTimes().Return(true)
|
||||
} else {
|
||||
cg.EXPECT().IsPublic().AnyTimes().Return(*param.IsPublic)
|
||||
}
|
||||
if param.Enabled == nil {
|
||||
cg.EXPECT().Enabled().AnyTimes().Return(true)
|
||||
} else {
|
||||
cg.EXPECT().Enabled().AnyTimes().Return(*param.Enabled)
|
||||
}
|
||||
cg.EXPECT().DomainId().AnyTimes().Return(param.Domain)
|
||||
cg.EXPECT().PublicScope().AnyTimes().Return(param.PublicScope)
|
||||
cg.EXPECT().Region().AnyTimes().Return(param.CloudRegion)
|
||||
cg.EXPECT().Cloudprovider().AnyTimes().Return(param.CloudProvider)
|
||||
cg.EXPECT().HostType().AnyTimes().Return(param.HostType)
|
||||
cg.EXPECT().Storages().AnyTimes().Return(param.Storages)
|
||||
cg.EXPECT().Networks().AnyTimes().Return(param.Networks)
|
||||
cg.EXPECT().Sku(gomock.Any()).AnyTimes().DoAndReturn(func(instanceType string) *sku.ServerSku {
|
||||
for _, t := range param.Skus {
|
||||
if t != instanceType {
|
||||
continue
|
||||
}
|
||||
return &sku.ServerSku{
|
||||
Id: fmt.Sprintf("%s-%s", param.Zone.Id, instanceType),
|
||||
ZoneId: param.Zone.Id,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if param.OvnCapable == nil {
|
||||
cg.EXPECT().OvnCapable().AnyTimes().Return(false)
|
||||
} else {
|
||||
cg.EXPECT().OvnCapable().AnyTimes().Return(*param.OvnCapable)
|
||||
}
|
||||
if len(param.Status) == 0 {
|
||||
cg.EXPECT().Status().AnyTimes().Return(computeapi.HOST_HEALTH_STATUS_RUNNING)
|
||||
} else {
|
||||
cg.EXPECT().Status().AnyTimes().Return(param.Status)
|
||||
}
|
||||
if len(param.HostStatus) == 0 {
|
||||
cg.EXPECT().HostStatus().AnyTimes().Return(computeapi.HOST_ONLINE)
|
||||
} else {
|
||||
cg.EXPECT().HostStatus().AnyTimes().Return(param.HostStatus)
|
||||
}
|
||||
if len(param.ResourceType) == 0 {
|
||||
cg.EXPECT().ResourceType().AnyTimes().Return(computeapi.HostResourceTypeDefault)
|
||||
} else {
|
||||
cg.EXPECT().ResourceType().AnyTimes().Return(param.ResourceType)
|
||||
}
|
||||
cg.EXPECT().TotalCPUCount(gomock.Any()).AnyTimes().Return(param.TotalCPUCount)
|
||||
cg.EXPECT().FreeCPUCount(gomock.Any()).AnyTimes().Return(param.FreeCPUCount)
|
||||
cg.EXPECT().TotalMemorySize(gomock.Any()).AnyTimes().Return(param.TotalMemorySize)
|
||||
cg.EXPECT().FreeMemorySize(gomock.Any()).AnyTimes().Return(param.FreeMemorySize)
|
||||
cg.EXPECT().GetFreeStorageSizeOfType(gomock.Any(), gomock.Any()).AnyTimes().Return(param.FreeStorageSizeAnyType)
|
||||
cg.EXPECT().GetFreePort(gomock.Any()).AnyTimes().Return(param.FreePort)
|
||||
if param.QuotaKeys != nil {
|
||||
cg.EXPECT().GetQuotaKeys(gomock.Any()).AnyTimes().Return(param.QuotaKeys)
|
||||
}
|
||||
cg.EXPECT().GetFreeGroupCount(gomock.Any()).AnyTimes().Return(param.FreeGroupCount, nil)
|
||||
return cg
|
||||
}
|
||||
|
||||
func buildScheduler(ctrl *gomock.Controller, predicates ...sPredicateName) core.Scheduler {
|
||||
pres := sets.NewString()
|
||||
for _, pre := range predicates {
|
||||
pres.Insert(string(pre))
|
||||
}
|
||||
algorithmProvider, _ := factory.GetAlgorithmProvider(factory.DefaultProvider)
|
||||
mockScheduler := mock.NewMockScheduler(ctrl)
|
||||
mockScheduler.EXPECT().BeforePredicate().AnyTimes().Return(nil)
|
||||
mockScheduler.EXPECT().Predicates().AnyTimes().DoAndReturn(func() (map[string]core.FitPredicate, error) {
|
||||
return factory.GetPredicates(pres)
|
||||
})
|
||||
mockScheduler.EXPECT().PriorityConfigs().AnyTimes().DoAndReturn(func() ([]core.PriorityConfig, error) {
|
||||
return factory.GetPriorityConfigs(algorithmProvider.PriorityKeys)
|
||||
})
|
||||
return mockScheduler
|
||||
}
|
||||
|
||||
func buildZone(id, name string) *models.SZone {
|
||||
zone := &models.SZone{}
|
||||
zone.Id = id
|
||||
zone.Name = name
|
||||
zone.Status = "enable"
|
||||
return zone
|
||||
}
|
||||
|
||||
func buildCloudregion(id, name, provider string) *models.SCloudregion {
|
||||
if len(provider) == 0 {
|
||||
provider = computeapi.CLOUD_PROVIDER_ONECLOUD
|
||||
}
|
||||
return &models.SCloudregion{
|
||||
SEnabledStatusStandaloneResourceBase: db.SEnabledStatusStandaloneResourceBase{
|
||||
SStatusStandaloneResourceBase: db.SStatusStandaloneResourceBase{
|
||||
SStandaloneResourceBase: db.SStandaloneResourceBase{
|
||||
Id: id,
|
||||
Name: name,
|
||||
},
|
||||
SStatusResourceBase: db.SStatusResourceBase{
|
||||
Status: "inservice",
|
||||
},
|
||||
},
|
||||
SEnabledResourceBase: db.SEnabledResourceBase{
|
||||
Enabled: "true",
|
||||
},
|
||||
},
|
||||
Provider: provider,
|
||||
}
|
||||
}
|
||||
|
||||
func buildStorage(id, name string, capacity int64) *api.CandidateStorage {
|
||||
storage := &models.SStorage{}
|
||||
storage.Id, storage.Name = id, name
|
||||
storage.DomainId = GlobalDoamin
|
||||
storage.IsPublic = true
|
||||
storage.PublicScope = "system"
|
||||
storage.Status = computeapi.STORAGE_ONLINE
|
||||
storage.Enabled = "true"
|
||||
storage.ZoneId = GlobalZone.GetId()
|
||||
storage.Capacity = capacity
|
||||
storage.StorageType = computeapi.STORAGE_LOCAL
|
||||
storage.MediumType = computeapi.DISK_TYPE_ROTATE
|
||||
storage.Cmtbound = 1.0
|
||||
storage.IsSysDiskStore = "true"
|
||||
return &api.CandidateStorage{
|
||||
SStorage: storage,
|
||||
}
|
||||
}
|
||||
|
||||
func buildNetwork(id, name string, cidr string) *api.CandidateNetwork {
|
||||
network := &models.SNetwork{}
|
||||
network.Id, network.Name = id, name
|
||||
network.Status = computeapi.NETWORK_STATUS_AVAILABLE
|
||||
network.DomainId = GlobalDoamin
|
||||
network.ProjectId = GlobalProject
|
||||
network.WireId = GlobalWire
|
||||
network.ServerType = computeapi.NETWORK_TYPE_GUEST
|
||||
prefix, err := netutils.NewIPV4Prefix(cidr)
|
||||
if err == nil {
|
||||
network.GuestIpMask = prefix.MaskLen
|
||||
ipRange := prefix.ToIPRange()
|
||||
network.GuestIpStart = ipRange.StartIp().String()
|
||||
network.GuestIpEnd = ipRange.EndIp().String()
|
||||
}
|
||||
return &api.CandidateNetwork{
|
||||
SNetwork: network,
|
||||
VpcId: GlobaleVPC,
|
||||
}
|
||||
}
|
||||
|
||||
func buildInstanceGroup(id string, granularity int, force bool) *models.SGroup {
|
||||
group := &models.SGroup{}
|
||||
group.Id = id
|
||||
group.Status = "ready"
|
||||
group.DomainId = GlobalDoamin
|
||||
group.ProjectId = GlobalProject
|
||||
group.Granularity = granularity
|
||||
group.ForceDispersion = tristate.NewFromBool(force)
|
||||
return nil
|
||||
}
|
||||
|
||||
func preSchedule(info *api.SchedInfo, candidates []core.Candidater, isForcast bool) (*core.Unit, []core.Candidater, core.IResultHelper) {
|
||||
resultHelper := core.SResultHelperFunc(core.ResultHelp)
|
||||
if isForcast {
|
||||
resultHelper = core.SResultHelperFunc(core.ResultHelpForForcast)
|
||||
info.Suggestion = true
|
||||
info.IsSuggestion = true
|
||||
info.SuggestionAll = true
|
||||
info.ShowSuggestionDetails = true
|
||||
info.SuggestionLimit = 100
|
||||
}
|
||||
return core.NewScheduleUnit(info, nil), candidates, resultHelper
|
||||
}
|
||||
|
||||
func deepCopy(info *api.SchedInfo) *api.SchedInfo {
|
||||
serverConfigs := *info.ServerConfigs
|
||||
// disks
|
||||
disks := make([]*compute.DiskConfig, len(info.Disks))
|
||||
for i := range disks {
|
||||
disk := *info.Disks[i]
|
||||
disks[i] = &disk
|
||||
}
|
||||
// network
|
||||
networks := make([]*compute.NetworkConfig, len(info.Networks))
|
||||
for i := range networks {
|
||||
network := *info.Networks[i]
|
||||
networks[i] = &network
|
||||
}
|
||||
// baremetal_disk_config
|
||||
bareConfigs := make([]*compute.BaremetalDiskConfig, len(info.BaremetalDiskConfigs))
|
||||
for i := range bareConfigs {
|
||||
bareConfig := *info.BaremetalDiskConfigs[i]
|
||||
bareConfigs[i] = &bareConfig
|
||||
}
|
||||
// instancegroup
|
||||
instancegroupIds := make([]string, len(info.InstanceGroupIds))
|
||||
for i := range instancegroupIds {
|
||||
instancegroupIds[i] = info.InstanceGroupIds[i]
|
||||
}
|
||||
serverConfigs.Disks = disks
|
||||
serverConfigs.Networks = networks
|
||||
serverConfigs.BaremetalDiskConfigs = bareConfigs
|
||||
|
||||
serverConfig := info.ServerConfig
|
||||
serverConfig.ServerConfigs = &serverConfigs
|
||||
|
||||
scheduInput := *info.ScheduleInput
|
||||
scheduInput.ServerConfig = serverConfig
|
||||
|
||||
copyInfo := *info
|
||||
copyInfo.ScheduleInput = &scheduInput
|
||||
preferCandidates := make([]string, len(info.PreferCandidates))
|
||||
for i := range preferCandidates {
|
||||
preferCandidates[i] = info.PreferCandidates[i]
|
||||
}
|
||||
instanceGroupDetail := make(map[string]*models.SGroup, len(info.InstanceGroupsDetail))
|
||||
for k, v := range info.InstanceGroupsDetail {
|
||||
// v only read
|
||||
instanceGroupDetail[k] = v
|
||||
}
|
||||
copyInfo.PreferCandidates = preferCandidates
|
||||
copyInfo.InstanceGroupsDetail = instanceGroupDetail
|
||||
|
||||
return ©Info
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
# This is the official list of GoMock authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
|
||||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Alex Reece <awreece@gmail.com>
|
||||
Google Inc.
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
# This is the official list of people who can contribute (and typically
|
||||
# have contributed) code to the gomock repository.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# The submission process automatically checks to make sure
|
||||
# that people submitting code are listed in this file (by email address).
|
||||
#
|
||||
# Names should be added to this file only after verifying that
|
||||
# the individual or the individual's organization has agreed to
|
||||
# the appropriate Contributor License Agreement, found here:
|
||||
#
|
||||
# http://code.google.com/legal/individual-cla-v1.0.html
|
||||
# http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
#
|
||||
# The agreement for individuals can be filled out on the web.
|
||||
#
|
||||
# When adding J Random Contributor's name to this file,
|
||||
# either J's name or J's organization's name should be
|
||||
# added to the AUTHORS file, depending on whether the
|
||||
# individual or corporate CLA was used.
|
||||
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
#
|
||||
# An entry with two email addresses specifies that the
|
||||
# first address should be used in the submit logs and
|
||||
# that the second address should be recognized as the
|
||||
# same person when interacting with Rietveld.
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Aaron Jacobs <jacobsa@google.com> <aaronjjacobs@gmail.com>
|
||||
Alex Reece <awreece@gmail.com>
|
||||
David Symonds <dsymonds@golang.org>
|
||||
Ryan Barrett <ryanb@google.com>
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
// Copyright 2010 Google Inc.
|
||||
//
|
||||
// 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 gomock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Call represents an expected call to a mock.
|
||||
type Call struct {
|
||||
t TestHelper // for triggering test failures on invalid call setup
|
||||
|
||||
receiver interface{} // the receiver of the method call
|
||||
method string // the name of the method
|
||||
methodType reflect.Type // the type of the method
|
||||
args []Matcher // the args
|
||||
origin string // file and line number of call setup
|
||||
|
||||
preReqs []*Call // prerequisite calls
|
||||
|
||||
// Expectations
|
||||
minCalls, maxCalls int
|
||||
|
||||
numCalls int // actual number made
|
||||
|
||||
// actions are called when this Call is called. Each action gets the args and
|
||||
// can set the return values by returning a non-nil slice. Actions run in the
|
||||
// order they are created.
|
||||
actions []func([]interface{}) []interface{}
|
||||
}
|
||||
|
||||
// newCall creates a *Call. It requires the method type in order to support
|
||||
// unexported methods.
|
||||
func newCall(t TestHelper, receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call {
|
||||
t.Helper()
|
||||
|
||||
// TODO: check arity, types.
|
||||
margs := make([]Matcher, len(args))
|
||||
for i, arg := range args {
|
||||
if m, ok := arg.(Matcher); ok {
|
||||
margs[i] = m
|
||||
} else if arg == nil {
|
||||
// Handle nil specially so that passing a nil interface value
|
||||
// will match the typed nils of concrete args.
|
||||
margs[i] = Nil()
|
||||
} else {
|
||||
margs[i] = Eq(arg)
|
||||
}
|
||||
}
|
||||
|
||||
origin := callerInfo(3)
|
||||
actions := []func([]interface{}) []interface{}{func([]interface{}) []interface{} {
|
||||
// Synthesize the zero value for each of the return args' types.
|
||||
rets := make([]interface{}, methodType.NumOut())
|
||||
for i := 0; i < methodType.NumOut(); i++ {
|
||||
rets[i] = reflect.Zero(methodType.Out(i)).Interface()
|
||||
}
|
||||
return rets
|
||||
}}
|
||||
return &Call{t: t, receiver: receiver, method: method, methodType: methodType,
|
||||
args: margs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions}
|
||||
}
|
||||
|
||||
// AnyTimes allows the expectation to be called 0 or more times
|
||||
func (c *Call) AnyTimes() *Call {
|
||||
c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity
|
||||
return c
|
||||
}
|
||||
|
||||
// MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called, MinTimes also
|
||||
// sets the maximum number of calls to infinity.
|
||||
func (c *Call) MinTimes(n int) *Call {
|
||||
c.minCalls = n
|
||||
if c.maxCalls == 1 {
|
||||
c.maxCalls = 1e8
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called, MaxTimes also
|
||||
// sets the minimum number of calls to 0.
|
||||
func (c *Call) MaxTimes(n int) *Call {
|
||||
c.maxCalls = n
|
||||
if c.minCalls == 1 {
|
||||
c.minCalls = 0
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// DoAndReturn declares the action to run when the call is matched.
|
||||
// The return values from this function are returned by the mocked function.
|
||||
// It takes an interface{} argument to support n-arity functions.
|
||||
func (c *Call) DoAndReturn(f interface{}) *Call {
|
||||
// TODO: Check arity and types here, rather than dying badly elsewhere.
|
||||
v := reflect.ValueOf(f)
|
||||
|
||||
c.addAction(func(args []interface{}) []interface{} {
|
||||
vargs := make([]reflect.Value, len(args))
|
||||
ft := v.Type()
|
||||
for i := 0; i < len(args); i++ {
|
||||
if args[i] != nil {
|
||||
vargs[i] = reflect.ValueOf(args[i])
|
||||
} else {
|
||||
// Use the zero value for the arg.
|
||||
vargs[i] = reflect.Zero(ft.In(i))
|
||||
}
|
||||
}
|
||||
vrets := v.Call(vargs)
|
||||
rets := make([]interface{}, len(vrets))
|
||||
for i, ret := range vrets {
|
||||
rets[i] = ret.Interface()
|
||||
}
|
||||
return rets
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
// Do declares the action to run when the call is matched. The function's
|
||||
// return values are ignored to retain backward compatibility. To use the
|
||||
// return values call DoAndReturn.
|
||||
// It takes an interface{} argument to support n-arity functions.
|
||||
func (c *Call) Do(f interface{}) *Call {
|
||||
// TODO: Check arity and types here, rather than dying badly elsewhere.
|
||||
v := reflect.ValueOf(f)
|
||||
|
||||
c.addAction(func(args []interface{}) []interface{} {
|
||||
vargs := make([]reflect.Value, len(args))
|
||||
ft := v.Type()
|
||||
for i := 0; i < len(args); i++ {
|
||||
if args[i] != nil {
|
||||
vargs[i] = reflect.ValueOf(args[i])
|
||||
} else {
|
||||
// Use the zero value for the arg.
|
||||
vargs[i] = reflect.Zero(ft.In(i))
|
||||
}
|
||||
}
|
||||
v.Call(vargs)
|
||||
return nil
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
// Return declares the values to be returned by the mocked function call.
|
||||
func (c *Call) Return(rets ...interface{}) *Call {
|
||||
c.t.Helper()
|
||||
|
||||
mt := c.methodType
|
||||
if len(rets) != mt.NumOut() {
|
||||
c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]",
|
||||
c.receiver, c.method, len(rets), mt.NumOut(), c.origin)
|
||||
}
|
||||
for i, ret := range rets {
|
||||
if got, want := reflect.TypeOf(ret), mt.Out(i); got == want {
|
||||
// Identical types; nothing to do.
|
||||
} else if got == nil {
|
||||
// Nil needs special handling.
|
||||
switch want.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
// ok
|
||||
default:
|
||||
c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]",
|
||||
i, c.receiver, c.method, want, c.origin)
|
||||
}
|
||||
} else if got.AssignableTo(want) {
|
||||
// Assignable type relation. Make the assignment now so that the generated code
|
||||
// can return the values with a type assertion.
|
||||
v := reflect.New(want).Elem()
|
||||
v.Set(reflect.ValueOf(ret))
|
||||
rets[i] = v.Interface()
|
||||
} else {
|
||||
c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]",
|
||||
i, c.receiver, c.method, got, want, c.origin)
|
||||
}
|
||||
}
|
||||
|
||||
c.addAction(func([]interface{}) []interface{} {
|
||||
return rets
|
||||
})
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Times declares the exact number of times a function call is expected to be executed.
|
||||
func (c *Call) Times(n int) *Call {
|
||||
c.minCalls, c.maxCalls = n, n
|
||||
return c
|
||||
}
|
||||
|
||||
// SetArg declares an action that will set the nth argument's value,
|
||||
// indirected through a pointer. Or, in the case of a slice, SetArg
|
||||
// will copy value's elements into the nth argument.
|
||||
func (c *Call) SetArg(n int, value interface{}) *Call {
|
||||
c.t.Helper()
|
||||
|
||||
mt := c.methodType
|
||||
// TODO: This will break on variadic methods.
|
||||
// We will need to check those at invocation time.
|
||||
if n < 0 || n >= mt.NumIn() {
|
||||
c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]",
|
||||
n, mt.NumIn(), c.origin)
|
||||
}
|
||||
// Permit setting argument through an interface.
|
||||
// In the interface case, we don't (nay, can't) check the type here.
|
||||
at := mt.In(n)
|
||||
switch at.Kind() {
|
||||
case reflect.Ptr:
|
||||
dt := at.Elem()
|
||||
if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) {
|
||||
c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]",
|
||||
n, vt, dt, c.origin)
|
||||
}
|
||||
case reflect.Interface:
|
||||
// nothing to do
|
||||
case reflect.Slice:
|
||||
// nothing to do
|
||||
default:
|
||||
c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]",
|
||||
n, at, c.origin)
|
||||
}
|
||||
|
||||
c.addAction(func(args []interface{}) []interface{} {
|
||||
v := reflect.ValueOf(value)
|
||||
switch reflect.TypeOf(args[n]).Kind() {
|
||||
case reflect.Slice:
|
||||
setSlice(args[n], v)
|
||||
default:
|
||||
reflect.ValueOf(args[n]).Elem().Set(v)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
// isPreReq returns true if other is a direct or indirect prerequisite to c.
|
||||
func (c *Call) isPreReq(other *Call) bool {
|
||||
for _, preReq := range c.preReqs {
|
||||
if other == preReq || preReq.isPreReq(other) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// After declares that the call may only match after preReq has been exhausted.
|
||||
func (c *Call) After(preReq *Call) *Call {
|
||||
c.t.Helper()
|
||||
|
||||
if c == preReq {
|
||||
c.t.Fatalf("A call isn't allowed to be its own prerequisite")
|
||||
}
|
||||
if preReq.isPreReq(c) {
|
||||
c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq)
|
||||
}
|
||||
|
||||
c.preReqs = append(c.preReqs, preReq)
|
||||
return c
|
||||
}
|
||||
|
||||
// Returns true if the minimum number of calls have been made.
|
||||
func (c *Call) satisfied() bool {
|
||||
return c.numCalls >= c.minCalls
|
||||
}
|
||||
|
||||
// Returns true iff the maximum number of calls have been made.
|
||||
func (c *Call) exhausted() bool {
|
||||
return c.numCalls >= c.maxCalls
|
||||
}
|
||||
|
||||
func (c *Call) String() string {
|
||||
args := make([]string, len(c.args))
|
||||
for i, arg := range c.args {
|
||||
args[i] = arg.String()
|
||||
}
|
||||
arguments := strings.Join(args, ", ")
|
||||
return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin)
|
||||
}
|
||||
|
||||
// Tests if the given call matches the expected call.
|
||||
// If yes, returns nil. If no, returns error with message explaining why it does not match.
|
||||
func (c *Call) matches(args []interface{}) error {
|
||||
if !c.methodType.IsVariadic() {
|
||||
if len(args) != len(c.args) {
|
||||
return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d",
|
||||
c.origin, len(args), len(c.args))
|
||||
}
|
||||
|
||||
for i, m := range c.args {
|
||||
if !m.Matches(args[i]) {
|
||||
return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
|
||||
c.origin, strconv.Itoa(i), args[i], m)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if len(c.args) < c.methodType.NumIn()-1 {
|
||||
return fmt.Errorf("Expected call at %s has the wrong number of matchers. Got: %d, want: %d",
|
||||
c.origin, len(c.args), c.methodType.NumIn()-1)
|
||||
}
|
||||
if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) {
|
||||
return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d",
|
||||
c.origin, len(args), len(c.args))
|
||||
}
|
||||
if len(args) < len(c.args)-1 {
|
||||
return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d",
|
||||
c.origin, len(args), len(c.args)-1)
|
||||
}
|
||||
|
||||
for i, m := range c.args {
|
||||
if i < c.methodType.NumIn()-1 {
|
||||
// Non-variadic args
|
||||
if !m.Matches(args[i]) {
|
||||
return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
|
||||
c.origin, strconv.Itoa(i), args[i], m)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// The last arg has a possibility of a variadic argument, so let it branch
|
||||
|
||||
// sample: Foo(a int, b int, c ...int)
|
||||
if i < len(c.args) && i < len(args) {
|
||||
if m.Matches(args[i]) {
|
||||
// Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any())
|
||||
// Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher)
|
||||
// Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC)
|
||||
// Got Foo(a, b) want Foo(matcherA, matcherB)
|
||||
// Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// The number of actual args don't match the number of matchers,
|
||||
// or the last matcher is a slice and the last arg is not.
|
||||
// If this function still matches it is because the last matcher
|
||||
// matches all the remaining arguments or the lack of any.
|
||||
// Convert the remaining arguments, if any, into a slice of the
|
||||
// expected type.
|
||||
vargsType := c.methodType.In(c.methodType.NumIn() - 1)
|
||||
vargs := reflect.MakeSlice(vargsType, 0, len(args)-i)
|
||||
for _, arg := range args[i:] {
|
||||
vargs = reflect.Append(vargs, reflect.ValueOf(arg))
|
||||
}
|
||||
if m.Matches(vargs.Interface()) {
|
||||
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any())
|
||||
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher)
|
||||
// Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any())
|
||||
// Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher)
|
||||
break
|
||||
}
|
||||
// Wrong number of matchers or not match. Fail.
|
||||
// Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD)
|
||||
// Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD)
|
||||
// Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE)
|
||||
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD)
|
||||
// Got Foo(a, b, c) want Foo(matcherA, matcherB)
|
||||
return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
|
||||
c.origin, strconv.Itoa(i), args[i:], c.args[i])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all prerequisite calls have been satisfied.
|
||||
for _, preReqCall := range c.preReqs {
|
||||
if !preReqCall.satisfied() {
|
||||
return fmt.Errorf("Expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v",
|
||||
c.origin, preReqCall, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the call is not exhausted.
|
||||
if c.exhausted() {
|
||||
return fmt.Errorf("Expected call at %s has already been called the max number of times.", c.origin)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// dropPrereqs tells the expected Call to not re-check prerequisite calls any
|
||||
// longer, and to return its current set.
|
||||
func (c *Call) dropPrereqs() (preReqs []*Call) {
|
||||
preReqs = c.preReqs
|
||||
c.preReqs = nil
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Call) call(args []interface{}) []func([]interface{}) []interface{} {
|
||||
c.numCalls++
|
||||
return c.actions
|
||||
}
|
||||
|
||||
// InOrder declares that the given calls should occur in order.
|
||||
func InOrder(calls ...*Call) {
|
||||
for i := 1; i < len(calls); i++ {
|
||||
calls[i].After(calls[i-1])
|
||||
}
|
||||
}
|
||||
|
||||
func setSlice(arg interface{}, v reflect.Value) {
|
||||
va := reflect.ValueOf(arg)
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
va.Index(i).Set(v.Index(i))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Call) addAction(action func([]interface{}) []interface{}) {
|
||||
c.actions = append(c.actions, action)
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
// Copyright 2011 Google Inc.
|
||||
//
|
||||
// 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 gomock
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// callSet represents a set of expected calls, indexed by receiver and method
|
||||
// name.
|
||||
type callSet struct {
|
||||
// Calls that are still expected.
|
||||
expected map[callSetKey][]*Call
|
||||
// Calls that have been exhausted.
|
||||
exhausted map[callSetKey][]*Call
|
||||
}
|
||||
|
||||
// callSetKey is the key in the maps in callSet
|
||||
type callSetKey struct {
|
||||
receiver interface{}
|
||||
fname string
|
||||
}
|
||||
|
||||
func newCallSet() *callSet {
|
||||
return &callSet{make(map[callSetKey][]*Call), make(map[callSetKey][]*Call)}
|
||||
}
|
||||
|
||||
// Add adds a new expected call.
|
||||
func (cs callSet) Add(call *Call) {
|
||||
key := callSetKey{call.receiver, call.method}
|
||||
m := cs.expected
|
||||
if call.exhausted() {
|
||||
m = cs.exhausted
|
||||
}
|
||||
m[key] = append(m[key], call)
|
||||
}
|
||||
|
||||
// Remove removes an expected call.
|
||||
func (cs callSet) Remove(call *Call) {
|
||||
key := callSetKey{call.receiver, call.method}
|
||||
calls := cs.expected[key]
|
||||
for i, c := range calls {
|
||||
if c == call {
|
||||
// maintain order for remaining calls
|
||||
cs.expected[key] = append(calls[:i], calls[i+1:]...)
|
||||
cs.exhausted[key] = append(cs.exhausted[key], call)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FindMatch searches for a matching call. Returns error with explanation message if no call matched.
|
||||
func (cs callSet) FindMatch(receiver interface{}, method string, args []interface{}) (*Call, error) {
|
||||
key := callSetKey{receiver, method}
|
||||
|
||||
// Search through the expected calls.
|
||||
expected := cs.expected[key]
|
||||
var callsErrors bytes.Buffer
|
||||
for _, call := range expected {
|
||||
err := call.matches(args)
|
||||
if err != nil {
|
||||
fmt.Fprintf(&callsErrors, "\n%v", err)
|
||||
} else {
|
||||
return call, nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't found a match then search through the exhausted calls so we
|
||||
// get useful error messages.
|
||||
exhausted := cs.exhausted[key]
|
||||
for _, call := range exhausted {
|
||||
if err := call.matches(args); err != nil {
|
||||
fmt.Fprintf(&callsErrors, "\n%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(expected)+len(exhausted) == 0 {
|
||||
fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf(callsErrors.String())
|
||||
}
|
||||
|
||||
// Failures returns the calls that are not satisfied.
|
||||
func (cs callSet) Failures() []*Call {
|
||||
failures := make([]*Call, 0, len(cs.expected))
|
||||
for _, calls := range cs.expected {
|
||||
for _, call := range calls {
|
||||
if !call.satisfied() {
|
||||
failures = append(failures, call)
|
||||
}
|
||||
}
|
||||
}
|
||||
return failures
|
||||
}
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
// Copyright 2010 Google Inc.
|
||||
//
|
||||
// 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 gomock is a mock framework for Go.
|
||||
//
|
||||
// Standard usage:
|
||||
// (1) Define an interface that you wish to mock.
|
||||
// type MyInterface interface {
|
||||
// SomeMethod(x int64, y string)
|
||||
// }
|
||||
// (2) Use mockgen to generate a mock from the interface.
|
||||
// (3) Use the mock in a test:
|
||||
// func TestMyThing(t *testing.T) {
|
||||
// mockCtrl := gomock.NewController(t)
|
||||
// defer mockCtrl.Finish()
|
||||
//
|
||||
// mockObj := something.NewMockMyInterface(mockCtrl)
|
||||
// mockObj.EXPECT().SomeMethod(4, "blah")
|
||||
// // pass mockObj to a real object and play with it.
|
||||
// }
|
||||
//
|
||||
// By default, expected calls are not enforced to run in any particular order.
|
||||
// Call order dependency can be enforced by use of InOrder and/or Call.After.
|
||||
// Call.After can create more varied call order dependencies, but InOrder is
|
||||
// often more convenient.
|
||||
//
|
||||
// The following examples create equivalent call order dependencies.
|
||||
//
|
||||
// Example of using Call.After to chain expected call order:
|
||||
//
|
||||
// firstCall := mockObj.EXPECT().SomeMethod(1, "first")
|
||||
// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall)
|
||||
// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall)
|
||||
//
|
||||
// Example of using InOrder to declare expected call order:
|
||||
//
|
||||
// gomock.InOrder(
|
||||
// mockObj.EXPECT().SomeMethod(1, "first"),
|
||||
// mockObj.EXPECT().SomeMethod(2, "second"),
|
||||
// mockObj.EXPECT().SomeMethod(3, "third"),
|
||||
// )
|
||||
//
|
||||
// TODO:
|
||||
// - Handle different argument/return types (e.g. ..., chan, map, interface).
|
||||
package gomock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A TestReporter is something that can be used to report test failures. It
|
||||
// is satisfied by the standard library's *testing.T.
|
||||
type TestReporter interface {
|
||||
Errorf(format string, args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
// TestHelper is a TestReporter that has the Helper method. It is satisfied
|
||||
// by the standard library's *testing.T.
|
||||
type TestHelper interface {
|
||||
TestReporter
|
||||
Helper()
|
||||
}
|
||||
|
||||
// A Controller represents the top-level control of a mock ecosystem. It
|
||||
// defines the scope and lifetime of mock objects, as well as their
|
||||
// expectations. It is safe to call Controller's methods from multiple
|
||||
// goroutines. Each test should create a new Controller and invoke Finish via
|
||||
// defer.
|
||||
//
|
||||
// func TestFoo(t *testing.T) {
|
||||
// ctrl := gomock.NewController(st)
|
||||
// defer ctrl.Finish()
|
||||
// // ..
|
||||
// }
|
||||
//
|
||||
// func TestBar(t *testing.T) {
|
||||
// t.Run("Sub-Test-1", st) {
|
||||
// ctrl := gomock.NewController(st)
|
||||
// defer ctrl.Finish()
|
||||
// // ..
|
||||
// })
|
||||
// t.Run("Sub-Test-2", st) {
|
||||
// ctrl := gomock.NewController(st)
|
||||
// defer ctrl.Finish()
|
||||
// // ..
|
||||
// })
|
||||
// })
|
||||
type Controller struct {
|
||||
// T should only be called within a generated mock. It is not intended to
|
||||
// be used in user code and may be changed in future versions. T is the
|
||||
// TestReporter passed in when creating the Controller via NewController.
|
||||
// If the TestReporter does not implement a TestHelper it will be wrapped
|
||||
// with a nopTestHelper.
|
||||
T TestHelper
|
||||
mu sync.Mutex
|
||||
expectedCalls *callSet
|
||||
finished bool
|
||||
}
|
||||
|
||||
// NewController returns a new Controller. It is the preferred way to create a
|
||||
// Controller.
|
||||
func NewController(t TestReporter) *Controller {
|
||||
h, ok := t.(TestHelper)
|
||||
if !ok {
|
||||
h = nopTestHelper{t}
|
||||
}
|
||||
|
||||
return &Controller{
|
||||
T: h,
|
||||
expectedCalls: newCallSet(),
|
||||
}
|
||||
}
|
||||
|
||||
type cancelReporter struct {
|
||||
TestHelper
|
||||
cancel func()
|
||||
}
|
||||
|
||||
func (r *cancelReporter) Errorf(format string, args ...interface{}) {
|
||||
r.TestHelper.Errorf(format, args...)
|
||||
}
|
||||
func (r *cancelReporter) Fatalf(format string, args ...interface{}) {
|
||||
defer r.cancel()
|
||||
r.TestHelper.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// WithContext returns a new Controller and a Context, which is cancelled on any
|
||||
// fatal failure.
|
||||
func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) {
|
||||
h, ok := t.(TestHelper)
|
||||
if !ok {
|
||||
h = nopTestHelper{t}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
return NewController(&cancelReporter{h, cancel}), ctx
|
||||
}
|
||||
|
||||
type nopTestHelper struct {
|
||||
TestReporter
|
||||
}
|
||||
|
||||
func (h nopTestHelper) Helper() {}
|
||||
|
||||
// RecordCall is called by a mock. It should not be called by user code.
|
||||
func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call {
|
||||
ctrl.T.Helper()
|
||||
|
||||
recv := reflect.ValueOf(receiver)
|
||||
for i := 0; i < recv.Type().NumMethod(); i++ {
|
||||
if recv.Type().Method(i).Name == method {
|
||||
return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...)
|
||||
}
|
||||
}
|
||||
ctrl.T.Fatalf("gomock: failed finding method %s on %T", method, receiver)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// RecordCallWithMethodType is called by a mock. It should not be called by user code.
|
||||
func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call {
|
||||
ctrl.T.Helper()
|
||||
|
||||
call := newCall(ctrl.T, receiver, method, methodType, args...)
|
||||
|
||||
ctrl.mu.Lock()
|
||||
defer ctrl.mu.Unlock()
|
||||
ctrl.expectedCalls.Add(call)
|
||||
|
||||
return call
|
||||
}
|
||||
|
||||
// Call is called by a mock. It should not be called by user code.
|
||||
func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} {
|
||||
ctrl.T.Helper()
|
||||
|
||||
// Nest this code so we can use defer to make sure the lock is released.
|
||||
actions := func() []func([]interface{}) []interface{} {
|
||||
ctrl.T.Helper()
|
||||
ctrl.mu.Lock()
|
||||
defer ctrl.mu.Unlock()
|
||||
|
||||
expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args)
|
||||
if err != nil {
|
||||
origin := callerInfo(2)
|
||||
ctrl.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err)
|
||||
}
|
||||
|
||||
// Two things happen here:
|
||||
// * the matching call no longer needs to check prerequite calls,
|
||||
// * and the prerequite calls are no longer expected, so remove them.
|
||||
preReqCalls := expected.dropPrereqs()
|
||||
for _, preReqCall := range preReqCalls {
|
||||
ctrl.expectedCalls.Remove(preReqCall)
|
||||
}
|
||||
|
||||
actions := expected.call(args)
|
||||
if expected.exhausted() {
|
||||
ctrl.expectedCalls.Remove(expected)
|
||||
}
|
||||
return actions
|
||||
}()
|
||||
|
||||
var rets []interface{}
|
||||
for _, action := range actions {
|
||||
if r := action(args); r != nil {
|
||||
rets = r
|
||||
}
|
||||
}
|
||||
|
||||
return rets
|
||||
}
|
||||
|
||||
// Finish checks to see if all the methods that were expected to be called
|
||||
// were called. It should be invoked for each Controller. It is not idempotent
|
||||
// and therefore can only be invoked once.
|
||||
func (ctrl *Controller) Finish() {
|
||||
ctrl.T.Helper()
|
||||
|
||||
ctrl.mu.Lock()
|
||||
defer ctrl.mu.Unlock()
|
||||
|
||||
if ctrl.finished {
|
||||
ctrl.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.")
|
||||
}
|
||||
ctrl.finished = true
|
||||
|
||||
// If we're currently panicking, probably because this is a deferred call,
|
||||
// pass through the panic.
|
||||
if err := recover(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Check that all remaining expected calls are satisfied.
|
||||
failures := ctrl.expectedCalls.Failures()
|
||||
for _, call := range failures {
|
||||
ctrl.T.Errorf("missing call(s) to %v", call)
|
||||
}
|
||||
if len(failures) != 0 {
|
||||
ctrl.T.Fatalf("aborting test due to missing call(s)")
|
||||
}
|
||||
}
|
||||
|
||||
func callerInfo(skip int) string {
|
||||
if _, file, line, ok := runtime.Caller(skip + 1); ok {
|
||||
return fmt.Sprintf("%s:%d", file, line)
|
||||
}
|
||||
return "unknown file"
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
// Copyright 2010 Google Inc.
|
||||
//
|
||||
// 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 gomock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// A Matcher is a representation of a class of values.
|
||||
// It is used to represent the valid or expected arguments to a mocked method.
|
||||
type Matcher interface {
|
||||
// Matches returns whether x is a match.
|
||||
Matches(x interface{}) bool
|
||||
|
||||
// String describes what the matcher matches.
|
||||
String() string
|
||||
}
|
||||
|
||||
type anyMatcher struct{}
|
||||
|
||||
func (anyMatcher) Matches(x interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (anyMatcher) String() string {
|
||||
return "is anything"
|
||||
}
|
||||
|
||||
type eqMatcher struct {
|
||||
x interface{}
|
||||
}
|
||||
|
||||
func (e eqMatcher) Matches(x interface{}) bool {
|
||||
return reflect.DeepEqual(e.x, x)
|
||||
}
|
||||
|
||||
func (e eqMatcher) String() string {
|
||||
return fmt.Sprintf("is equal to %v", e.x)
|
||||
}
|
||||
|
||||
type nilMatcher struct{}
|
||||
|
||||
func (nilMatcher) Matches(x interface{}) bool {
|
||||
if x == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(x)
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map,
|
||||
reflect.Ptr, reflect.Slice:
|
||||
return v.IsNil()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (nilMatcher) String() string {
|
||||
return "is nil"
|
||||
}
|
||||
|
||||
type notMatcher struct {
|
||||
m Matcher
|
||||
}
|
||||
|
||||
func (n notMatcher) Matches(x interface{}) bool {
|
||||
return !n.m.Matches(x)
|
||||
}
|
||||
|
||||
func (n notMatcher) String() string {
|
||||
// TODO: Improve this if we add a NotString method to the Matcher interface.
|
||||
return "not(" + n.m.String() + ")"
|
||||
}
|
||||
|
||||
type assignableToTypeOfMatcher struct {
|
||||
targetType reflect.Type
|
||||
}
|
||||
|
||||
func (m assignableToTypeOfMatcher) Matches(x interface{}) bool {
|
||||
return reflect.TypeOf(x).AssignableTo(m.targetType)
|
||||
}
|
||||
|
||||
func (m assignableToTypeOfMatcher) String() string {
|
||||
return "is assignable to " + m.targetType.Name()
|
||||
}
|
||||
|
||||
// Constructors
|
||||
// Any returns a matcher that always matches.
|
||||
func Any() Matcher { return anyMatcher{} }
|
||||
|
||||
// Eq returns a matcher that matches on equality.
|
||||
//
|
||||
// Example usage:
|
||||
// Eq(5).Matches(5) // returns true
|
||||
// Eq(5).Matches(4) // returns false
|
||||
func Eq(x interface{}) Matcher { return eqMatcher{x} }
|
||||
|
||||
// Nil returns a matcher that matches if the received value is nil.
|
||||
//
|
||||
// Example usage:
|
||||
// var x *bytes.Buffer
|
||||
// Nil().Matches(x) // returns true
|
||||
// x = &bytes.Buffer{}
|
||||
// Nil().Matches(x) // returns false
|
||||
func Nil() Matcher { return nilMatcher{} }
|
||||
|
||||
// Not reverses the results of its given child matcher.
|
||||
//
|
||||
// Example usage:
|
||||
// Not(Eq(5)).Matches(4) // returns true
|
||||
// Not(Eq(5)).Matches(5) // returns false
|
||||
func Not(x interface{}) Matcher {
|
||||
if m, ok := x.(Matcher); ok {
|
||||
return notMatcher{m}
|
||||
}
|
||||
return notMatcher{Eq(x)}
|
||||
}
|
||||
|
||||
// AssignableToTypeOf is a Matcher that matches if the parameter to the mock
|
||||
// function is assignable to the type of the parameter to this function.
|
||||
//
|
||||
// Example usage:
|
||||
// var s fmt.Stringer = &bytes.Buffer{}
|
||||
// AssignableToTypeOf(s).Matches(time.Second) // returns true
|
||||
// AssignableToTypeOf(s).Matches(99) // returns false
|
||||
func AssignableToTypeOf(x interface{}) Matcher {
|
||||
return assignableToTypeOfMatcher{reflect.TypeOf(x)}
|
||||
}
|
||||
Vendored
+2
@@ -318,6 +318,8 @@ github.com/golang-plus/uuid/internal/random
|
||||
github.com/golang-plus/uuid/internal/timebased
|
||||
# github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7
|
||||
github.com/golang/groupcache/lru
|
||||
# github.com/golang/mock v1.3.1
|
||||
github.com/golang/mock/gomock
|
||||
# github.com/golang/protobuf v1.3.2
|
||||
github.com/golang/protobuf/proto
|
||||
github.com/golang/protobuf/protoc-gen-go
|
||||
|
||||
Reference in New Issue
Block a user