Skip to content

Add Segment Audience resource, data source, tests, and documentation #193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions docs/data-sources/audience.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# segment_audience Data Source

Fetches a Segment Audience by space and ID.

## Example Usage

```hcl
resource "segment_audience" "example" {
space_id = "your_space_id"
name = "Test Audience"
description = "Created by Terraform"
definition = {
query = "event('Shoes Bought').count() >= 1"
}
}

data "segment_audience" "example" {
space_id = segment_audience.example.space_id
id = segment_audience.example.id
}
```

## Argument Reference

- `space_id` (Required) — The Segment Space ID.
- `id` (Required) — The Audience ID.

## Attributes Reference

The following attributes are exported:

- `name` — The name of the Audience.
- `description` — The description of the Audience.
- `key` — The key of the Audience.
- `enabled` — Whether the Audience is enabled.
- `definition` — The definition of the Audience (map).
- `status` — The status of the Audience.
- `options` — Additional options for the Audience (map).

## Advanced Usage & Test Scenarios

### Error Scenario: Not Found

If you attempt to look up an Audience that does not exist, the data source will return an error. This is useful for negative testing and validation.

**Example:**

```hcl
# This will fail if the audience does not exist

data "segment_audience" "not_found" {
space_id = "your_space_id"
id = "audience_does_not_exist"
}
```

**Expected error:**

```
Error: Unable to read Audience: ...
```

---

### Complex Attribute Validation

The data source supports complex/nested attributes, such as advanced queries and boolean options. You can validate these in your tests or usage.

**Example:**

```hcl
resource "segment_audience" "complex" {
space_id = "your_space_id"
name = "Complex Audience"
description = "Testing complex attributes"
definition = {
query = "event('Shoes Bought').count() >= 1 && event('Shirt Bought').count() >= 2"
}
options = {
includeHistoricalData = true
}
}

data "segment_audience" "complex" {
space_id = segment_audience.complex.space_id
id = segment_audience.complex.id
}
```

You can then assert on these attributes in your tests or outputs:

- `definition.query` should match the complex query string.
- `options.includeHistoricalData` should be `true`.

---

For more test examples, see the provider's `internal/provider/audience_data_source_test.go` file.
112 changes: 112 additions & 0 deletions internal/provider/audience_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package provider

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/segmentio/public-api-sdk-go/api"
"github.com/segmentio/terraform-provider-segment/internal/provider/models"
)

var _ datasource.DataSource = &audienceDataSource{}
var _ datasource.DataSourceWithConfigure = &audienceDataSource{}

func NewAudienceDataSource() datasource.DataSource {
return &audienceDataSource{}
}

type audienceDataSource struct {
client *api.APIClient
authContext context.Context
}

func (d *audienceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_audience"
}

func (d *audienceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"space_id": schema.StringAttribute{
Required: true,
Description: "The Space ID.",
},
"id": schema.StringAttribute{
Required: true,
Description: "The Audience ID.",
},
"name": schema.StringAttribute{
Computed: true,
Description: "The name of the Audience.",
},
"description": schema.StringAttribute{
Computed: true,
Description: "The description of the Audience.",
},
"key": schema.StringAttribute{
Computed: true,
Description: "The key of the Audience.",
},
"enabled": schema.BoolAttribute{
Computed: true,
Description: "Whether the Audience is enabled.",
},
"definition": schema.MapAttribute{
ElementType: types.StringType,
Computed: true,
Description: "The definition of the Audience.",
},
"status": schema.StringAttribute{
Computed: true,
Description: "The status of the Audience.",
},
"options": schema.MapAttribute{
ElementType: types.StringType,
Computed: true,
Description: "Additional options for the Audience.",
},
},
}
}

func (d *audienceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data models.AudienceState
diags := req.Config.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
out, _, err := d.client.GetAudience(d.authContext, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Unable to read Audience", err.Error())
return
}
audience := out.Data.Audience
data.Name = types.StringValue(audience.Name)
data.Description = types.StringValue(audience.Description)
data.Key = types.StringValue(audience.Key)
data.Enabled = types.BoolValue(audience.Enabled)
data.Status = types.StringValue(audience.Status)
// TODO: convert audience.Definition and audience.Options to types.Map
diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
}

func (d *audienceDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
config, ok := req.ProviderData.(*ClientInfo)
if !ok {
resp.Diagnostics.AddError(
"Unexpected DataSource Configure Type",
fmt.Sprintf("Expected ClientInfo, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}
d.client = config.client
d.authContext = config.authContext
}
108 changes: 108 additions & 0 deletions internal/provider/audience_data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package provider

import (
"os"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

func TestAccAudienceDataSource_basic(t *testing.T) {
spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID")
if spaceID == "" {
t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.")
}
resource.Test(t, resource.TestCase{
Steps: []resource.TestStep{
{
Config: testAccAudienceDataSourceConfig(spaceID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("data.segment_audience.test", "id"),
resource.TestCheckResourceAttr("data.segment_audience.test", "name", "Test Audience"),
),
},
},
})
}

func TestAccAudienceDataSource_notFound(t *testing.T) {
spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID")
if spaceID == "" {
t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.")
}
resource.Test(t, resource.TestCase{
Steps: []resource.TestStep{
{
Config: testAccAudienceDataSourceConfigNotFound(spaceID),
ExpectError: regexp.MustCompile(`(?i)Unable to read Audience`),
},
},
})
}

func TestAccAudienceDataSource_complexAttributes(t *testing.T) {
spaceID := os.Getenv("SEGMENT_TEST_SPACE_ID")
if spaceID == "" {
t.Skip("SEGMENT_TEST_SPACE_ID must be set for acceptance tests.")
}
resource.Test(t, resource.TestCase{
Steps: []resource.TestStep{
{
Config: testAccAudienceDataSourceConfigComplex(spaceID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.segment_audience.test", "definition.query", "event('Shoes Bought').count() >= 1 && event('Shirt Bought').count() >= 2"),
resource.TestCheckResourceAttr("data.segment_audience.test", "options.includeHistoricalData", "true"),
),
},
},
})
}

func testAccAudienceDataSourceConfig(spaceID string) string {
return `
resource "segment_audience" "test" {
space_id = "` + spaceID + `"
name = "Test Audience"
description = "Created by Terraform acceptance test"
definition = {
query = "event('Shoes Bought').count() >= 1"
}
}

data "segment_audience" "test" {
space_id = segment_audience.test.space_id
id = segment_audience.test.id
}
`
}

func testAccAudienceDataSourceConfigNotFound(spaceID string) string {
return `
data "segment_audience" "test" {
space_id = "` + spaceID + `"
id = "audience_does_not_exist"
}
`
}

func testAccAudienceDataSourceConfigComplex(spaceID string) string {
return `
resource "segment_audience" "test" {
space_id = "` + spaceID + `"
name = "Complex Audience"
description = "Testing complex attributes"
definition = {
query = "event('Shoes Bought').count() >= 1 && event('Shirt Bought').count() >= 2"
}
options = {
includeHistoricalData = true
}
}

data "segment_audience" "test" {
space_id = segment_audience.test.space_id
id = segment_audience.test.id
}
`
}
Loading