Skip to content

Commit

Permalink
Fixing tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelosalloum committed Apr 22, 2024
1 parent ead3cff commit 61d4709
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 139 deletions.
21 changes: 9 additions & 12 deletions cmd/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,27 @@ import (
"strings"
"testing"

"github.com/stellar/stellar-disbursement-platform-backend/db"
"github.com/stellar/stellar-disbursement-platform-backend/stellar-multitenant/pkg/tenant"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/stellar/stellar-disbursement-platform-backend/db/dbtest"
"github.com/stellar/stellar-disbursement-platform-backend/stellar-multitenant/pkg/tenant"
)

func Test_persistentPostRun(t *testing.T) {
tenantName := "tenant"
dbt := dbtest.OpenWithAdminMigrationsOnly(t)
dbt := dbtest.OpenWithoutMigrations(t)
defer dbt.Close()

tenant.PrepareDBForTenant(t, dbt, tenantName)

ctx := context.Background()
dbConnectionPool, outerErr := db.OpenDBConnectionPool(dbt.DSN)
require.NoError(t, outerErr)
defer dbConnectionPool.Close()

tenant := tenant.CreateTenantFixture(t, ctx, dbConnectionPool, tenantName, "pub-key")
adminDBConnectionPool := prepareAdminDBConnectionPool(t, ctx, dbt, true)
defer adminDBConnectionPool.Close()

tenant.PrepareDBForTenant(t, dbt, tenantName)
tnt := tenant.CreateTenantFixture(t, ctx, adminDBConnectionPool, tenantName, "pub-key")

t.Setenv("DATABASE_URL", dbt.DSN)
t.Setenv("EMAIL_SENDER_TYPE", "DRY_RUN")
Expand All @@ -52,7 +49,7 @@ func Test_persistentPostRun(t *testing.T) {
require.NoError(t, err)

rootCmd := SetupCLI("x.y.z", "1234567890abcdef")
rootCmd.SetArgs([]string{"auth", "add-user", "[email protected]", "First", "Last", "--roles", "developer", "--tenant-id", tenant.ID})
rootCmd.SetArgs([]string{"auth", "add-user", "[email protected]", "First", "Last", "--roles", "developer", "--tenant-id", tnt.ID})

for _, cmd := range rootCmd.Commands() {
if cmd.Name() == "auth" {
Expand Down Expand Up @@ -135,7 +132,7 @@ Content: <!DOCTYPE html>
assert.Contains(t, buf.String(), expectContains)

// Set another SDP UI base URL
rootCmd.SetArgs([]string{"auth", "add-user", "[email protected]", "First", "Last", "--roles", "developer", "--sdp-ui-base-url", "https://sdp-ui.org", "--tenant-id", tenant.ID})
rootCmd.SetArgs([]string{"auth", "add-user", "[email protected]", "First", "Last", "--roles", "developer", "--sdp-ui-base-url", "https://sdp-ui.org", "--tenant-id", tnt.ID})

stdOut = os.Stdout

Expand Down
6 changes: 4 additions & 2 deletions cmd/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,13 @@ func (c *DatabaseCommand) adminMigrationsCmd(ctx context.Context, globalOptions
return fmt.Errorf("getting the admin database DSN: %w", err)
}

tssMigrationsManager, err := NewSchemaMigrationManager(c.adminDBConnectionPool, migrations.AdminMigrationRouter, router.AdminSchemaName, dbURL)
tssMigrationsManager, err := NewSchemaMigrationManager(migrations.AdminMigrationRouter, router.AdminSchemaName, dbURL)
if err != nil {
return fmt.Errorf("creating admin database migration manager: %w", err)
}
defer tssMigrationsManager.Close()

if err = tssMigrationsManager.OrchestrateSchemaMigrations(ctx, dbURL, dir, count); err != nil {
if err = tssMigrationsManager.OrchestrateSchemaMigrations(ctx, dir, count); err != nil {
return fmt.Errorf("running admin migrations: %w", err)
}
return nil
Expand Down Expand Up @@ -244,6 +245,7 @@ func (c *DatabaseCommand) tssMigrationsCmd(ctx context.Context, globalOptions *u
if err != nil {
return fmt.Errorf("creating TSS database migration manager: %w", err)
}
defer tssMigrationsManager.Close()

if err = tssMigrationsManager.OrchestrateSchemaMigrations(ctx, dir, count); err != nil {
return fmt.Errorf("running TSS migrations: %w", err)
Expand Down
114 changes: 70 additions & 44 deletions cmd/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,45 @@ import (
"strings"
"testing"

migrate "github.com/rubenv/sql-migrate"
"github.com/stellar/go/keypair"
"github.com/stellar/go/network"
supportDBTest "github.com/stellar/go/support/db/dbtest"
"github.com/stellar/go/support/log"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

cmdDB "github.com/stellar/stellar-disbursement-platform-backend/cmd/db"
"github.com/stellar/stellar-disbursement-platform-backend/db"
"github.com/stellar/stellar-disbursement-platform-backend/db/dbtest"
"github.com/stellar/stellar-disbursement-platform-backend/db/migrations"
"github.com/stellar/stellar-disbursement-platform-backend/db/router"
"github.com/stellar/stellar-disbursement-platform-backend/internal/data"
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
"github.com/stellar/stellar-disbursement-platform-backend/stellar-multitenant/pkg/tenant"
)

func prepareAdminDBConnectionPool(t *testing.T, ctx context.Context, dbt *supportDBTest.DB, withMigrations bool) db.DBConnectionPool {
t.Helper()

adminDatabaseDNS, err := router.GetDNSForAdmin(dbt.DSN)
require.NoError(t, err)

if withMigrations {
var manager *cmdDB.SchemaMigrationManager
manager, err = cmdDB.NewSchemaMigrationManager(migrations.AdminMigrationRouter, router.AdminSchemaName, adminDatabaseDNS)
require.NoError(t, err)
defer manager.Close()
err = manager.OrchestrateSchemaMigrations(ctx, migrate.Up, 0)
require.NoError(t, err)
}

adminDBConnectionPool, err := db.OpenDBConnectionPool(adminDatabaseDNS)
require.NoError(t, err)

return adminDBConnectionPool
}

func getSDPMigrationsApplied(t *testing.T, ctx context.Context, db db.DBConnectionPool) []string {
t.Helper()

Expand Down Expand Up @@ -112,15 +138,15 @@ func Test_DatabaseCommand_db_help(t *testing.T) {
}

func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
dbt := dbtest.OpenWithAdminMigrationsOnly(t)
dbt := dbtest.OpenWithoutMigrations(t)
defer dbt.Close()

dbConnectionPool, err := db.OpenDBConnectionPool(dbt.DSN)
require.NoError(t, err)
defer dbConnectionPool.Close()

ctx := context.Background()
m := tenant.NewManager(tenant.WithDatabase(dbConnectionPool))

adminDBConnectionPool := prepareAdminDBConnectionPool(t, ctx, dbt, true)
defer adminDBConnectionPool.Close()

m := tenant.NewManager(tenant.WithDatabase(adminDBConnectionPool))
buf := new(strings.Builder)

t.Run("migrate usage", func(t *testing.T) {
Expand All @@ -131,7 +157,7 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
dbt.DSN,
})
rootCmd.SetOut(buf)
err = rootCmd.Execute()
err := rootCmd.Execute()
require.NoError(t, err)

expectedContains := []string{
Expand All @@ -158,7 +184,7 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
})

t.Run("db sdp migrate up and down --all", func(t *testing.T) {
tenant.DeleteAllTenantsFixture(t, ctx, dbConnectionPool)
tenant.DeleteAllTenantsFixture(t, ctx, adminDBConnectionPool)

// Creating Tenants
tnt1, err := m.AddTenant(ctx, "myorg1")
Expand All @@ -167,9 +193,9 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
tnt2, err := m.AddTenant(ctx, "myorg2")
require.NoError(t, err)

_, err = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
_, err = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
require.NoError(t, err)
_, err = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
_, err = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
require.NoError(t, err)

buf.Reset()
Expand Down Expand Up @@ -198,14 +224,14 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
assert.Equal(t, []string{"2023-01-20.0-initial.sql"}, ids)
assert.Contains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt1.ID))
assert.Contains(t, buf.String(), "Successfully applied 1 migrations up.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg1", []string{"sdp_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg1", []string{"sdp_migrations"})

// Checking if the migrations were applied on the Tenant 2
ids = getSDPMigrationsApplied(t, ctx, tenant2SchemaConnectionPool)
assert.Equal(t, []string{"2023-01-20.0-initial.sql"}, ids)
assert.Contains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt1.ID))
assert.Contains(t, buf.String(), "Successfully applied 1 migrations up.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg2", []string{"sdp_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg2", []string{"sdp_migrations"})

buf.Reset()
rootCmd.SetArgs([]string{"db", "sdp", "migrate", "down", "1", "--database-url", dbt.DSN, "--log-level", "TRACE", "--all"})
Expand All @@ -216,17 +242,17 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
ids = getSDPMigrationsApplied(t, context.Background(), tenant1SchemaConnectionPool)
assert.Equal(t, []string{}, ids)
assert.Contains(t, buf.String(), "Successfully applied 1 migrations down.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg1", []string{"sdp_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg1", []string{"sdp_migrations"})

// Checking if the migrations were applied on the Tenant 2
ids = getSDPMigrationsApplied(t, context.Background(), tenant2SchemaConnectionPool)
assert.Equal(t, []string{}, ids)
assert.Contains(t, buf.String(), "Successfully applied 1 migrations down.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg2", []string{"sdp_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg2", []string{"sdp_migrations"})
})

t.Run("db sdp migrate up and down --tenant-id", func(t *testing.T) {
tenant.DeleteAllTenantsFixture(t, ctx, dbConnectionPool)
tenant.DeleteAllTenantsFixture(t, ctx, adminDBConnectionPool)

// Creating Tenants
tnt1, err := m.AddTenant(ctx, "myorg1")
Expand All @@ -235,9 +261,9 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
tnt2, err := m.AddTenant(ctx, "myorg2")
require.NoError(t, err)

_, err = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
_, err = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
require.NoError(t, err)
_, err = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
_, err = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
require.NoError(t, err)

buf.Reset()
Expand Down Expand Up @@ -266,10 +292,10 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
assert.Equal(t, []string{"2023-01-20.0-initial.sql"}, ids)
assert.Contains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt1.ID))
assert.Contains(t, buf.String(), "Successfully applied 1 migrations up.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg1", []string{"sdp_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg1", []string{"sdp_migrations"})

// Checking if the migrations were not applied on the Tenant 2 schema
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg2", []string{})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg2", []string{})
assert.NotContains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt2.ID))

buf.Reset()
Expand All @@ -282,15 +308,15 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
assert.Equal(t, []string{}, ids)
assert.Contains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt1.ID))
assert.Contains(t, buf.String(), "Successfully applied 1 migrations down.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg1", []string{"sdp_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg1", []string{"sdp_migrations"})

// Checking if the migrations were not applied on the Tenant 2 schema
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg2", []string{})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg2", []string{})
assert.NotContains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt2.ID))
})

