Интеграция Splunk Java с JUnit

Я сделал модуль, который позволяет мне интегрироваться с splunk с помощью Java SDK. Мы используем 1.2.1.0 через maven.

Мой модуль работает отлично. Тем не менее, я хочу провести вокруг него модульные тесты junit. Я создал тесты, которые пытаются вернуть самое последнее событие, но если я не положу большой сон, я никогда не получу то, что я только что ввел, обычно событие перед ним. Я также пробовал это по количеству событий в индексе (я использую тестовый индекс), но он также не обновляется должным образом. Любая идея о хорошем способе сделать тест JUnit, который я могу проверить и подтвердить?

Я использую Spring в этом приложении, поэтому у меня есть одноэлементная служба для ведения этого журнала. Вот реализация сервиса:

/*
 * Copyright (c) 2015 POS Portal, Inc.
 * 180 Promenade Circle, Ste 215, Sacramento, CA 95834, USA
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of POS Portal, Inc.
 * 
 */
package com.posportal.splunk.impl;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.posportal.splunk.api.SplunkLog;
import com.posportal.splunk.enumeration.SplunkLoggingLevel;
import com.splunk.Receiver;
import com.splunk.Service;
import com.splunk.ServiceArgs;

/**
 * Represents a splunk logging instance.  This is a spring singleton for logging. 
 * 
 * We log to the index given, so it is acceptable to have a singleton on a per index basis.  
 * 
 * Splunk configuration including index name are injected via Spring. 
 * @author Michael Wenk
 *
 */
public class SplunkLogImpl implements SplunkLog {
    private static Logger log = LoggerFactory.getLogger(SplunkLogImpl.class); 
    private String host;
    private String user;
    private String password;
    private String scheme;
    private String indexName;

    private int port;

    private boolean disabled = false; 

    private Service splunksvc = null;
    private Receiver receiver = null; 

    @Override
    public void logMessage(String msg, SplunkLoggingLevel level) {
        if (disabled) {
            log.warn("Splunk system disabled.  Splunk message would be: " + msg + " on level: " + level);
        } else {
            if (receiver == null) {
                initService();
            }
            String formattedMessageData = formatMessage(msg, level); 
            receiver.log(indexName, formattedMessageData);
        }
    }

    private String formatMessage(String msg, SplunkLoggingLevel level) {
        String fmt = "timestamp=\"%s\",level=\"%s\",data=\"%s\""; 
        Date now = new Date(); 
        return String.format(fmt, now.toString(), level.toString(), msg); 
    }

    private void initService() {
        ServiceArgs loginArgs = new ServiceArgs();
        loginArgs.setUsername(user);
        loginArgs.setPassword(password);
        loginArgs.setHost(host);
        loginArgs.setScheme(scheme);
        loginArgs.setPort(port);

        splunksvc = Service.connect(loginArgs);
        receiver = splunksvc.getReceiver(); 
    }

    public void setHost(String host) {
        this.host = host;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setScheme(String scheme) {
        this.scheme = scheme;
    }

    public void setIndexName(String indexName) {
        this.indexName = indexName;
    }

    public void setPort(int port) {
        this.port = port;
    }

    @Override
    public void setDisabled(boolean disabled) {
        this.disabled = disabled;       
    }

    @Override
    public boolean isDisabled() {
        return disabled;
    }
}

Вот код модульного теста:

/*
 * Copyright (c) 2015 POS Portal, Inc.
 * 180 Promenade Circle, Ste 215, Sacramento, CA 95834, USA
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of POS Portal, Inc.
 * 
 */
package com.posportal.splunk.test;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.Map;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.posportal.splunk.api.SplunkLog;
import com.posportal.splunk.enumeration.SplunkLoggingLevel;
import com.splunk.Job;
import com.splunk.JobArgs;
import com.splunk.JobArgs.ExecutionMode;
import com.splunk.Service;
import com.splunk.ServiceArgs;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:pos-splunk-test-ctx.xml")
public class SplunkTest {
    //private static Logger log = LoggerFactory.getLogger(SplunkTest.class); 
    @Resource(name = "splunkLog")
    private SplunkLog splunk;

    @Resource(name = "splunkConfig")
    private Map<String,String> splunkConfig; 

    @Test
    public void testInitialMessage() throws InterruptedException
    {
        if (splunk.isDisabled())
        {
            String msg = "This is my test";
            splunk.logMessage(msg, SplunkLoggingLevel.INFO);
        }
        else
        {
            int startCount = getEventCountFromIndex(); 
            String msg = "This is my test";
            assertNotNull(splunk); 
            splunk.logMessage(msg, SplunkLoggingLevel.INFO);
            Service svc = getService(); 
            assertNotNull(svc); 
            // Sleep for a while. 
            Thread.sleep(4000);

            int finalCount = getEventCountFromIndex(); 


            assertTrue(finalCount > startCount); 

        }

    }

