/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.nifi.processors.cassandra; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Configuration; import com.datastax.driver.core.DataType; import com.datastax.driver.core.Metadata; import com.datastax.driver.core.Row; import com.google.common.collect.Sets; import org.apache.nifi.authentication.exception.ProviderCreationException; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessSession; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.ssl.SSLContextService; import org.apache.nifi.util.TestRunner; import org.apache.nifi.util.TestRunners; import org.junit.Before; import org.junit.Test; import javax.net.ssl.SSLContext; import java.net.InetSocketAddress; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * Unit tests for the AbstractCassandraProcessor class */ public class AbstractCassandraProcessorTest { MockAbstractCassandraProcessor processor; private TestRunner testRunner; @Before public void setUp() throws Exception { processor = new MockAbstractCassandraProcessor(); testRunner = TestRunners.newTestRunner(processor); } @Test public void testCustomValidate() throws Exception { testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, ""); testRunner.assertNotValid(); testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, "localhost"); testRunner.assertNotValid(); testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, "localhost:9042"); testRunner.assertValid(); testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, "localhost:9042, node2: 4399"); testRunner.assertValid(); testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, " localhost : 9042, node2: 4399"); testRunner.assertValid(); testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, "localhost:9042, node2"); testRunner.assertNotValid(); testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, "localhost:65536"); testRunner.assertNotValid(); testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, "localhost:9042"); testRunner.setProperty(AbstractCassandraProcessor.USERNAME, "user"); testRunner.assertNotValid(); // Needs a password set if user is set testRunner.setProperty(AbstractCassandraProcessor.PASSWORD, "password"); testRunner.assertValid(); } @Test public void testCustomValidateEL() throws Exception { testRunner.setProperty(AbstractCassandraProcessor.CONTACT_POINTS, "${host}"); testRunner.setProperty(AbstractCassandraProcessor.KEYSPACE, "${keyspace}"); testRunner.setProperty(AbstractCassandraProcessor.USERNAME, "${user}"); testRunner.setProperty(AbstractCassandraProcessor.PASSWORD, "${password}"); testRunner.setProperty(AbstractCassandraProcessor.CHARSET, "${charset}"); testRunner.assertValid(); } @SuppressWarnings("unchecked") @Test public void testGetCassandraObject() throws Exception { Row row = CassandraQueryTestUtil.createRow("user1", "Joe", "Smith", Sets.newHashSet("jsmith@notareal.com", "joes@fakedomain.com"), Arrays.asList("New York, NY", "Santa Clara, CA"), new HashMap<Date, String>() {{ put(Calendar.getInstance().getTime(), "Set my alarm for a month from now"); }}, true, 1.0f, 2.0); assertEquals("user1", AbstractCassandraProcessor.getCassandraObject(row, 0, DataType.text())); assertEquals("Joe", AbstractCassandraProcessor.getCassandraObject(row, 1, DataType.text())); assertEquals("Smith", AbstractCassandraProcessor.getCassandraObject(row, 2, DataType.text())); Set<String> emails = (Set<String>) AbstractCassandraProcessor.getCassandraObject(row, 3, DataType.set(DataType.text())); assertNotNull(emails); assertEquals(2, emails.size()); List<String> topPlaces = (List<String>) AbstractCassandraProcessor.getCassandraObject(row, 4, DataType.list(DataType.text())); assertNotNull(topPlaces); Map<Date, String> todoMap = (Map<Date, String>) AbstractCassandraProcessor.getCassandraObject( row, 5, DataType.map(DataType.timestamp(), DataType.text())); assertNotNull(todoMap); assertEquals(1, todoMap.values().size()); Boolean registered = (Boolean) AbstractCassandraProcessor.getCassandraObject(row, 6, DataType.cboolean()); assertNotNull(registered); assertTrue(registered); } @Test public void testGetSchemaForType() throws Exception { assertEquals(AbstractCassandraProcessor.getSchemaForType("string").getType().getName(), "string"); assertEquals(AbstractCassandraProcessor.getSchemaForType("boolean").getType().getName(), "boolean"); assertEquals(AbstractCassandraProcessor.getSchemaForType("int").getType().getName(), "int"); assertEquals(AbstractCassandraProcessor.getSchemaForType("long").getType().getName(), "long"); assertEquals(AbstractCassandraProcessor.getSchemaForType("float").getType().getName(), "float"); assertEquals(AbstractCassandraProcessor.getSchemaForType("double").getType().getName(), "double"); assertEquals(AbstractCassandraProcessor.getSchemaForType("bytes").getType().getName(), "bytes"); } @Test(expected = IllegalArgumentException.class) public void testGetSchemaForTypeBadType() throws Exception { AbstractCassandraProcessor.getSchemaForType("nothing"); } @Test public void testGetPrimitiveAvroTypeFromCassandraType() throws Exception { assertEquals("string", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.ascii())); assertEquals("string", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.text())); assertEquals("string", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.varchar())); assertEquals("string", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.timestamp())); assertEquals("string", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.timeuuid())); assertEquals("string", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.uuid())); assertEquals("string", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.inet())); assertEquals("string", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.varint())); assertEquals("boolean", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.cboolean())); assertEquals("int", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.cint())); assertEquals("long", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.bigint())); assertEquals("long", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.counter())); assertEquals("float", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.cfloat())); assertEquals("double", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.cdouble())); assertEquals("bytes", AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(DataType.blob())); } @Test(expected = IllegalArgumentException.class) public void testGetPrimitiveAvroTypeFromCassandraTypeBadType() throws Exception { DataType mockDataType = mock(DataType.class); AbstractCassandraProcessor.getPrimitiveAvroTypeFromCassandraType(mockDataType); } @Test public void testGetPrimitiveDataTypeFromString() { assertEquals(DataType.ascii(), AbstractCassandraProcessor.getPrimitiveDataTypeFromString("ascii")); } @Test public void testGetContactPoints() throws Exception { List<InetSocketAddress> contactPoints = processor.getContactPoints(""); assertNotNull(contactPoints); assertEquals(1, contactPoints.size()); assertEquals("localhost", contactPoints.get(0).getHostName()); assertEquals(AbstractCassandraProcessor.DEFAULT_CASSANDRA_PORT, contactPoints.get(0).getPort()); contactPoints = processor.getContactPoints("192.168.99.100:9042"); assertNotNull(contactPoints); assertEquals(1, contactPoints.size()); assertEquals("192.168.99.100", contactPoints.get(0).getAddress().getHostAddress()); assertEquals(9042, contactPoints.get(0).getPort()); contactPoints = processor.getContactPoints("192.168.99.100:9042, mydomain.com : 4000"); assertNotNull(contactPoints); assertEquals(2, contactPoints.size()); assertEquals("192.168.99.100", contactPoints.get(0).getAddress().getHostAddress()); assertEquals(9042, contactPoints.get(0).getPort()); assertEquals("mydomain.com", contactPoints.get(1).getHostName()); assertEquals(4000, contactPoints.get(1).getPort()); } @Test public void testConnectToCassandra() throws Exception { // Follow the non-null path Cluster cluster = mock(Cluster.class); processor.setCluster(cluster); testRunner.setProperty(AbstractCassandraProcessor.CONSISTENCY_LEVEL, "ONE"); processor.connectToCassandra(testRunner.getProcessContext()); processor.stop(); assertNull(processor.getCluster()); // Now do a connect where a cluster is "built" processor.connectToCassandra(testRunner.getProcessContext()); assertEquals("cluster1", processor.getCluster().getMetadata().getClusterName()); } @Test public void testConnectToCassandraWithSSL() throws Exception { SSLContextService sslService = mock(SSLContextService.class); when(sslService.getIdentifier()).thenReturn("ssl-context"); testRunner.addControllerService("ssl-context", sslService); testRunner.enableControllerService(sslService); testRunner.setProperty(AbstractCassandraProcessor.PROP_SSL_CONTEXT_SERVICE, "ssl-context"); testRunner.setProperty(AbstractCassandraProcessor.CONSISTENCY_LEVEL, "ONE"); testRunner.assertValid(sslService); processor.connectToCassandra(testRunner.getProcessContext()); assertNotNull(processor.getCluster()); processor.setCluster(null); // Try with a ClientAuth value testRunner.setProperty(AbstractCassandraProcessor.CLIENT_AUTH, "WANT"); processor.connectToCassandra(testRunner.getProcessContext()); assertNotNull(processor.getCluster()); } @Test(expected = ProviderCreationException.class) public void testConnectToCassandraWithSSLBadClientAuth() throws Exception { SSLContextService sslService = mock(SSLContextService.class); when(sslService.getIdentifier()).thenReturn("ssl-context"); testRunner.addControllerService("ssl-context", sslService); testRunner.enableControllerService(sslService); testRunner.setProperty(AbstractCassandraProcessor.PROP_SSL_CONTEXT_SERVICE, "ssl-context"); testRunner.setProperty(AbstractCassandraProcessor.CONSISTENCY_LEVEL, "ONE"); testRunner.assertValid(sslService); processor.connectToCassandra(testRunner.getProcessContext()); assertNotNull(processor.getCluster()); processor.setCluster(null); // Try with a ClientAuth value testRunner.setProperty(AbstractCassandraProcessor.CLIENT_AUTH, "BAD"); processor.connectToCassandra(testRunner.getProcessContext()); } @Test public void testConnectToCassandraUsernamePassword() throws Exception { testRunner.setProperty(AbstractCassandraProcessor.USERNAME, "user"); testRunner.setProperty(AbstractCassandraProcessor.PASSWORD, "password"); testRunner.setProperty(AbstractCassandraProcessor.CONSISTENCY_LEVEL, "ONE"); // Now do a connect where a cluster is "built" processor.connectToCassandra(testRunner.getProcessContext()); assertNotNull(processor.getCluster()); } /** * Provides a stubbed processor instance for testing */ public static class MockAbstractCassandraProcessor extends AbstractCassandraProcessor { @Override protected List<PropertyDescriptor> getSupportedPropertyDescriptors() { return Arrays.asList(CONTACT_POINTS, KEYSPACE, USERNAME, PASSWORD, CONSISTENCY_LEVEL, CHARSET); } @Override public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException { } @Override protected Cluster createCluster(List<InetSocketAddress> contactPoints, SSLContext sslContext, String username, String password) { Cluster mockCluster = mock(Cluster.class); Metadata mockMetadata = mock(Metadata.class); when(mockMetadata.getClusterName()).thenReturn("cluster1"); when(mockCluster.getMetadata()).thenReturn(mockMetadata); Configuration config = Configuration.builder().build(); when(mockCluster.getConfiguration()).thenReturn(config); return mockCluster; } public Cluster getCluster() { return cluster.get(); } public void setCluster(Cluster newCluster) { this.cluster.set(newCluster); } } }