Skip to content

Add tests for swagger datasource generation#6219

Open
PrinceAsiedu wants to merge 6 commits into
mindersec:mainfrom
PrinceAsiedu:test/datasource-generate-swagger
Open

Add tests for swagger datasource generation#6219
PrinceAsiedu wants to merge 6 commits into
mindersec:mainfrom
PrinceAsiedu:test/datasource-generate-swagger

Conversation

@PrinceAsiedu

@PrinceAsiedu PrinceAsiedu commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Add coverage for mindev datasource generate in cmd/dev/app/datasource/generate_test.go.

This exercises Swagger v2 datasource generation across the main success
paths and the expected error cases called out in #5300.

What changed

  • added table-driven unit tests for datasource generation
  • verified generated YAML by unmarshaling into the datasource proto
  • covered:
    • single endpoint with no parameters
    • path parameters
    • POST/PUT body handling
    • multiple endpoints
    • empty/invalid Swagger documents
    • unsupported header/body parameters
    • duplicate/conflicting generated operation names

Follow-up fixes included

While writing the tests, a few issues in the generator surfaced and were fixed:

  • preserve templated Swagger paths like /users/{id} instead of emitting URL-escaped paths
  • return a clear error for unsupported parameter locations
  • return a clear error when two operations collapse to the same generated name
  • fix required field encoding in the generated input schema so it is accepted by structpb

Closes #5300

Add unit tests for the `mindev datasource generate` command covering
Swagger v2 datasource generation and expected failures.

The new tests cover:
- single endpoints without parameters
- path parameters
- POST/PUT body handling
- multiple endpoints
- invalid or empty Swagger input
- unsupported header/body parameters
- duplicate generated operation names

This also fixes a few generator issues found while adding coverage:
- preserve templated path params instead of URL-escaping `{...}`
- reject duplicate generated operation names
- reject unsupported parameter locations with clear errors
- encode required input schema fields in a structpb-compatible form

Signed-off-by: Prince Oforh Asiedu <prince14asiedu@gmail.com>
@PrinceAsiedu PrinceAsiedu requested a review from a team as a code owner March 31, 2026 13:30
Copilot AI review requested due to automatic review settings March 31, 2026 13:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds unit test coverage for mindev datasource generate (Swagger v2 → Minder REST datasource YAML), and updates the generator to handle several edge/error cases more explicitly.

Changes:

  • Added table-driven tests validating generated datasource YAML by unmarshaling into the datasource proto.
  • Updated path joining to preserve templated Swagger paths (e.g. /users/{id}) and added validation for unsupported parameter locations.
  • Added generator safeguards for duplicate generated operation names and fixed required encoding to be structpb-compatible.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
cmd/dev/app/datasource/generate.go Adjusts datasource generation logic (path joining, parameter validation, duplicate op-name detection, required-field encoding).
cmd/dev/app/datasource/generate_test.go Introduces success/error-path tests for Swagger datasource generation and CLI parsing behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/dev/app/datasource/generate.go Outdated
Comment on lines +236 to +250
func testSwagger(paths map[string]spec.PathItem) *spec.Swagger {
return &spec.Swagger{
SwaggerProps: spec.SwaggerProps{
Swagger: "2.0",
BasePath: "/api/v1",
Info: &spec.Info{
InfoProps: spec.InfoProps{
Title: "users-api",
},
},
Paths: &spec.Paths{
Paths: paths,
},
},
}

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new tests validate generated REST defs but never assert the top-level DataSource.Name, even though it’s derived from swagger.Info.Title and is part of the generated YAML contract. Adding an assertion for ds.GetName() would strengthen coverage and would also catch that swaggerTitleToDataSourceName currently replaces a fully-valid title (e.g. users-api) with "-" due to using an anchored regexp with ReplaceAllString.

Copilot uses AI. Check for mistakes.
@coveralls

coveralls commented Mar 31, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 58.306%. remained the same
when pulling f593a8a on PrinceAsiedu:test/datasource-generate-swagger
into 62b505d on mindersec:main.

PrinceAsiedu and others added 4 commits March 31, 2026 13:43
Signed-off-by: Prince Oforh Asiedu <prince14asiedu@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Prince Oforh Asiedu <prince14asiedu@gmail.com>
…andling in tests

Signed-off-by: Prince Oforh Asiedu <prince14asiedu@gmail.com>

@evankanderson evankanderson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks very good overall! Thanks for adding the coverage (which seems to have motivated some improvements in the actual tool as well)!

return &ds, nil
}