t.Run("db sdp migrate up and down auth migrations --all", func(t *testing.T) {
tenant.DeleteAllTenantsFixture(t, ctx, dbConnectionPool)
tenant.DeleteAllTenantsFixture(t, ctx, adminDBConnectionPool)

// Creating Tenants
tnt1, err := m.AddTenant(ctx, "myorg1")
Expand All @@ -299,9 +325,9 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
tnt2, err := m.AddTenant(ctx, "myorg2")
require.NoError(t, err)

_, err = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
_, err = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
require.NoError(t, err)
_, err = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
_, err = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
require.NoError(t, err)

buf.Reset()
Expand Down Expand Up @@ -330,14 +356,14 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
assert.Equal(t, []string{"2023-02-09.0.add-users-table.sql"}, ids)
assert.Contains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt1.ID))
assert.Contains(t, buf.String(), "Successfully applied 1 migrations up.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg1", []string{"auth_migrations", "auth_users"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg1", []string{"auth_migrations", "auth_users"})

// Checking if the migrations were applied on the Tenant 2
ids = getAuthMigrationsApplied(t, ctx, tenant2SchemaConnectionPool)
assert.Equal(t, []string{"2023-02-09.0.add-users-table.sql"}, ids)
assert.Contains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt1.ID))
assert.Contains(t, buf.String(), "Successfully applied 1 migrations up.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg2", []string{"auth_migrations", "auth_users"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg2", []string{"auth_migrations", "auth_users"})

buf.Reset()
rootCmd.SetArgs([]string{"db", "auth", "migrate", "down", "1", "--database-url", dbt.DSN, "--log-level", "TRACE", "--all"})
Expand All @@ -348,17 +374,17 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
ids = getAuthMigrationsApplied(t, context.Background(), tenant1SchemaConnectionPool)
assert.Equal(t, []string{}, ids)
assert.Contains(t, buf.String(), "Successfully applied 1 migrations down.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg1", []string{"auth_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg1", []string{"auth_migrations"})

// Checking if the migrations were applied on the Tenant 2
ids = getAuthMigrationsApplied(t, context.Background(), tenant2SchemaConnectionPool)
assert.Equal(t, []string{}, ids)
assert.Contains(t, buf.String(), "Successfully applied 1 migrations down.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg2", []string{"auth_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg2", []string{"auth_migrations"})
})

t.Run("db sdp migrate up and down auth migrations --tenant-id", func(t *testing.T) {
tenant.DeleteAllTenantsFixture(t, ctx, dbConnectionPool)
tenant.DeleteAllTenantsFixture(t, ctx, adminDBConnectionPool)

// Creating Tenants
tnt1, err := m.AddTenant(ctx, "myorg1")
Expand All @@ -367,9 +393,9 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
tnt2, err := m.AddTenant(ctx, "myorg2")
require.NoError(t, err)

_, err = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
_, err = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
require.NoError(t, err)
_, err = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
_, err = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
require.NoError(t, err)

buf.Reset()
Expand Down Expand Up @@ -398,10 +424,10 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
assert.Equal(t, []string{"2023-02-09.0.add-users-table.sql"}, ids)
assert.Contains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt1.ID))
assert.Contains(t, buf.String(), "Successfully applied 1 migrations up.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg1", []string{"auth_migrations", "auth_users"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg1", []string{"auth_migrations", "auth_users"})

// Checking if the migrations were not applied on the Tenant 2 schema
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg2", []string{})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg2", []string{})
assert.NotContains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt2.ID))

buf.Reset()
Expand All @@ -414,10 +440,10 @@ func Test_DatabaseCommand_db_sdp_migrate(t *testing.T) {
assert.Equal(t, []string{}, ids)
assert.Contains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt1.ID))
assert.Contains(t, buf.String(), "Successfully applied 1 migrations down.")
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg1", []string{"auth_migrations"})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg1", []string{"auth_migrations"})

