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

@clairemcginty

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions