diff --git a/packages/binding-http/src/routes/action.ts b/packages/binding-http/src/routes/action.ts index 4cad36d9b..88e6943f6 100644 --- a/packages/binding-http/src/routes/action.ts +++ b/packages/binding-http/src/routes/action.ts @@ -83,7 +83,7 @@ export default async function actionRoute( res.writeHead(200); output.body.pipe(res); } else { - res.writeHead(200); + res.writeHead(204); res.end(); } } catch (err) { diff --git a/packages/binding-http/test/http-server-test.ts b/packages/binding-http/test/http-server-test.ts index ff69c9f66..38ba34f87 100644 --- a/packages/binding-http/test/http-server-test.ts +++ b/packages/binding-http/test/http-server-test.ts @@ -204,15 +204,51 @@ class HttpServerTest { resp = await (await fetch(uri + "properties/test")).text(); expect(resp).to.equal('"on"'); - resp = await (await fetch(uri + "actions/try", { method: "POST", body: "toggle" })).text(); + let actionHttpResponse = await fetch(uri + "actions/try", { method: "POST", body: "toggle" }); + resp = await actionHttpResponse.text(); + + expect(actionHttpResponse.status).to.equal(200); expect(resp).to.equal('"TEST"'); + actionHttpResponse = await fetch(uri + "actions/try", { method: "POST", body: undefined }); resp = await (await fetch(uri + "actions/try", { method: "POST", body: undefined })).text(); + + expect(actionHttpResponse.status).to.equal(200); expect(resp).to.equal('"TEST"'); return httpServer.stop(); } + @test async "should return 204 when action has not output"() { + const httpServer = new HttpServer({ port: 0 }); + + await httpServer.start(null); + + const testThing = new ExposedThing(null, { + title: "Test", + actions: { + noOutput: { + output: { type: "string" }, + forms: [], + }, + }, + }); + + testThing.setActionHandler("noOutput", async () => undefined); + + await httpServer.expose(testThing); + + const uri = `http://localhost:${httpServer.getPort()}/test/`; + + debug(`Testing ${uri}`); + + const resp = await fetch(uri + "actions/noOutput", { method: "POST" }); + + expect(resp.status).to.equal(204); + + return httpServer.stop(); + } + @test async "should check uriVariables consistency"() { const httpServer = new HttpServer({ port: 0 }); diff --git a/packages/core/src/exposed-thing.ts b/packages/core/src/exposed-thing.ts index bb6d27c50..846c82a60 100644 --- a/packages/core/src/exposed-thing.ts +++ b/packages/core/src/exposed-thing.ts @@ -369,7 +369,7 @@ export default class ExposedThing extends TD.Thing implements WoT.ExposedThing { new InteractionOutput(inputContent, form, this.actions[name].input), options ); - if (result) { + if (result !== undefined) { // TODO: handle form.response.contentType return ContentManager.valueToContent(result, this.actions[name].output, form.contentType); } diff --git a/packages/core/test/ServerTest.ts b/packages/core/test/ServerTest.ts index 791f24750..03744f45e 100644 --- a/packages/core/test/ServerTest.ts +++ b/packages/core/test/ServerTest.ts @@ -1022,6 +1022,39 @@ class WoTServerTest { callback.should.have.been.called(); } + @test async "should return content when returning 0 for action handler"() { + const thing = await WoTServerTest.WoT.produce({ + title: "The Machine", + actions: { + test: { + output: { + type: "number", + }, + forms: [ + { + href: "http://example.org/test", + op: ["invokeaction"], + }, + ], + }, + }, + }); + const callback = spy(async (params: InteractionOutput) => { + return 0; + }); + + thing.setActionHandler("test", callback); + + const result = await (thing).handleInvokeAction( + "test", + new Content("application/json", Readable.from(Buffer.from(""))), + { formIndex: 0 } + ); + + callback.should.have.been.called(); + expect(result).to.be.instanceOf(Content); + } + @test async "should fail due to wrong uriVariable"() { const thing = await WoTServerTest.WoT.produce({ title: "The Machine",