Skip to content
This repository was archived by the owner on Apr 21, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion ffwd-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@
<artifactId>protoc</artifactId>
<type>pom</type>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
47 changes: 42 additions & 5 deletions ffwd-client/src/main/java/com/spotify/ffwd/FastForward.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*-
* -\-\-
* FastForward Client
* FastForward Java Client
* --
* Copyright (C) 2016 - 2019 Spotify AB
* Copyright (C) 2016 - 2020 Spotify AB
* --
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,10 +31,31 @@

public class FastForward {

/**
* If you are using an older version, please use Version.V0.
* This variable will eventually be removed.
*/
@Deprecated()
public static final int LATEST_VERSION = 0;

public static final String DEFAULT_HOST = "localhost";
public static final int DEFAULT_PORT = 19091;

public enum Version {
V0(0),
V1(1);
private final int version;

Version(final int version) {
this.version = version;
}

public int getVersion() {
return version;
}

}


public static FastForward setup() throws UnknownHostException, SocketException {
return setup(InetAddress.getByName(DEFAULT_HOST), DEFAULT_PORT);
Expand All @@ -57,6 +78,7 @@ public static FastForward setup(InetAddress addr) throws SocketException {
* Initialization method for a FastForward client.
*
* @return A new instance of a FastForward client.
*
* @throws SocketException If a datagram socket cannot be created.
*/
public static FastForward setup(InetAddress addr, int port) throws SocketException {
Expand All @@ -74,15 +96,26 @@ private FastForward(InetAddress addr, int port, DatagramSocket socket) {
this.socket = socket;
}

protected FastForward() throws UnknownHostException, SocketException {
this.addr = InetAddress.getByName(DEFAULT_HOST);
this.port = DEFAULT_PORT;
this.socket = new DatagramSocket();
}


public void send(Metric metric) throws IOException {
sendFrame(metric.serialize());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should both of these send functions just be combined into one that takes in the version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you thinking about something like this send(Metric metric , Version v1) ?if not, Give me the signature of the combine function you have in mind.

Copy link
Member

@lmuhlha lmuhlha Aug 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I'm a little confused by both send functions having the same name but maybe that's how it needs to be written and I'm missing something. Was thinking something like public void send(Metric metric, version) but since it's two different types of metrics, maybe we can just be explicit with the names if possible?

  public void sendV0(Metric metric) throws IOException {
    sendFrame(metric.serialize(), Version.V0);
  }

  public void sendV1(com.spotify.ffwd.v1.Metric metric) throws IOException {
    sendFrame(metric.serialize(), Version.V1);
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see your point now. We are not using a different name because we don't want to change ForwardClient public interface. With different names such as sendV1 or sendV0, users will have to make a code change whether they are using distribution or not. This is something we want to avoid.
With the overload approach (using the same name), you don't have to change anything if you are not using distribution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay cool, thank you for clarifying :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! can you merge it for me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll get you permissions 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to merge now :)

sendFrame(metric.serialize(), Version.V0);
}

private void sendFrame(byte[] bytes) throws IOException {
public void send(com.spotify.ffwd.v1.Metric metric) throws IOException {
sendFrame(metric.serialize(), Version.V1);
}

void sendFrame(byte[] bytes, Version v) throws IOException {
final ByteBuffer buffer = ByteBuffer.allocate(bytes.length + 8);
buffer.order(ByteOrder.BIG_ENDIAN);

buffer.putInt(LATEST_VERSION);
buffer.putInt(v.getVersion());
buffer.putInt(buffer.capacity());
buffer.put(bytes);
buffer.rewind();
Expand All @@ -100,4 +133,8 @@ public static Metric metric(String key) {
return new Metric().key(key);
}

public static com.spotify.ffwd.v1.Metric metricV1(String key) {
return new com.spotify.ffwd.v1.Metric().key(key);
}

}
31 changes: 8 additions & 23 deletions ffwd-client/src/main/java/com/spotify/ffwd/v1/Metric.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,6 @@
* -/-/-
*/

/*
* FastForward Client
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this needs to be at the top of all our open source files, would be good to add back

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what's happening, but if you check the actual file you will see the header.

* --
* Copyright (C) 2016 - 2019 Spotify AB
* --
* Licensed 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.spotify.ffwd.v1;

import com.google.protobuf.ByteString;
Expand Down Expand Up @@ -67,7 +49,7 @@ public Metric() {
this.has = 0;
this.time = 0;
this.key = null;
this.value = null;
this.value = Value.doubleValue(0);
this.host = null;
this.tags = new ArrayList<>();
this.attributes = new HashMap<>();
Expand All @@ -80,7 +62,7 @@ public Metric(
this.has = has;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lmuhlha @sjoeboo
I don't see has() method in this class to set that field and I have a suspicion we are not using it.
I for sure knew about "proc" field and it's gone. I think we could clean it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is probably safe to keep it for now.
In the context of Metric class, it is used to determine which attribute is set.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. I didn't see that. 👍

this.time = time;
this.key = key;
this.value = value;
this.value = (value == null) ? Value.doubleValue(0) : value;
this.host = host;
this.tags = tags;
this.attributes = attributes;
Expand All @@ -103,7 +85,8 @@ public Metric key(String key) {
}

public Metric value(Value value) {
return new Metric(set(VALUE), time, key, value, host, tags, attributes);
Value newValue = (value == null) ? Value.doubleValue(0) : value;
return new Metric(set(VALUE), time, key, newValue, host, tags, attributes);
}

public Metric host(String host) {
Expand Down Expand Up @@ -149,10 +132,12 @@ public byte[] serialize() {
builder.setValue(Protocol1.Value.newBuilder().setDoubleValue(doubleValue.getValue()));
} else if (value instanceof Value.DistributionValue) {
Value.DistributionValue distributionValue = (Value.DistributionValue) value;
ByteString byteString = ByteString.copyFrom(distributionValue.getValue());
ByteString byteString = ByteString.copyFrom(distributionValue.getValue().array());
builder.setValue(Protocol1.Value.newBuilder().setDistributionValue(byteString));
} else {
throw new IllegalArgumentException("Failed to identify distribution type : [" + value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the error message say "distribution type" instead of "value type"?

+ "]");
}

}

if (test(HOST)) {
Expand Down
8 changes: 6 additions & 2 deletions ffwd-client/src/main/java/com/spotify/ffwd/v1/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@
package com.spotify.ffwd.v1;

import com.google.auto.value.AutoValue;

import java.nio.ByteBuffer;
import java.util.function.Function;



/**
* The actual value of the data point.
* Currently we support two value types:
* Double and Distribution.
*
*/
public abstract class Value {

Value() {}
Expand Down
1 change: 1 addition & 0 deletions ffwd-client/src/main/proto/protocol1.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ message Metric {

}

// Actual data point value. We currently support 2 types, distribution and double.
message Value {
oneof value {
double double_value = 1;
Expand Down
93 changes: 93 additions & 0 deletions ffwd-client/src/test/java/com/spotify/ffwd/FastForwardTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*-
* -\-\-
* FastForward Java Client
* --
* Copyright (C) 2016 - 2020 Spotify AB
* --
* Licensed 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.spotify.ffwd;

import com.spotify.ffwd.v1.Metric;
import java.io.IOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.times;


public class FastForwardTest {
private static final String KEY = "key";


@Spy
private FastForward client;

private ArgumentCaptor<byte []> inputCaptor;
private ArgumentCaptor<FastForward.Version> versionCaptor;

@BeforeEach
public void before() throws IOException{
MockitoAnnotations.initMocks(this);
inputCaptor = ArgumentCaptor.forClass(byte[].class);
versionCaptor = ArgumentCaptor.forClass(FastForward.Version.class);
Mockito.doNothing().when(client).sendFrame(inputCaptor.capture(), versionCaptor.capture());
}

@Test
public void testSendV1() throws SocketException, UnknownHostException , IOException {
final Metric metricV1 = FastForward.metricV1(KEY);
client.send(metricV1);
Mockito.verify(client,times(1)).sendFrame(Mockito.any(byte[].class) ,
Mockito.any(FastForward.Version.class));
assertArrayEquals(metricV1.serialize(), inputCaptor.getValue());
assertEquals(FastForward.Version.V1,versionCaptor.getValue());
}

@Test
public void testSendV0() throws SocketException, UnknownHostException , IOException {
final com.spotify.ffwd.Metric metricV0 = FastForward.metric(KEY);
client.send(metricV0);
Mockito.verify(client,times(1)).sendFrame(Mockito.any(byte[].class) ,
Mockito.any(FastForward.Version.class));
assertArrayEquals(metricV0.serialize(), inputCaptor.getValue());
assertEquals(FastForward.Version.V0,versionCaptor.getValue());
}

@Test
public void testMetricV0(){
com.spotify.ffwd.Metric metricV0 = FastForward.metric(KEY);
assertEquals(com.spotify.ffwd.Metric.class, metricV0.getClass());
assertEquals(KEY,metricV0.getKey());
}

@Test
public void testMetricV1(){
Metric metricV1 = FastForward.metricV1(KEY);
assertEquals(Metric.class, metricV1.getClass());
assertEquals(KEY,metricV1.getKey());
}


}
Loading