blob: d0ec460710faba65c6b670a9c0be34aae3412e8b [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;
21import net.named_data.jndn.encoding.tlv.TlvEncoder;
22import net.named_data.jndn.security.KeyChain;
23import net.named_data.jndn.security.SecurityException;
24import net.named_data.jndn.transport.Transport;
25import net.named_data.jndn.util.Blob;
26
andrewsbrown1f28bcf2015-04-20 13:29:20 -070027import java.nio.ByteBuffer;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080028import java.util.ArrayList;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080029import java.util.List;
Andrew Brown58191872016-02-05 22:16:57 -080030import java.util.logging.Level;
Andrew Brownec1b0d02015-02-21 13:11:42 -080031import java.util.logging.Logger;
Alexander Afanasyev8e9330f2016-01-25 19:13:40 -080032
Andrew Brown58191872016-02-05 22:16:57 -080033/**
34 * A client-side face for unit testing
andrewsbrown8e517fa2016-02-12 15:51:19 -080035 *
36 * @author Alexander Afanasyev, <aa@cs.ucla.edu>
37 * @author Andrew Brown <andrew.brown@intel.com>
Andrew Brown3831baf2015-01-19 13:38:52 -080038 */
Andrew Brown58191872016-02-05 22:16:57 -080039public class MockFace extends Face {
40
andrewsbrown8e517fa2016-02-12 15:51:19 -080041 /**
42 * API for handling {@link Interest}s
43 */
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080044 public interface SignalOnSendInterest {
45 void emit(Interest interest) throws EncodingException, SecurityException;
46 }
47
andrewsbrown8e517fa2016-02-12 15:51:19 -080048 /**
49 * API for handling {@link Data}s
50 */
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080051 public interface SignalOnSendData {
52 void emit(Data data);
53 }
54
55 /**
56 * Options for MockFace
57 */
Andrew Brown58191872016-02-05 22:16:57 -080058 public static class Options {
59
60 /**
61 * If true, packets sent out of MockFace will be appended to a container
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080062 */
63 boolean enablePacketLogging = false;
64
65 /**
Andrew Brown58191872016-02-05 22:16:57 -080066 * If true, prefix registration command will be automatically replied with a
67 * successful response
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080068 */
69 boolean enableRegistrationReply = false;
70 }
71
andrewsbrown8e517fa2016-02-12 15:51:19 -080072 /**
73 * Default options
74 */
75 public static final Options DEFAULT_OPTIONS = new Options() {
Andrew Brown58191872016-02-05 22:16:57 -080076 {
77 enablePacketLogging = true;
78 enableRegistrationReply = true;
79 }
80 };
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080081
82 /**
andrewsbrown8e517fa2016-02-12 15:51:19 -080083 * Create MockFace that logs packets in {@link #sentInterests} and
84 * {@link #sentData} and emulates NFD prefix registration
85 *
86 * @throws SecurityException should not be thrown by this test class
Alexander Afanasyev83a26d32016-01-26 01:04:32 -080087 */
88 public MockFace() throws SecurityException {
89 this(DEFAULT_OPTIONS);
90 }
91
92 /**
93 * Create MockFace with the specified options
94 * <p>
95 * To create Face that does not log packets:
96 * <pre>
97 * new MockFace(new Options());
98 * // use onSendInterest.add(handler) and onSendData.add(handler)
99 * // to add custom logic when Interest or Data packet are sent
100 * // from the upper level (to transport)
101 * </pre>
102 *
103 * To create Face that just logs packets in sentInterests and sentData:
104 * <pre>
andrewsbrown8e517fa2016-02-12 15:51:19 -0800105 * new MockFace(new Options(){ enablePacketLogging = true; });
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800106 * </pre>
andrewsbrown8e517fa2016-02-12 15:51:19 -0800107 *
108 * @param options see {@link Options}
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800109 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800110 public MockFace(Options options) {
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800111 super(new MockFaceTransport(), null);
andrewsbrown8e517fa2016-02-12 15:51:19 -0800112 transport = (MockFaceTransport) node_.getTransport();
113 transport.setOnSendBlock(new OnIncomingPacket());
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800114
andrewsbrown8e517fa2016-02-12 15:51:19 -0800115 try {
116 keyChain = MockKeyChain.configure(new Name("/mock/key"));
117 setCommandSigningInfo(keyChain, keyChain.getDefaultCertificateName());
118 } catch (SecurityException ex) {
119 LOGGER.log(Level.SEVERE, "Unexpected error in MockKeyChain; this class should never throw", ex);
120 throw new Error(ex);
121 }
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800122
123 if (options.enablePacketLogging) {
124 onSendInterest.add(new SignalOnSendInterest() {
125 @Override
126 public void emit(Interest interest) {
127 sentInterests.add(interest);
128 }
129 });
130
131 onSendData.add(new SignalOnSendData() {
132 @Override
133 public void emit(Data data) {
134 sentData.add(data);
135 }
136 });
137 }
138
139 if (options.enableRegistrationReply) {
andrewsbrown8e517fa2016-02-12 15:51:19 -0800140 onSendInterest.add(new OnPrefixRegistration());
141 }
142 }
143
144 /**
145 * Route incoming packets to the correct callbacks
146 */
147 private class OnIncomingPacket implements MockFaceTransport.OnSendBlockSignal {
148
149 @Override
150 public void emit(ByteBuffer buffer) throws EncodingException, SecurityException {
151 // @todo Implement NDNLP processing
152
153 if (buffer.get(0) == Tlv.Interest || buffer.get(0) == Tlv.Data) {
154 TlvDecoder decoder = new TlvDecoder(buffer);
155 if (decoder.peekType(Tlv.Interest, buffer.remaining())) {
156 Interest interest = new Interest();
157 interest.wireDecode(buffer, TlvWireFormat.get());
158
159 for (SignalOnSendInterest signal : onSendInterest) {
160 signal.emit(interest);
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800161 }
andrewsbrown8e517fa2016-02-12 15:51:19 -0800162 } else if (decoder.peekType(Tlv.Data, buffer.remaining())) {
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800163 Data data = new Data();
andrewsbrown8e517fa2016-02-12 15:51:19 -0800164 data.wireDecode(buffer, TlvWireFormat.get());
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800165
andrewsbrown8e517fa2016-02-12 15:51:19 -0800166 for (SignalOnSendData signal : onSendData) {
167 signal.emit(data);
168 }
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800169 }
andrewsbrown8e517fa2016-02-12 15:51:19 -0800170 } else {
171 LOGGER.info("Received an unknown packet");
172 }
173 }
174 }
175
176 /**
177 * Handle prefix registration requests
178 */
179 private class OnPrefixRegistration implements SignalOnSendInterest {
180
181 @Override
182 public void emit(Interest interest) throws EncodingException, SecurityException {
183 final Name localhostRegistration = new Name("/localhost/nfd/rib");
184 if (!interest.getName().getPrefix(3).equals(localhostRegistration)) {
185 return;
186 }
187
188 ControlParameters params = new ControlParameters();
189 params.wireDecode(interest.getName().get(-5).getValue());
190 params.setFaceId(1);
191 params.setOrigin(0);
192
193 if ("register".equals(interest.getName().get(3).toString())) {
194 params.setCost(0);
195 }
196
197 // TODO: replace with jNDN ControlResponse encoding when available
198 // http://redmine.named-data.net/issues/3455
199 TlvEncoder encoder = new TlvEncoder(256);
200 int saveLength = encoder.getLength();
201 encoder.writeBuffer(params.wireEncode().buf());
202 encoder.writeBlobTlv(Tlv.NfdCommand_StatusText, new Blob("OK").buf());
203 encoder.writeNonNegativeIntegerTlv(Tlv.NfdCommand_StatusCode, 200);
204 encoder.writeTypeAndLength(Tlv.NfdCommand_ControlResponse, encoder.getLength() - saveLength);
205
206 Data data = new Data();
207 data.setName(interest.getName());
208 data.setContent(new Blob(encoder.getOutput(), false));
209 keyChain.sign(data);
210
211 receive(data);
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800212 }
213 }
214
215 /**
216 * Mock reception of the Interest packet on the Face (from transport)
andrewsbrown8e517fa2016-02-12 15:51:19 -0800217 *
Andrew Brown58191872016-02-05 22:16:57 -0800218 * @param interest the mock-remote interest to add to the PIT
219 * @throws EncodingException if packet encoding fails (it should not)
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800220 */
221 public void receive(Interest interest) throws EncodingException {
andrewsbrown8e517fa2016-02-12 15:51:19 -0800222 transport.receive(interest.wireEncode().buf());
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800223 }
224
225 /**
226 * Mock reception of the Data packet on the Face (from transport)
andrewsbrown8e517fa2016-02-12 15:51:19 -0800227 *
Andrew Brown58191872016-02-05 22:16:57 -0800228 * @param data the mock-remote data to add to the CS
229 * @throws EncodingException if packet encoding fails (it should not)
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800230 */
231 public void receive(Data data) throws EncodingException {
andrewsbrown8e517fa2016-02-12 15:51:19 -0800232 transport.receive(data.wireEncode().buf());
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800233 }
234
Andrew Brown58191872016-02-05 22:16:57 -0800235 /**
236 * @return the transport for this face
237 */
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800238 public Transport getTransport() {
andrewsbrown8e517fa2016-02-12 15:51:19 -0800239 return transport;
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800240 }
241
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800242 /**
243 * Interests sent out of this MockFace
244 * <p>
Andrew Brown58191872016-02-05 22:16:57 -0800245 * Sent Interests are appended to this container if options.enablePacketLogger
246 * is true. User of this class is responsible for cleaning up the container,
247 * if necessary. After .expressInterest, .processEvents must be called before
248 * the Interest would show up here.
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800249 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800250 public final List<Interest> sentInterests = new ArrayList<>();
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800251
252 /**
253 * Data sent out of this MockFace
254 * <p>
Andrew Brown58191872016-02-05 22:16:57 -0800255 * Sent Data are appended to this container if options.enablePacketLogger is
256 * true. User of this class is responsible for cleaning up the container, if
257 * necessary. After .put, .processEvents must be called before the Data would
258 * show up here.
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800259 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800260 public final List<Data> sentData = new ArrayList<>();
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800261
262 /**
263 * Emits whenever an Interest is sent
264 * <p>
Andrew Brown58191872016-02-05 22:16:57 -0800265 * After .expressInterest, .processEvents must be called before this signal
266 * would be emitted.
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800267 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800268 public final List<SignalOnSendInterest> onSendInterest = new ArrayList<>();
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800269
270 /**
271 * Emits whenever a Data packet is sent
272 * <p>
Andrew Brown58191872016-02-05 22:16:57 -0800273 * After .putData, .processEvents must be called before this signal would be
274 * emitted.
Alexander Afanasyev83a26d32016-01-26 01:04:32 -0800275 */
andrewsbrown8e517fa2016-02-12 15:51:19 -0800276 public final List<SignalOnSendData> onSendData = new ArrayList<>();
Andrew Brown3831baf2015-01-19 13:38:52 -0800277
andrewsbrown8e517fa2016-02-12 15:51:19 -0800278 private static final Logger LOGGER = Logger.getLogger(MockFace.class.getName());
279 private MockFaceTransport transport;
280 private KeyChain keyChain;
Andrew Brown3831baf2015-01-19 13:38:52 -0800281}