// Checking if the migrations were not applied on the Tenant 2 schema
tenant.TenantSchemaMatchTablesFixture(t, ctx, dbConnectionPool, "sdp_myorg2", []string{})
tenant.TenantSchemaMatchTablesFixture(t, ctx, adminDBConnectionPool, "sdp_myorg2", []string{})
assert.NotContains(t, buf.String(), fmt.Sprintf("Applying migrations on tenant ID %s", tnt2.ID))
})
}
Expand All @@ -426,12 +452,12 @@ func Test_DatabaseCommand_db_setup_for_network(t *testing.T) {
dbt := dbtest.Open(t)
defer dbt.Close()

dbConnectionPool, outerErr := db.OpenDBConnectionPool(dbt.DSN)
require.NoError(t, outerErr)
defer dbConnectionPool.Close()

ctx := context.Background()
m := tenant.NewManager(tenant.WithDatabase(dbConnectionPool))

adminDBConnectionPool := prepareAdminDBConnectionPool(t, ctx, dbt, true)
defer adminDBConnectionPool.Close()

m := tenant.NewManager(tenant.WithDatabase(adminDBConnectionPool))

// Creating Tenants
tnt1, outerErr := m.AddTenant(ctx, "myorg1")
Expand All @@ -440,13 +466,13 @@ func Test_DatabaseCommand_db_setup_for_network(t *testing.T) {
tnt2, outerErr := m.AddTenant(ctx, "myorg2")
require.NoError(t, outerErr)

_, outerErr = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
_, outerErr = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg1")
require.NoError(t, outerErr)
_, outerErr = dbConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
_, outerErr = adminDBConnectionPool.ExecContext(ctx, "CREATE SCHEMA sdp_myorg2")
require.NoError(t, outerErr)

tenant.ApplyMigrationsForTenantFixture(t, ctx, dbConnectionPool, tnt1.Name)
tenant.ApplyMigrationsForTenantFixture(t, ctx, dbConnectionPool, tnt2.Name)
tenant.ApplyMigrationsForTenantFixture(t, ctx, adminDBConnectionPool, tnt1.Name)
tenant.ApplyMigrationsForTenantFixture(t, ctx, adminDBConnectionPool, tnt2.Name)

tnt1DSN, outerErr := m.GetDSNForTenant(ctx, tnt1.Name)
require.NoError(t, outerErr)
Expand Down
Loading

0 comments on commit 61d4709

Please sign in to comment.