func testSwagger(paths map[string]spec.PathItem) *spec.Swagger {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option here would be to create a testdata directory, and store actual sample Swagger JSON documents in the directory. I don't feel strongly about that approach, but it has the advantage of being able to add real-world examples with less Go typing boilerplate.

Comment on lines +37 to +48
assert: func(t *testing.T, ds *minderv1.DataSource) {
t.Helper()
assert.Equal(t, "users-api", ds.GetName())
require.NotNil(t, ds.GetRest())
require.Len(t, ds.GetRest().GetDef(), 1)

def := ds.GetRest().GetDef()["get_users"]
require.NotNil(t, def)
assert.Equal(t, "GET", def.GetMethod())
assert.Equal(t, "/api/v1/users", def.GetEndpoint())
assert.Equal(t, "json", def.GetParse())
assert.Empty(t, def.GetInputSchema().AsMap())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we do this in a bunch of our tests, but this sort of helper function in a table test is a little bit of a "smell". In this case, you might look at using go-cmp or protocmp to allow specifying the expected result (with a side effect of getting nice-looking diffs when there's a problem).

Using prototext, this could be:

Suggested change
assert: func(t *testing.T, ds *minderv1.DataSource) {
t.Helper()
assert.Equal(t, "users-api", ds.GetName())
require.NotNil(t, ds.GetRest())
require.Len(t, ds.GetRest().GetDef(), 1)
def := ds.GetRest().GetDef()["get_users"]
require.NotNil(t, def)
assert.Equal(t, "GET", def.GetMethod())
assert.Equal(t, "/api/v1/users", def.GetEndpoint())
assert.Equal(t, "json", def.GetParse())
assert.Empty(t, def.GetInputSchema().AsMap())
expected: `
name: users-api
rest [
def : {
key: "get_users"
value: {
method: "GET"
endpoint: "/api/v1/users"
parse: "json"
}
}
]
`,

"/users/id/": pathItem("GET", op()),
"/users/{id}": pathItem("GET", op(param("id", "path"))),
}),
wantErr: `duplicate generated operation name "get_users_id_"`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ wantErr as a string to test the error messages. Thanks!

Comment on lines +83 to +91
if out := cmd.OutOrStdout(); out != os.Stdout {
if f, ok := out.(*os.File); ok {
prev := os.Stdout
os.Stdout = f
defer func() {
os.Stdout = prev
}()
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than overwriting os.Stdout, let's pass the file from cmd.OutOrStdout to the writers, and use Command.SetOut() in the tests to override Stdout. This avoids mutating global state across tests run with t.Parallel().

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is just adding an argument to writeDataSourceToFile

Comment on lines +154 to +162
func joinPaths(basepath, path string) string {
basepath = strings.TrimSuffix(basepath, "/")
path = strings.TrimPrefix(path, "/")
if path == "" {
return basepath
}

return basepath + "/" + path
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

url.JoinPath should do this. Is it not?

Comment on lines +198 to +199
if !slices.Contains([]string{"path", "query"}, p.In) {
return fmt.Errorf("unsupported parameter %q in %q", p.Name, p.In)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could support e.g. headers, but we don't at the moment, right? It seems worth a comment to indicate whether this is a limitation of the generation tool, or a limit of the underlying datasource API.

os.Stdout = stdoutFile
defer func() {
os.Stdout = originalStdout
}()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer to use Command.SetOut here -- all you need is an io.Writer, so this could simply be a bytes.Buffer rather than needing any actual files at all. (and then you won't need the lock!)

Comment on lines +322 to +332
stdoutFile, err := os.CreateTemp(t.TempDir(), "stdout-*.yaml")
require.NoError(t, err)

stdoutMu.Lock()
defer stdoutMu.Unlock()

originalStdout := os.Stdout
os.Stdout = stdoutFile
defer func() {
os.Stdout = originalStdout
}()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, prefer Command.SetOut here.

@evankanderson evankanderson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment when this is ready for review; at a minimum, we should use Command.SetOut rather than overwriting os.Stdout, but you may want to review the other comments as well.

@evankanderson evankanderson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking as "Request changes" (for at least cmd.Stdout), so I can more easily track which PRs need maintainer attention again.

@github-actions

Copy link
Copy Markdown
Contributor

This PR needs additional information before we can continue. It is now marked as stale because it has been open for 30 days with no activity. Please provide the necessary details to continue or it will be closed in 30 days.

@github-actions github-actions Bot added the Stale label May 30, 2026
@evankanderson

Copy link
Copy Markdown
Member

@PrinceAsiedu -- are you likely to get back to this PR?

@github-actions github-actions Bot removed the Stale label Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add unit tests for generating a data source definition from Swagger

4 participants