Skip to main content

Gosoline Fixture Loader

While using gosoline you are able to define fixtures directly in code.

Usage

  • Enable fixture loading in your config.dist.yml File
fixtures:
enabled: true
  • Make sure to use a custom build tag named fixtures

  • Define your fixtures in code while using one of the built in FixtureWriters and defining a slice of []fixtures.FixtureSet{} or use fixtures.FixtureSetFactory or fixtures.FixtureSetsFactory depending on your use-case. For more details check the /examples/fixtures Directory or read the short example below.

  • The fixtures.FixtureSet interface allows you to define any custom implementation for writing fixture sets to their destination and take control of purging prior writing too. You can however use the fixures.simpleFixtureSet via the fixtures.NewSimpleFixtureSet factory func to use a simple yet effective and prebuilt solution. This is the simpleFixtureSet struct definition:

type simpleFixtureSet[T any] struct {
Enabled bool
Purge bool
Writer FixtureWriter
Fixtures NamedFixtures[T]
}

You can easily define multiple fixtures for different destinations in one file, enable/disable them or even enable/disable purging for each fixtures.FixtureSet via the fixtures.WithEnabled and fixtures.WithPurge fixtures.FixtureSetOption for the fixtures.NewSimpleFixtureSet func.

  • Currently there are 7 different FixtureWriter implementations for loading fixtures:
    ImplementationDirect creationFactory for use with fixtures.NewFixtureSetsFactory
    Blob stores (AWS S3)fixtures.NewBlobFixtureWriter`fixtures.BlobFixtureSetFactory
    AWS DynamoDBfixtures.NewDynamoDbFixtureWriter`fixtures.DynamoDbFixtureSetFactory
    KvStore backed by AWS DynamoDBfixtures.DynamoDbKvStoreFixtureWriterFactory`fixtures.DynamoDbKvStoreFixtureSetFactory
    MySQL (backed by gosoline ORM implementation)fixtures.MysqlOrmFixtureWriterFactory`fixtures.MysqlOrmFixtureSetFactory
    MySQL (plain columns/values)fixtures.MysqlPlainFixtureWriterFactory`fixtures.MysqlPlainFixtureSetFactory
    MySQL (sqlx named prepared statements)fixtures.NewMysqlSqlxFixtureWriter`fixtures.MysqlSqlxFixtureSetFactory
    Redisfixtures.NewRedisFixtureWriter`fixtures.RedisFixtureSetFactory
    KvStore backed by Redisfixtures.NewRedisKvStoreFixtureWriter`fixtures.RedisKvStoreFixtureSetFactory

Quick Usage

  • During the creation of your Application make sure to pass the WithFixtureSetsFactory option and provide the group name and a fixture sets factory as arguments of type fixtures.WithFixtureSetsFactory. The default group is enabled by default.
func main() {
app := application.Default(
application.WithFixtureSetFactory("default", fixtureSetsFactory),
)

app.Run()
}

For blob stores (when using the BlobFixtureWriterFactory) you need a configuration entry added:

blob:
blobconfig:
bucket: s3-fixtures-bucket

ID Generation

You can also generate a locally unique identifier for your fixtures via fixtures.AutoNumbered.

Example with available fixture writers:

func main() {
app := application.Default(
application.WithFixtureSetFactory(fixtureSetsFactory),
)

app.Run()
}

var autoNumbered = fixtures.NewAutoNumberedFrom(2)

func mysqlOrmFixtureSet(ctx context.Context, config cfg.Config, logger log.Logger) (fixtures.FixtureSet, error) {
mysqlMetadata := &db_repo.Metadata{
ModelId: mdl.ModelId{
Name: "orm_fixture_example",
},
}
mysqlOrmWriter, err := fixtures.NewMysqlOrmFixtureWriter(ctx, config, logger, mysqlMetadata)
if err != nil {
return nil, fmt.Errorf("failed to initialize mysql orm writer: %w", err)
}

return fixtures.NewSimpleFixtureSet(fixtures.NamedFixtures[OrmFixtureExample]{
&fixtures.NamedFixture[OrmFixtureExample]{
Name: "foo",
Value: OrmFixtureExample{
Model: db_repo.Model{
Id: autoNumbered.GetNext(),
},
Name: mdl.Box("example"),
},
},
}, mysqlOrmWriter), nil
}

func mysqlPlainFixtureSet(ctx context.Context, config cfg.Config, logger log.Logger) (fixtures.FixtureSet, error) {
mysqlPlainWriter, err := fixtures.NewMysqlPlainFixtureWriter(ctx, config, logger, &fixtures.MysqlPlainMetaData{
TableName: "plain_fixture_example",
Columns: []string{"id", "name"},
})
if err != nil {
return nil, fmt.Errorf("failed to initialize mysql plain writer: %w", err)
}

return fixtures.NewSimpleFixtureSet(fixtures.NamedFixtures[fixtures.MysqlPlainFixtureValues]{
{
Name: "foo2",
Value: fixtures.MysqlPlainFixtureValues{1, "testName1"},
},
{
Name: "foo3",
Value: fixtures.MysqlPlainFixtureValues{2, "testName2"},
},
}, mysqlPlainWriter), nil
}

