Skip to content
Merged
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
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ The `arazzo` package provides an API for working with Arazzo documents including

The `openapi` package provides an API for working with OpenAPI documents including reading, creating, mutating, walking, validating and upgrading them. Supports both OpenAPI 3.0.x and 3.1.x specifications.

### [swagger](./swagger)

The `swagger` package provides an API for working with Swagger 2.0 documents including reading, creating, mutating, walking, validating, and upgrading them to OpenAPI 3.0.

### [overlay](./overlay)

The `overlay` package provides an API for working with OpenAPI Overlays including applying overlays to specifications, comparing specifications to generate overlays, and validating overlay documents.
Expand All @@ -93,7 +97,7 @@ go install github.com/speakeasy-api/openapi/cmd/openapi@latest

### Usage

The CLI provides three main command groups:
The CLI provides four main command groups:

- **`openapi spec`** - Commands for working with OpenAPI specifications ([documentation](./cmd/openapi/commands/openapi/README.md))
- `bootstrap` - Create a new OpenAPI document with best practice examples
Expand All @@ -109,6 +113,10 @@ The CLI provides three main command groups:
- `upgrade` - Upgrade an OpenAPI specification to the latest supported version
- `validate` - Validate an OpenAPI specification document

- **`openapi swagger`** - Commands for working with Swagger 2.0 documents ([documentation](./cmd/openapi/commands/swagger/README.md))
- `validate` - Validate a Swagger 2.0 specification document
- `upgrade` - Upgrade a Swagger 2.0 specification to OpenAPI 3.0

- **`openapi arazzo`** - Commands for working with Arazzo workflow documents ([documentation](./cmd/openapi/commands/arazzo/README.md))
- `validate` - Validate an Arazzo workflow document

Expand Down Expand Up @@ -137,6 +145,12 @@ openapi overlay apply --overlay overlay.yaml --schema spec.yaml

# Validate an Arazzo workflow document
openapi arazzo validate ./workflow.arazzo.yaml

# Validate a Swagger 2.0 document
openapi swagger validate ./api.swagger.yaml

