Skip to content
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

Add unit test for generating data source #5439

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
141 changes: 141 additions & 0 deletions cmd/dev/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// SPDX-FileCopyrightText: Copyright 2023 The Minder Authors
// SPDX-License-Identifier: Apache-2.0

package main

import (
"bytes"
"io"
"os"
"path/filepath"
"strings"
"sync"
"testing"
"time"

"github.com/stretchr/testify/assert"

"github.com/mindersec/minder/cmd/dev/app"
)

func TestCobraMain(t *testing.T) {

t.Parallel()

// Create test files
testDir := t.TempDir()

// Create a simple OpenAPI v2 document with basePath
simpleOpenAPI := `swagger: "2.0"
info:
title: "Test API"
version: "1.0.0"
basePath: "/api"
paths:
/test:
get:
summary: "Test endpoint"
operationId: "getTest"
parameters: []
responses:
"200":
description: "Successful response"
content:
application/json: {}`

simpleOpenAPIPath := filepath.Join(testDir, "simple_openapi.json")
err := os.WriteFile(simpleOpenAPIPath, []byte(simpleOpenAPI), 0600)
assert.NoError(t, err, "Failed to create simple OpenAPI file")

tests := []struct {
name string
openAPIFile string
expectedData string
expectedError bool
}{
{
name: "simple API",
openAPIFile: simpleOpenAPIPath,
expectedData: `version: v1
type: data-source
context: {}
name: Test API
rest:
def:
get_test:
endpoint: /api/test
method: GET
parse: json
inputSchema: {}`,
expectedError: false,
},
{
name: "missing OpenAPI file",
openAPIFile: filepath.Join(testDir, "missing_openapi.json"),
expectedData: "",
expectedError: true,
},
}
var mu sync.Mutex
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

cmd := app.CmdRoot()

cmd.SetArgs([]string{"datasource", "generate", tt.openAPIFile})

// Save the original os.Stdout
originalStdout := os.Stdout

// Create a pipe to capture the output,
r, w, _ := os.Pipe()
os.Stdout = w

// Redirect the output to the buffer in a separate goroutine
outC := make(chan string)
go func() {
var buf bytes.Buffer
_, err = io.Copy(&buf, r)
assert.NoError(t, err, "Buffer copy should not produce an error")

outC <- buf.String()
}()

// Execute command and capture any errors
err = cmd.Execute()
if tt.expectedError {
assert.Error(t, err, "Expected an error but got none")
return
}
// Close the writer and restore original os.Stdout
err = w.Close()
assert.NoError(t, err, "File close should not produce an error")
os.Stdout = originalStdout

// Read the captured output
output := <-outC

assert.NoError(t, err, "Command execution should not produce an error")

// Handle the case for missing OpenAPI file
if tt.name == "missing OpenAPI file" {
mu.Lock()
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need a mutex around this?

Copy link
Contributor Author

@gajananan gajananan Feb 17, 2025

Choose a reason for hiding this comment

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

This segment of code should not be there, the mutex. should not be.

assert.FileExists(t, tt.openAPIFile, "OpenAPI file should not exist")
mu.Unlock()
return
}
Comment on lines +122 to +127
Copy link
Member

Choose a reason for hiding this comment

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

Do we ever get here, given that tt.expectedError == true for the "missing OpenAPI file" case, and that exits on line 109?

(This will allow you to simplify the test code, which is another win)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is correct. it won't reach there.


assert.NoError(t, err, "Command execution should not produce an error")

// Normalize and compare the YAML strings
expectedYAML := strings.Join(strings.Fields(string(tt.expectedData)), "")
generatedYAML := strings.Join(strings.Fields(string(output)), "")
// Compare the YAML strings directly
assert.Equal(t, expectedYAML, generatedYAML, "Generated datasource definition should match expected")

// Add a slight delay to ensure the output is captured correctly
time.Sleep(100 * time.Millisecond)
Comment on lines +137 to +138
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need a "Sleep" after we've read and compared all the content?

Copy link
Contributor Author

@gajananan gajananan Feb 17, 2025

Choose a reason for hiding this comment

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

Due to the following code to capture output from Command execution, at times the output was not captured properly, I tried few option to see, it is one of them. I agree it does not make sense when I look at it.

                       // Create a pipe to capture the output,
			r, w, _ := os.Pipe()
			os.Stdout = w
			// Redirect the output to the buffer in a separate goroutine
			outC := make(chan string)
			go func() {
				var buf bytes.Buffer
				_, err = io.Copy(&buf, r)
				assert.NoError(t, err, "Buffer copy should not produce an error")

				outC <- buf.String()
			}()

})
}
}
Loading