func dynamodbKvstoreFixtureSet(ctx context.Context, config cfg.Config, logger log.Logger) (fixtures.FixtureSet, error) {
dynamoDbKvStoreWriter, err := fixtures.NewDynamoDbKvStoreFixtureWriter[DynamoDbExampleModel](ctx, config, logger, &mdl.ModelId{
Project: "gosoline",
Environment: "dev",
Family: "example",
Application: "fixture-loader",
Name: "exampleModel",
})
if err != nil {
return nil, fmt.Errorf("failed to initialize dynamodb kvstore writer: %w", err)
}

return fixtures.NewSimpleFixtureSet(fixtures.NamedFixtures[*fixtures.KvStoreFixture]{
{
Name: "kv_somekey",
Value: &fixtures.KvStoreFixture{
Key: "SomeKey",
Value: DynamoDbExampleModel{Name: "Some Name", Value: "Some Value"},
},
},
}, dynamoDbKvStoreWriter), nil
}

func redisFixtureSet(ctx context.Context, config cfg.Config, logger log.Logger) (fixtures.FixtureSet, error) {
redisWriter, err := fixtures.NewRedisFixtureWriter(ctx, config, logger, "default", fixtures.RedisOpSet)
if err != nil {
return nil, fmt.Errorf("failed to initialize redis writer: %w", err)
}

return fixtures.NewSimpleFixtureSet(fixtures.NamedFixtures[*fixtures.RedisFixture]{
{
Name: "redis_example",
Value: &fixtures.RedisFixture{
Key: "example-key",
Value: "bar",
Expiry: 1 * time.Hour,
},
},
}, redisWriter), nil
}

func dynamodbFixtureSet(ctx context.Context, config cfg.Config, logger log.Logger) (fixtures.FixtureSet, error) {
dynamodbWriter, err := fixtures.NewDynamoDbFixtureWriter(ctx, config, logger, &ddb.Settings{
ModelId: mdl.ModelId{
Project: "gosoline",
Environment: "dev",
Family: "example",
Application: "fixture-loader",
Name: "exampleModel",
},
Main: ddb.MainSettings{
Model: DynamoDbExampleModel{},
},
Global: []ddb.GlobalSettings{
{
Name: "IDX_Name",
Model: DynamoDbExampleModel{},
ReadCapacityUnits: 1,
WriteCapacityUnits: 1,
},
},
})
if err != nil {
return nil, fmt.Errorf("failed to initialize dynamodb writer: %w", err)
}

return fixtures.NewSimpleFixtureSet(fixtures.NamedFixtures[*DynamoDbExampleModel]{
{
Name: "ddb",
Value: &DynamoDbExampleModel{Name: "Some Name", Value: "Some Value"},
},
}, dynamodbWriter), nil
}

func blobFixtureSet(ctx context.Context, config cfg.Config, logger log.Logger) (fixtures.FixtureSet, error) {
blobWriter, err := fixtures.NewBlobFixtureWriter(ctx, config, logger, &fixtures.BlobFixturesSettings{
ConfigName: "test",
BasePath: "../../test/test_data/s3_fixtures_test_data",
})
if err != nil {
return nil, fmt.Errorf("failed to initialize blob writer: %w", err)
}

return fixtures.NewSimpleFixtureSet(fixtures.NamedFixtures[*fixtures.BlobFixture]{}, blobWriter), nil
}

func fixtureSetsFactory(ctx context.Context, config cfg.Config, logger log.Logger) ([]fixtures.FixtureSet, error) {
mysqlOrmFs, err := mysqlOrmFixtureSet(ctx, config, logger)
if err != nil {
return nil, err
}

mysqlPlainFs, err := mysqlPlainFixtureSet(ctx, config, logger)
if err != nil {
return nil, err
}

dynamodbKvstoreFs, err := dynamodbKvstoreFixtureSet(ctx, config, logger)
if err != nil {
return nil, err
}

redisFs, err := redisFixtureSet(ctx, config, logger)
if err != nil {
return nil, err
}

dynamodbFs, err := dynamodbFixtureSet(ctx, config, logger)
if err != nil {
return nil, err
}

blobFs, err := blobFixtureSet(ctx, config, logger)
if err != nil {
return nil, err
}

return []fixtures.FixtureSet{
mysqlOrmFs,
mysqlPlainFs,
dynamodbKvstoreFs,
redisFs,
dynamodbFs,
blobFs,
}, nil
}

Named Fixtures

With named fixtures you can create some fixtures and in future fixtures refer to the already created ones, e.g. for referencing (auto numbered) IDs:

type DynamoDbExampleModel struct {
Name string `ddb:"key=hash"`
Value string `ddb:"global=hash"`
}

var namedFixtures = fixtures.NamedFixtures[*DynamoDbExampleModel]{
{
Name: "test",
Value: &DynamoDbExampleModel{Name: "Some Name", Value: "Some Value"},
},
}

func fixtureSetsFactory(ctx context.Context, config cfg.Config, logger log.Logger) ([]fixtures.FixtureSet, error) {
mysqlWriter, err := fixtures.NewMysqlOrmFixtureWriter(ctx, config, logger, &db_repo.Metadata{
ModelId: mdl.ModelId{
Name: "orm_named_fixture_example",
},
})
if err != nil {
return nil, fmt.Errorf("failed to create orm fixture writer: %w", err)
}

return []fixtures.FixtureSet{
fixtures.NewSimpleFixtureSet(namedFixtures, mysqlWriter),
}, nil
}

func main() {
app := application.Default(
application.WithFixtureSetFactory(fixtureSetsFactory),
)

app.Run()

// then you can access them later
fx := namedFixtures.GetValueByName("test")
_ = fx.Value
}

Further Information

  • Existing fixtures will be updated instead of created.
  • When purge is enabled only the destination of the fixtures will be purged, not everything. That means for example while loading MySQL Fixtures with purge only the tables will be purged not the whole database.
  • If you want to use the MySQL ORM based implementation make sure that your fixture struct embeds db_repo.Model