    @Test
    public void testDisabled() {
        if (!splunk.isDisabled())
        {
            splunk.setDisabled(true);
            splunk.logMessage("This is a disabled test", SplunkLoggingLevel.INFO);
            // Can't assert unfortunately, 
            //FIXME see if I can assert using log4j itself. 
        }
    }
    private int getEventCountFromIndex() {
        String searchString = "search index="+ splunkConfig.get("indexName");
        JobArgs jargs = new JobArgs();
        jargs.setExecutionMode(ExecutionMode.BLOCKING);
        Service svc = getService(); 
        Job j = svc.getJobs().create(searchString, jargs);
        return j != null ? j.getEventCount() : -1; 
    }
    @Test
    public void testSecondMessage() throws  InterruptedException
    {
        if (splunk.isDisabled())
        {
            String msg = "This is my second test";
            splunk.logMessage(msg, SplunkLoggingLevel.INFO);
        }
        else
        {
            int startCount = getEventCountFromIndex(); 
            String msg = "This is my second test";
            assertNotNull(splunk); 
            splunk.logMessage(msg, SplunkLoggingLevel.INFO);
            Service svc = getService(); 
            assertNotNull(svc); 
            // Sleep for a while. 
            Thread.sleep(4000);
            int finalCount = getEventCountFromIndex(); 
            assertTrue(finalCount > startCount); 
        }
    }


    private Service getService() {
        ServiceArgs loginArgs = new ServiceArgs();
        loginArgs.setUsername(splunkConfig.get("user"));
        loginArgs.setPassword(splunkConfig.get("password"));
        loginArgs.setHost(splunkConfig.get("host"));
        loginArgs.setScheme(splunkConfig.get("scheme"));
        int port = Integer.parseInt(splunkConfig.get("port"));
        loginArgs.setPort(port);
        Service service = Service.connect(loginArgs);
        return service;
    }

}

Если вы обратите внимание на сны там. Если я не сплю, количество событий в индексе не увеличивается. И к сожалению иногда 4 секунды не хватает.


person mjwenk    schedule 19.02.2015    source источник
comment
Можете ли вы опубликовать свой анонимный код?   -  person Shakeel    schedule 23.02.2015
comment
Тесты, которые у меня есть сейчас, сравнивают только количество событий в индексе до и после журнала. У меня это было, поэтому я возвращал данные о событиях и обрабатывал их, но это было намного хуже в том смысле, что я перехватывал события из старых модульных тестов. Т.е. у меня есть другие тесты Junit, которые также вызывают код, который логирует splunk.   -  person mjwenk    schedule 24.02.2015
comment
Почему вы пытаетесь написать тесты для сторонней библиотеки? Смоделируйте это в своих собственных тестах.   -  person chrylis -cautiouslyoptimistic-    schedule 25.02.2015
comment
Ну, мне недостаточно просто издеваться над моим клиентом. Я понятия не имею, дойдет ли то, что я отправляю, на самом деле. Я не думаю, что издеваться над ним будет хорошо, если я действительно не считаю сервис вездесущим, чего я не считаю.   -  person mjwenk    schedule 02.03.2015


Ответы (2)


Задержка по времени, которую вы видите, — это Splunk, индексирующий событие, которое включает запись на диск и может занять некоторое время. Решение, как вы уже пробовали, заключается в том, чтобы дождаться завершения работы Splunk.

Я предлагаю установить верхнюю границу того, сколько раз вы хотите попробовать, и проверять каждые x секунд (время сна).

В Splunk SDK для Java (см. SearchJobTest .java и SDKTestCase. java), мы делаем то же самое с нашим методом assertEventuallyTrue():

public static boolean assertEventuallyTrue(EventuallyTrueBehavior behavior) {
    int remainingTries = behavior.tries;
    while (remainingTries > 0) {
        boolean succeeded = behavior.predicate();
        if (succeeded) {
            return true;
        } else {
            remainingTries -= 1;
            try {
                Thread.sleep(behavior.pauseTime);
            } catch (InterruptedException e) {}
        }
    }
    Assert.fail(behavior.timeoutMessage);
    return false;
}
person Shakeel    schedule 24.02.2015

Я предполагаю, что это модульное тестирование, поэтому вам не следует интегрироваться с splunk для модульного тестирования. Может быть, то, что вы пытаетесь, является приемочным тестом.

Для вашего модульного теста вам нужно абстрагироваться от Splunk. Так что просто создайте свой собственный уровень абстракции из Splunk или смоделируйте реализацию Splunk.

Таким образом, вы можете проверить, соблюдаются ли все ваши аргументы, и приступить к созданию службы, а также вы можете проверить, достаточно ли хорошо отформатированы все ваши сообщения журнала и вообще ли они отправляются в службу.

Так что, в конце концов, это все, что нужно сделать. Абстрагируйтесь от Splunk или имитируйте его, и все будет в порядке.

person Martin Kersten    schedule 25.02.2015
comment
+1 за правильность фиктивного ответа Splunk, но... мне было несколько сложно сделать это с помощью Splunk API. Существуют ли хорошие примеры того, как сделать это таким образом, чтобы имитировать Splunk API и продолжать работать так, как это действительно напоминает Splunk API. У меня было много проблем с этим. - person Paul Cunningham; 04.09.2018