diff options
author | Magnus Feuer <mfeuer@jaguarlandrover.com> | 2015-04-12 13:40:53 -0700 |
---|---|---|
committer | Magnus Feuer <mfeuer@jaguarlandrover.com> | 2015-04-12 13:40:53 -0700 |
commit | 56a06b1b0f1583c39c1aad8d74e0b791e78a4db8 (patch) | |
tree | fb4354cdaf22225ff2c610c8ae00a99892fe07e3 | |
parent | ffe60f97c1ec46aae1b62f0867b755095cf659ec (diff) | |
download | rvi_core-56a06b1b0f1583c39c1aad8d74e0b791e78a4db8.tar.gz |
Test
-rw-r--r-- | components/dlink_tcp/src/dlink_tcp_rpc.erl | 2 | ||||
-rw-r--r-- | components/schedule/src/rvi_routing.erl | 52 | ||||
-rw-r--r-- | components/schedule/src/schedule_rpc.erl | 99 | ||||
-rw-r--r-- | rvi_sample.config | 58 | ||||
-rw-r--r-- | test/test_plan.md | 54 |
5 files changed, 188 insertions, 77 deletions
diff --git a/components/dlink_tcp/src/dlink_tcp_rpc.erl b/components/dlink_tcp/src/dlink_tcp_rpc.erl index 9ff68f0..84d6517 100644 --- a/components/dlink_tcp/src/dlink_tcp_rpc.erl +++ b/components/dlink_tcp/src/dlink_tcp_rpc.erl @@ -541,7 +541,7 @@ handle_call({rvi, setup_data_link, [ Service, Opts ]}, _From, St) -> undefined -> ?info("dlink_tcp:setup_data_link(~p) Failed: no target given in options.", [Service]), - { reply, [ no_route, 0 ], St }; + { reply, [ok, -1 ], St }; Addr -> [ Address, Port] = string:tokens(Addr, ":"), diff --git a/components/schedule/src/rvi_routing.erl b/components/schedule/src/rvi_routing.erl index 0e6dfbe..3bbc16f 100644 --- a/components/schedule/src/rvi_routing.erl +++ b/components/schedule/src/rvi_routing.erl @@ -16,6 +16,9 @@ -export([get_service_routes/1]). -export([start_link/0]). +-export([find_routes_/2, + normalize_routes_/2]). + %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -91,7 +94,7 @@ init([]) -> %% @end %%-------------------------------------------------------------------- handle_call( { rvi_get_service_routes, Service }, _From, St) -> - {reply, normalize_routes_(find_routes_( St#st.routes, Service), []), t}; + {reply, find_routes_( St#st.routes, Service), St}; handle_call(_Request, _From, St) -> Reply = ok, @@ -155,17 +158,25 @@ code_change(_OldVsn, St, _Extra) -> %%%=================================================================== -prefix_match_(_, [], Len) -> +%% We ran out of prefix chars. +%% Service is a prefix match +prefix_match_(_Service, [], Len) -> Len; -prefix_match_([], _, Len ) -> - Len; +%% We ran out of service chars. +%% Service is shorter than prefix no match. +prefix_match_([], _Prefix, _Len ) -> + -1; -prefix_match_([ C1 | T1], [ C2 | T2 ], Len) when C1 =:= C2 -> - prefix_match_(T1, T2, Len +1); +%% +prefix_match_([ ServiceH | ServiceT], [ PrefixH | PrefixT ], Len) + when ServiceH =:= PrefixH -> -prefix_match_(_,_, Len) -> - Len. + prefix_match_(ServiceT, PrefixT, Len + 1); + +%% Mismatch between the the service and candidate. No match +prefix_match_(_Service, _Prefix, _Len) -> + -1. find_routes_([], _Service, CurRoutes, CurMatchLen ) -> { CurRoutes, CurMatchLen }; @@ -178,32 +189,38 @@ find_routes_([ { ServicePrefix, Routes } | T], Service, CurRoutes, CurMatchLen ) true -> %% Continue with the new routes and matching len installed find_routes_(T, Service, Routes, MatchLen); - + false -> %% Continue with the old routes and matching len installed find_routes_(T, Service, CurRoutes, CurMatchLen) end; - -find_routes_(Rt, Svc, CurRoutes, CurMatchLen) -> - ?info("----------------Failed on ~p", [Rt]), - { x, y}. + +find_routes_(Rt, _Svc, CurRoutes, CurMatchLen) -> + ?warning("rvi_routing(): Incorrect route entry: ~p", [Rt]), + { CurRoutes, CurMatchLen }. find_routes_(Routes, Service) -> case find_routes_(Routes, Service, undefined, 0) of { undefined, 0 } -> - not_found; + ?debug("rvi_routing(): ~p -> unknown", [ Service]), + []; %% No routes found - { Routes, _MatchLen } -> - Routes + { MatchRoutes, _MatchLen } -> + ?debug("rvi_routing(): ~p -> ~p", [ Service, MatchRoutes ]), + normalize_routes_(MatchRoutes, []) end. +%% { Protocol, DataLink } -> { {Protocol, [] }, {DataLink, [] } }, +%% { Protocol, { DataLink, DOpts } -> { {Protocol, [] }, {DataLink, DOpts } }, +%% { { Protocol, POpts }, DataLink } -> { {Protocol, POpts}, {DataLink, [] }}, +%% { { Protocol, POpts }, { DataLink, DOpts } -> { {Protocol, POpts}, {DataLink, DOpts }}, normalize_routes_({ServicePrefix, []}, Acc) -> { ServicePrefix, lists:reverse(Acc) }; normalize_routes_({ServicePrefix, [ {{ Pr, PrOp }, { DL, DLOp }} | Rem ]}, Acc) -> - normalize_routes_({ServicePrefix, Rem}, [ { {Pr, PrOp}, { DL, DLOp } } | Acc]); + normalize_routes_({ServicePrefix, Rem}, [ {{Pr, PrOp}, { DL, DLOp } } | Acc]); normalize_routes_({ServicePrefix, [ { Pr, { DL, DLOp }} | Rem ]}, Acc) -> normalize_routes_({ServicePrefix, Rem}, [ { {Pr, []}, { DL, DLOp } } | Acc]); @@ -213,3 +230,4 @@ normalize_routes_({ServicePrefix, [ {{ Pr, PrOp}, DL } | Rem ]}, Acc) -> normalize_routes_({ServicePrefix, [ {Pr, DL} | Rem ]}, Acc) -> normalize_routes_({ServicePrefix, Rem}, [ { {Pr, []}, { DL, [] } } | Acc]). + diff --git a/components/schedule/src/schedule_rpc.erl b/components/schedule/src/schedule_rpc.erl index 7a1b23a..be05d92 100644 --- a/components/schedule/src/schedule_rpc.erl +++ b/components/schedule/src/schedule_rpc.erl @@ -219,27 +219,22 @@ handle_call( { rvi, schedule_message, ?debug("schedule:sched_msg(): certificate ~p", [Certificate]), %%?debug("schedule:sched_msg(): St: ~p", [St]), - %% - %% Retrieve the routes that we should try for this message - %% - case rvi_routing:get_service_routes(SvcName) of - not_found -> - {reply, [ no_route ], St }; - - Routes -> - { TransID, NSt1} = create_transaction_id(St), - NSt2 = queue_message(SvcName, - TransID, - Routes, - Timeout, - calc_relative_tout(Timeout), - Parameters, - Signature, - Certificate, - NSt1), - - { reply, [ok, TransID], NSt2 } - end; + %% Create a transaction ID + { TransID, NSt1} = create_transaction_id(St), + + %% Queue the message + NSt2 = queue_message(SvcName, + TransID, + rvi_routing:get_service_routes(SvcName), %% Can be no_route + Timeout, + calc_relative_tout(Timeout), + Parameters, + Signature, + Certificate, + NSt1), + + { reply, [ok, TransID], NSt2 }; + handle_call(Other, _From, St) -> @@ -382,21 +377,6 @@ code_change(_OldVsn, St, _Extra) -> -%% -%% No more routes to try -%% -queue_message(SvcName, - _TransID, - [ ], - _MessageTimeout, - _RelativeTimeout, - _Parameters, - _Signature, - _Certificate, St) -> - - %% FIXME: Handle route failure - ?notice("schedule:queue_message(): Ran out of routes to try for ~p", [SvcName]), - { route_failed, St }; %% @@ -414,6 +394,25 @@ queue_message(SvcName, do_timeout_callback(St#st.cs, SvcName, TransID), { timeout, St }; +%% +%% No more routes to try, or no routes found at all +%% by rvi_routing:get_service_routes() +%% +%% Stash the message in the unknown datalinvariant of the service +%% and opportunistically send it if the service +queue_message(SvcName, + _TransID, + [ ], + _MessageTimeout, + _RelativeTimeout, + _Parameters, + _Signature, + _Certificate, St) -> + + %% FIXME: Handle route failure + ?notice("schedule:queue_message(): Ran out of routes to try for ~p", [SvcName]), + { route_failed, St }; + %% Try to queue message queue_message(SvcName, @@ -442,6 +441,7 @@ queue_message(SvcName, { _ , NSt } -> %% Failed to send message. Setup data link + %% %% Bring up the relevant data link for the given route. %% Once up, the data link will invoke service_availble() @@ -453,10 +453,12 @@ queue_message(SvcName, %% Setup a timeout that triggers on whatever %% comes first of the message's general timeout %% or the timeout of the data link bringup - TRef = erlang:send_after(min(RelativeTimeout, DLTimeout), + %% + TRef = erlang:send_after(select_timeout(RelativeTimeout, DLTimeout), self(), { rvi_message_timeout, SvcName, DLMod, TransID }), + %% Setup a message to be added to the service / dl table. Msg = #message { transaction_id = TransID, @@ -469,7 +471,6 @@ queue_message(SvcName, certificate = Certificate }, - %% Add to ets table TransID = ets:insert(SvcRec#service.messages_tid, Msg), {ok, NSt}; @@ -689,4 +690,24 @@ first_service_message(#service { messages_tid = Tid }) -> end end. - + +%% A timeout of -1 means 'does not apply' +%% +%% However, if both are -1, we just return the shortest posssible +%% timeout. +%% If both timeouts are specified, we select the shortest one. +%% +select_timeout(TimeOut1, TimeOut2) -> + + case { TimeOut1 =:= -1, TimeOut2 =:= -1 } of + { true, true } -> 1; + + { true, false } -> TimeOut2; + + { false, true } -> TimeOut1; + + { false, false } -> min(TimeOut1, TimeOut2) + end. + + + diff --git a/rvi_sample.config b/rvi_sample.config index 9815697..aa2a12b 100644 --- a/rvi_sample.config +++ b/rvi_sample.config @@ -171,31 +171,49 @@ %% { node_service_prefix, "jlr.com/vin/$rvi_uuid(default_vin)/"}, - %% Specify static service prefixes with well known addresses + + %% Routing rules determining how to get a message targeting a specific + %% service to its destination. %% - %% Static nodes allows a local RVI node to route services with - %% matching prefixes to a well known address of a remote node. A - %% static node is often a backend/cloud server that is assumed to - %% be found at a given address as soon as network connectivity - %% has been established. - %% - %% When a locally connected service issues a message or rpc to a - %% service, and the network address of the service cannot be - %% found in the tables maintained by the peer-to-peer service - %% discovery process, the static nodes table below is scanned as - %% to prefix match the service and locate a suitable network - %% address. + %% Please note that if a remotely initiated (== client) data link is + %% available and has announced that the targeted service is available, + %% that data link will be used regardless of what it is. + %% + %% In other words, if you setup routing rules for how to reach out + %% to a vehicle using SMS, and that vehicle happens to have a 3G + %% connection up when the message is sent, the 3G connection will be used. %% - { static_nodes, - [ - %% rvi1.nginfotpdx.net is the JLR hosted RVI server. - %% { "jlr.com/backend/", } - ] - }, - + %% We will add a blacklist feature in the future to optionally block + %% such opportunistic routing in the future. + %% { routing_rules, [ %% Service name prefix that rules are specified for + %% The service prefix with the longest match against the service targeted + %% by the message will be used. + %% + %% Example: Targeted service = jlr.com/backend/sota/get_updates + %% + %% Prefix1: { "jlr.com/backend", [...]} + %% Prefix2: { "jlr.com/backend/sota", [...]} + %% + %% Prefix2 will be used. + %% + %% This allows you, for example, to setup different servers + %% for different types of services (SOTA, remote door unlock, + %% HVAC etc). + %% + + %% Make sure to have a default if you don't want your message + %% to error out immediately. With a default the message will + %% be queued until it times out, waiting for a remote node + %% to connect and announce that it can handle the targeted service. + { "", + [ + { proto_bert_rpc, dlink_tcp_rpc} + ] + }, + { "jlr.com/backend/", %% Which protocol and data link pair to use when transmitting the message %% to the targeted service. If a pair reports a failure, the next pair is tried. diff --git a/test/test_plan.md b/test/test_plan.md new file mode 100644 index 0000000..e5634d8 --- /dev/null +++ b/test/test_plan.md @@ -0,0 +1,54 @@ +# RVI TEST PLAN + +While we are implementing an automated test suite, we will start with a simple manual test schedule + + +# LOCAL SERVICES + +## SERVICE REGISTRATION + +## SERVICE QUERYING (RVI_GET_SERVICES) + +## SERVICE AVAILABILITY NOTIFICATION + +## SERVICE DEREGISTRATION + +## SERVICE INVOCATION + +## INVOCATION OF NON-EXISTENT SERVICE + +## STRESS TEST + + + +# REMOTE SERVICES + +## SERVICE REGISTRATION + +## SERVICE QUERYING (RVI_GET_SERVICES) + +## SERVICE AVAILABILITY NOTIFICATION + +## SERVICE DEREGISTRATION + +## SERVICE INVOCATION + +## INVOCATION OF NON-EXISTENT SERVICE + +## LINK LOSS + +## LINK RECONNECT + +## LINK ESTABLISHMENT + +## STRESS TEST + + +# MULTI-PATHED SERVICES + +## TCP + +## BT + +## SMS + |