1393 lines
42 KiB
Go
1393 lines
42 KiB
Go
|
|
package eula_test
|
||
|
|
|
||
|
|
import (
|
||
|
|
"os"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"queryorchestration/internal/database/repository"
|
||
|
|
"queryorchestration/internal/eula"
|
||
|
|
"queryorchestration/internal/serviceconfig"
|
||
|
|
"queryorchestration/internal/test"
|
||
|
|
"queryorchestration/internal/usermanagement"
|
||
|
|
|
||
|
|
"github.com/aws/aws-sdk-go-v2/config"
|
||
|
|
"github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider"
|
||
|
|
"github.com/google/uuid"
|
||
|
|
"github.com/jackc/pgx/v5/pgtype"
|
||
|
|
"github.com/stretchr/testify/assert"
|
||
|
|
"github.com/stretchr/testify/require"
|
||
|
|
)
|
||
|
|
|
||
|
|
// TestConfig embeds BaseConfig for test database setup.
|
||
|
|
type TestConfig struct {
|
||
|
|
serviceconfig.BaseConfig
|
||
|
|
}
|
||
|
|
|
||
|
|
// ptrTime is a helper to create a pointer to a time.Time value.
|
||
|
|
func ptrTime(t time.Time) *time.Time {
|
||
|
|
return &t
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestCreateVersion(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
t.Run("create version successfully", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "1.0.0-test-" + uuid.New().String()[:8],
|
||
|
|
Title: "Test EULA v1.0",
|
||
|
|
Content: "# Terms and Conditions\n\nThis is the EULA content.",
|
||
|
|
EffectiveDate: ptrTime(time.Now().Add(24 * time.Hour)),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.NotNil(t, result)
|
||
|
|
assert.Equal(t, input.Version, result.Version)
|
||
|
|
assert.Equal(t, input.Title, result.Title)
|
||
|
|
assert.Equal(t, input.Content, result.Content)
|
||
|
|
assert.Equal(t, input.CreatedBy, result.Createdby)
|
||
|
|
assert.False(t, result.Iscurrent)
|
||
|
|
assert.NotEqual(t, uuid.Nil, result.ID)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty version string", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "",
|
||
|
|
Title: "Test EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "version string cannot be empty")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty title", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "2.0.0",
|
||
|
|
Title: "",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "title cannot be empty")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty content", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "2.0.0",
|
||
|
|
Title: "Title",
|
||
|
|
Content: "",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "content cannot be empty")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty createdBy", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "2.0.0",
|
||
|
|
Title: "Title",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "createdBy cannot be empty")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject duplicate version string", func(t *testing.T) {
|
||
|
|
uniqueVersion := "dup-" + uuid.New().String()[:8]
|
||
|
|
input1 := &eula.CreateVersionInput{
|
||
|
|
Version: uniqueVersion,
|
||
|
|
Title: "First EULA",
|
||
|
|
Content: "Content 1",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.CreateVersion(ctx, input1)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
input2 := &eula.CreateVersionInput{
|
||
|
|
Version: uniqueVersion,
|
||
|
|
Title: "Second EULA",
|
||
|
|
Content: "Content 2",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err = svc.CreateVersion(ctx, input2)
|
||
|
|
require.Error(t, err)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetVersionByID(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
t.Run("get existing version", func(t *testing.T) {
|
||
|
|
// Create a version first
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "getbyid-" + uuid.New().String()[:8],
|
||
|
|
Title: "Test EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
created, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Retrieve it
|
||
|
|
result, err := svc.GetVersionByID(ctx, created.ID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, created.ID, result.ID)
|
||
|
|
assert.Equal(t, created.Version, result.Version)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("return ErrVersionNotFound for non-existent ID", func(t *testing.T) {
|
||
|
|
nonExistentID := uuid.New()
|
||
|
|
_, err := svc.GetVersionByID(ctx, nonExistentID)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.ErrorIs(t, err, eula.ErrVersionNotFound)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestListVersions(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Create multiple versions
|
||
|
|
for i := 0; i < 5; i++ {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "list-" + uuid.New().String()[:8],
|
||
|
|
Title: "List EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
_, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
t.Run("list with pagination", func(t *testing.T) {
|
||
|
|
result, err := svc.ListVersions(ctx, &eula.ListVersionsInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 3,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.LessOrEqual(t, len(result.Versions), 3)
|
||
|
|
assert.GreaterOrEqual(t, result.Total, int64(5))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("apply default pagination values", func(t *testing.T) {
|
||
|
|
result, err := svc.ListVersions(ctx, &eula.ListVersionsInput{
|
||
|
|
Page: 0,
|
||
|
|
PageSize: 0,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.LessOrEqual(t, len(result.Versions), 20)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("cap page size at 100", func(t *testing.T) {
|
||
|
|
result, err := svc.ListVersions(ctx, &eula.ListVersionsInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 500,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.LessOrEqual(t, len(result.Versions), 100)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestUpdateVersion(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
t.Run("update title only", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "update-" + uuid.New().String()[:8],
|
||
|
|
Title: "Original Title",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
created, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
newTitle := "Updated Title"
|
||
|
|
updated, err := svc.UpdateVersion(ctx, created.ID, &eula.UpdateVersionInput{
|
||
|
|
Title: &newTitle,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, newTitle, updated.Title)
|
||
|
|
assert.Equal(t, created.Content, updated.Content) // Content unchanged
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("update effective date only", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "update2-" + uuid.New().String()[:8],
|
||
|
|
Title: "Title",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
created, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
newDate := time.Now().Add(48 * time.Hour)
|
||
|
|
updated, err := svc.UpdateVersion(ctx, created.ID, &eula.UpdateVersionInput{
|
||
|
|
EffectiveDate: &newDate,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.WithinDuration(t, newDate, updated.Effectivedate.Time, time.Second)
|
||
|
|
assert.Equal(t, created.Title, updated.Title) // Title unchanged
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("return error for non-existent version", func(t *testing.T) {
|
||
|
|
newTitle := "Updated Title"
|
||
|
|
_, err := svc.UpdateVersion(ctx, uuid.New(), &eula.UpdateVersionInput{
|
||
|
|
Title: &newTitle,
|
||
|
|
})
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.ErrorIs(t, err, eula.ErrVersionNotFound)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestActivateVersion(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
t.Run("activate version successfully", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "activate-" + uuid.New().String()[:8],
|
||
|
|
Title: "Activate EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
created, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.False(t, created.Iscurrent)
|
||
|
|
|
||
|
|
// Activate it
|
||
|
|
activated, err := svc.ActivateVersion(ctx, created.ID, "activator@test.com")
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.True(t, activated.Iscurrent)
|
||
|
|
assert.NotNil(t, activated.Activatedby)
|
||
|
|
assert.Equal(t, "activator@test.com", *activated.Activatedby)
|
||
|
|
assert.True(t, activated.Activatedat.Valid)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("activating new version deactivates previous", func(t *testing.T) {
|
||
|
|
// Create and activate first version
|
||
|
|
input1 := &eula.CreateVersionInput{
|
||
|
|
Version: "first-" + uuid.New().String()[:8],
|
||
|
|
Title: "First EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
first, err := svc.CreateVersion(ctx, input1)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
_, err = svc.ActivateVersion(ctx, first.ID, "admin@test.com")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Create and activate second version
|
||
|
|
input2 := &eula.CreateVersionInput{
|
||
|
|
Version: "second-" + uuid.New().String()[:8],
|
||
|
|
Title: "Second EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
second, err := svc.CreateVersion(ctx, input2)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
_, err = svc.ActivateVersion(ctx, second.ID, "admin@test.com")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Verify first is no longer current
|
||
|
|
firstAfter, err := svc.GetVersionByID(ctx, first.ID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.False(t, firstAfter.Iscurrent)
|
||
|
|
|
||
|
|
// Verify second is current
|
||
|
|
secondAfter, err := svc.GetVersionByID(ctx, second.ID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.True(t, secondAfter.Iscurrent)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("return error for non-existent version", func(t *testing.T) {
|
||
|
|
_, err := svc.ActivateVersion(ctx, uuid.New(), "admin@test.com")
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.ErrorIs(t, err, eula.ErrVersionNotFound)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetCurrentVersion(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
t.Run("return current version after activation", func(t *testing.T) {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "current-" + uuid.New().String()[:8],
|
||
|
|
Title: "Current EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
created, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
_, err = svc.ActivateVersion(ctx, created.ID, "admin@test.com")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
current, err := svc.GetCurrentVersion(ctx)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, created.ID, current.ID)
|
||
|
|
assert.True(t, current.Iscurrent)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRecordAgreement(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Create and activate a version for agreements
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "agree-" + uuid.New().String()[:8],
|
||
|
|
Title: "Agreement EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
version, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("record agreement successfully", func(t *testing.T) {
|
||
|
|
userSubject := "user-" + uuid.New().String()[:8]
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: userSubject,
|
||
|
|
UserEmail: "user@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.NotNil(t, result)
|
||
|
|
assert.False(t, result.AlreadyAgreed)
|
||
|
|
assert.Equal(t, userSubject, result.Agreement.Cognitosubjectid)
|
||
|
|
assert.Equal(t, version.ID, result.Agreement.Eulaversionid)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("idempotent - return existing agreement if already agreed", func(t *testing.T) {
|
||
|
|
userSubject := "idempotent-" + uuid.New().String()[:8]
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: userSubject,
|
||
|
|
UserEmail: "idempotent@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1.2",
|
||
|
|
}
|
||
|
|
|
||
|
|
// First agreement
|
||
|
|
result1, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.False(t, result1.AlreadyAgreed)
|
||
|
|
|
||
|
|
// Second agreement (same user, same version)
|
||
|
|
result2, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.True(t, result2.AlreadyAgreed)
|
||
|
|
assert.Equal(t, result1.Agreement.ID, result2.Agreement.ID)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty cognitoSubjectID", func(t *testing.T) {
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: "",
|
||
|
|
UserEmail: "user@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "cognitoSubjectID cannot be empty")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty userEmail", func(t *testing.T) {
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: "user123",
|
||
|
|
UserEmail: "",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "userEmail cannot be empty")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject nil eulaVersionID", func(t *testing.T) {
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: "user123",
|
||
|
|
UserEmail: "user@test.com",
|
||
|
|
EulaVersionID: uuid.Nil,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "eulaVersionID cannot be nil")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty ipAddress", func(t *testing.T) {
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: "user123",
|
||
|
|
UserEmail: "user@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "",
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "ipAddress cannot be empty")
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestHasUserAgreedToCurrent(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Create and activate a version
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "hasagreed-" + uuid.New().String()[:8],
|
||
|
|
Title: "Has Agreed EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
version, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
_, err = svc.ActivateVersion(ctx, version.ID, "admin@test.com")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("return false for user who has not agreed", func(t *testing.T) {
|
||
|
|
hasAgreed, err := svc.HasUserAgreedToCurrent(ctx, "non-existent-user")
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.False(t, hasAgreed)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("return true for user who has agreed", func(t *testing.T) {
|
||
|
|
userSubject := "agreed-user-" + uuid.New().String()[:8]
|
||
|
|
|
||
|
|
// Record agreement
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: userSubject,
|
||
|
|
UserEmail: "agreed@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
}
|
||
|
|
_, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Check if agreed
|
||
|
|
hasAgreed, err := svc.HasUserAgreedToCurrent(ctx, userSubject)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.True(t, hasAgreed)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetUserEulaStatus(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Create and activate a version
|
||
|
|
versionStr := "status-" + uuid.New().String()[:8]
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: versionStr,
|
||
|
|
Title: "Status EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
version, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
_, err = svc.ActivateVersion(ctx, version.ID, "admin@test.com")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("return status for user who has not agreed", func(t *testing.T) {
|
||
|
|
status, err := svc.GetUserEulaStatus(ctx, "new-user-"+uuid.New().String()[:8])
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.False(t, status.HasAgreed)
|
||
|
|
assert.Equal(t, versionStr, status.CurrentVersion)
|
||
|
|
assert.Equal(t, version.ID, status.CurrentVersionID)
|
||
|
|
assert.Nil(t, status.AgreedAt)
|
||
|
|
assert.Nil(t, status.AgreedVersion)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("return status for user who has agreed", func(t *testing.T) {
|
||
|
|
userSubject := "status-user-" + uuid.New().String()[:8]
|
||
|
|
|
||
|
|
// Record agreement
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: userSubject,
|
||
|
|
UserEmail: "status@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
}
|
||
|
|
_, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Get status
|
||
|
|
status, err := svc.GetUserEulaStatus(ctx, userSubject)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.True(t, status.HasAgreed)
|
||
|
|
assert.Equal(t, versionStr, status.CurrentVersion)
|
||
|
|
assert.NotNil(t, status.AgreedAt)
|
||
|
|
assert.NotNil(t, status.AgreedVersion)
|
||
|
|
assert.Equal(t, versionStr, *status.AgreedVersion)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestListAgreements(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Create a version for agreements
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "listagreements-" + uuid.New().String()[:8],
|
||
|
|
Title: "List Agreements EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
version, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Create multiple agreements
|
||
|
|
for i := 0; i < 5; i++ {
|
||
|
|
userSubject := "list-user-" + uuid.New().String()[:8]
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: userSubject,
|
||
|
|
UserEmail: userSubject + "@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1." + string(rune('1'+i)),
|
||
|
|
}
|
||
|
|
_, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
t.Run("list with pagination", func(t *testing.T) {
|
||
|
|
result, err := svc.ListAgreements(ctx, &eula.ListAgreementsInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 3,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.LessOrEqual(t, len(result.Agreements), 3)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("filter by version ID", func(t *testing.T) {
|
||
|
|
result, err := svc.ListAgreements(ctx, &eula.ListAgreementsInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 20,
|
||
|
|
VersionID: &version.ID,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.GreaterOrEqual(t, len(result.Agreements), 5)
|
||
|
|
for _, a := range result.Agreements {
|
||
|
|
assert.Equal(t, version.ID, a.Eulaversionid)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("apply default pagination values", func(t *testing.T) {
|
||
|
|
result, err := svc.ListAgreements(ctx, &eula.ListAgreementsInput{
|
||
|
|
Page: 0,
|
||
|
|
PageSize: 0,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.LessOrEqual(t, len(result.Agreements), 20)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetUserAgreementHistory(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
userSubject := "history-user-" + uuid.New().String()[:8]
|
||
|
|
|
||
|
|
// Create multiple versions and record agreements for same user
|
||
|
|
for i := 0; i < 3; i++ {
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: "history-v" + string(rune('1'+i)) + "-" + uuid.New().String()[:8],
|
||
|
|
Title: "History EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
version, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: userSubject,
|
||
|
|
UserEmail: "history@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
}
|
||
|
|
_, err = svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
t.Run("get all agreements for user", func(t *testing.T) {
|
||
|
|
history, err := svc.GetUserAgreementHistory(ctx, userSubject)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.GreaterOrEqual(t, len(history), 3)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("return empty for user with no agreements", func(t *testing.T) {
|
||
|
|
history, err := svc.GetUserAgreementHistory(ctx, "no-history-user")
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Len(t, history, 0)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestComplianceHelperFunctions tests the compliance report helper functions
|
||
|
|
// that don't require Cognito.
|
||
|
|
func TestComplianceHelperFunctions(t *testing.T) {
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
t.Run("applyCompliancePaginationDefaults_sets_defaults", func(t *testing.T) {
|
||
|
|
input := &eula.ComplianceReportInput{
|
||
|
|
Page: 0,
|
||
|
|
PageSize: 0,
|
||
|
|
}
|
||
|
|
svc.ApplyCompliancePaginationDefaults(input)
|
||
|
|
assert.Equal(t, int32(1), input.Page)
|
||
|
|
assert.Equal(t, int32(50), input.PageSize)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("applyCompliancePaginationDefaults_caps_page_size", func(t *testing.T) {
|
||
|
|
input := &eula.ComplianceReportInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 500,
|
||
|
|
}
|
||
|
|
svc.ApplyCompliancePaginationDefaults(input)
|
||
|
|
assert.Equal(t, int32(100), input.PageSize)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("safeIntToInt32_handles_normal_values", func(t *testing.T) {
|
||
|
|
assert.Equal(t, int32(100), eula.SafeIntToInt32(100))
|
||
|
|
assert.Equal(t, int32(0), eula.SafeIntToInt32(0))
|
||
|
|
assert.Equal(t, int32(0), eula.SafeIntToInt32(-5))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("compareComplianceUsers_agreed_first", func(t *testing.T) {
|
||
|
|
agreedAt := time.Now()
|
||
|
|
agreed := eula.ComplianceReportUser{Agreed: true, AgreedAt: &agreedAt, CurrentEmail: "z@test.com"}
|
||
|
|
notAgreed := eula.ComplianceReportUser{Agreed: false, CurrentEmail: "a@test.com"}
|
||
|
|
|
||
|
|
assert.True(t, eula.CompareComplianceUsers(agreed, notAgreed))
|
||
|
|
assert.False(t, eula.CompareComplianceUsers(notAgreed, agreed))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("compareComplianceUsers_agreed_sorted_by_date", func(t *testing.T) {
|
||
|
|
recent := time.Now()
|
||
|
|
older := time.Now().Add(-24 * time.Hour)
|
||
|
|
user1 := eula.ComplianceReportUser{Agreed: true, AgreedAt: &recent, CurrentEmail: "a@test.com"}
|
||
|
|
user2 := eula.ComplianceReportUser{Agreed: true, AgreedAt: &older, CurrentEmail: "b@test.com"}
|
||
|
|
|
||
|
|
assert.True(t, eula.CompareComplianceUsers(user1, user2))
|
||
|
|
assert.False(t, eula.CompareComplianceUsers(user2, user1))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("compareComplianceUsers_notagreed_sorted_by_email", func(t *testing.T) {
|
||
|
|
user1 := eula.ComplianceReportUser{Agreed: false, CurrentEmail: "a@test.com"}
|
||
|
|
user2 := eula.ComplianceReportUser{Agreed: false, CurrentEmail: "b@test.com"}
|
||
|
|
|
||
|
|
assert.True(t, eula.CompareComplianceUsers(user1, user2))
|
||
|
|
assert.False(t, eula.CompareComplianceUsers(user2, user1))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("paginateComplianceUsers_calculates_correctly", func(t *testing.T) {
|
||
|
|
users := make([]eula.ComplianceReportUser, 25)
|
||
|
|
for i := range users {
|
||
|
|
users[i] = eula.ComplianceReportUser{CurrentEmail: "user" + string(rune('A'+i)) + "@test.com"}
|
||
|
|
}
|
||
|
|
|
||
|
|
paginated, totalItems, totalPages := svc.PaginateComplianceUsers(users, 1, 10)
|
||
|
|
assert.Equal(t, 10, len(paginated))
|
||
|
|
assert.Equal(t, int32(25), totalItems)
|
||
|
|
assert.Equal(t, int32(3), totalPages)
|
||
|
|
|
||
|
|
// Second page
|
||
|
|
paginated2, _, _ := svc.PaginateComplianceUsers(users, 2, 10)
|
||
|
|
assert.Equal(t, 10, len(paginated2))
|
||
|
|
|
||
|
|
// Third page (partial)
|
||
|
|
paginated3, _, _ := svc.PaginateComplianceUsers(users, 3, 10)
|
||
|
|
assert.Equal(t, 5, len(paginated3))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("paginateComplianceUsers_handles_empty", func(t *testing.T) {
|
||
|
|
users := []eula.ComplianceReportUser{}
|
||
|
|
paginated, totalItems, totalPages := svc.PaginateComplianceUsers(users, 1, 10)
|
||
|
|
assert.Equal(t, 0, len(paginated))
|
||
|
|
assert.Equal(t, int32(0), totalItems)
|
||
|
|
assert.Equal(t, int32(1), totalPages) // At least 1 page
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("filterAndSortComplianceUsers_filters_agreed", func(t *testing.T) {
|
||
|
|
agreedAt := time.Now()
|
||
|
|
users := []eula.ComplianceReportUser{
|
||
|
|
{Agreed: true, AgreedAt: &agreedAt, CurrentEmail: "agreed1@test.com"},
|
||
|
|
{Agreed: false, CurrentEmail: "notagreed1@test.com"},
|
||
|
|
{Agreed: true, AgreedAt: &agreedAt, CurrentEmail: "agreed2@test.com"},
|
||
|
|
{Agreed: false, CurrentEmail: "notagreed2@test.com"},
|
||
|
|
}
|
||
|
|
|
||
|
|
agreedFilter := true
|
||
|
|
filtered := svc.FilterAndSortComplianceUsers(users, &agreedFilter)
|
||
|
|
assert.Equal(t, 2, len(filtered))
|
||
|
|
for _, u := range filtered {
|
||
|
|
assert.True(t, u.Agreed)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("filterAndSortComplianceUsers_filters_not_agreed", func(t *testing.T) {
|
||
|
|
agreedAt := time.Now()
|
||
|
|
users := []eula.ComplianceReportUser{
|
||
|
|
{Agreed: true, AgreedAt: &agreedAt, CurrentEmail: "agreed1@test.com"},
|
||
|
|
{Agreed: false, CurrentEmail: "notagreed1@test.com"},
|
||
|
|
{Agreed: true, AgreedAt: &agreedAt, CurrentEmail: "agreed2@test.com"},
|
||
|
|
{Agreed: false, CurrentEmail: "notagreed2@test.com"},
|
||
|
|
}
|
||
|
|
|
||
|
|
notAgreedFilter := false
|
||
|
|
filtered := svc.FilterAndSortComplianceUsers(users, ¬AgreedFilter)
|
||
|
|
assert.Equal(t, 2, len(filtered))
|
||
|
|
for _, u := range filtered {
|
||
|
|
assert.False(t, u.Agreed)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("filterAndSortComplianceUsers_nil_filter_returns_all", func(t *testing.T) {
|
||
|
|
agreedAt := time.Now()
|
||
|
|
users := []eula.ComplianceReportUser{
|
||
|
|
{Agreed: true, AgreedAt: &agreedAt, CurrentEmail: "agreed@test.com"},
|
||
|
|
{Agreed: false, CurrentEmail: "notagreed@test.com"},
|
||
|
|
}
|
||
|
|
|
||
|
|
filtered := svc.FilterAndSortComplianceUsers(users, nil)
|
||
|
|
assert.Equal(t, 2, len(filtered))
|
||
|
|
// First user should be the agreed one (sorted)
|
||
|
|
assert.True(t, filtered[0].Agreed)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestGetComplianceReport tests the compliance report functionality.
|
||
|
|
// These tests require real Cognito access - opt-in via env var.
|
||
|
|
func TestGetComplianceReport(t *testing.T) {
|
||
|
|
// Opt-in: requires ENABLE_COGNITO_INTEGRATION_TESTS=true
|
||
|
|
if os.Getenv("ENABLE_COGNITO_INTEGRATION_TESTS") != "true" {
|
||
|
|
t.Skip("Skipping Cognito integration test: set ENABLE_COGNITO_INTEGRATION_TESTS=true to run")
|
||
|
|
}
|
||
|
|
|
||
|
|
userPoolID := os.Getenv("COGNITO_USER_POOL_ID")
|
||
|
|
awsRegion := os.Getenv("AWS_REGION")
|
||
|
|
if awsRegion == "" {
|
||
|
|
awsRegion = os.Getenv("AUTH_REGION")
|
||
|
|
}
|
||
|
|
|
||
|
|
if userPoolID == "" || awsRegion == "" {
|
||
|
|
t.Skip("Skipping compliance report test: COGNITO_USER_POOL_ID and AWS_REGION/AUTH_REGION must be set")
|
||
|
|
}
|
||
|
|
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Set up Cognito client
|
||
|
|
awsCfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(awsRegion))
|
||
|
|
require.NoError(t, err, "Failed to load AWS config")
|
||
|
|
cognitoClient := cognitoidentityprovider.NewFromConfig(awsCfg)
|
||
|
|
|
||
|
|
// Create and activate a version for testing
|
||
|
|
versionStr := "compliance-" + uuid.New().String()[:8]
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: versionStr,
|
||
|
|
Title: "Compliance Test EULA",
|
||
|
|
Content: "# Test Content\n\nThis is test content for compliance report testing.",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
version, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
_, err = svc.ActivateVersion(ctx, version.ID, "admin@test.com")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("returns_report_for_current_version", func(t *testing.T) {
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 50,
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result)
|
||
|
|
|
||
|
|
// Verify version is the current one
|
||
|
|
assert.Equal(t, version.ID, result.Version.ID)
|
||
|
|
assert.True(t, result.Version.Iscurrent)
|
||
|
|
|
||
|
|
// Verify summary counts are consistent
|
||
|
|
assert.Equal(t, result.Summary.TotalUsers, result.Summary.AgreedCount+result.Summary.NotAgreedCount)
|
||
|
|
|
||
|
|
// Verify pagination info
|
||
|
|
assert.Equal(t, int32(1), result.Page)
|
||
|
|
assert.Equal(t, int32(50), result.PageSize)
|
||
|
|
assert.GreaterOrEqual(t, result.TotalPages, int32(1))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("returns_report_for_specific_version", func(t *testing.T) {
|
||
|
|
// Create a non-current version
|
||
|
|
nonCurrentVersion, err := svc.CreateVersion(ctx, &eula.CreateVersionInput{
|
||
|
|
Version: "specific-" + uuid.New().String()[:8],
|
||
|
|
Title: "Specific Version EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
VersionID: &nonCurrentVersion.ID,
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 50,
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result)
|
||
|
|
|
||
|
|
// Verify version matches the specified one
|
||
|
|
assert.Equal(t, nonCurrentVersion.ID, result.Version.ID)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("returns_error_for_nonexistent_version", func(t *testing.T) {
|
||
|
|
nonExistentID := uuid.New()
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
VersionID: &nonExistentID,
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 50,
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.ErrorIs(t, err, eula.ErrVersionNotFound)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("filters_agreed_only", func(t *testing.T) {
|
||
|
|
agreed := true
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 50,
|
||
|
|
Agreed: &agreed,
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result)
|
||
|
|
|
||
|
|
// All users in the result should have agreed=true
|
||
|
|
for _, user := range result.Users {
|
||
|
|
assert.True(t, user.Agreed, "Expected all users to have agreed=true when filtering agreed only")
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("filters_not_agreed_only", func(t *testing.T) {
|
||
|
|
agreed := false
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 50,
|
||
|
|
Agreed: &agreed,
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result)
|
||
|
|
|
||
|
|
// All users in the result should have agreed=false
|
||
|
|
for _, user := range result.Users {
|
||
|
|
assert.False(t, user.Agreed, "Expected all users to have agreed=false when filtering not agreed only")
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("pagination_works", func(t *testing.T) {
|
||
|
|
// Request small page size to test pagination
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 2,
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result)
|
||
|
|
|
||
|
|
// Verify pagination calculations
|
||
|
|
if result.TotalItems > 2 {
|
||
|
|
assert.LessOrEqual(t, len(result.Users), 2)
|
||
|
|
assert.Greater(t, result.TotalPages, int32(1))
|
||
|
|
}
|
||
|
|
|
||
|
|
// Request page 2
|
||
|
|
reportInput.Page = 2
|
||
|
|
result2, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result2)
|
||
|
|
assert.Equal(t, int32(2), result2.Page)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("applies_default_pagination", func(t *testing.T) {
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
Page: 0,
|
||
|
|
PageSize: 0,
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result)
|
||
|
|
|
||
|
|
// Defaults should be applied
|
||
|
|
assert.Equal(t, int32(1), result.Page)
|
||
|
|
assert.Equal(t, int32(50), result.PageSize)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("caps_page_size_at_100", func(t *testing.T) {
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 500,
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result)
|
||
|
|
|
||
|
|
// Page size should be capped
|
||
|
|
assert.Equal(t, int32(100), result.PageSize)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("compliance_percentage_calculation", func(t *testing.T) {
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 50,
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
require.NotNil(t, result)
|
||
|
|
|
||
|
|
// Verify percentage is between 0 and 100
|
||
|
|
assert.GreaterOrEqual(t, result.Summary.CompliancePercentage, float32(0))
|
||
|
|
assert.LessOrEqual(t, result.Summary.CompliancePercentage, float32(100))
|
||
|
|
|
||
|
|
// Verify percentage calculation if there are users
|
||
|
|
if result.Summary.TotalUsers > 0 {
|
||
|
|
expectedPct := float32(result.Summary.AgreedCount) / float32(result.Summary.TotalUsers) * 100
|
||
|
|
assert.InDelta(t, expectedPct, result.Summary.CompliancePercentage, 0.01)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestGetComplianceReportNoCurrentVersion tests error handling when no current version exists.
|
||
|
|
func TestGetComplianceReportNoCurrentVersion(t *testing.T) {
|
||
|
|
// Opt-in: requires ENABLE_COGNITO_INTEGRATION_TESTS=true
|
||
|
|
if os.Getenv("ENABLE_COGNITO_INTEGRATION_TESTS") != "true" {
|
||
|
|
t.Skip("Skipping Cognito integration test: set ENABLE_COGNITO_INTEGRATION_TESTS=true to run")
|
||
|
|
}
|
||
|
|
|
||
|
|
userPoolID := os.Getenv("COGNITO_USER_POOL_ID")
|
||
|
|
awsRegion := os.Getenv("AWS_REGION")
|
||
|
|
if awsRegion == "" {
|
||
|
|
awsRegion = os.Getenv("AUTH_REGION")
|
||
|
|
}
|
||
|
|
|
||
|
|
if userPoolID == "" || awsRegion == "" {
|
||
|
|
t.Skip("Skipping compliance report test: COGNITO_USER_POOL_ID and AWS_REGION/AUTH_REGION must be set")
|
||
|
|
}
|
||
|
|
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg) // Fresh DB with no EULA versions
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Set up Cognito client
|
||
|
|
awsCfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(awsRegion))
|
||
|
|
require.NoError(t, err, "Failed to load AWS config")
|
||
|
|
cognitoClient := cognitoidentityprovider.NewFromConfig(awsCfg)
|
||
|
|
|
||
|
|
t.Run("returns_error_when_no_current_version", func(t *testing.T) {
|
||
|
|
reportInput := &eula.ComplianceReportInput{
|
||
|
|
Page: 1,
|
||
|
|
PageSize: 50,
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := svc.GetComplianceReport(ctx, cognitoClient, userPoolID, reportInput)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.ErrorIs(t, err, eula.ErrNoCurrentVersion)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestResolveComplianceVersion tests the ResolveComplianceVersion function.
|
||
|
|
// This test uses real DB and doesn't require Cognito.
|
||
|
|
func TestResolveComplianceVersion(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Create and activate a version
|
||
|
|
versionStr := "resolve-" + uuid.New().String()[:8]
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: versionStr,
|
||
|
|
Title: "Resolve Test EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
version, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
_, err = svc.ActivateVersion(ctx, version.ID, "admin@test.com")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("resolves_current_version_when_nil", func(t *testing.T) {
|
||
|
|
resolved, err := svc.ResolveComplianceVersion(ctx, nil)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, version.ID, resolved.ID)
|
||
|
|
assert.True(t, resolved.Iscurrent)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("resolves_specific_version_when_provided", func(t *testing.T) {
|
||
|
|
// Create a non-current version
|
||
|
|
nonCurrent, err := svc.CreateVersion(ctx, &eula.CreateVersionInput{
|
||
|
|
Version: "noncurrent-" + uuid.New().String()[:8],
|
||
|
|
Title: "Non-current EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
resolved, err := svc.ResolveComplianceVersion(ctx, &nonCurrent.ID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, nonCurrent.ID, resolved.ID)
|
||
|
|
assert.False(t, resolved.Iscurrent)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("returns_error_for_nonexistent_version", func(t *testing.T) {
|
||
|
|
nonExistentID := uuid.New()
|
||
|
|
_, err := svc.ResolveComplianceVersion(ctx, &nonExistentID)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.ErrorIs(t, err, eula.ErrVersionNotFound)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestBuildComplianceUserList tests the BuildComplianceUserList function.
|
||
|
|
// This test uses mock data and doesn't require Cognito or DB.
|
||
|
|
func TestBuildComplianceUserList(t *testing.T) {
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
t.Run("builds_user_list_with_agreements", func(t *testing.T) {
|
||
|
|
versionID := uuid.New()
|
||
|
|
agreedAt := time.Now()
|
||
|
|
|
||
|
|
cognitoUsers := []usermanagement.CognitoUserResponse{
|
||
|
|
{SubjectID: "user1", Email: "user1@test.com", Enabled: true},
|
||
|
|
{SubjectID: "user2", Email: "user2@test.com", Enabled: true},
|
||
|
|
{SubjectID: "user3", Email: "user3@test.com", Enabled: true},
|
||
|
|
}
|
||
|
|
|
||
|
|
agreements := []*repository.Eulaagreement{
|
||
|
|
{
|
||
|
|
ID: uuid.New(),
|
||
|
|
Cognitosubjectid: "user1",
|
||
|
|
Useremail: "user1@test.com",
|
||
|
|
Eulaversionid: versionID,
|
||
|
|
Agreedat: pgtype.Timestamptz{Time: agreedAt, Valid: true},
|
||
|
|
Agreedfromip: "192.168.1.1",
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
users, summary := svc.BuildComplianceUserList(cognitoUsers, agreements)
|
||
|
|
|
||
|
|
// Verify user count
|
||
|
|
assert.Equal(t, 3, len(users))
|
||
|
|
|
||
|
|
// Verify summary
|
||
|
|
assert.Equal(t, int32(3), summary.TotalUsers)
|
||
|
|
assert.Equal(t, int32(1), summary.AgreedCount)
|
||
|
|
assert.Equal(t, int32(2), summary.NotAgreedCount)
|
||
|
|
assert.InDelta(t, 33.33, summary.CompliancePercentage, 0.1)
|
||
|
|
|
||
|
|
// Verify user1 is marked as agreed
|
||
|
|
var user1Found bool
|
||
|
|
for _, u := range users {
|
||
|
|
if u.CognitoSubjectID == "user1" {
|
||
|
|
user1Found = true
|
||
|
|
assert.True(t, u.Agreed)
|
||
|
|
assert.NotNil(t, u.AgreedAt)
|
||
|
|
assert.Equal(t, "192.168.1.1", *u.AgreedFromIP)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
assert.True(t, user1Found, "user1 should be in the list")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("handles_empty_users", func(t *testing.T) {
|
||
|
|
users, summary := svc.BuildComplianceUserList(nil, nil)
|
||
|
|
|
||
|
|
assert.Equal(t, 0, len(users))
|
||
|
|
assert.Equal(t, int32(0), summary.TotalUsers)
|
||
|
|
assert.Equal(t, int32(0), summary.AgreedCount)
|
||
|
|
assert.Equal(t, int32(0), summary.NotAgreedCount)
|
||
|
|
assert.Equal(t, float32(0), summary.CompliancePercentage)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("handles_all_agreed", func(t *testing.T) {
|
||
|
|
versionID := uuid.New()
|
||
|
|
agreedAt := time.Now()
|
||
|
|
|
||
|
|
cognitoUsers := []usermanagement.CognitoUserResponse{
|
||
|
|
{SubjectID: "user1", Email: "user1@test.com", Enabled: true},
|
||
|
|
{SubjectID: "user2", Email: "user2@test.com", Enabled: true},
|
||
|
|
}
|
||
|
|
|
||
|
|
agreements := []*repository.Eulaagreement{
|
||
|
|
{
|
||
|
|
ID: uuid.New(),
|
||
|
|
Cognitosubjectid: "user1",
|
||
|
|
Useremail: "user1@test.com",
|
||
|
|
Eulaversionid: versionID,
|
||
|
|
Agreedat: pgtype.Timestamptz{Time: agreedAt, Valid: true},
|
||
|
|
Agreedfromip: "192.168.1.1",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
ID: uuid.New(),
|
||
|
|
Cognitosubjectid: "user2",
|
||
|
|
Useremail: "user2@test.com",
|
||
|
|
Eulaversionid: versionID,
|
||
|
|
Agreedat: pgtype.Timestamptz{Time: agreedAt, Valid: true},
|
||
|
|
Agreedfromip: "192.168.1.2",
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
users, summary := svc.BuildComplianceUserList(cognitoUsers, agreements)
|
||
|
|
|
||
|
|
assert.Equal(t, 2, len(users))
|
||
|
|
assert.Equal(t, int32(2), summary.TotalUsers)
|
||
|
|
assert.Equal(t, int32(2), summary.AgreedCount)
|
||
|
|
assert.Equal(t, int32(0), summary.NotAgreedCount)
|
||
|
|
assert.Equal(t, float32(100), summary.CompliancePercentage)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestBuildComplianceUser tests the BuildComplianceUser function.
|
||
|
|
// This test uses mock data and doesn't require Cognito.
|
||
|
|
func TestBuildComplianceUser(t *testing.T) {
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
t.Run("builds_user_with_agreement", func(t *testing.T) {
|
||
|
|
agreedAt := time.Now()
|
||
|
|
cognitoUser := usermanagement.CognitoUserResponse{
|
||
|
|
SubjectID: "user1",
|
||
|
|
Email: "user1@test.com",
|
||
|
|
Enabled: true,
|
||
|
|
}
|
||
|
|
|
||
|
|
agreementMap := map[string]*repository.Eulaagreement{
|
||
|
|
"user1": {
|
||
|
|
ID: uuid.New(),
|
||
|
|
Cognitosubjectid: "user1",
|
||
|
|
Useremail: "user1-old@test.com",
|
||
|
|
Eulaversionid: uuid.New(),
|
||
|
|
Agreedat: pgtype.Timestamptz{Time: agreedAt, Valid: true},
|
||
|
|
Agreedfromip: "10.0.0.1",
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
user := svc.BuildComplianceUser(cognitoUser, agreementMap)
|
||
|
|
|
||
|
|
assert.Equal(t, "user1", user.CognitoSubjectID)
|
||
|
|
assert.Equal(t, "user1@test.com", user.CurrentEmail)
|
||
|
|
assert.True(t, user.Agreed)
|
||
|
|
assert.NotNil(t, user.Email)
|
||
|
|
assert.Equal(t, "user1-old@test.com", *user.Email)
|
||
|
|
assert.NotNil(t, user.AgreedAt)
|
||
|
|
assert.Equal(t, "10.0.0.1", *user.AgreedFromIP)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("builds_user_without_agreement", func(t *testing.T) {
|
||
|
|
cognitoUser := usermanagement.CognitoUserResponse{
|
||
|
|
SubjectID: "user2",
|
||
|
|
Email: "user2@test.com",
|
||
|
|
Enabled: true,
|
||
|
|
}
|
||
|
|
|
||
|
|
agreementMap := make(map[string]*repository.Eulaagreement)
|
||
|
|
|
||
|
|
user := svc.BuildComplianceUser(cognitoUser, agreementMap)
|
||
|
|
|
||
|
|
assert.Equal(t, "user2", user.CognitoSubjectID)
|
||
|
|
assert.Equal(t, "user2@test.com", user.CurrentEmail)
|
||
|
|
assert.False(t, user.Agreed)
|
||
|
|
assert.Nil(t, user.Email)
|
||
|
|
assert.Nil(t, user.AgreedAt)
|
||
|
|
assert.Nil(t, user.AgreedFromIP)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("handles_missing_agreedat", func(t *testing.T) {
|
||
|
|
cognitoUser := usermanagement.CognitoUserResponse{
|
||
|
|
SubjectID: "user3",
|
||
|
|
Email: "user3@test.com",
|
||
|
|
Enabled: true,
|
||
|
|
}
|
||
|
|
|
||
|
|
agreementMap := map[string]*repository.Eulaagreement{
|
||
|
|
"user3": {
|
||
|
|
ID: uuid.New(),
|
||
|
|
Cognitosubjectid: "user3",
|
||
|
|
Useremail: "user3@test.com",
|
||
|
|
Eulaversionid: uuid.New(),
|
||
|
|
Agreedat: pgtype.Timestamptz{Valid: false}, // Not set
|
||
|
|
Agreedfromip: "10.0.0.3",
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
user := svc.BuildComplianceUser(cognitoUser, agreementMap)
|
||
|
|
|
||
|
|
assert.True(t, user.Agreed)
|
||
|
|
assert.Nil(t, user.AgreedAt)
|
||
|
|
assert.Equal(t, "10.0.0.3", *user.AgreedFromIP)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestFetchAllAgreementsForVersion tests the FetchAllAgreementsForVersion function.
|
||
|
|
// This test uses real DB and doesn't require Cognito.
|
||
|
|
func TestFetchAllAgreementsForVersion(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := eula.New(cfg)
|
||
|
|
|
||
|
|
// Create a version
|
||
|
|
versionStr := "fetch-agreements-" + uuid.New().String()[:8]
|
||
|
|
input := &eula.CreateVersionInput{
|
||
|
|
Version: versionStr,
|
||
|
|
Title: "Fetch Agreements EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
}
|
||
|
|
version, err := svc.CreateVersion(ctx, input)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("returns_empty_for_version_with_no_agreements", func(t *testing.T) {
|
||
|
|
agreements, err := svc.FetchAllAgreementsForVersion(ctx, version.ID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, 0, len(agreements))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("returns_agreements_for_version", func(t *testing.T) {
|
||
|
|
// Record some agreements
|
||
|
|
for i := 0; i < 5; i++ {
|
||
|
|
agreementInput := &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: "fetch-user-" + uuid.New().String()[:8],
|
||
|
|
UserEmail: "user@test.com",
|
||
|
|
EulaVersionID: version.ID,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
}
|
||
|
|
_, err := svc.RecordAgreement(ctx, agreementInput)
|
||
|
|
require.NoError(t, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
agreements, err := svc.FetchAllAgreementsForVersion(ctx, version.ID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, 5, len(agreements))
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("returns_only_agreements_for_specific_version", func(t *testing.T) {
|
||
|
|
// Create another version
|
||
|
|
otherVersion, err := svc.CreateVersion(ctx, &eula.CreateVersionInput{
|
||
|
|
Version: "other-" + uuid.New().String()[:8],
|
||
|
|
Title: "Other EULA",
|
||
|
|
Content: "Content",
|
||
|
|
EffectiveDate: ptrTime(time.Now()),
|
||
|
|
CreatedBy: "admin@test.com",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Record agreement for the other version
|
||
|
|
_, err = svc.RecordAgreement(ctx, &eula.RecordAgreementInput{
|
||
|
|
CognitoSubjectID: "other-user-" + uuid.New().String()[:8],
|
||
|
|
UserEmail: "other@test.com",
|
||
|
|
EulaVersionID: otherVersion.ID,
|
||
|
|
IPAddress: "192.168.1.1",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Fetch agreements for original version - should not include other version's agreement
|
||
|
|
agreements, err := svc.FetchAllAgreementsForVersion(ctx, version.ID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// All agreements should be for our version
|
||
|
|
for _, agreement := range agreements {
|
||
|
|
assert.Equal(t, version.ID, agreement.Eulaversionid)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|