diff --git a/docs/api/README.md b/docs/api/README.md new file mode 100644 index 0000000..99e9007 --- /dev/null +++ b/docs/api/README.md @@ -0,0 +1,13 @@ +# Domo API documentation + +## Quick overview + +This documentation allow you to control the domo system. + + +## API design + +- http://dev.enchant.com/api/v1 +- http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#useful-post-responses +- https://restfulapi.net/resource-naming/ + diff --git a/docs/api/test-rest-api.md b/docs/api/test-rest-api.md new file mode 100644 index 0000000..a634075 --- /dev/null +++ b/docs/api/test-rest-api.md @@ -0,0 +1,77 @@ +# Test all the REST API of domo. + +## Outlets + +### list + +``` +curl -v http://localhost:34000/v1/outlets +``` + +```json +{ + "id": "", + "outlets": [ + { + "id": 1, + "name": "Bureau JB", + "sender": 12797322, + "speech_name": "bureau", + "state": true, + "switch": 0 + }, + { + "id": 2, + "name": "Salon", + "sender": 12797322, + "speech_name": "salon", + "state": false, + "switch": 1 + }, + { + "id": 3, + "name": "Sapin", + "sender": 12797322, + "speech_name": "sapin", + "state": false, + "switch": 2 + } + ], + "response_code": 200, + "status": "passed" +} +``` +### read + +``` +curl -v http://localhost:34000/v1/outlets/2 +``` + +```json +{ + "id": 2, + "name": "Salon", + "sender": 12797322, + "speech_name": "salon", + "state": false, + "switch": 1 +} +``` + +### create + +``` +curl -X POST -v http://localhost:34000/v1/outlets -d "{\"name\":\"test\", \"sender\": 12797322, \"switch\": 4}" +``` + +### update + +``` +curl -X PUT -v http://localhost:34000/v1/outlets/4 -d "{\"name\":\"test1\", \"sender\": 1, \"switch\": 2}" +``` + +### delete + +``` +curl -v http://localhost:34000/v1/outlets/2 +``` diff --git a/docs/api/tests-ubus-api.md b/docs/api/tests-ubus-api.md new file mode 100644 index 0000000..398f642 --- /dev/null +++ b/docs/api/tests-ubus-api.md @@ -0,0 +1,238 @@ +# Test all the ubus API of domo. + + +## domo.capabilities + +### list + +``` +./usr/bin/ubus call domo.capabilities list +``` + +```json +{ + "capabilities": [ + { + "name": "outlets", + "speech_name": "lumière" + }, + { + "name": "shutters", + "speech_name": "volet" + }, + { + "name": "sprinklers", + "speech_name": "station" + } + ] +} + +``` + +## domo.outlets + +### create + +``` +./usr/bin/ubus call domo.outlets create "{\"name\":\"test\", \"sender\": 12797322, \"switch\": 4}" +``` + +#### create failed 1 + +Name is missing. + +``` +./usr/bin/ubus call domo.outlets create "{\"sender\": 12797322, \"switch\": 4}" +./usr/bin/ubus call domo.outlets create "{\"name\":\"test\", \"switch\": 4}" +./usr/bin/ubus call domo.outlets create "{\"name\":\"test\", \"sender\": 12797322}" +``` + +### list + +``` +./usr/bin/ubus call domo.outlets list +``` + +```json +{ + "outlets": [ + { + "id": 1, + "name": "Bureau JB", + "speech_name": "bureau", + "zone": "", + "state": true, + "sender": 12797322, + "switch": 0 + }, + { + "id": 2, + "name": "Salon", + "speech_name": "salon", + "zone": "", + "state": false, + "sender": 12797322, + "switch": 1 + }, + { + "id": 3, + "name": "Sapin", + "speech_name": "sapin", + "zone": "", + "state": false, + "sender": 12797322, + "switch": 2 + } + ] +} +``` + +### read + +``` +./usr/bin/ubus call domo.outlets read "{\"id\":2}" +``` + +```json +{ + "id": 2, + "name": "Salon", + "speech_name": "salon", + "state": false, + "zone": "", + "sender": 12797322, + "switch": 1 +} +``` + +### update + +``` +./usr/bin/ubus call domo.outlets update "{\"id\": 4, \"name\":\"test1\", \"sender\": 1, \"switch\": 2}" +``` + +### delete + +``` +./usr/bin/ubus call domo.outlets delete "{\"id\": 4}" +``` + +## domo.sequences + +### create + +``` +./usr/bin/ubus call domo.sequences create +``` + +### list + +``` +./usr/bin/ubus call domo.sequences list +``` + +### read + +``` +./usr/bin/ubus call domo.sequences read +``` + +### update + +``` +./usr/bin/ubus call domo.sequences update +``` + +### delete + +``` +./usr/bin/ubus call domo.sequences delete +``` + +## domo.shutters + +### create + +``` +./usr/bin/ubus call domo.shutters create +``` + +### list + +``` +./usr/bin/ubus call domo.shutters list +``` + +### read + +``` +./usr/bin/ubus call domo.shutters read +``` + +### update + +``` +./usr/bin/ubus call domo.shutters update +``` + +### delete + +``` +./usr/bin/ubus call domo.shutters delete +``` + +### up + +``` +./usr/bin/ubus call domo.shutters up +``` + +### down + +``` +./usr/bin/ubus call domo.shutters down +``` + +## domo.sprinklers + +### create + +``` +./usr/bin/ubus call domo.sprinklers create +``` + +### list + +``` +./usr/bin/ubus call domo.sprinklers list +``` + +### read + +``` +./usr/bin/ubus call domo.sprinklers read +``` + +### update + +``` +./usr/bin/ubus call domo.sprinklers update +``` + +### delete + +``` +./usr/bin/ubus call domo.sprinklers delete +``` + +### open + +``` +./usr/bin/ubus call domo.sprinklers open +``` + +### close + +``` +./usr/bin/ubus call domo.sprinklers close +``` diff --git a/src/devices/device.c b/src/devices/device.c index 5bc309b..4169340 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -98,11 +98,15 @@ int device_from_json(device_t *device, struct json_object *node) // name if (json_object_object_get_ex(node, k_entry_name, &value_node)) { + if (device->name != NULL) + free(device->name); device->name = strdup(json_object_get_string(value_node)); } // speech_name if (json_object_object_get_ex(node, k_entry_speech_name, &value_node)) { + if (device->speech_name != NULL) + free(device->speech_name); device->speech_name = strdup(json_object_get_string(value_node)); } // state diff --git a/src/devices/devices_manager.c b/src/devices/devices_manager.c index 41ebbb3..0610daa 100644 --- a/src/devices/devices_manager.c +++ b/src/devices/devices_manager.c @@ -289,30 +289,6 @@ char *devices_manager_get_by_id(devices_manager_t *dm, const char *capability, u /*--------------------------------------------------------------------------*/ -struct json_object *devices_manager_to_json_object(devices_manager_t *dm, const char *capability) -{ - struct json_object *root_node; - // Sanity Checks - if (dm == NULL) - return NULL; - - root_node = json_object_new_array(); - - if (capability == kOutletEntry) - { - } - else if (capability == kShutterEntry) - { - } - else if (capability == kSprinklerEntry) - { - } - - return root_node; -} - -/*--------------------------------------------------------------------------*/ - int devices_manager_create(devices_manager_t *dm, const char *capability, struct json_object *node) { // Sanity checks @@ -378,17 +354,8 @@ int devices_manager_update(devices_manager_t *dm, const char *capability, struct /*--------------------------------------------------------------------------*/ -int devices_manager_delete(devices_manager_t *dm, const char *capability, struct json_object *node) +int devices_manager_delete(devices_manager_t *dm, const char *capability, uint32_t id) { - int32_t id = -1; - struct json_object *value_node; - - // id - if (json_object_object_get_ex(node, k_entry_id, &value_node)) - { - id = json_object_get_int(value_node); - } - // Sanity checks. if (id == -1) return -1; diff --git a/src/devices/devices_manager.h b/src/devices/devices_manager.h index 1005b2e..2f32662 100644 --- a/src/devices/devices_manager.h +++ b/src/devices/devices_manager.h @@ -74,6 +74,6 @@ extern struct json_object *devices_manager_to_json_object(devices_manager_t *dm, extern int devices_manager_create(devices_manager_t *dm, const char *capability, struct json_object *node); extern int devices_manager_update(devices_manager_t *dm, const char *capability, struct json_object *node); -extern int devices_manager_delete(devices_manager_t *dm, const char *capability, struct json_object *node); +extern int devices_manager_delete(devices_manager_t *dm, const char *capability, uint32_t id); #endif /*_DEVICES_MANAGER_H */ diff --git a/src/devices/outlet_dio.c b/src/devices/outlet_dio.c index f376b4a..7245e4e 100644 --- a/src/devices/outlet_dio.c +++ b/src/devices/outlet_dio.c @@ -87,6 +87,8 @@ int outlet_dio_from_json(outlet_dio_t *outlet, struct json_object *node) // zone if (json_object_object_get_ex(node, k_entry_zone, &value_node)) { + if (outlet->zone != NULL) + free(outlet->zone); outlet->zone = strdup(json_object_get_string(value_node)); } // sender diff --git a/src/rest/rest_devices_handlers.c b/src/rest/rest_devices_handlers.c index c90b239..aa9a8bd 100644 --- a/src/rest/rest_devices_handlers.c +++ b/src/rest/rest_devices_handlers.c @@ -34,10 +34,10 @@ #include "domo.h" // Code Description +// 201 201 Created - Resource created. // 204 Success. No content. // 400 Bad request - /*--------------------------------------------------------------------------*/ int capabilities_handler(restd_resp_t *response, void *arg) @@ -56,8 +56,8 @@ int capabilities_handler(restd_resp_t *response, void *arg) if (s == 0) restd_http_response(response, 500, "application/json", kempty_body); - buf[s]='\0'; - + buf[s] = '\0'; + restd_http_response(response, 200, "application/json", buf); return RESTD_OK; @@ -71,8 +71,6 @@ int outlet_create_handler(restd_resp_t *response, void *arg) char *data; devices_manager_t *dm = (devices_manager_t *)arg; - printf("outlet_create_handler\n\n"); - data = restd_http_get_body(response); if (data == NULL) @@ -105,8 +103,19 @@ int outlet_create_handler(restd_resp_t *response, void *arg) int outlet_list_handler(restd_resp_t *response, void *arg) { - printf("outlet_list_handler\n\n"); - restd_http_response(response, 200, "application/json", kempty_body); + devices_manager_t *dm = (devices_manager_t *)arg; + char *data; + + data = devices_manager_get(dm, kOutletEntry); + if (data == NULL) + { + restd_http_response(response, 500, "application/json", kempty_body); + return RESTD_OK; + } + + restd_http_response(response, 200, "application/json", data); + free(data); + return RESTD_OK; } @@ -114,19 +123,85 @@ int outlet_list_handler(restd_resp_t *response, void *arg) int outlet_get_handler(restd_resp_t *response, void *arg) { - return 0; + struct json_object *root_node = NULL; + char *data; + devices_manager_t *dm = (devices_manager_t *)arg; + + if (response->has_parameter == false) + { + restd_http_response(response, 500, "application/json", kerror_body); + return RESTD_OK; + } + + data = devices_manager_get_by_id(dm, kOutletEntry, response->parameter_value); + restd_http_response(response, 200, "application/json", data); + free(data); + + return RESTD_OK; } /*--------------------------------------------------------------------------*/ int outlet_update_handler(restd_resp_t *response, void *arg) { - return 0; + struct json_object *root_node = NULL; + char *data; + devices_manager_t *dm = (devices_manager_t *)arg; + + data = restd_http_get_body(response); + + if (data == NULL) + { + restd_http_response(response, 400, "application/json", kerror_body); + return RESTD_OK; + } + + root_node = json_tokener_parse(data); + free(data); + + if (root_node != NULL) + { + int ret; + if (response->has_parameter == true) + { + if (response->parameter_name != NULL) + { + json_object_object_add(root_node, response->parameter_name, json_object_new_int(response->parameter_value)); + } + } + + ret = devices_manager_update(dm, kOutletEntry, root_node); + json_object_put(root_node); + if (ret == 0) + { + restd_http_response(response, 204, "application/json", kempty_body); + return RESTD_OK; + } + } + + restd_http_response(response, 500, "application/json", kerror_body); + return RESTD_OK; } /*--------------------------------------------------------------------------*/ int outlet_remove_handler(restd_resp_t *response, void *arg) { - return 0; + struct json_object *root_node = NULL; + int ret; + devices_manager_t *dm = (devices_manager_t *)arg; + + if (response->has_parameter == false) + { + restd_http_response(response, 500, "application/json", kerror_body); + return RESTD_OK; + } + + ret = devices_manager_delete(dm, kOutletEntry, response->parameter_value); + if (ret == 0) + restd_http_response(response, 204, "application/json", ""); + else + restd_http_response(response, 400, "application/json", kerror_body); + + return RESTD_OK; } diff --git a/src/tests/dump_domo.h b/src/tests/dump_domo.h index 4ae8dd1..fdecbcd 100644 --- a/src/tests/dump_domo.h +++ b/src/tests/dump_domo.h @@ -1,16 +1,10 @@ -#define k_device_list_empty "{\n\ - \"capabilities\": [\n\ - {\n\ - \"name\": \"outlets\",\n\ - \"speech_name\": \"lumière\"\n\ - },\n\ - {\n\ - \"name\": \"shutters\",\n\ - \"speech_name\": \"volet\"\n\ - },\n\ - {\n\ - \"name\": \"sprinklers\",\n\ - \"speech_name\": \"station\"\n\ - }\n\ - ]\n\ -}" +#define k_outlet_list_empty "[ ]" + +#define k_create_outlet_1 "{\"name\":\"outlet_1\", \"sender\": 12797322, \"switch\": 4}" +#define k_create_outlet_2 "{\"name\":\"outlet_2\", \"sender\": 87654321, \"switch\": 2}" + +#define k_update_outlet_2 "{\"name\":\"updated_name\", \"sender\": 12345678, \"switch\": 3, \"state\": true}" + +#define k_outlet_list_one_elem "[ { \"id\": 1, \"name\": \"outlet_1\", \"state\": false, \"zone\": \"\", \"sender\": 12797322, \"switch\": 4 } ]" +#define k_outlet_list_two_elem "[ { \"id\": 1, \"name\": \"outlet_1\", \"state\": false, \"zone\": \"\", \"sender\": 12797322, \"switch\": 4 }, { \"id\": 2, \"name\": \"outlet_2\", \"state\": false, \"zone\": \"\", \"sender\": 87654321, \"switch\": 2 } ]" +#define k_outlet_list_elem_2 "{ \"id\": 2, \"name\": \"updated_name\", \"state\": true, \"zone\": \"\", \"sender\": 12345678, \"switch\": 3 }" diff --git a/src/tests/test_devices.c b/src/tests/test_devices.c index 4c5b43c..b500013 100644 --- a/src/tests/test_devices.c +++ b/src/tests/test_devices.c @@ -114,10 +114,7 @@ void device_create_three_devices_remove_second(const char *capability, const ch free(device_serialized); // Remove ID 2. - root_node = json_object_new_object(); - json_object_object_add(root_node, k_entry_id, json_object_new_int(2)); - ret = devices_manager_delete(dm, capability, root_node); - json_object_put(root_node); + ret = devices_manager_delete(dm, capability, 2); ASSERT_EQUAL_INT(ret, 0); device_serialized = devices_manager_get(dm, capability); diff --git a/src/tests/test_domo.c b/src/tests/test_domo.c index c5188a4..33ffa4c 100644 --- a/src/tests/test_domo.c +++ b/src/tests/test_domo.c @@ -142,36 +142,41 @@ TEST("Domo - Test API /api/v1/outlets - correct access\t") // Outlets // Get All Devices. Should be empty. - ret = exec_request(kget_method, "http://localhost:" kserver_port "/api/v1/capabilities", 200, "", k_device_list_empty, false); + ret = exec_request(kget_method, "http://localhost:" kserver_port "/api/v1/outlets", 200, "", k_outlet_list_empty, false); ASSERT_EQUAL_INT(ret, 0); // Create An Outlet. Should be empty. - + ret = exec_request(kpost_method, "http://localhost:" kserver_port "/api/v1/outlets", 204, k_create_outlet_1, "", false); + ASSERT_EQUAL_INT(ret, 0); // Get All Devices. Should Contain One Device. - + ret = exec_request(kget_method, "http://localhost:" kserver_port "/api/v1/outlets", 200, "", k_outlet_list_one_elem, false); + ASSERT_EQUAL_INT(ret, 0); // Create A second Outlet. Should Contain two Device. + ret = exec_request(kpost_method, "http://localhost:" kserver_port "/api/v1/outlets", 204, k_create_outlet_2, "", false); + ASSERT_EQUAL_INT(ret, 0); + // Get All Devices. Should Contain two Devices. + ret = exec_request(kget_method, "http://localhost:" kserver_port "/api/v1/outlets", 200, "", k_outlet_list_two_elem, false); + ASSERT_EQUAL_INT(ret, 0); // Update the second Outlet. Device should contain. + ret = exec_request(kput_method, "http://localhost:" kserver_port "/api/v1/outlets/2", 204, k_update_outlet_2, "", false); + ASSERT_EQUAL_INT(ret, 0); // Get Device 2 only. Should Contain Device two updated. + ret = exec_request(kget_method, "http://localhost:" kserver_port "/api/v1/outlets/2", 200, "", k_outlet_list_elem_2, false); + ASSERT_EQUAL_INT(ret, 0); // Delete Device 2. - + ret = exec_request(kdelete_method, "http://localhost:" kserver_port "/api/v1/outlets/2", 204, "", "", false); + ASSERT_EQUAL_INT(ret, 0); // Get All Devices. Should Contain One Device. + ret = exec_request(kget_method, "http://localhost:" kserver_port "/api/v1/outlets", 200, "", k_outlet_list_one_elem, false); + ASSERT_EQUAL_INT(ret, 0); restd_server_free(rest_server); devices_manager_free(dm); } - -#if 0 - // Outlets - restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_POST, "/api/v1/outlets", outlet_create_handler, dm); - restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, "/api/v1/outlets", outlet_list_handler, dm); - restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, "/api/v1/outlets/:id", outlet_get_handler, dm); - restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_PUT, "/api/v1/outlets/:id", outlet_update_handler, dm); - restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_DELETE, "/api/v1/outlets/:id", outlet_remove_handler, dm); -#endif \ No newline at end of file diff --git a/src/tests/test_main.c b/src/tests/test_main.c index b57f5e2..c8d272f 100644 --- a/src/tests/test_main.c +++ b/src/tests/test_main.c @@ -116,11 +116,13 @@ TEST("devices_manager create and free\t") } #include "test_utils.c" +#if 1 #include "test_devices.c" #include "test_sprinkler.c" #include "test_shutter.c" #include "test_outlet.c" #include "test_rest.c" +#endif #include "test_domo.c" QUNIT_END(); diff --git a/src/tests/test_rest.c b/src/tests/test_rest.c index 916d420..90bcaa2 100644 --- a/src/tests/test_rest.c +++ b/src/tests/test_rest.c @@ -43,8 +43,6 @@ #define kapi_test_put_id2 "/api/v1/test_put/:year/todo" #define kapi_test_put_id2_body "/api/v1/test_put/1977/todo" -#define kserver_port "7777" - /*--------------------------------------------------------------------------*/ int my_error_handler(restd_resp_t *response, int reason, void *arg) diff --git a/src/tests/test_utils.c b/src/tests/test_utils.c index 22ff7a1..6618545 100644 --- a/src/tests/test_utils.c +++ b/src/tests/test_utils.c @@ -30,6 +30,8 @@ #define kput_method "PUT" #define kdelete_method "DELETE" +#define kserver_port "7777" + /*--------------------------------------------------------------------------*/ int rows_eq(int *a, int *b) @@ -239,7 +241,8 @@ int exec_request(const char *request, const char *path, int expected_code, const if (resp_body == NULL) { - res = 1; + if (expected_code != 204) + res = 1; } else {