blob: 89a9c97bf000c19f11e32edc68e66357ee731360 [file] [log] [blame]
Andrew Brown3831baf2015-01-19 13:38:52 -08001/*
andrewsbrown533c6ef2015-03-03 16:08:41 -08002 * jndn-mock
Alexander Afanasyev83a26d32016-01-26 01:04:32 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
andrewsbrown533c6ef2015-03-03 16:08:41 -08004 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 3, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
12 * more details.
Andrew Brown3831baf2015-01-19 13:38:52 -080013 */
14package com.intel.jndn.mock;
15
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080016import net.named_data.jndn.*;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080017import net.named_data.jndn.encoding.EncodingException;
18import net.named_data.jndn.encoding.TlvWireFormat;
19import net.named_data.jndn.encoding.tlv.Tlv;
20import net.named_data.jndn.encoding.tlv.TlvDecoder;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080021import net.named_data.jndn.security.KeyChain;
22import net.named_data.jndn.security.SecurityException;
23import net.named_data.jndn.transport.Transport;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080024
andrewsbrown1f28bcf2015-04-20 13:29:20 -070025import java.nio.ByteBuffer;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080026import java.util.ArrayList;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080027import java.util.List;
Andrew Brown58191872016-02-05 22:16:57 -080028import java.util.logging.Level;
Andrew Brownec1b0d02015-02-21 13:11:42 -080029import java.util.logging.Logger;
Alexander Afanasyev8e9330f2016-01-25 19:13:40 -080030
Andrew Brown58191872016-02-05 22:16:57 -080031/**
32 * A client-side face for unit testing
andrewsbrown8e517fa2016-02-12 15:51:19 -080033 *
34 * @author Alexander Afanasyev, <aa@cs.ucla.edu>
35 * @author Andrew Brown <andrew.brown@intel.com>
Andrew Brown3831baf2015-01-19 13:38:52 -080036 */
Andrew Brown58191872016-02-05 22:16:57 -080037public class MockFace extends Face {
38
andrewsbrown8e517fa2016-02-12 15:51:19 -080039 /**
40 * API for handling {@link Interest}s
41 */
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080042 public interface SignalOnSendInterest {
43 void emit(Interest interest) throws EncodingException, SecurityException;
44 }
45
andrewsbrown8e517fa2016-02-12 15:51:19 -080046 /**
47 * API for handling {@link Data}s
48 */
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080049 public interface SignalOnSendData {
50 void emit(Data data);
51 }
52
53 /**
54 * Options for MockFace
55 */
Andrew Brown58191872016-02-05 22:16:57 -080056 public static class Options {
57
58 /**
59 * If true, packets sent out of MockFace will be appended to a container
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080060 */
61 boolean enablePacketLogging = false;
62
63 /**
Andrew Brown58191872016-02-05 22:16:57 -080064 * If true, prefix registration command will be automatically replied with a
65 * successful response
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080066 */
67 boolean enableRegistrationReply = false;
68 }
69
andrewsbrown8e517fa2016-02-12 15:51:19 -080070 /**
71 * Default options
72 */
73 public static final Options DEFAULT_OPTIONS = new Options() {
Andrew Brown58191872016-02-05 22:16:57 -080074 {
75 enablePacketLogging = true;
76 enableRegistrationReply = true;
77 }
78 };
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080079
80 /**
andrewsbrown8e517fa2016-02-12 15:51:19 -080081 * Create MockFace that logs packets in {@link #sentInterests} and
82 * {@link #sentData} and emulates NFD prefix registration
83 *
84 * @throws SecurityException should not be thrown by this test class
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080085 */
86 public MockFace() throws SecurityException {
87 this(DEFAULT_OPTIONS);
88 }
89
90 /**
91 * Create MockFace with the specified options
92 * <p>
93 * To create Face that does not log packets:
94 * <pre>
95 * new MockFace(new Options());
96 * // use onSendInterest.add(handler) and onSendData.add(handler)
97 * // to add custom logic when Interest or Data packet are sent
98 * // from the upper level (to transport)
99 * </pre>
100 *
101 * To create Face that just logs packets in sentInterests and sentData:
102 * <pre>
andrewsbrown8e517fa2016-02-12 15:51:19 -0800103 * new MockFace(new Options(){ enablePacketLogging = true; });
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800104 * </pre>
andrewsbrown8e517fa2016-02-12 15:51:19 -0800105 *
106 * @param options see {@link Options}
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800107 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800108 public MockFace(Options options) {
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800109 super(new MockFaceTransport(), null);
andrewsbrown8e517fa2016-02-12 15:51:19 -0800110 transport = (MockFaceTransport) node_.getTransport();
111 transport.setOnSendBlock(new OnIncomingPacket());
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800112
andrewsbrown8e517fa2016-02-12 15:51:19 -0800113 try {
114 keyChain = MockKeyChain.configure(new Name("/mock/key"));
115 setCommandSigningInfo(keyChain, keyChain.getDefaultCertificateName());
116 } catch (SecurityException ex) {
117 LOGGER.log(Level.SEVERE, "Unexpected error in MockKeyChain; this class should never throw", ex);
118 throw new Error(ex);
119 }
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800120
121 if (options.enablePacketLogging) {
122 onSendInterest.add(new SignalOnSendInterest() {
123 @Override
124 public void emit(Interest interest) {
125 sentInterests.add(interest);
126 }
127 });
128
129 onSendData.add(new SignalOnSendData() {
130 @Override
131 public void emit(Data data) {
132 sentData.add(data);
133 }
134 });
135 }
136
137 if (options.enableRegistrationReply) {
andrewsbrown8e517fa2016-02-12 15:51:19 -0800138 onSendInterest.add(new OnPrefixRegistration());
139 }
140 }
141
142 /**
143 * Route incoming packets to the correct callbacks
144 */
145 private class OnIncomingPacket implements MockFaceTransport.OnSendBlockSignal {
146
147 @Override
148 public void emit(ByteBuffer buffer) throws EncodingException, SecurityException {
149 // @todo Implement NDNLP processing
150
151 if (buffer.get(0) == Tlv.Interest || buffer.get(0) == Tlv.Data) {
152 TlvDecoder decoder = new TlvDecoder(buffer);
153 if (decoder.peekType(Tlv.Interest, buffer.remaining())) {
154 Interest interest = new Interest();
155 interest.wireDecode(buffer, TlvWireFormat.get());
156
157 for (SignalOnSendInterest signal : onSendInterest) {
158 signal.emit(interest);
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800159 }
andrewsbrown8e517fa2016-02-12 15:51:19 -0800160 } else if (decoder.peekType(Tlv.Data, buffer.remaining())) {
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800161 Data data = new Data();
andrewsbrown8e517fa2016-02-12 15:51:19 -0800162 data.wireDecode(buffer, TlvWireFormat.get());
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800163
andrewsbrown8e517fa2016-02-12 15:51:19 -0800164 for (SignalOnSendData signal : onSendData) {
165 signal.emit(data);
166 }
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800167 }
andrewsbrown8e517fa2016-02-12 15:51:19 -0800168 } else {
169 LOGGER.info("Received an unknown packet");
170 }
171 }
172 }
173
174 /**
175 * Handle prefix registration requests
176 */
177 private class OnPrefixRegistration implements SignalOnSendInterest {
178
179 @Override
180 public void emit(Interest interest) throws EncodingException, SecurityException {
181 final Name localhostRegistration = new Name("/localhost/nfd/rib");
182 if (!interest.getName().getPrefix(3).equals(localhostRegistration)) {
183 return;
184 }
185
186 ControlParameters params = new ControlParameters();
187 params.wireDecode(interest.getName().get(-5).getValue());
188 params.setFaceId(1);
189 params.setOrigin(0);
190
191 if ("register".equals(interest.getName().get(3).toString())) {
192 params.setCost(0);
193 }
194
andrewsbrown6d700282016-02-16 18:29:46 -0800195 ControlResponse response = new ControlResponse();
196 response.setStatusCode(200);
197 response.setStatusText("OK");
198 response.setBodyAsControlParameters(params);
andrewsbrown8e517fa2016-02-12 15:51:19 -0800199
200 Data data = new Data();
201 data.setName(interest.getName());
andrewsbrown6d700282016-02-16 18:29:46 -0800202 data.setContent(response.wireEncode());
andrewsbrown8e517fa2016-02-12 15:51:19 -0800203 keyChain.sign(data);
204
205 receive(data);
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800206 }
207 }
208
209 /**
210 * Mock reception of the Interest packet on the Face (from transport)
andrewsbrown8e517fa2016-02-12 15:51:19 -0800211 *
Andrew Brown58191872016-02-05 22:16:57 -0800212 * @param interest the mock-remote interest to add to the PIT
213 * @throws EncodingException if packet encoding fails (it should not)
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800214 */
215 public void receive(Interest interest) throws EncodingException {
andrewsbrown8e517fa2016-02-12 15:51:19 -0800216 transport.receive(interest.wireEncode().buf());
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800217 }
218
219 /**
220 * Mock reception of the Data packet on the Face (from transport)
andrewsbrown8e517fa2016-02-12 15:51:19 -0800221 *
Andrew Brown58191872016-02-05 22:16:57 -0800222 * @param data the mock-remote data to add to the CS
223 * @throws EncodingException if packet encoding fails (it should not)
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800224 */
225 public void receive(Data data) throws EncodingException {
andrewsbrown8e517fa2016-02-12 15:51:19 -0800226 transport.receive(data.wireEncode().buf());
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800227 }
228
Andrew Brown58191872016-02-05 22:16:57 -0800229 /**
230 * @return the transport for this face
231 */
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800232 public Transport getTransport() {
andrewsbrown8e517fa2016-02-12 15:51:19 -0800233 return transport;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800234 }
235
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800236 /**
237 * Interests sent out of this MockFace
238 * <p>
Andrew Brown58191872016-02-05 22:16:57 -0800239 * Sent Interests are appended to this container if options.enablePacketLogger
240 * is true. User of this class is responsible for cleaning up the container,
241 * if necessary. After .expressInterest, .processEvents must be called before
242 * the Interest would show up here.
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800243 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800244 public final List<Interest> sentInterests = new ArrayList<>();
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800245
246 /**
247 * Data sent out of this MockFace
248 * <p>
Andrew Brown58191872016-02-05 22:16:57 -0800249 * Sent Data are appended to this container if options.enablePacketLogger is
250 * true. User of this class is responsible for cleaning up the container, if
251 * necessary. After .put, .processEvents must be called before the Data would
252 * show up here.
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800253 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800254 public final List<Data> sentData = new ArrayList<>();
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800255
256 /**
257 * Emits whenever an Interest is sent
258 * <p>
Andrew Brown58191872016-02-05 22:16:57 -0800259 * After .expressInterest, .processEvents must be called before this signal
260 * would be emitted.
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800261 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800262 public final List<SignalOnSendInterest> onSendInterest = new ArrayList<>();
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800263
264 /**
265 * Emits whenever a Data packet is sent
266 * <p>
Andrew Brown58191872016-02-05 22:16:57 -0800267 * After .putData, .processEvents must be called before this signal would be
268 * emitted.
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800269 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800270 public final List<SignalOnSendData> onSendData = new ArrayList<>();
Andrew Brown3831baf2015-01-19 13:38:52 -0800271
andrewsbrown8e517fa2016-02-12 15:51:19 -0800272 private static final Logger LOGGER = Logger.getLogger(MockFace.class.getName());
273 private MockFaceTransport transport;
274 private KeyChain keyChain;
Andrew Brown3831baf2015-01-19 13:38:52 -0800275}