### Question:
GeoPackageImageEnvoy extends AbstractEnvoy implements DataRegistryDataProvider { @Override public void query(DataModelCategory category, Collection<? extends Satisfaction> satisfactions, List<? extends PropertyMatcher<?>> parameters, List<? extends OrderSpecifier> orderSpecifiers, int limit, Collection<? extends PropertyDescriptor<?>> propertyDescriptors, CacheDepositReceiver queryReceiver) throws InterruptedException, QueryException { if (parameters.size() != 1 || !(parameters.get(0) instanceof ZYXKeyPropertyMatcher)) { throw new IllegalArgumentException(ZYXKeyPropertyMatcher.class.getSimpleName() + " was not found in parameters."); } String layer = category.getFamily(); ZYXKeyPropertyMatcher param = (ZYXKeyPropertyMatcher)parameters.get(0); ZYXImageKey key = param.getImageKey(); long zoomLevel = key.getZ(); TileDao dao; synchronized (myGeoPackage) { dao = myGeoPackage.getTileDao(layer); } long column = key.getX(); long row = key.getY(); TileRow tileRow = dao.queryForTile(column, row, zoomLevel); if (tileRow != null && tileRow.getTileData() != null) { InputStream imageData = myEncoder.encodeImage(tileRow.getTileData()); DataModelCategory imageCategory = new DataModelCategory(category.getSource(), layer, Image.class.getName()); Collection<PropertyAccessor<InputStream, ?>> imageAccessors = New.collection(); imageAccessors.add(SerializableAccessor.<InputStream, String>getSingletonAccessor( GeoPackagePropertyDescriptors.KEY_PROPERTY_DESCRIPTOR, param.getOperand())); imageAccessors.add(IMAGE_STREAM_ACCESSOR); DefaultCacheDeposit<InputStream> imageDeposit = new DefaultCacheDeposit<>(imageCategory, imageAccessors, New.list(imageData), true, CacheDeposit.SESSION_END, false); try { queryReceiver.receive(imageDeposit); } catch (CacheException e) { throw new QueryException(e); } } } GeoPackageImageEnvoy(Toolbox toolbox, GeoPackage geoPackage); @Override void close(); @Override Collection<? extends Satisfaction> getSatisfaction(DataModelCategory dataModelCategory,
            Collection<? extends IntervalPropertyValueSet> intervalSets); @Override String getThreadPoolName(); @Override void open(); @Override boolean providesDataFor(DataModelCategory category); @Override void query(DataModelCategory category, Collection<? extends Satisfaction> satisfactions,
            List<? extends PropertyMatcher<?>> parameters, List<? extends OrderSpecifier> orderSpecifiers, int limit,
            Collection<? extends PropertyDescriptor<?>> propertyDescriptors, CacheDepositReceiver queryReceiver);  }### Answer:
@Test public void testQuery() throws InterruptedException, QueryException, CacheException { EasyMockSupport support = new EasyMockSupport(); TileDao dao = createTileDao(support); GeoPackage geopackage = createGeoPackage(support, dao); Toolbox toolbox = support.createMock(Toolbox.class); CacheDepositReceiver receiver = createReceiver(support); support.replayAll(); GeoPackageImageEnvoy envoy = new GeoPackageImageEnvoy(toolbox, geopackage); ZYXImageKey key = new ZYXImageKey(ourZoomLevel, ourY, ourX, ourTileBoundingBox); DataModelCategory category = new DataModelCategory(ourPackageFile, ourTileLayerName, Image.class.getName()); List<PropertyMatcher<?>> matchers = New.list(); ZYXKeyPropertyMatcher matcher = new ZYXKeyPropertyMatcher(GeoPackagePropertyDescriptors.KEY_PROPERTY_DESCRIPTOR, key); matchers.add(matcher); envoy.query(category, Collections.emptyList(), matchers, Collections.emptyList(), -1, New.list(GeoPackagePropertyDescriptors.IMAGE_PROPERTY_DESCRIPTOR), receiver); support.verifyAll(); }