Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored GPIO to be testable and gradle upgrade #116

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

ecsedigergo
Copy link
Collaborator

No description provided.

Copy link
Member

@benedekh benedekh left a comment

Choose a reason for hiding this comment

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

Why were the version upgrades of gradle, junit, mockito necessary?

Copy link
Member

@benedekh benedekh left a comment

Choose a reason for hiding this comment

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

Why was this version upgrade necessary?

Copy link
Member

@benedekh benedekh left a comment

Choose a reason for hiding this comment

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

Why do we commit code (dependency imports and source code) in comments?

@zsoltmazlo
Copy link
Contributor

If I may interrupt, I think version upgrades are not that big a deal

Copy link
Member

@benedekh benedekh left a comment

Choose a reason for hiding this comment

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

See the individual comments and recommendations.

@@ -57,13 +55,17 @@

private TimerTask _inputListenerTask;

private static CommandWriter WRITER;
Copy link
Member

Choose a reason for hiding this comment

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

Why is this field static instead of instance level?

Copy link
Member

Choose a reason for hiding this comment

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

If the field will be instance-level, then please follow the lowercase naming convention also.

Copy link
Collaborator Author

@ecsedigergo ecsedigergo Oct 9, 2018

Choose a reason for hiding this comment

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

Because the GIPO Manager is a Singleton class and I want to set this writer from outside of the manager. So anyway it will have 1 instance.

Copy link
Member

Choose a reason for hiding this comment

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

But here the Gpio is neither a singleton nor a static-only class. So its methods and fields should be instance level.

That's another question, why is GpioManager a Singleton class with static-only methods? It should be either singleton or static-only. Mixing the two does not make too much sense.

w.flush();
}
Logger.info(TAG, "Succeeded!");
public static void setWriter(CommandWriter writer) {
Copy link
Member

Choose a reason for hiding this comment

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

Please make this setter instance-level, instead of class-level.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Makes instance level setter any sense with Singleton GPIO manager?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, because Gpio itself is neither Singleton, nor static-only. Here we are talking about Gpio.java and not GpioManager.java.

private static CommandWriter WRITER;

private static CommandReader READER;

public Gpio(int pin, Direction direction) throws IOException, GpioNotConfiguratedException {
Copy link
Member

Choose a reason for hiding this comment

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

The initialization of READER and WRITER are missing here. You may end up having a NullPointerException.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If I got in this case (with static variables) a nullpointer, that is definitely a misconfiguration (you must set those before usage), so the exception must occur. Should I rather instantiate the variables with GPIOWriter/Reader when the GPIO manager is instantiated?

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 always make sure, that whenever the constructor is invoked, all the fields and variables that this constructor uses (invokes) must have been instantiated.

Having a separate setter of a field and making sure that that setter must have been invoked before anyone creates an instance of Gpio is very dangerous. (You rely on someone else to invoke those setters before any instance of this class is created.)

infos.put(targetFile.substring(targetFile.lastIndexOf("/") + 1), value);
} catch (Exception e) {
// TODO: handle exception
throw e;
Copy link
Member

Choose a reason for hiding this comment

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

Please do proper error handling.

@@ -41,6 +42,8 @@ class TrackElementController implements ITrackElementController, PhysicalTurnout
config = Configuration::loadPinoutConfig(turnoutID, factory)
pinout = ExpanderConfigInterpreter.loadPinoutConfig(factory)
GpioManager::loadGpioMappingFromFile(GPIO_JSON)
// TODO Check validity
GpioManager::setGpioWriter(new GpioWriter)
Copy link
Member

Choose a reason for hiding this comment

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

Why is only the GpioWriter instantiated here? What about GpioReader?


import hu.bme.mit.inf.modes3.components.gpiomanager.Gpio.Level;

public class TestGpioReader implements CommandReader {
Copy link
Member

Choose a reason for hiding this comment

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

Why is a separate class created for test, instead of using Mockito and creating a Mock in the test case itself?
If you just return the same static value every time, then a Mock might be more suitable instead of a generally named TestGpioReader class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

True, it can be refactored.

import java.util.HashMap;
import java.util.Map;

public class TestGpioWriter implements CommandWriter {
Copy link
Member

Choose a reason for hiding this comment

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

What is the reason for having a 'dedicated' TestGpioWriter class instead of just mocking the corresponding field by mockito in the unit tests?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

True, it can be refactored.

}

@Override
public void executeCommand(String value, String targetFile) throws IOException {
Copy link
Member

Choose a reason for hiding this comment

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

Is this method invoked by different value and targetFile parameters in the unit tests? If so, then does it that unit test test this class itself or it is just a side-effect that this method will also be invoked and executed when you test another method (of another class) which invokes this class?

So, is there a reason why this 'test' class was implemented instead of just mocking it in the class/instance where it is invoked?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not really

Copy link
Member

@benedekh benedekh left a comment

Choose a reason for hiding this comment

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

See comments and recommendations.

// assert
assertAll("properties", () -> assertEquals("in", tgw.getInfos().get("direction")),
() -> assertEquals(datas[0].port, Integer.parseInt(tgw.getInfos().get("export")))
// ,() -> assertEquals("both", tgw.getInfos().get("edge"))
Copy link
Member

Choose a reason for hiding this comment

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

Why do we commit code in comments?

() -> assertEquals("0", tgw.getInfos().get("value")));
}

// @Test
Copy link
Member

Choose a reason for hiding this comment

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

Why do we commit code in comments?

@benedekh
Copy link
Member

benedekh commented Oct 8, 2018

A general question in the end: did you test the changes together with the modules (components) which use the GpioManager? Do these components work correctly after introducing the separate classes for CommandWriter and CommandReader in GpioManager?

@ecsedigergo
Copy link
Collaborator Author

General answer: First of all I did not have yet opportunity and the knowledge to test it, but its true, its necessary before the merge.

@benedekh
Copy link
Member

If I may interrupt, I think version upgrades are not that big a deal

@zsoltmazlo There are two issues which might arise:

  1. some internal code might broke within the modules if they heavily rely on some specific features of the dependencies.
  2. every gradle project ought to use the same version of the dependency to avoid incompatibility / inconsistency issues. ('Everyone should be on the same page.' as the saying goes.)

}

public static void setGpioWriter(CommandWriter writer) {
Gpio.setWriter(writer);
Copy link
Member

Choose a reason for hiding this comment

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

Btw, why do you have to invoke Gpio.setWriter here? It has nothing to do with the GpioManager class. Gpio.setWriter coud be invoked anywhere else in the code.

(The same applies for the setGpioReader function also.)

@ecsedigergo
Copy link
Collaborator Author

I wanted to use JUnit 5 and for that I had to upgrade the versions.

@benedekh
Copy link
Member

@ecsedigergo Argument is accepted. If it does not cause any compilation (/ runtime) problems, then the version upgrade is good to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants