Skip to content

Commit

Permalink
feat(go): add basic westhttp
Browse files Browse the repository at this point in the history
Signed-off-by: Roman Volosatovs <[email protected]>
  • Loading branch information
rvolosatovs committed Sep 23, 2024
1 parent 34117f0 commit 10e0f1a
Show file tree
Hide file tree
Showing 4 changed files with 316 additions and 192 deletions.
2 changes: 1 addition & 1 deletion examples/go/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func handle(req types.IncomingRequest, out types.ResponseOutparam) *types.ErrorC
slog.Debug("setting response outparam")
types.ResponseOutparamSet(out, cm.OK[cm.Result[types.ErrorCodeShape, types.OutgoingResponse, types.ErrorCode]](resp))
stream := bodyWrite.OK()
s := "foo bar baz"
s := "hello world"
writeRes := stream.BlockingWriteAndFlush(cm.NewList(unsafe.StringData(s), uint(len(s))))
if writeRes.IsErr() {
slog.Error("failed to write to stream", "err", writeRes.Err())
Expand Down
100 changes: 22 additions & 78 deletions examples/go/http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,100 +3,44 @@
package wasi_test

import (
"io"
"net/http"
"testing"
"unsafe"

"github.com/bytecodealliance/wasm-tools-go/cm"
west "github.com/rvolosatovs/west"
_ "github.com/rvolosatovs/west/bindings"
testtypes "github.com/rvolosatovs/west/bindings/wasi/http/types"
httpext "github.com/rvolosatovs/west/bindings/wasiext/http/ext"
incominghandler "github.com/rvolosatovs/west/tests/go/wasi/bindings/wasi/http/incoming-handler"
"github.com/rvolosatovs/west/tests/go/wasi/bindings/wasi/http/types"
"github.com/rvolosatovs/west/westhttp"
"github.com/stretchr/testify/assert"
)

func TestIncomingHandler(t *testing.T) {
west.RunTest(t, func() {
headers := testtypes.NewFields()
headers.Append(
testtypes.FieldKey("foo"),
testtypes.FieldValue(cm.NewList(
unsafe.SliceData([]byte("bar")),
3,
)),
)
headers.Append(
testtypes.FieldKey("foo"),
testtypes.FieldValue(cm.NewList(
unsafe.SliceData([]byte("baz")),
3,
)),
)
headers.Set(
testtypes.FieldKey("key"),
cm.NewList(
unsafe.SliceData(
[]testtypes.FieldValue{
testtypes.FieldValue(cm.NewList(
unsafe.SliceData([]byte("value")),
5,
)),
},
),
1,
),
)
req := testtypes.NewOutgoingRequest(headers)
req.SetPathWithQuery(cm.Some("test"))
req.SetMethod(testtypes.MethodGet())
out := httpext.NewResponseOutparam()
incominghandler.Exports.Handle(
types.IncomingRequest(httpext.NewIncomingRequest(req)),
types.ResponseOutparam(out.F0),
)
out.F1.Subscribe().Block()
respOptResRes := out.F1.Get()
respResRes := respOptResRes.Some()
if !assert.NotNil(t, respResRes) {
t.FailNow()
req, err := http.NewRequest("", "test", nil)
if err != nil {
t.Fatalf("failed to create new HTTP request: %s", err)
}
respRes := respResRes.OK()
if !assert.NotNil(t, respRes) || !assert.Nil(t, respRes.Err()) {
t.FailNow()
req.Header.Add("foo", "bar")
req.Header.Add("foo", "baz")
req.Header.Add("key", "value")
resp, err := westhttp.HandleIncomingRequest(incominghandler.Exports.Handle, req)
if err != nil {
t.Fatalf("failed to handle incoming HTTP request: %s", err)
}
resp := respRes.OK()
assert.Equal(t, testtypes.StatusCode(200), resp.Status())
hs := map[string][][]byte{}
for _, h := range resp.Headers().Entries().Slice() {
k := string(h.F0)
hs[k] = append(hs[k], h.F1.Slice())
}
assert.Equal(t, map[string][][]byte{
assert.Equal(t, 200, resp.StatusCode)
assert.Equal(t, http.Header{
"foo": {
[]byte("bar"),
[]byte("baz"),
"bar",
"baz",
},
"key": {
[]byte("value"),
"value",
},
}, hs)
bodyRes := resp.Consume()
body := bodyRes.OK()
if !assert.NotNil(t, body) {
t.FailNow()
}
bodyStreamRes := body.Stream()
bodyStream := bodyStreamRes.OK()
if !assert.NotNil(t, bodyStream) {
t.FailNow()
}
bufRes := bodyStream.BlockingRead(4096)
buf := bufRes.OK()
if !assert.NotNil(t, buf) {
t.FailNow()
}, resp.Header)
buf, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed to read HTTP response body: %s", err)
}
assert.Equal(t, []byte("foo bar baz"), buf.Slice())
bodyStream.ResourceDrop()
assert.Equal(t, []byte("hello world"), buf)
})
}
135 changes: 22 additions & 113 deletions tests/go/wasi/wasi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,19 @@
package wasi_test

import (
"bytes"
_ "embed"
"io"
"log"
"log/slog"
"net/http"
"os"
"testing"
"unsafe"

"github.com/bytecodealliance/wasm-tools-go/cm"
west "github.com/rvolosatovs/west"
_ "github.com/rvolosatovs/west/bindings"
testtypes "github.com/rvolosatovs/west/bindings/wasi/http/types"
teststreams "github.com/rvolosatovs/west/bindings/wasi/io/streams"
httpext "github.com/rvolosatovs/west/bindings/wasiext/http/ext"
incominghandler "github.com/rvolosatovs/west/tests/go/wasi/bindings/wasi/http/incoming-handler"
"github.com/rvolosatovs/west/tests/go/wasi/bindings/wasi/http/types"
"github.com/rvolosatovs/west/westhttp"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -48,120 +46,31 @@ func init() {

func TestIncomingHandler(t *testing.T) {
west.RunTest(t, func() {
headers := testtypes.NewFields()
headers.Append(
testtypes.FieldKey("foo"),
testtypes.FieldValue(cm.NewList(
unsafe.SliceData([]byte("bar")),
3,
)),
)
headers.Append(
testtypes.FieldKey("foo"),
testtypes.FieldValue(cm.NewList(
unsafe.SliceData([]byte("baz")),
3,
)),
)
headers.Set(
testtypes.FieldKey("key"),
cm.NewList(
unsafe.SliceData(
[]testtypes.FieldValue{
testtypes.FieldValue(cm.NewList(
unsafe.SliceData([]byte("value")),
5,
)),
},
),
1,
),
)
req := testtypes.NewOutgoingRequest(headers)
req.SetPathWithQuery(cm.Some("5"))
req.SetMethod(testtypes.MethodPost())
reqBodyRes := req.Body()
if !assert.Nil(t, reqBodyRes.Err()) {
t.FailNow()
req, err := http.NewRequest(http.MethodPost, "5", bytes.NewReader([]byte("foo bar baz")))
if err != nil {
t.Fatalf("failed to create new HTTP request: %s", err)
}
reqBody := reqBodyRes.OK()
reqStreamRes := reqBody.Write()
if !assert.Nil(t, reqStreamRes.Err()) {
t.FailNow()
req.Header.Add("foo", "bar")
req.Header.Add("foo", "baz")
req.Header.Add("key", "value")
resp, err := westhttp.HandleIncomingRequest(incominghandler.Exports.Handle, req)
if err != nil {
t.Fatalf("failed to handle incoming HTTP request: %s", err)
}
reqStream := reqStreamRes.OK()
writeRes := reqStream.BlockingWriteAndFlush(cm.NewList(
unsafe.SliceData([]byte("foo bar baz")),
11,
))
if !assert.Nil(t, writeRes.Err()) {
t.FailNow()
}
reqStream.ResourceDrop()
reqBodyFinishRes := testtypes.OutgoingBodyFinish(*reqBody, cm.None[testtypes.Fields]())
if !assert.Nil(t, reqBodyFinishRes.Err()) {
t.FailNow()
}

out := httpext.NewResponseOutparam()
incominghandler.Exports.Handle(
types.IncomingRequest(httpext.NewIncomingRequest(req)),
types.ResponseOutparam(out.F0),
)
out.F1.Subscribe().Block()
respOptResRes := out.F1.Get()
respResRes := respOptResRes.Some()
if !assert.NotNil(t, respResRes) || !assert.Nil(t, respResRes.Err()) {
t.FailNow()
}
respRes := respResRes.OK()
if !assert.Nil(t, respRes.Err()) {
t.Fatal(*respRes.Err())
}
resp := respRes.OK()
assert.Equal(t, testtypes.StatusCode(200), resp.Status())
hs := map[string][][]byte{}
for _, h := range resp.Headers().Entries().Slice() {
k := string(h.F0)
hs[k] = append(hs[k], h.F1.Slice())
}
assert.Equal(t, map[string][][]byte{
assert.Equal(t, 200, resp.StatusCode)
assert.Equal(t, http.Header{
"foo": {
[]byte("bar"),
[]byte("baz"),
"bar",
"baz",
},
"key": {
[]byte("value"),
"value",
},
}, hs)
bodyRes := resp.Consume()
if !assert.Nil(t, bodyRes.Err()) {
t.FailNow()
}

body := bodyRes.OK()
bodyStreamRes := body.Stream()
if !assert.Nil(t, bodyStreamRes.Err()) {
t.FailNow()
}

bodyStream := bodyStreamRes.OK()
var buf []byte
for {
bufRes := bodyStream.BlockingRead(4096)
if bufRes.IsErr() && *bufRes.Err() == teststreams.StreamErrorClosed() {
break
}
if !assert.Nil(t, bufRes.Err()) {
if !assert.False(t, bufRes.Err().Closed()) {
t.FailNow()
} else {
t.Fatal(*bufRes.Err().LastOperationFailed())
}
}
buf = append(buf, bufRes.OK().Slice()...)
}, resp.Header)
buf, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed to read HTTP response body: %s", err)
}
assert.Equal(t, []byte("🧭🧭🧭🧭🧭foo bar baz"), buf)
bodyStream.ResourceDrop()
})
}
Loading

0 comments on commit 10e0f1a

Please sign in to comment.