Skip to content
This repository was archived by the owner on Apr 21, 2025. It is now read-only.
This repository was archived by the owner on Apr 21, 2025. It is now read-only.

(discuss) Make FastForward an abstract class with default implementation #12

Description

@clairemcginty

Prior discussion here: spotify/semantic-metrics#76

This is an extension of the discussion above ^ re: testability in the FastForwardReporter in semantic-metrics repo. Basically, in a production environment the FastForward client would be already running within the container, but in a local unit testing environment this can be pretty cumbersome to set up. I think making FastForward an abstract class (with a default implementation) would be really helpful, because for simple unit tests we could plug in a stubbed implementation that doesn't require a datagram socket running and can easily verify the metrics being sent. I initially suggested making an abstraction layer for it in semantic-metrics, but they suggested the change be more appropriate here.

for example:

public abstract class FastForward {
  public abstract void send(Metric metric) throws IOException;
  public abstract void send(Event event) throws IOException;

  // Default implementation
  public static FastForward setup(String host, int port) throws UnknownHostException, SocketException {
    return new FastForward() {
      private final DatagramSocket socket = new DatagramSocket();
      
      @Override
      public void send(Metric metric) throws IOException {
         // existing implementation here, send through socket
      }

      @Override
      public void event(Event metric) throws IOException {
         // existing implementation here, send through socket
      }
    };
  }
}

and a user could create their own stub implementation for unit testing, like:

public class StubbedFastForwardClient extends FastForward {
  private final List<Metric> sentMetrics;
  private final List<Event> sentEvents;

  public StubbedFastForwardClient(List<Metric> collectedMetrics) {
    this.sentMetrics = new ArrayList<>();
    this.sentEvents = new ArrayList<>();
  }

  @Override
  public void send(Metric metric) throws IOException {
    sentMetrics.add(metric);
  }

  @Override
  public void send(Event event) throws IOException {
    sentEvents.add(metric);
  }

 // Called in unit test
  public void verifySentMetrics(Consumer<List<Metric>> verifyFn) {
    verifyFn.accept(sentMetrics);
  }

  public void verifySentEvents(Consumer<List<Event>> verifyFn) {
    verifyFn.accept(sentEvents);
  }
}

wdyt? I'm happy to make the PR myself it sounds reasonable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions