Package com.cloudera.flume.handlers.debug

Source Code of com.cloudera.flume.handlers.debug.TestStubbornAppendSink

/**
* Licensed to Cloudera, Inc. under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  Cloudera, Inc. 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 com.cloudera.flume.handlers.debug;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.concurrent.atomic.AtomicInteger;

import org.codehaus.jettison.json.JSONException;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloudera.flume.conf.FlumeBuilder;
import com.cloudera.flume.conf.FlumeSpecException;
import com.cloudera.flume.conf.ReportTestingContext;
import com.cloudera.flume.core.Event;
import com.cloudera.flume.core.EventImpl;
import com.cloudera.flume.core.EventSink;
import com.cloudera.flume.reporter.ReportEvent;
import com.cloudera.flume.reporter.ReportTestUtils;
import com.cloudera.flume.reporter.ReportUtil;

/**
* This makes sure that if an exception occurs, that the subordinate sink is
* closed and re-opened.
*/
public class TestStubbornAppendSink {
  public static final Logger LOG = LoggerFactory
      .getLogger(TestStubbornAppendSink.class);

  @Test
  public void testStubborn() throws IOException, InterruptedException {
    // just using as an int reference
    final AtomicInteger ok = new AtomicInteger();

    EventSink failAppend = new EventSink.Base() {
      int n = 4; // fail every nth append
      int count = 0;

      @Override
      public void append(Event e) throws IOException {
        count++;
        if (count % n == 0) {
          System.out.println("failed at " + count);
          throw new IOException("Failed, but will succeed later");
        }
        ok.incrementAndGet();
        System.out.print(".");
      }

      @Override
      public void close() throws IOException {
        System.out.println("close");
      }

      @Override
      public void open() throws IOException {
        System.out.println("open");
      }
    };

    StubbornAppendSink<EventSink> sink = new StubbornAppendSink<EventSink>(
        failAppend);
    sink.open();
    for (int i = 0; i < 100; i++) {
      Event e = new EventImpl(("attempt " + i).getBytes());
      sink.append(e);
    }
    Assert.assertEquals(ok.get(), 100);

    ReportEvent rpt = sink.getMetrics();
    Writer out = new OutputStreamWriter(System.out);
    rpt.toJson(out);
    out.flush();

    // 100 good messages. every 4th message fails -- 3 good 1 bad.
    // 00 01 02 xx 03 04 05 xx 06 07 08 xx ...
    // so 100 good msgs, 133 total messages, 33 bad msgs
    Assert.assertEquals(new Long(100), rpt
        .getLongMetric(StubbornAppendSink.A_SUCCESSES));
    Assert.assertEquals(new Long(33), rpt
        .getLongMetric(StubbornAppendSink.A_FAILS));
    Assert.assertEquals(new Long(33), rpt
        .getLongMetric(StubbornAppendSink.A_RECOVERS));
  }

  /**
   * This test is similar to the previous but uses mockito. (and make much fewer
   * calls)
   *
   * @throws InterruptedException
   */
  @Test
  public void testStubbornNew() throws IOException, InterruptedException {
    EventSink failAppend = mock(EventSink.class);
    Event e = new EventImpl("test".getBytes());

    // for mocking void void returning calls, we use this mockito
    // syntax (it is kinda gross but still cleaner than the version above)
    // the first two calls "succeed", the third throws io exn, and then the
    // fourth
    doNothing().doNothing().doThrow(new IOException()).doNothing().when(
        failAppend).append(Mockito.<Event> anyObject());
    doReturn(new ReportEvent("stub")).when(failAppend).getMetrics();

    StubbornAppendSink<EventSink> sink = new StubbornAppendSink<EventSink>(
        failAppend);
    sink.open();

    for (int i = 0; i < 3; i++) {
      sink.append(e);
      System.out.println(i);
    }

    ReportEvent rpt = sink.getMetrics();
    Assert.assertEquals(new Long(1), rpt
        .getLongMetric(StubbornAppendSink.A_FAILS));
    Assert.assertEquals(new Long(1), rpt
        .getLongMetric(StubbornAppendSink.A_RECOVERS));
  }

  @Test
  public void testStubbornIntervalFlakey() throws IOException,
      InterruptedException {

    // count resets on open and close, this one does not.
    final AtomicInteger ok = new AtomicInteger();

    EventSink cnt = new EventSink.Base() {
      @Override
      public void append(Event e) throws IOException {
        ok.incrementAndGet();
      }
    };

    // Every 5th event throws IOException
    IntervalFlakeyEventSink<EventSink> flake = new IntervalFlakeyEventSink<EventSink>(
        cnt, 5);
    StubbornAppendSink<EventSink> sink = new StubbornAppendSink<EventSink>(
        flake);
    sink.open();
    for (int i = 0; i < 100; i++) {
      Event e = new EventImpl(("attempt " + i).getBytes());
      sink.append(e);
    }
    Assert.assertEquals(ok.get(), 100);

    ReportEvent rpt = sink.getMetrics();
    // why isn't this 25?
    Assert.assertEquals(new Long(24), rpt
        .getLongMetric(StubbornAppendSink.A_FAILS));
    Assert.assertEquals(new Long(24), rpt
        .getLongMetric(StubbornAppendSink.A_RECOVERS));

  }

  @Test
  public void testExceptionFallthrough() throws IOException,
      InterruptedException {
    EventSink mock = mock(EventSink.class);
    // two ok, and then two exception throwing cases
    doNothing().doNothing().doThrow(new IOException()).doThrow(
        new IOException()).when(mock).append(Mockito.<Event> anyObject());
    doReturn(new ReportEvent("stub")).when(mock).getMetrics();

    StubbornAppendSink<EventSink> sink = new StubbornAppendSink<EventSink>(mock);
    Event e = new EventImpl("foo".getBytes());
    sink.open();
    sink.append(e);
    sink.append(e);
    try {
      sink.append(e);
    } catch (Exception exn) {
      ReportEvent rpt = sink.getMetrics();
      Assert.assertEquals(new Long(2), rpt
          .getLongMetric(StubbornAppendSink.A_SUCCESSES));
      Assert.assertEquals(new Long(1), rpt
          .getLongMetric(StubbornAppendSink.A_FAILS));
      Assert.assertEquals(new Long(0), rpt
          .getLongMetric(StubbornAppendSink.A_RECOVERS));
      return;
    }
    Assert.fail("should have thrown exception");
  }

  /**
   * Test insistent append metrics
   */
  @Test
  public void testStubbornAppendMetrics() throws JSONException,
      FlumeSpecException, IOException, InterruptedException {
    ReportTestUtils.setupSinkFactory();

    EventSink snk = FlumeBuilder.buildSink(new ReportTestingContext(),
        "stubbornAppend one");
    ReportEvent rpt = ReportUtil.getFlattenedReport(snk);
    LOG.info(ReportUtil.toJSONObject(rpt).toString());
    assertNotNull(rpt.getLongMetric(StubbornAppendSink.A_FAILS));
    assertNotNull(rpt.getLongMetric(StubbornAppendSink.A_RECOVERS));
    assertNotNull(rpt.getLongMetric(StubbornAppendSink.A_SUCCESSES));
    assertEquals("One", rpt.getStringMetric("One.name"));

  }

}
TOP

Related Classes of com.cloudera.flume.handlers.debug.TestStubbornAppendSink

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.