2020-08-21 10:57:30 -07:00
// Copyright (c) HashiCorp, Inc.
2021-11-02 14:06:20 -07:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2020-08-20 08:20:26 -07:00
package hosts_test
import (
"context"
2020-09-23 08:10:27 -07:00
"errors"
2020-08-20 08:20:26 -07:00
"fmt"
2023-10-30 14:41:12 -07:00
"slices"
2020-08-20 08:20:26 -07:00
"strings"
"testing"
"github.com/golang/protobuf/ptypes/wrappers"
"github.com/google/go-cmp/cmp"
2023-10-31 13:44:17 +00:00
"github.com/google/go-cmp/cmp/cmpopts"
2022-10-28 15:52:06 -04:00
"github.com/hashicorp/boundary/globals"
2023-10-30 14:41:12 -07:00
"github.com/hashicorp/boundary/internal/authtoken"
2022-05-09 12:45:10 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/hosts"
2020-08-20 08:20:26 -07:00
"github.com/hashicorp/boundary/internal/db"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
2023-10-30 14:41:12 -07:00
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
"github.com/hashicorp/boundary/internal/host"
2023-04-24 19:27:41 -04:00
hostplugin "github.com/hashicorp/boundary/internal/host/plugin"
2020-08-20 08:20:26 -07:00
"github.com/hashicorp/boundary/internal/host/static"
2023-10-30 14:41:12 -07:00
"github.com/hashicorp/boundary/internal/host/static/store"
2020-08-20 08:20:26 -07:00
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
2023-04-24 19:27:41 -04:00
"github.com/hashicorp/boundary/internal/plugin"
2023-04-19 11:27:00 -07:00
"github.com/hashicorp/boundary/internal/plugin/loopback"
2023-10-30 14:41:12 -07:00
"github.com/hashicorp/boundary/internal/requests"
2021-11-02 14:06:20 -07:00
"github.com/hashicorp/boundary/internal/scheduler"
2023-10-30 14:41:12 -07:00
"github.com/hashicorp/boundary/internal/server"
2020-08-20 08:20:26 -07:00
"github.com/hashicorp/boundary/internal/types/scope"
2021-08-26 10:44:41 -04:00
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hosts"
2021-11-02 14:06:20 -07:00
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/plugins"
2021-08-26 10:44:41 -04:00
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
2021-11-02 14:06:20 -07:00
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
2020-08-20 08:20:26 -07:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
2021-04-23 09:13:37 -05:00
"google.golang.org/protobuf/types/known/timestamppb"
2021-11-02 14:06:20 -07:00
"google.golang.org/protobuf/types/known/wrapperspb"
2020-08-20 08:20:26 -07:00
)
2023-11-15 19:55:46 -05:00
var testAuthorizedActions = map [ globals . Subtype ][] string {
2023-11-02 16:03:47 -04:00
static . Subtype : { "no-op" , "read" , "update" , "delete" },
hostplugin . Subtype : { "no-op" , "read" },
2021-11-03 12:39:41 -04:00
}
2021-04-23 09:13:37 -05:00
2023-10-30 14:41:12 -07:00
func staticHostToProto ( h host . Host , proj * iam . Scope , hostSet * static . HostSet ) * pb . Host {
return & pb . Host {
Id : h . GetPublicId (),
HostCatalogId : h . GetCatalogId (),
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : proj . GetParentId ()},
CreatedTime : h . GetCreateTime (). GetTimestamp (),
UpdatedTime : h . GetUpdateTime (). GetTimestamp (),
Version : h . GetVersion (),
Type : static . Subtype . String (),
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( h . GetAddress ()),
},
},
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
HostSetIds : [] string { hostSet . GetPublicId ()},
}
}
func pluginHostToProto ( h host . Host , proj * iam . Scope , hostSet * hostplugin . HostSet , plg * plugin . Plugin , extId string , extName string ) * pb . Host {
return & pb . Host {
Id : h . GetPublicId (),
HostCatalogId : h . GetCatalogId (),
Plugin : & plugins . PluginInfo {
Id : plg . GetPublicId (),
Name : plg . GetName (),
Description : plg . GetDescription (),
},
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : proj . GetParentId ()},
CreatedTime : h . GetCreateTime (). GetTimestamp (),
UpdatedTime : h . GetUpdateTime (). GetTimestamp (),
HostSetIds : [] string { hostSet . GetPublicId ()},
Version : 1 ,
ExternalId : extId ,
ExternalName : extName ,
Type : hostplugin . Subtype . String (),
AuthorizedActions : testAuthorizedActions [ hostplugin . Subtype ],
}
}
2021-11-02 14:06:20 -07:00
func TestGet_Static ( t * testing . T ) {
2020-08-20 08:20:26 -07:00
t . Parallel ()
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2020-08-20 08:20:26 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
2021-03-25 03:15:43 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
2023-10-30 14:41:12 -07:00
_ , proj := iam . TestScopes ( t , iamRepo )
2020-08-20 08:20:26 -07:00
rw := db . New ( conn )
2021-11-02 14:06:20 -07:00
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , map [ string ] plgpb . HostPluginServiceClient {})
2021-11-02 14:06:20 -07:00
}
2020-08-20 08:20:26 -07:00
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( ctx , rw , rw , kms )
2020-08-20 08:20:26 -07:00
}
hc := static . TestCatalogs ( t , conn , proj . GetPublicId (), 1 )[ 0 ]
h := static . TestHosts ( t , conn , hc . GetPublicId (), 1 )[ 0 ]
2022-02-01 10:06:13 -08:00
s := static . TestSets ( t , conn , hc . GetPublicId (), 1 )[ 0 ]
static . TestSetMembers ( t , conn , s . GetPublicId (), [] * static . Host { h })
2020-08-20 08:20:26 -07:00
2023-10-30 14:41:12 -07:00
pHost := staticHostToProto ( h , proj , s )
2020-08-20 08:20:26 -07:00
cases := [] struct {
2020-09-23 08:10:27 -07:00
name string
req * pbs . GetHostRequest
res * pbs . GetHostResponse
err error
2020-08-20 08:20:26 -07:00
}{
{
2020-09-23 08:10:27 -07:00
name : "Get an Existing Host" ,
req : & pbs . GetHostRequest { Id : h . GetPublicId ()},
res : & pbs . GetHostResponse { Item : pHost },
2020-08-20 08:20:26 -07:00
},
{
2020-09-23 08:10:27 -07:00
name : "Get a non existing Host Set" ,
2023-03-10 15:06:39 -05:00
req : & pbs . GetHostRequest { Id : globals . StaticHostPrefix + "_DoesntExis" },
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . NotFound ),
2020-08-20 08:20:26 -07:00
},
{
2020-09-23 08:10:27 -07:00
name : "Wrong id prefix" ,
req : & pbs . GetHostRequest { Id : "j_1234567890" },
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-08-20 08:20:26 -07:00
},
{
2020-09-23 08:10:27 -07:00
name : "space in id" ,
2023-03-10 15:06:39 -05:00
req : & pbs . GetHostRequest { Id : globals . StaticHostPrefix + "_1 23456789" },
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-08-20 08:20:26 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
2020-09-23 08:10:27 -07:00
assert , require := assert . New ( t ), require . New ( t )
2023-10-30 14:41:12 -07:00
s , err := hosts . NewService ( ctx , repoFn , pluginRepoFn , 1000 )
2021-11-02 14:06:20 -07:00
require . NoError ( err , "Couldn't create a new host service." )
2020-08-20 08:20:26 -07:00
2021-03-25 03:15:43 -04:00
got , gErr := s . GetHost ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), tc . req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "GetHost(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
}
2020-08-20 08:20:26 -07:00
if tc . res != nil {
tc . res . Item . Version = 1
}
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
), "GetHost(%q) got response %q, wanted %q" , tc . req , got , tc . res )
2020-08-20 08:20:26 -07:00
})
}
}
2021-11-02 14:06:20 -07:00
func TestGet_Plugin ( t * testing . T ) {
t . Parallel ()
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2020-08-20 08:20:26 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
2021-03-25 03:15:43 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
2023-10-30 14:41:12 -07:00
_ , proj := iam . TestScopes ( t , iamRepo )
2020-08-20 08:20:26 -07:00
2023-04-24 19:27:41 -04:00
plg := plugin . TestPlugin ( t , conn , "test" )
2021-11-02 14:06:20 -07:00
plgm := map [ string ] plgpb . HostPluginServiceClient {
2023-04-18 21:12:05 -07:00
plg . GetPublicId (): loopback . NewWrappingPluginHostClient ( & loopback . TestPluginServer {}),
2021-11-02 14:06:20 -07:00
}
2020-08-20 08:20:26 -07:00
rw := db . New ( conn )
2021-11-02 14:06:20 -07:00
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , plgm )
2021-11-02 14:06:20 -07:00
}
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( ctx , rw , rw , kms )
2021-11-02 14:06:20 -07:00
}
2023-04-24 19:27:41 -04:00
hc := hostplugin . TestCatalog ( t , conn , proj . GetPublicId (), plg . GetPublicId ())
h := hostplugin . TestHost ( t , conn , hc . GetPublicId (), "test" , hostplugin . WithExternalName ( "test-ext-name" ))
hPrev := hostplugin . TestHost ( t , conn , hc . GetPublicId (), "test-prev" ,
hostplugin . WithPublicId ( fmt . Sprintf ( "%s_1234567890" , globals . PluginHostPreviousPrefix )),
hostplugin . WithExternalName ( "test-prev-name" ),
2023-03-15 15:24:25 +00:00
)
2023-04-24 19:27:41 -04:00
hs := hostplugin . TestSet ( t , conn , kms , sche , hc , plgm )
hostplugin . TestSetMembers ( t , conn , hs . GetPublicId (), [] * hostplugin . Host { h , hPrev })
2021-11-02 14:06:20 -07:00
2023-10-30 14:41:12 -07:00
pHost := pluginHostToProto ( h , proj , hs , plg , "test" , "test-ext-name" )
2021-11-02 14:06:20 -07:00
cases := [] struct {
name string
req * pbs . GetHostRequest
res * pbs . GetHostResponse
err error
}{
{
name : "Get an Existing Host" ,
req : & pbs . GetHostRequest { Id : h . GetPublicId ()},
res : & pbs . GetHostResponse { Item : pHost },
},
2022-07-15 13:09:55 -04:00
{
name : "Get an Existing Previous-ID Host" ,
req : & pbs . GetHostRequest { Id : hPrev . GetPublicId ()},
res : func () * pbs . GetHostResponse {
resp := proto . Clone ( pHost ).( * pb . Host )
resp . Id = hPrev . PublicId
resp . CreatedTime = hPrev . CreateTime . GetTimestamp ()
resp . UpdatedTime = hPrev . UpdateTime . GetTimestamp ()
resp . ExternalId = "test-prev"
2023-03-15 15:24:25 +00:00
resp . ExternalName = "test-prev-name"
2022-07-15 13:09:55 -04:00
return & pbs . GetHostResponse { Item : resp }
}(),
},
2021-11-02 14:06:20 -07:00
{
name : "non existing" ,
2023-03-10 15:06:39 -05:00
req : & pbs . GetHostRequest { Id : globals . PluginHostPrefix + "_DoesntExis" },
2021-11-02 14:06:20 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . NotFound ),
},
{
name : "Wrong id prefix" ,
req : & pbs . GetHostRequest { Id : "j_1234567890" },
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "space in id" ,
2023-03-10 15:06:39 -05:00
req : & pbs . GetHostRequest { Id : globals . PluginHostPrefix + "_1 23456789" },
2021-11-02 14:06:20 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2023-10-30 14:41:12 -07:00
s , err := hosts . NewService ( ctx , repoFn , pluginRepoFn , 1000 )
2021-11-02 14:06:20 -07:00
require . NoError ( err , "Couldn't create a new host service." )
got , gErr := s . GetHost ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), tc . req )
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "GetHost(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
return
}
require . NoError ( gErr )
if tc . res != nil {
tc . res . Item . Version = 1
}
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
), "GetHost(%q) got response %q, wanted %q" , tc . req , got , tc . res )
2021-11-02 14:06:20 -07:00
})
}
}
func TestList_Static ( t * testing . T ) {
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2021-11-02 14:06:20 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
2023-10-30 14:41:12 -07:00
_ , proj := iam . TestScopes ( t , iamRepo )
2021-11-02 14:06:20 -07:00
rw := db . New ( conn )
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , map [ string ] plgpb . HostPluginServiceClient {})
2021-11-02 14:06:20 -07:00
}
2020-08-20 08:20:26 -07:00
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( ctx , rw , rw , kms )
2020-08-20 08:20:26 -07:00
}
hcs := static . TestCatalogs ( t , conn , proj . GetPublicId (), 2 )
hc , hcNoHosts := hcs [ 0 ], hcs [ 1 ]
2022-02-01 10:06:13 -08:00
hset := static . TestSets ( t , conn , hc . GetPublicId (), 1 )[ 0 ]
2020-08-20 08:20:26 -07:00
var wantHs [] * pb . Host
2022-02-01 10:06:13 -08:00
testHosts := static . TestHosts ( t , conn , hc . GetPublicId (), 10 )
static . TestSetMembers ( t , conn , hset . GetPublicId (), testHosts )
for _ , h := range testHosts {
2023-10-30 14:41:12 -07:00
wantHs = append ( wantHs , staticHostToProto ( h , proj , hset ))
2020-08-20 08:20:26 -07:00
}
2023-10-30 14:41:12 -07:00
slices . Reverse ( wantHs )
2020-08-20 08:20:26 -07:00
cases := [] struct {
2021-02-22 10:09:25 -07:00
name string
req * pbs . ListHostsRequest
res * pbs . ListHostsResponse
err error
2020-08-20 08:20:26 -07:00
}{
{
2021-02-22 10:09:25 -07:00
name : "List Many Hosts" ,
req : & pbs . ListHostsRequest { HostCatalogId : hc . GetPublicId ()},
2023-10-30 14:41:12 -07:00
res : & pbs . ListHostsResponse {
Items : wantHs ,
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
EstItemCount : 10 ,
},
2021-02-22 10:09:25 -07:00
},
2021-11-16 17:36:09 -07:00
{
name : "List Non Existing Hosts" ,
req : & pbs . ListHostsRequest { HostCatalogId : "hcst_doesntexist" },
2021-11-16 17:27:16 -08:00
err : handlers . NotFoundError (),
2021-11-16 17:36:09 -07:00
},
2021-02-22 10:09:25 -07:00
{
name : "List No Hosts" ,
req : & pbs . ListHostsRequest { HostCatalogId : hcNoHosts . GetPublicId ()},
2023-10-30 14:41:12 -07:00
res : & pbs . ListHostsResponse {
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2021-02-22 10:09:25 -07:00
},
{
name : "Filter to One Host" ,
req : & pbs . ListHostsRequest { HostCatalogId : hc . GetPublicId (), Filter : fmt . Sprintf ( `"/item/id"==%q` , wantHs [ 1 ]. GetId ())},
2023-10-30 14:41:12 -07:00
res : & pbs . ListHostsResponse {
Items : wantHs [ 1 : 2 ],
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
EstItemCount : 1 ,
},
2021-02-22 10:09:25 -07:00
},
{
name : "Filter to No Hosts" ,
req : & pbs . ListHostsRequest { HostCatalogId : hc . GetPublicId (), Filter : `"/item/id"=="doesnt match"` },
2023-10-30 14:41:12 -07:00
res : & pbs . ListHostsResponse {
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2020-08-20 08:20:26 -07:00
},
{
2021-02-22 10:09:25 -07:00
name : "Filter Bad Format" ,
req : & pbs . ListHostsRequest { HostCatalogId : hc . GetPublicId (), Filter : `"//id/"=="bad"` },
err : handlers . InvalidArgumentErrorf ( "bad format" , nil ),
2020-08-20 08:20:26 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2023-10-30 14:41:12 -07:00
s , err := hosts . NewService ( ctx , repoFn , pluginRepoFn , 1000 )
2020-08-20 08:20:26 -07:00
require . NoError ( err , "Couldn't create new host set service." )
2021-05-04 19:57:35 -05:00
// Test non-anonymous listing
2021-03-25 03:15:43 -04:00
got , gErr := s . ListHosts ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), tc . req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
2021-02-22 10:09:25 -07:00
assert . True ( errors . Is ( gErr , tc . err ), "ListHosts(%q) got error %v, wanted %v" , tc . req , gErr , tc . err )
2021-05-04 19:57:35 -05:00
return
2020-09-23 08:10:27 -07:00
}
2021-05-04 19:57:35 -05:00
require . NoError ( gErr )
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
2023-10-30 14:41:12 -07:00
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
))
2021-05-04 19:57:35 -05:00
// Test anonymous listing
2022-10-28 15:52:06 -04:00
got , gErr = s . ListHosts ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId (), auth . WithUserId ( globals . AnonymousUserId )), tc . req )
2021-05-04 19:57:35 -05:00
require . NoError ( gErr )
assert . Len ( got . Items , len ( tc . res . Items ))
for _ , item := range got . GetItems () {
require . Nil ( item . CreatedTime )
require . Nil ( item . UpdatedTime )
require . Zero ( item . Version )
}
2020-08-20 08:20:26 -07:00
})
}
}
2021-11-02 14:06:20 -07:00
func TestList_Plugin ( t * testing . T ) {
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2021-11-02 14:06:20 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
2023-10-30 14:41:12 -07:00
_ , proj := iam . TestScopes ( t , iamRepo )
2023-04-24 19:27:41 -04:00
plg := plugin . TestPlugin ( t , conn , "test" )
2021-11-02 14:06:20 -07:00
plgm := map [ string ] plgpb . HostPluginServiceClient {
2023-04-18 21:12:05 -07:00
plg . GetPublicId (): loopback . NewWrappingPluginHostClient ( & loopback . TestPluginServer {}),
2021-11-02 14:06:20 -07:00
}
rw := db . New ( conn )
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , plgm )
2021-11-02 14:06:20 -07:00
}
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( ctx , rw , rw , kms )
2021-11-02 14:06:20 -07:00
}
2023-04-24 19:27:41 -04:00
hcs := hostplugin . TestCatalogs ( t , conn , proj . GetPublicId (), plg . GetPublicId (), 2 )
2021-11-02 14:06:20 -07:00
hc , hcNoHosts := hcs [ 0 ], hcs [ 1 ]
2023-04-24 19:27:41 -04:00
hs := hostplugin . TestSet ( t , conn , kms , sche , hc , plgm )
2021-11-02 14:06:20 -07:00
var wantHs [] * pb . Host
for i := 0 ; i < 10 ; i ++ {
2023-10-30 14:41:12 -07:00
extId := fmt . Sprintf ( "ext-id-%d" , i )
extName := fmt . Sprintf ( "ext-name-%d" , i )
h := hostplugin . TestHost ( t , conn , hc . GetPublicId (), extId , hostplugin . WithExternalName ( extName ))
2023-04-24 19:27:41 -04:00
hostplugin . TestSetMembers ( t , conn , hs . GetPublicId (), [] * hostplugin . Host { h })
2023-10-30 14:41:12 -07:00
wantHs = append ( wantHs , pluginHostToProto ( h , proj , hs , plg , extId , extName ))
2021-11-02 14:06:20 -07:00
}
2023-10-30 14:41:12 -07:00
slices . Reverse ( wantHs )
2021-11-02 14:06:20 -07:00
cases := [] struct {
name string
req * pbs . ListHostsRequest
res * pbs . ListHostsResponse
err error
}{
{
name : "List Many Hosts" ,
req : & pbs . ListHostsRequest { HostCatalogId : hc . GetPublicId ()},
2023-10-30 14:41:12 -07:00
res : & pbs . ListHostsResponse {
Items : wantHs ,
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
EstItemCount : 10 ,
},
2021-11-02 14:06:20 -07:00
},
2021-11-16 17:36:09 -07:00
{
name : "List Non Existing Hosts" ,
req : & pbs . ListHostsRequest { HostCatalogId : "hc_doesntexist" },
2021-11-16 17:27:16 -08:00
err : handlers . NotFoundError (),
2021-11-16 17:36:09 -07:00
},
2021-11-02 14:06:20 -07:00
{
name : "List No Hosts" ,
req : & pbs . ListHostsRequest { HostCatalogId : hcNoHosts . GetPublicId ()},
2023-10-30 14:41:12 -07:00
res : & pbs . ListHostsResponse {
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2021-11-02 14:06:20 -07:00
},
{
name : "Filter to One Host" ,
req : & pbs . ListHostsRequest { HostCatalogId : hc . GetPublicId (), Filter : fmt . Sprintf ( `"/item/id"==%q` , wantHs [ 1 ]. GetId ())},
2023-10-30 14:41:12 -07:00
res : & pbs . ListHostsResponse {
Items : wantHs [ 1 : 2 ],
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
EstItemCount : 1 ,
},
2021-11-02 14:06:20 -07:00
},
{
name : "Filter to No Hosts" ,
req : & pbs . ListHostsRequest { HostCatalogId : hc . GetPublicId (), Filter : `"/item/id"=="doesnt match"` },
2023-10-30 14:41:12 -07:00
res : & pbs . ListHostsResponse {
ResponseType : "complete" ,
SortBy : "created_time" ,
SortDir : "desc" ,
},
2021-11-02 14:06:20 -07:00
},
{
name : "Filter Bad Format" ,
req : & pbs . ListHostsRequest { HostCatalogId : hc . GetPublicId (), Filter : `"//id/"=="bad"` },
err : handlers . InvalidArgumentErrorf ( "bad format" , nil ),
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2023-10-30 14:41:12 -07:00
s , err := hosts . NewService ( ctx , repoFn , pluginRepoFn , 1000 )
2021-11-02 14:06:20 -07:00
require . NoError ( err , "Couldn't create new host set service." )
// Test non-anonymous listing
got , gErr := s . ListHosts ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), tc . req )
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "ListHosts(%q) got error %v, wanted %v" , tc . req , gErr , tc . err )
return
}
require . NoError ( gErr )
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
2023-10-30 14:41:12 -07:00
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
))
2021-11-02 14:06:20 -07:00
// Test anonymous listing
2022-10-28 15:52:06 -04:00
got , gErr = s . ListHosts ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId (), auth . WithUserId ( globals . AnonymousUserId )), tc . req )
2021-11-02 14:06:20 -07:00
require . NoError ( gErr )
assert . Len ( got . Items , len ( tc . res . Items ))
for _ , item := range got . GetItems () {
require . Nil ( item . CreatedTime )
require . Nil ( item . UpdatedTime )
require . Zero ( item . Version )
}
})
}
}
2023-10-30 14:41:12 -07:00
func TestListPagination ( t * testing . T ) {
// Set database read timeout to avoid duplicates in response
oldReadTimeout := globals . RefreshReadLookbackDuration
globals . RefreshReadLookbackDuration = 0
t . Cleanup ( func () {
globals . RefreshReadLookbackDuration = oldReadTimeout
})
ctx := context . Background ()
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
sqlDB , err := conn . SqlDB ( ctx )
require . NoError ( t , err )
kms := kms . TestKms ( t , conn , wrapper )
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
org , proj := iam . TestScopes ( t , iamRepo )
plg := plugin . TestPlugin ( t , conn , "test" )
plgm := map [ string ] plgpb . HostPluginServiceClient {
plg . GetPublicId (): loopback . NewWrappingPluginHostClient ( & loopback . TestPluginServer {}),
}
rw := db . New ( conn )
sche := scheduler . TestScheduler ( t , conn , wrapper )
tokenRepoFn := func () ( * authtoken . Repository , error ) {
return authtoken . NewRepository ( ctx , rw , rw , kms )
}
serversRepoFn := func () ( * server . Repository , error ) {
return server . NewRepository ( ctx , rw , rw , kms )
}
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , plgm )
}
staticRepoFn := func () ( * static . Repository , error ) {
return static . NewRepository ( ctx , rw , rw , kms )
}
staticRepo , err := staticRepoFn ()
require . NoError ( t , err )
at := authtoken . TestAuthToken ( t , conn , kms , org . GetPublicId ())
r := iam . TestRole ( t , conn , proj . GetPublicId ())
_ = iam . TestUserRole ( t , conn , r . GetPublicId (), at . GetIamUserId ())
2024-01-17 23:54:49 -08:00
_ = iam . TestRoleGrant ( t , conn , r . GetPublicId (), "ids=*;type=*;actions=*" )
2023-10-30 14:41:12 -07:00
phc := hostplugin . TestCatalogs ( t , conn , proj . GetPublicId (), plg . GetPublicId (), 1 )[ 0 ]
phs := hostplugin . TestSet ( t , conn , kms , sche , phc , plgm )
shc := static . TestCatalogs ( t , conn , proj . GetPublicId (), 1 )[ 0 ]
shs := static . TestSets ( t , conn , shc . GetPublicId (), 1 )[ 0 ]
var staticPbHosts [] * pb . Host
staticHosts := static . TestHosts ( t , conn , shc . GetPublicId (), 10 )
static . TestSetMembers ( t , conn , shs . GetPublicId (), staticHosts )
for _ , host := range staticHosts {
staticPbHosts = append ( staticPbHosts , staticHostToProto ( host , proj , shs ))
}
var pluginPbHosts [] * pb . Host
for i := 0 ; i < 10 ; i ++ {
extId := fmt . Sprintf ( "ext-id-%d" , i )
extName := fmt . Sprintf ( "ext-name-%d" , i )
pluginHost := hostplugin . TestHost ( t , conn , phc . GetPublicId (), extId , hostplugin . WithExternalName ( extName ))
hostplugin . TestSetMembers ( t , conn , phs . GetPublicId (), [] * hostplugin . Host { pluginHost })
pluginPbHosts = append ( pluginPbHosts , pluginHostToProto ( pluginHost , proj , phs , plg , extId , extName ))
}
// Since we list by create_time descending, we need to reverse slices
slices . Reverse ( staticPbHosts )
slices . Reverse ( pluginPbHosts )
// Run analyze to update postgres estimates
_ , err = sqlDB . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
// Test without anon user
requestInfo := authpb . RequestInfo {
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
PublicId : at . GetPublicId (),
Token : at . GetToken (),
}
requestContext := context . WithValue ( context . Background (), requests . ContextRequestInformationKey , & requests . RequestContext {})
ctx = auth . NewVerifierContext ( requestContext , iamRepoFn , tokenRepoFn , serversRepoFn , kms , & requestInfo )
s , err := hosts . NewService ( ctx , staticRepoFn , pluginRepoFn , 1000 )
require . NoError ( t , err )
t . Run ( "static-hosts" , func ( t * testing . T ) {
// Start paginating, recursively
req := & pbs . ListHostsRequest {
HostCatalogId : shc . GetPublicId (),
Filter : "" ,
ListToken : "" ,
PageSize : 2 ,
}
got , err := s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 2 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : staticPbHosts [ 0 : 2 ],
ResponseType : "delta" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Request second page
req . ListToken = got . ListToken
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 2 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : staticPbHosts [ 2 : 4 ],
ResponseType : "delta" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Request rest of results
req . ListToken = got . ListToken
req . PageSize = 10
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 6 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : staticPbHosts [ 4 :],
ResponseType : "complete" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Create another Host
staticHost := static . TestHosts ( t , conn , shc . GetPublicId (), 1 )[ 0 ]
static . TestSetMembers ( t , conn , shs . GetPublicId (), [] * static . Host { staticHost })
// Add to the front since it's most recently updated
staticPbHosts = append ([] * pb . Host { staticHostToProto ( staticHost , proj , shs )}, staticPbHosts ... )
// Delete one of the other Hosts
_ , err = staticRepo . DeleteHost ( ctx , proj . GetPublicId (), staticPbHosts [ len ( staticPbHosts ) - 1 ]. Id )
require . NoError ( t , err )
deletedHost := staticPbHosts [ len ( staticPbHosts ) - 1 ]
staticPbHosts = staticPbHosts [: len ( staticPbHosts ) - 1 ]
// Update one of the other Hosts
staticPbHosts [ 1 ]. Name = wrapperspb . String ( "new-name" )
staticPbHosts [ 1 ]. Version = 2
h := & static . Host {
Host : & store . Host {
PublicId : staticPbHosts [ 1 ]. Id ,
CatalogId : staticPbHosts [ 1 ]. HostCatalogId ,
Name : staticPbHosts [ 1 ]. Name . GetValue (),
},
}
newHost , _ , err := staticRepo . UpdateHost ( ctx , proj . PublicId , h , 1 , [] string { "name" })
require . NoError ( t , err )
staticPbHosts [ 1 ]. UpdatedTime = newHost . GetUpdateTime (). GetTimestamp ()
staticPbHosts [ 1 ]. Version = newHost . GetVersion ()
// Add to the front since it's most recently updated
staticPbHosts = append (
[] * pb . Host { staticPbHosts [ 1 ]},
append (
[] * pb . Host { staticPbHosts [ 0 ]},
staticPbHosts [ 2 :] ... ,
) ... ,
)
// Run analyze to update postgres estimates
_ , err = sqlDB . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
// Request updated results
req . ListToken = got . ListToken
req . PageSize = 1
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : [] * pb . Host { staticPbHosts [ 0 ]},
ResponseType : "delta" ,
ListToken : "" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
// Should contain the deleted Host
RemovedIds : [] string { deletedHost . Id },
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Get next page
req . ListToken = got . ListToken
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : [] * pb . Host { staticPbHosts [ 1 ]},
ResponseType : "complete" ,
ListToken : "" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Request new page with filter requiring looping
// to fill the page.
req . ListToken = ""
req . PageSize = 1
req . Filter = fmt . Sprintf ( `"/item/id"==%q or "/item/id"==%q` , staticPbHosts [ len ( staticPbHosts ) - 2 ]. Id , staticPbHosts [ len ( staticPbHosts ) - 1 ]. Id )
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : [] * pb . Host { staticPbHosts [ len ( staticPbHosts ) - 2 ]},
ResponseType : "delta" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
// Should be empty again
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Get the second page
req . ListToken = got . ListToken
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : [] * pb . Host { staticPbHosts [ len ( staticPbHosts ) - 1 ]},
ResponseType : "complete" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
2024-02-15 09:26:29 -08:00
// Create unauthenticated user
unauthAt := authtoken . TestAuthToken ( t , conn , kms , org . GetPublicId ())
unauthR := iam . TestRole ( t , conn , proj . GetPublicId ())
_ = iam . TestUserRole ( t , conn , unauthR . GetPublicId (), unauthAt . GetIamUserId ())
// Make a request with the unauthenticated user,
// ensure the response contains the pagination parameters.
requestInfo := authpb . RequestInfo {
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
PublicId : unauthAt . GetPublicId (),
Token : unauthAt . GetToken (),
}
requestContext := context . WithValue ( context . Background (), requests . ContextRequestInformationKey , & requests . RequestContext {})
ctx := auth . NewVerifierContext ( requestContext , iamRepoFn , tokenRepoFn , serversRepoFn , kms , & requestInfo )
_ , err = s . ListHosts ( ctx , & pbs . ListHostsRequest {
HostCatalogId : shc . GetPublicId (),
})
require . Error ( t , err )
assert . ErrorIs ( t , handlers . ForbiddenError (), err )
2023-10-30 14:41:12 -07:00
})
t . Run ( "plugin-hosts" , func ( t * testing . T ) {
// Start paginating, recursively
req := & pbs . ListHostsRequest {
HostCatalogId : phc . GetPublicId (),
Filter : "" ,
ListToken : "" ,
PageSize : 2 ,
}
got , err := s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 2 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : pluginPbHosts [ 0 : 2 ],
ResponseType : "delta" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Request second page
req . ListToken = got . ListToken
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 2 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : pluginPbHosts [ 2 : 4 ],
ResponseType : "delta" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Request rest of results
req . ListToken = got . ListToken
req . PageSize = 10
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 6 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : pluginPbHosts [ 4 :],
ResponseType : "complete" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 10 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Create another Host
extId := "ext-id-10"
extName := "ext-name-10"
pluginHost := hostplugin . TestHost ( t , conn , phc . GetPublicId (), extId , hostplugin . WithExternalName ( extName ))
hostplugin . TestSetMembers ( t , conn , phs . GetPublicId (), [] * hostplugin . Host { pluginHost })
// Add to the front since it's most recently updated
pluginPbHosts = append ([] * pb . Host { pluginHostToProto ( pluginHost , proj , phs , plg , extId , extName )}, pluginPbHosts ... )
// Note: it's non-trivial to delete and update plugin hosts, so we skip that part here.
// Run analyze to update postgres estimates
_ , err = sqlDB . ExecContext ( ctx , "analyze" )
require . NoError ( t , err )
// Request updated results
req . ListToken = got . ListToken
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
// Compare without comparing the list token
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : [] * pb . Host { pluginPbHosts [ 0 ]},
ResponseType : "complete" ,
ListToken : "" ,
SortBy : "updated_time" ,
SortDir : "desc" ,
EstItemCount : 11 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
// Request new page with filter requiring looping
// to fill the page.
req . ListToken = ""
req . PageSize = 1
req . Filter = fmt . Sprintf ( `"/item/id"==%q or "/item/id"==%q` , pluginPbHosts [ len ( pluginPbHosts ) - 2 ]. Id , pluginPbHosts [ len ( pluginPbHosts ) - 1 ]. Id )
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : [] * pb . Host { pluginPbHosts [ len ( pluginPbHosts ) - 2 ]},
ResponseType : "delta" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 11 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
req . ListToken = got . ListToken
// Get the second page
got , err = s . ListHosts ( ctx , req )
require . NoError ( t , err )
require . Len ( t , got . GetItems (), 1 )
assert . Empty ( t ,
cmp . Diff (
got ,
& pbs . ListHostsResponse {
Items : [] * pb . Host { pluginPbHosts [ len ( pluginPbHosts ) - 1 ]},
ResponseType : "complete" ,
ListToken : "" ,
SortBy : "created_time" ,
SortDir : "desc" ,
RemovedIds : nil ,
EstItemCount : 11 ,
},
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
protocmp . Transform (),
protocmp . IgnoreFields ( & pbs . ListHostsResponse {}, "list_token" ),
),
)
2024-02-15 09:26:29 -08:00
// Create unauthenticated user
unauthAt := authtoken . TestAuthToken ( t , conn , kms , org . GetPublicId ())
unauthR := iam . TestRole ( t , conn , proj . GetPublicId ())
_ = iam . TestUserRole ( t , conn , unauthR . GetPublicId (), unauthAt . GetIamUserId ())
// Make a request with the unauthenticated user,
// ensure the response contains the pagination parameters.
requestInfo := authpb . RequestInfo {
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
PublicId : unauthAt . GetPublicId (),
Token : unauthAt . GetToken (),
}
requestContext := context . WithValue ( context . Background (), requests . ContextRequestInformationKey , & requests . RequestContext {})
ctx := auth . NewVerifierContext ( requestContext , iamRepoFn , tokenRepoFn , serversRepoFn , kms , & requestInfo )
_ , err = s . ListHosts ( ctx , & pbs . ListHostsRequest {
HostCatalogId : phc . GetPublicId (),
})
require . Error ( t , err )
assert . ErrorIs ( t , handlers . ForbiddenError (), err )
2023-10-30 14:41:12 -07:00
})
}
2020-08-20 08:20:26 -07:00
func TestDelete ( t * testing . T ) {
t . Parallel ()
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2020-08-20 08:20:26 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
2021-03-25 03:15:43 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
_ , proj := iam . TestScopes ( t , iamRepo )
2020-08-20 08:20:26 -07:00
rw := db . New ( conn )
2021-11-02 14:06:20 -07:00
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , map [ string ] plgpb . HostPluginServiceClient {})
2021-11-02 14:06:20 -07:00
}
2020-08-20 08:20:26 -07:00
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( ctx , rw , rw , kms )
2020-08-20 08:20:26 -07:00
}
hc := static . TestCatalogs ( t , conn , proj . GetPublicId (), 1 )[ 0 ]
h := static . TestHosts ( t , conn , hc . GetPublicId (), 1 )[ 0 ]
2023-04-24 19:27:41 -04:00
plg := plugin . TestPlugin ( t , conn , "test" )
pluginHc := hostplugin . TestCatalog ( t , conn , proj . GetPublicId (), plg . GetPublicId ())
pluginH := hostplugin . TestHost ( t , conn , pluginHc . GetPublicId (), "test" )
2021-11-02 14:06:20 -07:00
2023-10-30 14:41:12 -07:00
s , err := hosts . NewService ( ctx , repoFn , pluginRepoFn , 1000 )
2020-08-20 08:20:26 -07:00
require . NoError ( t , err , "Couldn't create a new host set service." )
cases := [] struct {
2022-07-20 16:24:46 -07:00
name string
projectId string
req * pbs . DeleteHostRequest
res * pbs . DeleteHostResponse
err error
2020-08-20 08:20:26 -07:00
}{
{
2022-07-20 16:24:46 -07:00
name : "Delete an Existing Host" ,
projectId : proj . GetPublicId (),
2020-08-20 08:20:26 -07:00
req : & pbs . DeleteHostRequest {
2020-09-02 19:43:41 -07:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
},
},
2021-11-02 14:06:20 -07:00
{
2022-07-20 16:24:46 -07:00
name : "Delete a plugin Host" ,
projectId : proj . GetPublicId (),
2021-11-02 14:06:20 -07:00
req : & pbs . DeleteHostRequest {
Id : pluginH . GetPublicId (),
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-08-20 08:20:26 -07:00
{
2022-07-20 16:24:46 -07:00
name : "Delete bad id Host" ,
projectId : proj . GetPublicId (),
2020-08-20 08:20:26 -07:00
req : & pbs . DeleteHostRequest {
2023-03-10 15:06:39 -05:00
Id : globals . StaticHostPrefix + "_doesntexis" ,
2020-08-20 08:20:26 -07:00
},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . NotFound ),
2020-08-20 08:20:26 -07:00
},
{
2022-07-20 16:24:46 -07:00
name : "Bad Host Id formatting" ,
projectId : proj . GetPublicId (),
2020-08-20 08:20:26 -07:00
req : & pbs . DeleteHostRequest {
2023-03-10 15:06:39 -05:00
Id : globals . StaticHostPrefix + "_bad_format" ,
2020-08-20 08:20:26 -07:00
},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-08-20 08:20:26 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
2020-09-23 08:10:27 -07:00
assert , require := assert . New ( t ), require . New ( t )
2022-07-20 16:24:46 -07:00
got , gErr := s . DeleteHost ( auth . DisabledAuthTestContext ( iamRepoFn , tc . projectId ), tc . req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
assert . True ( errors . Is ( gErr , tc . err ), "DeleteHost(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
}
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
tc . res ,
got ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
), "DeleteHost(%q) got response %q, wanted %q" , tc . req , got , tc . res )
2020-08-20 08:20:26 -07:00
})
}
}
func TestDelete_twice ( t * testing . T ) {
t . Parallel ()
2023-06-06 17:09:08 -04:00
testCtx := context . Background ()
2020-09-23 08:10:27 -07:00
assert , require := assert . New ( t ), require . New ( t )
2020-08-20 08:20:26 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
2021-03-25 03:15:43 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
_ , proj := iam . TestScopes ( t , iamRepo )
2020-08-20 08:20:26 -07:00
rw := db . New ( conn )
2021-11-02 14:06:20 -07:00
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( testCtx , rw , rw , kms , sche , map [ string ] plgpb . HostPluginServiceClient {})
2021-11-02 14:06:20 -07:00
}
2020-08-20 08:20:26 -07:00
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( testCtx , rw , rw , kms )
2020-08-20 08:20:26 -07:00
}
hc := static . TestCatalogs ( t , conn , proj . GetPublicId (), 1 )[ 0 ]
h := static . TestHosts ( t , conn , hc . GetPublicId (), 1 )[ 0 ]
2023-10-30 14:41:12 -07:00
s , err := hosts . NewService ( testCtx , repoFn , pluginRepoFn , 1000 )
2020-09-23 08:10:27 -07:00
require . NoError ( err , "Couldn't create a new host set service." )
2020-08-20 08:20:26 -07:00
req := & pbs . DeleteHostRequest {
2020-09-02 19:43:41 -07:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
}
2021-03-25 03:15:43 -04:00
ctx := auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ())
2020-09-08 23:57:26 -04:00
_ , gErr := s . DeleteHost ( ctx , req )
2020-08-20 08:20:26 -07:00
assert . NoError ( gErr , "First attempt" )
2020-09-08 23:57:26 -04:00
_ , gErr = s . DeleteHost ( ctx , req )
2020-09-04 14:48:11 -07:00
assert . Error ( gErr , "Second attempt" )
2020-09-23 08:10:27 -07:00
assert . True ( errors . Is ( gErr , handlers . ApiErrorWithCode ( codes . NotFound )), "Expected permission denied for the second delete." )
2020-08-20 08:20:26 -07:00
}
func TestCreate ( t * testing . T ) {
t . Parallel ()
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2020-08-20 08:20:26 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
2021-03-25 03:15:43 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
org , proj := iam . TestScopes ( t , iamRepo )
2020-08-20 08:20:26 -07:00
rw := db . New ( conn )
2021-11-02 14:06:20 -07:00
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , map [ string ] plgpb . HostPluginServiceClient {})
2021-11-02 14:06:20 -07:00
}
2020-08-20 08:20:26 -07:00
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( ctx , rw , rw , kms )
2020-08-20 08:20:26 -07:00
}
hc := static . TestCatalogs ( t , conn , proj . GetPublicId (), 1 )[ 0 ]
2023-04-24 19:27:41 -04:00
plg := plugin . TestPlugin ( t , conn , "test" )
pluginHc := hostplugin . TestCatalog ( t , conn , proj . GetPublicId (), plg . GetPublicId ())
2021-11-02 14:06:20 -07:00
2021-04-23 09:13:37 -05:00
defaultHcCreated := hc . GetCreateTime (). GetTimestamp (). AsTime ()
2020-08-20 08:20:26 -07:00
cases := [] struct {
2022-06-19 10:55:37 -04:00
name string
req * pbs . CreateHostRequest
res * pbs . CreateHostResponse
err error
wantErrContains string
2020-08-20 08:20:26 -07:00
}{
{
name : "Create a valid Host" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
2020-09-02 19:43:41 -07:00
HostCatalogId : hc . GetPublicId (),
Name : & wrappers . StringValue { Value : "name" },
Description : & wrappers . StringValue { Value : "desc" },
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "123.456.789" ),
},
},
2020-08-20 08:20:26 -07:00
}},
res : & pbs . CreateHostResponse {
2023-03-10 15:06:39 -05:00
Uri : fmt . Sprintf ( "hosts/%s_" , globals . StaticHostPrefix ),
2020-08-20 08:20:26 -07:00
Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Name : & wrappers . StringValue { Value : "name" },
Description : & wrappers . StringValue { Value : "desc" },
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "123.456.789" ),
},
},
2023-11-02 16:03:47 -04:00
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
2020-08-20 08:20:26 -07:00
},
},
},
2022-06-19 10:55:37 -04:00
{
name : "no-attributes" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Name : & wrappers . StringValue { Value : "name" },
Description : & wrappers . StringValue { Value : "desc" },
Type : "static" ,
}},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : `Details: {{ name : "attributes" , desc : "This is a required field." }} ` ,
},
2021-11-02 14:06:20 -07:00
{
name : "Create a plugin Host" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
HostCatalogId : pluginHc . GetPublicId (),
Type : "plugin" ,
}},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-09-12 22:07:56 -07:00
{
name : "Create with empty address" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Name : & wrappers . StringValue { Value : "name" },
Description : & wrappers . StringValue { Value : "desc" },
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "" ),
},
},
2020-09-12 22:07:56 -07:00
}},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-09-12 22:07:56 -07:00
},
2020-08-20 08:20:26 -07:00
{
name : "Create without address" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
2020-09-02 19:43:41 -07:00
HostCatalogId : hc . GetPublicId (),
Name : & wrappers . StringValue { Value : "name" },
Description : & wrappers . StringValue { Value : "desc" },
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : nil ,
},
},
2020-08-20 08:20:26 -07:00
}},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-08-20 08:20:26 -07:00
},
{
name : "Create with unknown type" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
2020-09-02 19:43:41 -07:00
HostCatalogId : hc . GetPublicId (),
Name : & wrappers . StringValue { Value : "name" },
Description : & wrappers . StringValue { Value : "desc" },
Type : "ThisIsMadeUp" ,
2020-08-20 08:20:26 -07:00
}},
2020-09-23 08:10:27 -07:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-08-20 08:20:26 -07:00
},
{
name : "Create with no type" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
2020-09-02 19:43:41 -07:00
HostCatalogId : hc . GetPublicId (),
Name : & wrappers . StringValue { Value : "no type name" },
Description : & wrappers . StringValue { Value : "no type desc" },
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "123.456.789" ),
},
},
2020-08-20 08:20:26 -07:00
}},
2020-08-21 10:57:30 -07:00
res : & pbs . CreateHostResponse {
2023-03-10 15:06:39 -05:00
Uri : fmt . Sprintf ( "hosts/%s_" , globals . StaticHostPrefix ),
2020-08-21 10:57:30 -07:00
Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-21 10:57:30 -07:00
Name : & wrappers . StringValue { Value : "no type name" },
Description : & wrappers . StringValue { Value : "no type desc" },
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "123.456.789" ),
},
},
2023-11-02 16:03:47 -04:00
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
2020-08-21 10:57:30 -07:00
},
},
2020-08-20 08:20:26 -07:00
},
{
name : "Can't specify Id" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
2020-09-02 19:43:41 -07:00
HostCatalogId : hc . GetPublicId (),
Id : "not allowed to be set" ,
2020-08-20 08:20:26 -07:00
}},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-08-20 08:20:26 -07:00
},
2023-01-26 10:35:29 -08:00
{
name : "Can't specify port" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Name : & wrappers . StringValue { Value : "port name" },
Description : & wrappers . StringValue { Value : "port desc" },
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "123.456.789:12345" ),
},
},
}},
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2020-08-20 08:20:26 -07:00
{
name : "Can't specify Created Time" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
2020-09-02 19:43:41 -07:00
HostCatalogId : hc . GetPublicId (),
2021-04-23 09:13:37 -05:00
CreatedTime : timestamppb . Now (),
2020-08-20 08:20:26 -07:00
}},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-08-20 08:20:26 -07:00
},
{
name : "Can't specify Update Time" ,
req : & pbs . CreateHostRequest { Item : & pb . Host {
2021-04-23 09:13:37 -05:00
UpdatedTime : timestamppb . Now (),
2020-08-20 08:20:26 -07:00
}},
2020-09-23 08:10:27 -07:00
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2020-08-20 08:20:26 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
2023-10-30 14:41:12 -07:00
s , err := hosts . NewService ( ctx , repoFn , pluginRepoFn , 1000 )
2020-08-20 08:20:26 -07:00
require . NoError ( err , "Failed to create a new host set service." )
2021-03-25 03:15:43 -04:00
got , gErr := s . CreateHost ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), tc . req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
2023-01-26 10:35:29 -08:00
assert . Nil ( got )
2020-09-23 08:10:27 -07:00
assert . True ( errors . Is ( gErr , tc . err ), "CreateHost(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
2022-06-19 10:55:37 -04:00
if tc . wantErrContains != "" {
assert . Contains ( gErr . Error (), tc . wantErrContains )
}
2023-01-26 10:35:29 -08:00
return
2020-09-23 08:10:27 -07:00
}
2023-01-26 10:35:29 -08:00
require . NoError ( gErr )
require . NotNil ( got )
2020-08-20 08:20:26 -07:00
if got != nil {
assert . Contains ( got . GetUri (), tc . res . GetUri ())
2023-03-10 15:06:39 -05:00
assert . True ( strings . HasPrefix ( got . GetItem (). GetId (), globals . StaticHostPrefix ))
2021-04-23 09:13:37 -05:00
gotCreateTime := got . GetItem (). GetCreatedTime (). AsTime ()
gotUpdateTime := got . GetItem (). GetUpdatedTime (). AsTime ()
2020-08-20 08:20:26 -07:00
// Verify it is a set created after the test setup's default set
2020-08-21 10:57:30 -07:00
assert . True ( gotCreateTime . After ( defaultHcCreated ), "New host should have been created after default host. Was created %v, which is after %v" , gotCreateTime , defaultHcCreated )
assert . True ( gotUpdateTime . After ( defaultHcCreated ), "New host should have been updated after default host. Was updated %v, which is after %v" , gotUpdateTime , defaultHcCreated )
2020-08-20 08:20:26 -07:00
// Clear all values which are hard to compare against.
got . Uri , tc . res . Uri = "" , ""
got . Item . Id , tc . res . Item . Id = "" , ""
got . Item . CreatedTime , got . Item . UpdatedTime , tc . res . Item . CreatedTime , tc . res . Item . UpdatedTime = nil , nil , nil , nil
}
if tc . res != nil {
tc . res . Item . Version = 1
}
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
), "CreateHost(%q) got response %q, wanted %q" , tc . req , got , tc . res )
2020-08-20 08:20:26 -07:00
})
}
}
2021-11-15 12:22:39 -05:00
func TestUpdate_Static ( t * testing . T ) {
2020-08-20 08:20:26 -07:00
t . Parallel ()
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2020-08-20 08:20:26 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
2021-03-25 03:15:43 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
org , proj := iam . TestScopes ( t , iamRepo )
2020-08-20 08:20:26 -07:00
rw := db . New ( conn )
2021-11-02 14:06:20 -07:00
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , map [ string ] plgpb . HostPluginServiceClient {})
2021-11-02 14:06:20 -07:00
}
2020-08-20 08:20:26 -07:00
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( ctx , rw , rw , kms )
2020-08-20 08:20:26 -07:00
}
repo , err := repoFn ()
require . NoError ( t , err , "Couldn't create new static repo." )
hc := static . TestCatalogs ( t , conn , proj . GetPublicId (), 1 )[ 0 ]
2022-02-01 10:06:13 -08:00
s := static . TestSets ( t , conn , hc . GetPublicId (), 1 )[ 0 ]
2020-08-20 08:20:26 -07:00
2023-06-06 17:09:08 -04:00
h , err := static . NewHost ( ctx , hc . GetPublicId (), static . WithName ( "default" ), static . WithDescription ( "default" ), static . WithAddress ( "defaultaddress" ))
2020-08-20 08:20:26 -07:00
require . NoError ( t , err )
2023-06-06 17:09:08 -04:00
h , err = repo . CreateHost ( ctx , proj . GetPublicId (), h )
2020-08-20 08:20:26 -07:00
require . NoError ( t , err )
2022-02-01 10:06:13 -08:00
static . TestSetMembers ( t , conn , s . GetPublicId (), [] * static . Host { h })
2020-08-20 08:20:26 -07:00
var version uint32 = 1
resetHost := func () {
version ++
2023-06-06 17:09:08 -04:00
_ , _ , err = repo . UpdateHost ( ctx , proj . GetPublicId (), h , version , [] string { "Name" , "Description" , "Address" })
2020-08-20 08:20:26 -07:00
require . NoError ( t , err , "Failed to reset host." )
version ++
}
2021-04-23 09:13:37 -05:00
hCreated := h . GetCreateTime (). GetTimestamp (). AsTime ()
2020-08-20 08:20:26 -07:00
2023-10-30 14:41:12 -07:00
tested , err := hosts . NewService ( ctx , repoFn , pluginRepoFn , 1000 )
2020-08-20 08:20:26 -07:00
require . NoError ( t , err , "Failed to create a new host set service." )
cases := [] struct {
2023-01-26 10:35:29 -08:00
name string
req * pbs . UpdateHostRequest
res * pbs . UpdateHostResponse
err error
wantErrContains string
2020-08-20 08:20:26 -07:00
}{
{
name : "Update an Existing Host" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
2020-09-08 16:04:19 -07:00
Paths : [] string { "name" , "description" , "type" },
2020-08-20 08:20:26 -07:00
},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "new" },
Description : & wrappers . StringValue { Value : "desc" },
2020-09-08 16:04:19 -07:00
Type : "static" ,
2020-08-20 08:20:26 -07:00
},
},
res : & pbs . UpdateHostResponse {
Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Id : h . GetPublicId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Name : & wrappers . StringValue { Value : "new" },
Description : & wrappers . StringValue { Value : "desc" },
CreatedTime : h . GetCreateTime (). GetTimestamp (),
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "defaultaddress" ),
},
},
2023-11-02 16:03:47 -04:00
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
2022-02-01 10:06:13 -08:00
HostSetIds : [] string { s . GetPublicId ()},
2020-08-20 08:20:26 -07:00
},
},
},
{
name : "Multiple Paths in single string" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
2020-09-08 16:04:19 -07:00
Paths : [] string { "name,description,type" },
2020-08-20 08:20:26 -07:00
},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "new" },
Description : & wrappers . StringValue { Value : "desc" },
2020-09-08 16:04:19 -07:00
Type : "static" ,
2020-08-20 08:20:26 -07:00
},
},
res : & pbs . UpdateHostResponse {
Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Id : h . GetPublicId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Name : & wrappers . StringValue { Value : "new" },
Description : & wrappers . StringValue { Value : "desc" },
CreatedTime : h . GetCreateTime (). GetTimestamp (),
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "defaultaddress" ),
},
},
2023-11-02 16:03:47 -04:00
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
2022-02-01 10:06:13 -08:00
HostSetIds : [] string { s . GetPublicId ()},
2020-08-20 08:20:26 -07:00
},
},
},
{
name : "No Update Mask" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "updated name" },
Description : & wrappers . StringValue { Value : "updated desc" },
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "UpdateMask not provided" ,
2020-08-20 08:20:26 -07:00
},
2020-09-08 16:04:19 -07:00
{
2023-01-26 10:35:29 -08:00
name : "Changing Type" ,
2020-09-08 16:04:19 -07:00
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-09-08 16:04:19 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name,type" },
},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "updated name" },
Type : "ec2" ,
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "Cannot modify the resource type" ,
2020-09-08 16:04:19 -07:00
},
2020-08-20 08:20:26 -07:00
{
name : "Empty Path" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask { Paths : [] string {}},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "updated name" },
Description : & wrappers . StringValue { Value : "updated desc" },
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "No valid fields provided" ,
2020-08-20 08:20:26 -07:00
},
{
2023-01-26 10:35:29 -08:00
name : "Only non-existent paths in Mask" ,
2020-08-20 08:20:26 -07:00
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2024-02-16 08:30:16 -05:00
UpdateMask : & field_mask . FieldMask { Paths : [] string { "nonexistent_field" }},
2020-08-20 08:20:26 -07:00
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "updated name" },
Description : & wrappers . StringValue { Value : "updated desc" },
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "No valid fields provided" ,
2020-08-20 08:20:26 -07:00
},
{
name : "Unset Name" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" },
},
Item : & pb . Host {
Description : & wrappers . StringValue { Value : "ignored" },
},
},
res : & pbs . UpdateHostResponse {
Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Id : h . GetPublicId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Description : & wrappers . StringValue { Value : "default" },
CreatedTime : h . GetCreateTime (). GetTimestamp (),
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "defaultaddress" ),
},
},
2023-11-02 16:03:47 -04:00
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
2022-02-01 10:06:13 -08:00
HostSetIds : [] string { s . GetPublicId ()},
2020-08-20 08:20:26 -07:00
},
},
},
{
name : "Unset Description" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "description" },
},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "ignored" },
},
},
res : & pbs . UpdateHostResponse {
Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Id : h . GetPublicId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Name : & wrappers . StringValue { Value : "default" },
CreatedTime : h . GetCreateTime (). GetTimestamp (),
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "defaultaddress" ),
},
},
2023-11-02 16:03:47 -04:00
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
2022-02-01 10:06:13 -08:00
HostSetIds : [] string { s . GetPublicId ()},
2020-08-20 08:20:26 -07:00
},
},
},
{
name : "Update Only Name" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" },
},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "updated" },
Description : & wrappers . StringValue { Value : "ignored" },
},
},
res : & pbs . UpdateHostResponse {
Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Id : h . GetPublicId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Name : & wrappers . StringValue { Value : "updated" },
Description : & wrappers . StringValue { Value : "default" },
CreatedTime : h . GetCreateTime (). GetTimestamp (),
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "defaultaddress" ),
},
},
2023-11-02 16:03:47 -04:00
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
2022-02-01 10:06:13 -08:00
HostSetIds : [] string { s . GetPublicId ()},
2020-08-20 08:20:26 -07:00
},
},
},
{
name : "Update Only Description" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "description" },
},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "ignored" },
Description : & wrappers . StringValue { Value : "notignored" },
},
},
res : & pbs . UpdateHostResponse {
Item : & pb . Host {
HostCatalogId : hc . GetPublicId (),
Id : h . GetPublicId (),
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Name : & wrappers . StringValue { Value : "default" },
Description : & wrappers . StringValue { Value : "notignored" },
CreatedTime : h . GetCreateTime (). GetTimestamp (),
Type : "static" ,
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "defaultaddress" ),
},
},
2023-11-02 16:03:47 -04:00
AuthorizedActions : testAuthorizedActions [ static . Subtype ],
2022-02-01 10:06:13 -08:00
HostSetIds : [] string { s . GetPublicId ()},
2020-08-20 08:20:26 -07:00
},
},
},
{
name : "Update a Non Existing Host" ,
req : & pbs . UpdateHostRequest {
2023-03-10 15:06:39 -05:00
Id : globals . StaticHostPrefix + "_DoesntExis" ,
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "description" },
},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "new" },
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Description : & wrappers . StringValue { Value : "desc" },
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . NotFound ),
wantErrContains : "Resource not found" ,
2020-08-20 08:20:26 -07:00
},
{
name : "Cant change Id" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "id" },
},
Item : & pb . Host {
Id : "p_somethinge" ,
2021-03-25 03:15:43 -04:00
Scope : & scopes . ScopeInfo { Id : proj . GetPublicId (), Type : scope . Project . String (), ParentScopeId : org . GetPublicId ()},
2020-08-20 08:20:26 -07:00
Name : & wrappers . StringValue { Value : "new" },
Description : & wrappers . StringValue { Value : "new desc" },
2021-01-07 10:02:32 -05:00
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "This is a read only field" ,
2020-08-20 08:20:26 -07:00
},
2020-09-12 22:07:56 -07:00
{
name : "Cant unset address" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-09-12 22:07:56 -07:00
UpdateMask : & field_mask . FieldMask {
2023-01-26 10:35:29 -08:00
Paths : [] string { globals . AttributesAddressField },
2020-09-12 22:07:56 -07:00
},
Item : & pb . Host {
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : nil ,
},
},
2021-01-07 10:02:32 -05:00
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "Address length must be" ,
2020-09-12 22:07:56 -07:00
},
{
name : "Cant set address to empty string" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-09-12 22:07:56 -07:00
UpdateMask : & field_mask . FieldMask {
2023-01-26 10:35:29 -08:00
Paths : [] string { globals . AttributesAddressField },
2020-09-12 22:07:56 -07:00
},
Item : & pb . Host {
2022-04-13 12:56:31 -04:00
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "" ),
},
},
2021-01-07 10:02:32 -05:00
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "Address length must be" ,
},
{
name : "Cant specify port in address" ,
req : & pbs . UpdateHostRequest {
Id : h . GetPublicId (),
UpdateMask : & field_mask . FieldMask {
Paths : [] string { globals . AttributesAddressField },
},
Item : & pb . Host {
Name : & wrappers . StringValue { Value : "port name" },
Description : & wrappers . StringValue { Value : "port desc" },
Attrs : & pb . Host_StaticHostAttributes {
StaticHostAttributes : & pb . StaticHostAttributes {
Address : wrapperspb . String ( "123.456.789:12345" ),
},
},
},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "does not support a port" ,
2020-09-12 22:07:56 -07:00
},
2020-08-20 08:20:26 -07:00
{
name : "Cant specify Created Time" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "created_time" },
},
Item : & pb . Host {
2021-04-23 09:13:37 -05:00
CreatedTime : timestamppb . Now (),
2020-08-20 08:20:26 -07:00
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "This is a read only field" ,
2020-08-20 08:20:26 -07:00
},
{
name : "Cant specify Updated Time" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "updated_time" },
},
Item : & pb . Host {
2021-04-23 09:13:37 -05:00
UpdatedTime : timestamppb . Now (),
2020-08-20 08:20:26 -07:00
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "This is a read only field" ,
2020-08-20 08:20:26 -07:00
},
{
name : "Valid mask, cant specify type" ,
req : & pbs . UpdateHostRequest {
2023-01-26 10:35:29 -08:00
Id : h . GetPublicId (),
2020-08-20 08:20:26 -07:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" },
},
Item : & pb . Host {
Type : "Unknown" ,
},
},
2023-01-26 10:35:29 -08:00
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
wantErrContains : "Cannot modify the resource type" ,
2020-08-20 08:20:26 -07:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
tc . req . Item . Version = version
2023-01-26 10:35:29 -08:00
req := tc . req
2020-08-20 08:20:26 -07:00
// Test some bad versions
req . Item . Version = version + 2
2021-03-25 03:15:43 -04:00
_ , gErr := tested . UpdateHost ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), req )
2020-08-20 08:20:26 -07:00
require . Error ( gErr )
req . Item . Version = version - 1
2021-03-25 03:15:43 -04:00
_ , gErr = tested . UpdateHost ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), req )
2020-08-20 08:20:26 -07:00
require . Error ( gErr )
req . Item . Version = version
2021-03-25 03:15:43 -04:00
got , gErr := tested . UpdateHost ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), req )
2020-09-23 08:10:27 -07:00
if tc . err != nil {
require . Error ( gErr )
2023-01-26 10:35:29 -08:00
assert . Nil ( got )
2020-09-23 08:10:27 -07:00
assert . True ( errors . Is ( gErr , tc . err ), "UpdateHost(%+v) got error %v, wanted %v" , req , gErr , tc . err )
2023-01-26 10:35:29 -08:00
if tc . wantErrContains != "" {
assert . Contains ( gErr . Error (), tc . wantErrContains )
}
return
2020-09-23 08:10:27 -07:00
}
2020-08-20 08:20:26 -07:00
2023-01-26 10:35:29 -08:00
defer resetHost ()
require . NoError ( gErr )
require . NotNil ( got )
2020-08-20 08:20:26 -07:00
2023-01-26 10:35:29 -08:00
require . NotNilf ( tc . res , "Expected UpdateHost response to be nil, but was %v" , got )
gotUpdateTime := got . GetItem (). GetUpdatedTime (). AsTime ()
// Verify it is a set updated after it was created
assert . True ( gotUpdateTime . After ( hCreated ), "Updated set should have been updated after its creation. Was updated %v, which is after %v" , gotUpdateTime , hCreated )
2020-08-20 08:20:26 -07:00
2023-01-26 10:35:29 -08:00
// Clear all values which are hard to compare against.
got . Item . UpdatedTime , tc . res . Item . UpdatedTime = nil , nil
tc . res . Item . Version = version + 1
2023-10-31 13:44:17 +00:00
assert . Empty ( cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
), "UpdateHost(%q) got response %q, wanted %q" , req , got , tc . res )
2020-08-20 08:20:26 -07:00
})
}
}
2021-11-02 14:06:20 -07:00
func TestUpdate_Plugin ( t * testing . T ) {
t . Parallel ()
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2021-11-02 14:06:20 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
iamRepo := iam . TestRepo ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iamRepo , nil
}
_ , proj := iam . TestScopes ( t , iamRepo )
rw := db . New ( conn )
sche := scheduler . TestScheduler ( t , conn , wrapper )
2023-04-24 19:27:41 -04:00
pluginRepoFn := func () ( * hostplugin . Repository , error ) {
2023-06-06 17:09:08 -04:00
return hostplugin . NewRepository ( ctx , rw , rw , kms , sche , map [ string ] plgpb . HostPluginServiceClient {})
2021-11-02 14:06:20 -07:00
}
repoFn := func () ( * static . Repository , error ) {
2023-06-06 17:09:08 -04:00
return static . NewRepository ( ctx , rw , rw , kms )
2021-11-02 14:06:20 -07:00
}
2023-04-24 19:27:41 -04:00
plg := plugin . TestPlugin ( t , conn , "test" )
hc := hostplugin . TestCatalog ( t , conn , proj . GetPublicId (), plg . GetPublicId ())
h := hostplugin . TestHost ( t , conn , hc . GetPublicId (), "test" )
2021-11-02 14:06:20 -07:00
2023-10-30 14:41:12 -07:00
tested , err := hosts . NewService ( ctx , repoFn , pluginRepoFn , 1000 )
2021-11-02 14:06:20 -07:00
require . NoError ( t , err )
got , err := tested . UpdateHost ( auth . DisabledAuthTestContext ( iamRepoFn , proj . GetPublicId ()), & pbs . UpdateHostRequest {
Id : h . GetPublicId (),
Item : & pb . Host { Name : wrapperspb . String ( "foo" )},
UpdateMask : & field_mask . FieldMask { Paths : [] string { "name" }},
})
assert . Nil ( t , got )
require . Error ( t , err )
assert . True ( t , errors . Is ( err , handlers . ApiErrorWithCode ( codes . InvalidArgument )))
}