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

test: add runtime testing for Go models #1484

Merged
merged 5 commits into from
Aug 28, 2023
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
32 changes: 32 additions & 0 deletions .github/workflows/runtime-go-testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Runtime Testing Go Models
on:
push:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
paths:
- 'src/generators/go/**'
- 'test/runtime/runtime-go/**'
- test/runtime/**go**

jobs:
test:
name: Runtime testing Go Models
if: "github.event.pull_request.draft == false &&!((github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'ci: update global workflows')) || (github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'chore(release):')) || (github.actor == 'allcontributors' && startsWith(github.event.pull_request.title, 'docs: add')))"
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 14
- name: Build Library
run: npm install && npm run build:prod
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.20
-name: Generate Go Models
run: npm run generate:runtime:go
-name: Run runtime Tests
run: npm run test:runtime:go
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
"test:blackbox:java": "cross-env CI=true jest ./test/blackbox/blackbox-java.spec.ts",
"test:runtime:java": "cross-env CI=true jest ./test/runtime/runtime-java.spec.ts",
"generate:runtime:java": "cross-env CI=true ts-node ./test/runtime/runtime-java.ts",
"test:runtime:go": "cross-env CI=true jest ./test/runtime/runtime-go.spec.ts",
"generate:runtime:go": "cross-env CI=true ts-node ./test/runtime/runtime-go.ts",
"test:runtime:cplusplus": "cross-env CI=true jest ./test/runtime/runtime-cplusplus.spec.ts",
"generate:runtime:cplusplus": "cross-env CI=true ts-node ./test/runtime/runtime-cplusplus.ts",
"test:runtime:kotlin": "cross-env CI=true jest ./test/runtime/runtime-kotlin.spec.ts",
Expand Down
13 changes: 13 additions & 0 deletions test/runtime/runtime-go.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { execCommand } from "../blackbox/utils/Utils";
import path from 'path';

jest.setTimeout(50000);

test('Go runtime testing', async () => {
const compileCommand = `cd ${path.resolve(
__dirname,
'./runtime-go'
)} && go test`;
await execCommand(compileCommand);
})

15 changes: 15 additions & 0 deletions test/runtime/runtime-go.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {GoFileGenerator, GO_DEFAULT_PRESET} from "../../src";
import path from "path";
import input from "./generic-input.json";


const generator = new GoFileGenerator({
presets : [GO_DEFAULT_PRESET],

})

generator.generateToFiles(
input,
path.resolve(__dirname,'./runtime-go'),
{packageName : "runtimego"}
)
1 change: 1 addition & 0 deletions test/runtime/runtime-go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
10 changes: 10 additions & 0 deletions test/runtime/runtime-go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Modelina Go Runtime Project

This is the Modelina Go runtime project that is used to test the Go-generated code from Modelina at
runtime to ensure that everything works as expected.

Here is how it works:
- The models are first generated during the build phase of the project, by running the root npm script
`npm run generate:runtime:go`. These models are pre-defined with the [generic input](../generic-input.json)
- The tests are manually added and changed
- When the project is tested, it tests the generated models at runtime for semantic errors.
64 changes: 64 additions & 0 deletions test/runtime/runtime-go/Test_Go/Test_Address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package Test_Go

import (
"encoding/json"
runtimego "runtimego/target"
"testing"
)

func TestShouldbeAbleToSerializeModel(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

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

We still need to compare the actual serialized value with something we expect, you can grab the one in the other runtime test 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jonaslagoni .. I tried to find the expected json in other runtime-tests but couldn't find one. The closest thing i found was under typescript-test where the serialized json was expected : {\"street_name\": \"test\",\"house_number\": 1,\"array_type\": [1,\"test\"],\"nestedObject\": {\"test\": \"test\"}} and this was done for every field of the Address Struct.
Do you expect me to do the same as done in typescript ?
[As in java and other languages i did not find any expected json's] 🙂

Copy link
Member

Choose a reason for hiding this comment

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

Yep, thats about it 👍

nestedobj := runtimego.NestedObject{
Test: "test",
}
address := runtimego.Address{
StreetName: "Test Address 2",
HouseNumber: 2,
Marriage: true,
Members: 2,
ArrayType: []interface{}{2, "test"},
NestedObject: &nestedobj,
AdditionalProperties: nil,
}

jsonBytes, err := json.Marshal(address)

if err != nil {
t.Fatalf("Failed to serialize Address to JSON: %v", err)
}
jsonStr := string(jsonBytes)

if jsonStr == "" {
t.Errorf("Serialize JSON is empty")
}
}

func TestShouldNotContainAdditionalPropertiesWhenSerialized(t *testing.T) {
nestedobj := runtimego.NestedObject{
Test: "test",
}
address := runtimego.Address{
StreetName: "Test Address 2",
HouseNumber: 2.0,
Marriage: true,
Members: 2,
ArrayType: []interface{}{2, "test"},
NestedObject: &nestedobj,
AdditionalProperties: nil,
}

jsonBytes, err := json.Marshal(address)

if err != nil {
t.Fatalf("Failed to serialize Address to JSON: %v", err)
}

var JsonObject map[string]interface{}

if err := json.Unmarshal(jsonBytes, &JsonObject); err != nil {
t.Fatalf("Failed to deserialize JSON: %v", err)
}

if _, found := JsonObject["AdditionalProperties"]; found {
t.Errorf("Serialize JSON contains 'Additional Properties' key")
}
}
117 changes: 117 additions & 0 deletions test/runtime/runtime-go/Test_Go/Test_Marshall_Address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package Test_Go

import (
"encoding/json"
runtimego "runtimego/target"
"testing"
)

func Test(expected string, address runtimego.Address, t *testing.T) {
// Marshalling Test
serialized, err := json.Marshal(address)
if err != nil {
t.Errorf("Failed to serialize Address to JSON: %v", err)
}

serializedStr := string(serialized)
if serializedStr != expected {
t.Errorf("Expected marshalled JSON: %s, but got: %s", expected, serialized)
}

// Unmarshalling Test
var newAddress runtimego.Address
if err := json.Unmarshal([]byte(expected), &newAddress); err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
reSerialized, err := json.Marshal(newAddress)
if err != nil {
t.Fatalf("Failed to marshal Address: %v", err)
}
reSerializedStr := string(reSerialized)

if serializedStr != reSerializedStr {
t.Errorf("Serialized JSON after unmarshalling does not match: %s", reSerializedStr)
}
}

func TestAddressMarshalling(t *testing.T) {

// Testing Address with Required Properties

t.Run("required properties", func(t *testing.T) {
address := runtimego.Address{
StreetName: "test",
HouseNumber: 1,
ArrayType: []interface{}{1, "test"},
}
expected := "{\"street_name\": \"test\",\"house_number\": 1,\"array_type\": [1,\"test\"]}"

Test(expected, address, t)
})

// Testing Address with Marriage

t.Run("marriage", func(t *testing.T) {
address := runtimego.Address{
StreetName: "test",
HouseNumber: 1,
Marriage: true,
ArrayType: []interface{}{1, "test"},
}
expected := "{\"street_name\": \"test\",\"house_number\": 1,\"marriage\": true,\"array_type\": [1,\"test\"]}"

Test(expected, address, t)

})

// Testing Address with Members

t.Run("members", func(t *testing.T) {
address := runtimego.Address{
StreetName: "test",
HouseNumber: 1,
ArrayType: []interface{}{1, "test"},
Members: 2,
}
expected := "{\"street_name\": \"test\",\"house_number\": 1,\"members\": 2,\"array_type\": [1,\"test\"]}"

Test(expected, address, t)
})

// Testing Address with Nested Object

t.Run("nestedObject", func(t *testing.T) {
nestedObj := runtimego.NestedObject{
Test: "test",
}
address := runtimego.Address{
StreetName: "test",
HouseNumber: 1,
ArrayType: []interface{}{1, "test"},
NestedObject: &nestedObj,
}
expected := "{\"street_name\": \"test\",\"house_number\": 1,\"array_type\": [1,\"test\"],\"nestedObject\": {\"test\": \"test\"}}"

Test(expected, address, t)
})

// Testing Address Full Model

t.Run("full model", func(t *testing.T) {
nestedObj := runtimego.NestedObject{
Test: "test",
}
address := runtimego.Address{
StreetName: "test",
HouseNumber: 1,
Marriage: true,
Members: 2,
ArrayType: []interface{}{1, "test"},
NestedObject: &nestedObj,
AdditionalProperties: nil,
}
expected := "{\"street_name\": \"test\",\"house_number\": 1,\"marriage\": true,\"members\": 2,\"array_type\": [1,\"test\"],\"nestedObject\": {\"test\": \"test\"}}"

Test(expected, address, t)
})
}
3 changes: 3 additions & 0 deletions test/runtime/runtime-go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module runtimego

go 1.20