Files
threshold/internal/servers/worker_test.go
T
Todd a281d10206 Add worker config table and view (#2090)
* Remove the server_id from session table, change it to worker_id on session_connection

This is step 1 in updating the worker table.  The worker is becoming a public resource so it must have
a public id.  We drop the server_id column on the session_connection table and add the worker_id column
so we can use the wt_public_key type.  Since db migrations are applied while the controller is offline,
it should be safe to assume all session connections are not in a running state, thus allowing us to null
out all the worker ids in the session_connection table.

For now we don't have very good enforcement of the wt_public_id constraints, since the id is currently
defined in the worker config, but this will soon change and the worker's id will be generated by the
controller.
2022-05-24 15:08:02 -07:00

396 lines
9.4 KiB
Go

package servers
import (
"context"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/servers/store"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/testing/protocmp"
)
func TestWorkerCanonicalAddress(t *testing.T) {
worker := NewWorker(scope.Global.String())
worker.ReportedStatus = NewWorkerStatus("foo", WithAddress("status"))
assert.Equal(t, "status", worker.CanonicalAddress())
worker.Address = "worker"
assert.Equal(t, "worker", worker.CanonicalAddress())
}
func TestWorkerCanonicalTags(t *testing.T) {
w := NewWorker(scope.Global.String(),
WithWorkerTags(
&Tag{Key: "key", Value: "apis unique"},
&Tag{Key: "key", Value: "shared"},
&Tag{Key: "key2", Value: "apis key2 unique"},
))
w.ReportedStatus = NewWorkerStatus("",
WithWorkerTags(
&Tag{Key: "key", Value: "configs unique"},
&Tag{Key: "key", Value: "shared"},
&Tag{Key: "key3", Value: "configs key3 unique"},
))
got := w.CanonicalTags()
assert.Len(t, got, 3, "2 keys expected, 'key' and 'key2'")
assert.ElementsMatch(t, got["key"], []string{"shared", "apis unique", "configs unique"})
assert.ElementsMatch(t, got["key2"], []string{"apis key2 unique"})
assert.ElementsMatch(t, got["key3"], []string{"configs key3 unique"})
}
func TestWorkerAggregate(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
ctx := context.Background()
getAggWorker := func(id string) *Worker {
agg := &workerAggregate{PublicId: id}
require.NoError(t, rw.LookupById(ctx, agg))
got, err := agg.toWorker(ctx)
assert.NoError(t, err)
return got
}
// Worker without a status
{
id, err := newWorkerId(ctx)
require.NoError(t, err)
require.NoError(t, rw.Create(ctx,
NewWorker(scope.Global.String(),
WithPublicId(id),
WithName(id),
WithAddress("address"))))
got := getAggWorker(id)
assert.Equal(t, id, got.GetPublicId())
assert.Equal(t, scope.Global.String(), got.GetScopeId())
assert.Equal(t, id, got.GetName())
assert.Equal(t, "address", got.GetAddress())
assert.Equal(t, uint32(1), got.GetVersion())
assert.Nil(t, got.ReportedStatus)
assert.Empty(t, got.CanonicalTags())
}
// Worker with status
{
id, err := newWorkerId(ctx)
require.NoError(t, err)
require.NoError(t, rw.Create(ctx,
NewWorker(scope.Global.String(), WithPublicId(id))))
require.NoError(t, rw.Create(ctx,
NewWorkerStatus(id,
WithAddress("address"),
WithName(id))))
got := getAggWorker(id)
assert.Equal(t, id, got.GetPublicId())
assert.Equal(t, uint32(1), got.GetVersion())
assert.NotNil(t, got.ReportedStatus)
assert.Equal(t, id, got.ReportedStatus.GetWorkerId())
assert.Equal(t, id, got.ReportedStatus.GetName())
assert.NotNil(t, got.ReportedStatus.CreateTime)
assert.NotNil(t, got.ReportedStatus.UpdateTime)
assert.Equal(t, "address", got.ReportedStatus.GetAddress())
}
// Worker with a config tag
{
id, err := newWorkerId(ctx)
require.NoError(t, err)
require.NoError(t, rw.Create(ctx,
NewWorker(scope.Global.String(), WithPublicId(id))))
require.NoError(t, rw.Create(ctx,
NewWorkerStatus(id, WithAddress("address"))))
require.NoError(t, rw.Create(ctx,
&store.WorkerTag{
WorkerId: id,
Key: "key",
Value: "val",
Source: ConfigurationTagSource.String(),
}))
got := getAggWorker(id)
assert.Equal(t, id, got.GetPublicId())
assert.Equal(t, uint32(1), got.GetVersion())
assert.NotNil(t, got.ReportedStatus)
assert.Empty(t, got.Tags)
assert.Equal(t, got.ReportedStatus.Tags, []*Tag{{Key: "key", Value: "val"}})
}
// Worker with many config tag
{
id, err := newWorkerId(ctx)
require.NoError(t, err)
require.NoError(t, rw.Create(ctx,
NewWorker(scope.Global.String(), WithPublicId(id))))
require.NoError(t, rw.Create(ctx,
NewWorkerStatus(id, WithAddress("address"))))
require.NoError(t, rw.Create(ctx, &store.WorkerTag{
WorkerId: id,
Key: "key",
Value: "val",
Source: ConfigurationTagSource.String(),
}))
require.NoError(t, rw.Create(ctx, &store.WorkerTag{
WorkerId: id,
Key: "key",
Value: "val2",
Source: ConfigurationTagSource.String(),
}))
require.NoError(t, rw.Create(ctx, &store.WorkerTag{
WorkerId: id,
Key: "key2",
Value: "val2",
Source: ConfigurationTagSource.String(),
}))
got := getAggWorker(id)
require.NotNil(t, got.ReportedStatus)
assert.Empty(t, got.Tags)
assert.ElementsMatch(t, got.ReportedStatus.Tags, []*Tag{
{Key: "key", Value: "val"},
{Key: "key", Value: "val2"},
{Key: "key2", Value: "val2"},
})
}
// Worker with an api tag
{
id, err := newWorkerId(ctx)
require.NoError(t, err)
require.NoError(t, rw.Create(ctx,
NewWorker(scope.Global.String(), WithPublicId(id))))
require.NoError(t, rw.Create(ctx,
NewWorkerStatus(id, WithAddress("address"))))
require.NoError(t, rw.Create(ctx,
&store.WorkerTag{
WorkerId: id,
Key: "key",
Value: "val",
Source: ApiTagSource.String(),
}))
got := getAggWorker(id)
assert.Equal(t, id, got.GetPublicId())
assert.Equal(t, uint32(1), got.GetVersion())
assert.NotNil(t, got.ReportedStatus)
assert.Empty(t, got.ReportedStatus.Tags)
assert.Equal(t, got.Tags, []*Tag{{Key: "key", Value: "val"}})
}
// Worker with mix of tag sources
{
id, err := newWorkerId(ctx)
require.NoError(t, err)
require.NoError(t, rw.Create(ctx,
NewWorker(scope.Global.String(), WithPublicId(id))))
require.NoError(t, rw.Create(ctx,
NewWorkerStatus(id, WithAddress("address"))))
require.NoError(t, rw.Create(ctx, &store.WorkerTag{
WorkerId: id,
Key: "key",
Value: "val",
Source: ConfigurationTagSource.String(),
}))
require.NoError(t, rw.Create(ctx, &store.WorkerTag{
WorkerId: id,
Key: "key",
Value: "val2",
Source: ApiTagSource.String(),
}))
require.NoError(t, rw.Create(ctx, &store.WorkerTag{
WorkerId: id,
Key: "key2",
Value: "val2",
Source: ApiTagSource.String(),
}))
got := getAggWorker(id)
require.NotNil(t, got.ReportedStatus)
assert.ElementsMatch(t, got.Tags, []*Tag{
{Key: "key", Value: "val2"},
{Key: "key2", Value: "val2"},
})
assert.ElementsMatch(t, got.ReportedStatus.Tags, []*Tag{
{Key: "key", Value: "val"},
})
}
}
func TestWorker_New(t *testing.T) {
t.Parallel()
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
rw := db.New(conn)
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
type args struct {
scopeId string
opts []Option
}
tests := []struct {
name string
args args
want *Worker
wantCreateErr bool
}{
{
name: "missing-scope-id",
args: args{},
want: &Worker{
Worker: &store.Worker{},
},
wantCreateErr: true,
},
{
name: "global-scope-id",
args: args{
scopeId: scope.Global.String(),
},
want: &Worker{
Worker: &store.Worker{
ScopeId: scope.Global.String(),
},
},
},
{
name: "org-scope-id",
args: args{
scopeId: org.GetPublicId(),
},
want: &Worker{
Worker: &store.Worker{
ScopeId: org.GetPublicId(),
},
},
wantCreateErr: true,
},
{
name: "project-scope-id",
args: args{
scopeId: prj.GetPublicId(),
},
want: &Worker{
Worker: &store.Worker{
ScopeId: prj.GetPublicId(),
},
},
wantCreateErr: true,
},
{
name: "with public id",
args: args{
scopeId: scope.Global.String(),
opts: []Option{
WithPublicId("w_test_public_id"),
},
},
want: &Worker{
Worker: &store.Worker{
PublicId: "w_test_public_id",
ScopeId: scope.Global.String(),
},
},
},
{
name: "with name",
args: args{
scopeId: scope.Global.String(),
opts: []Option{
WithName("foo"),
},
},
want: &Worker{
Worker: &store.Worker{
ScopeId: scope.Global.String(),
Name: "foo",
},
},
},
{
name: "with description",
args: args{
scopeId: scope.Global.String(),
opts: []Option{
WithDescription("foo"),
},
},
want: &Worker{
Worker: &store.Worker{
ScopeId: scope.Global.String(),
Description: "foo",
},
},
},
{
name: "with address",
args: args{
scopeId: scope.Global.String(),
opts: []Option{
WithAddress("foo"),
},
},
want: &Worker{
Worker: &store.Worker{
ScopeId: scope.Global.String(),
Address: "foo",
},
},
},
{
name: "with Tags",
args: args{
scopeId: scope.Global.String(),
opts: []Option{
WithWorkerTags(&Tag{
Key: "key",
Value: "val",
}),
},
},
want: &Worker{
Worker: &store.Worker{
ScopeId: scope.Global.String(),
},
Tags: []*Tag{
{
Key: "key",
Value: "val",
},
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)
got := NewWorker(tt.args.scopeId, tt.args.opts...)
assert.Empty(cmp.Diff(tt.want, got.clone(), protocmp.Transform()))
id, err := newWorkerId(context.Background())
assert.NoError(err)
tt.want.PublicId = id
got.PublicId = id
err2 := rw.Create(context.Background(), got)
if tt.wantCreateErr {
assert.Error(err2)
} else {
assert.NoError(err2)
assert.Equal(uint32(1), got.Version)
}
})
}
}