# Upgrade Swagger 2.0 to OpenAPI 3.0
openapi swagger upgrade ./api.swagger.yaml ./openapi.yaml
```

For detailed usage instructions for each command group, see the individual documentation linked above.
Expand Down
9 changes: 0 additions & 9 deletions RELEASE_NOTES.md

This file was deleted.

61 changes: 3 additions & 58 deletions arazzo/arazzo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ package arazzo_test

import (
"bytes"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"testing"

Expand All @@ -18,6 +14,7 @@ import (
"github.com/speakeasy-api/openapi/arazzo/criterion"
"github.com/speakeasy-api/openapi/expression"
"github.com/speakeasy-api/openapi/extensions"
"github.com/speakeasy-api/openapi/internal/testutils"
"github.com/speakeasy-api/openapi/jsonpointer"
"github.com/speakeasy-api/openapi/jsonschema/oas3"
jsonschema_core "github.com/speakeasy-api/openapi/jsonschema/oas3/core"
Expand Down Expand Up @@ -726,7 +723,7 @@ func TestArazzo_StressTests_Validate(t *testing.T) {
require.NoError(t, err)
} else {
var err error
r, err = downloadFile(tt.args.location)
r, err = testutils.DownloadFile(tt.args.location, "ARAZZO_CACHE_DIR", "speakeasy-api_arazzo")
require.NoError(t, err)
}
defer r.Close()
Expand Down Expand Up @@ -759,7 +756,7 @@ func TestArazzo_StressTests_RoundTrip(t *testing.T) {
require.NoError(t, err)
} else {
var err error
r, err = downloadFile(tt.args.location)
r, err = testutils.DownloadFile(tt.args.location, "ARAZZO_CACHE_DIR", "speakeasy-api_arazzo")
require.NoError(t, err)
}
defer r.Close()
Expand Down Expand Up @@ -787,58 +784,6 @@ func TestArazzo_StressTests_RoundTrip(t *testing.T) {
}
}

func downloadFile(url string) (io.ReadCloser, error) {
// Use environment variable for cache directory, fallback to system temp dir
cacheDir := os.Getenv("ARAZZO_CACHE_DIR")
if cacheDir == "" {
cacheDir = os.TempDir()
}
tempDir := filepath.Join(cacheDir, "speakeasy-api_arazzo")

if err := os.MkdirAll(tempDir, os.ModePerm); err != nil {
return nil, err
}

// hash url to create a unique filename
hash := sha256.Sum256([]byte(url))
filename := hex.EncodeToString(hash[:])

filepath := filepath.Join(tempDir, filename)

// check if file exists and return it otherwise download it
r, err := os.Open(filepath)
if err == nil {
return r, nil
}

resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()

// Read all data from response body
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

// Write data to cache file
f, err := os.OpenFile(filepath, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return nil, err
}
defer f.Close()

_, err = f.Write(data)
if err != nil {
return nil, err
}

// Return the data as a ReadCloser
return io.NopCloser(bytes.NewReader(data)), nil
}

func roundTripYamlOnly(data []byte) ([]byte, error) {
var node yaml.Node

Expand Down
45 changes: 45 additions & 0 deletions arazzo/core/criterion_syncchanges_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package core

import (
"testing"

"github.com/speakeasy-api/openapi/pointer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

func TestCriterionTypeUnion_SyncChanges_WithStringType_Success(t *testing.T) {
t.Parallel()

yamlContent := "simple"
var node yaml.Node
err := yaml.Unmarshal([]byte(yamlContent), &node)
require.NoError(t, err, "unmarshal should succeed")

var ctu CriterionTypeUnion
validationErrs, err := ctu.Unmarshal(t.Context(), "test", node.Content[0])
require.NoError(t, err, "unmarshal should succeed")
require.Empty(t, validationErrs, "validation errors should be empty")

model := CriterionTypeUnion{
Type: pointer.From("simple"),
}

resultNode, err := ctu.SyncChanges(t.Context(), model, node.Content[0])
require.NoError(t, err, "SyncChanges should succeed")
assert.NotNil(t, resultNode, "result node should not be nil")
}

func TestCriterionTypeUnion_SyncChanges_NonStruct_Error(t *testing.T) {
t.Parallel()

var node yaml.Node
err := yaml.Unmarshal([]byte("simple"), &node)
require.NoError(t, err, "unmarshal should succeed")

ctu := CriterionTypeUnion{}
_, err = ctu.SyncChanges(t.Context(), "not a struct", node.Content[0])
require.Error(t, err, "SyncChanges should fail")
assert.Contains(t, err.Error(), "CriterionTypeUnion.SyncChanges expected a struct, got string", "error message should match")
}
57 changes: 57 additions & 0 deletions arazzo/core/reusable_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package core

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

func TestReusable_Unmarshal_WithReference_Success(t *testing.T) {
t.Parallel()

yamlContent := `reference: '#/components/parameters/userId'`

var node yaml.Node
err := yaml.Unmarshal([]byte(yamlContent), &node)
require.NoError(t, err, "unmarshal should succeed")

var reusable Reusable[*Parameter]
validationErrs, err := reusable.Unmarshal(t.Context(), "test", node.Content[0])
require.NoError(t, err, "unmarshal should succeed")
require.Empty(t, validationErrs, "validation errors should be empty")
assert.True(t, reusable.GetValid(), "reusable should be valid")
assert.True(t, reusable.Reference.Present, "reference should be present")
assert.NotNil(t, reusable.Reference.Value, "reference value should not be nil")
}

func TestReusable_Unmarshal_NonMappingNode_Error(t *testing.T) {
t.Parallel()

yamlContent := "- item1\n- item2"

var node yaml.Node
err := yaml.Unmarshal([]byte(yamlContent), &node)
require.NoError(t, err, "unmarshal should succeed")

var reusable Reusable[*Parameter]
validationErrs, err := reusable.Unmarshal(t.Context(), "test", node.Content[0])
require.NoError(t, err, "unmarshal error should be nil")
require.NotEmpty(t, validationErrs, "validation errors should not be empty")
assert.Contains(t, validationErrs[0].Error(), "reusable expected object", "error message should match")
assert.False(t, reusable.GetValid(), "reusable should not be valid")
}

func TestReusable_SyncChanges_NonStruct_Error(t *testing.T) {
t.Parallel()

var node yaml.Node
err := yaml.Unmarshal([]byte(`reference: '#/test'`), &node)
require.NoError(t, err, "unmarshal should succeed")

reusable := Reusable[*Parameter]{}
_, err = reusable.SyncChanges(t.Context(), "not a struct", node.Content[0])
require.Error(t, err, "SyncChanges should fail")
assert.Contains(t, err.Error(), "Reusable.SyncChanges expected a struct, got string", "error message should match")
}
Loading