/*
* 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.usergrid.rest;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import org.apache.commons.lang.RandomStringUtils;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.text.DecimalFormat;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static com.codahale.metrics.MetricRegistry.name;
/**
* Unique values performance test, not intended for use in normal JUnit testing.
*
* Just tests how fast we can create users, optionally against multiple end-points.
* (for multi-region testing).
*/
public class UniqueValuesPerformanceIT {
private static final Logger logger = LoggerFactory.getLogger( UniqueValuesPerformanceIT.class );
private static final AtomicInteger successCounter = new AtomicInteger( 0 );
private static final AtomicInteger errorCounter = new AtomicInteger( 0 );
@Test
@Ignore("Intended for use against prod-like cluster")
public void testBasicOperation() throws Exception {
int numUsers = 1000;
int numThreads = 100;
int poolsize = 50;
ExecutorService execService = Executors.newFixedThreadPool( poolsize );
Multimap<String, Form> usersCreated =
Multimaps.synchronizedListMultimap( ArrayListMultimap.create( numUsers, 1 ) );
Client client = ClientBuilder.newClient();
String randomizer = RandomStringUtils.randomAlphanumeric( 8 );
String[] targetHosts = {"http://macsnoopdave2013:8080","http://macsnoopdave2010:9090"};
final MetricRegistry metrics = new MetricRegistry();
final Timer responses = metrics.timer( name( UniqueValuesPerformanceIT.class, "responses" ) );
long startTime = System.currentTimeMillis();
for (int i = 0; i < numThreads; i++) {
execService.submit( () -> {
for (int j = 0; j < numUsers / numThreads; j++) {
// every user gets unique name, no duplicates in this test
UUID uuid = UUID.randomUUID();
String username = "uv_test_user_" + uuid;
Form form = new Form();
form.param( "name", username );
form.param( "username", username );
form.param( "email", username + "@example.org" );
form.param( "password", "s3cr3t" );
Timer.Context time = responses.time();
try {
final String host = targetHosts[j % targetHosts.length];
WebTarget target = client.target( host ).path( "/management/users" );
Response response = target.request()
.post( Entity.entity( form, MediaType.APPLICATION_FORM_URLENCODED ));
if (response.getStatus() == 200 || response.getStatus() == 201) {
usersCreated.put( username, form);
successCounter.incrementAndGet();
} else {
String responseBody = response.readEntity( String.class );
logger.error( "User creation failed status {} - {}", response.getStatus(), responseBody );
errorCounter.incrementAndGet();
}
} catch (Exception e) {
errorCounter.incrementAndGet();
logger.error( "Error", e );
}
time.stop();
}
} );
}
execService.shutdown();
try {
while (!execService.awaitTermination( 30, TimeUnit.SECONDS )) {
System.out.println( "Waiting..." );
}
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
logger.info( "Total time {}s", (endTime - startTime) / 1000 );
DecimalFormat format = new DecimalFormat("##.###");
logger.info( "Timed {} requests:\n" +
"mean rate {}/s\n" +
"min {}s\n" +
"max {}s\n" +
"mean {}s",
responses.getCount(),
format.format( responses.getMeanRate() ),
format.format( (double)responses.getSnapshot().getMin() / 1000000000 ),
format.format( (double)responses.getSnapshot().getMax() / 1000000000 ),
format.format( responses.getSnapshot().getMean() / 1000000000 )
);
logger.info( "Error count {} ratio = {}",
errorCounter.get(), (float) errorCounter.get() / (float) responses.getCount() );
logger.info( "Success count = {}",
successCounter.get() );
Assert.assertEquals( 0, errorCounter.get() );
Assert.assertEquals( numUsers, successCounter.get() );
}
}