They have added support for Kubernetes lately. I must say I was pleasantly surprised about it.
It works perfectly.
So, here is a little tutorial if you want to play with it.
It uses Terraform. Oracle Cloud has developed a connector to it. It makes everything easier and command line.
The first step is to configure correctly your Oracle Cloud Infrastructure (OCI). You can more or less follow this.
I will comment and summarize here
Install Terraform (brew install terraform, you probably have brew already on a mac so no need to install it and do the chown)
Generate a ssh key for oci. Follow the instructions. You could use an existing key. But other scripts are assuming you have a key in the .oci directory so it’s just easier to create a new one
Add the public key on the Oracle console.
Your life will be easier if you log yourself before clicking on all the links
Create a env-vars.sh. I haven’t added it in my .bash_profile. I just do a source env-vars.sh when needed. There are 2 fun values to find: TF_VAR_tenancy_ocid and TF_VAR_user_ocid.
The tenancy is here.
The user is here.
You can, of course, use the region you prefer.
Create the OKE
Now we get serious and we will create the Oracle Kubernetes Engine (OKE). This is explained here.
Again, the steps with my comments
Get the git repository for oke: git clone https://github.com/cloud-partners/oke-how-to.git. You might want to fork and commit since you will tweak it
Init terraform: terraform init
Generate the plan to make sure it works: terracotta plan. You might want to modify terraform/variables.tf first.
This file contains the name of your cluster, the number of nodes per subnet you want, the server instance type and the OKE version used.
You can then apply the plan to create your cluster; terracotta apply. It should work magically. I had one problem on my side though. I think it’s because I have an old account. My OKE limit was at 0. So I couldn’t create a cluster. I had to ask the support to fix it. Which was done pretty quickly.
One thing I am not sure about is if you will need to add some policies.
Just in case, here are mine (I’m in the group Administrators):
ListandGetVCNs: Allow group Administrators to manage vcn in tenancy
ListGetsubnets: Allow group Administrators to manage virtual-network-family in tenancy
OKE: Allow service OKE to manage all-resources in tenancy
I haven’t mastered the policy system yet to I’m not quite sure what is doing what.
Deploy on the cluster
You now have a running cluster so let’s deploy some stuff on it.
For that you need kubectl: brew install kubectl kubernetes-helm
Add the kube config for the cluster. The doc will tell you to use the config file generated by Terraform. It works but in general you want to keep the configuration of other clusters (e.g docker-for-desktop-cluster or minikube). So you will probably prefer to give it another name. You can then switch from one context to another using kubectl config use-context oci
Then just deploy whatever you want to deploy.
Destroy your cluster
Really important when you are done: terraform destroy
This release adds a support of Java 9, 10 and 11. It also drops support of Java 6 and 7. So it is now a Java 8+. This
brought easier maintenance and some performance improvement.
Modules are partly supported with an automatic module name.
If also changes the way EasyMock will determine the type of the returned mock. The idea is to solve a heavily annoying
problem most mocking frameworks have with generics.
To be clear, starting now List<String> list = mock(List.class); will compile perfectly without
any “unchecked” warning.
However, String s = mock(List.class); will also compile.
But I’m expecting you not to be crazy enough to do such thing.
It will do a ClassCastException at runtime anyway.
The only side effect is that in rare cases, the compiler might fail to infer the return type and give a compilation error.
If it ever happen, the solution is to use a type witness, e.g. foo(EasyMock.<List<String>>mock(List.class).
It should solve the problem nicely, and, again, without a warning.
About a month ago, I was preparing my OracleOne talk and
tripped on a slide. I was trying to explain the new delivery process and how long the support of each version will last.
It wasn’t that clear at all.
So, I asked my felow Java Champions
about it. It triggered a discussion about the fact that it is indeed quite misunderstood.
We got together. Or to be honest, Martijn led the way and wrote an article to clarify the situation.
We then made multiple suggestions and corrections. Representatives of the main OpenJDK providers were also
After years missing it, I finally went to JCrete last year for the first time. I went with my
family and we had a great time. This year, I went back again but alone.
For those who never went, it is hard to describe the event. The boring way would be to say that it is a Java unconference.
But it is a really bad way to describe it.
Here is my current explanation.
Close your eyes. Imagine you can gather all the almighty experts in your field and put them in one place. Then imagine
this place has multiple beaches, great (cheap!) food and good wine. That everyone is friendly and wants to help each other without judging.
And that you will talk will all these experts all day, in formal classrooms and on the beach. You will gather a tremendous amount of knowledge.
This is JCrete.
This was my experience last year. This was my experience this year. It almost feels surreal.
I still don’t know how it happened. Is it Crete? Is it Heinz and Kirk’s magical touch?
Is it the Java community that is awesome? Probably all of the above sincerely.
Then, if you have never heard of JCrete let me explain a bit more what it is about.
First, it’s an unconference with a limited number of participants. Those participants are selected for their accomplishments.
It means that you are well-known in the Java community for something. Of course, a lot of Java Champions are
attending. To prevent too much inbreeding, a little amount of entropy coming from random senior lead developers is added.
However, the rule is that anyone attending should be able to propose a subject and talk about it. You can see it as a conference
with only speakers talking to one another.
Then, a typical day looks like that:
Go jogging with some of the attendees (chatting about interesting stuff)
Get breakfast with the attendees (chatting about interesting stuff)
Gather in the main room
Morning briefing and subject proposition for the day
Attend sessions with subjects you care about. Learn
Lunch (chatting about interesting stuff)
Go to some beach (chatting about interesting stuff)
Hack a bit. When stuck, there are high chances that one of the lead committers on the thing you are stuck on is attending too
Get unstuck by the lead committer (this year it was Matt Raible)
Go dinner to some restaurant or at an evening event (chatting about interesting stuff, around a bottle of wine)
Go to bed happy
Last year, this article when out of it. This year, some cool stuff that I will
talk about when it’s ready.
Here is the long awaited 3.5 version. It contains many bug fixes and some improvement. We allowed ourselves to possibly break
the compatibility with older versions for the greater good. So please read these notes thoroughly.
Java 5 is no longer supported. I dearly hope this won’t harm anyone
Java 9 is supported
TestNG support is added. Have a look at EasyMockListener
Class Mocking now works correctly for cross bundle mocking
verify() now checks for unexpected calls in case an AssertionError was swallowed during the test. It is in general
what you want but you can use verifyRecording() to bring back the old behavior
Default matcher for an array argument is now aryEq instead of eq. This should as well make sense for everyone and should
allow you to remove tons of aryEq all over your code. If you don’t like it, you can specify eq explicitly for the array
isNull and notNull with generic class parameter (#93)
Return a meaningful error when null on a primitive (#92)
Create opportunity to disable SingleThread checks (#88)
A long time ago (year 2000), the mock objects were
invented. It is now one of the most important parts of unit testing.
For those you don’t know, the idea of a mock object is to simulate a dependency to easily test a class. Quick example.
I have a class Pricer.
Being a nice human being, I want to test my calculations but I don’t want to use a real PriceFeed. The real implementation
has to an actual MQSeries queue that received prices from Reuters. It’s not something you want to do during your unit tests
(if at all).
So you will instead do a mock object, an object that will behave as you see fit for your test but that isn’t a real PriceFeed. It just
Not so long ago, Uncle Bob did a blog post about mock objects. He classifies
them into five different types or levels. Levels because each type is wiser than the previous one. He calls them “Test Doubles”.
I’ve decided to show you how to code them. Using EasyMock (of course), Mockito and by hand.
Type of mocks
From the most basic to the most advanced type.
A class that you pass into something when you don’t care how it’s used. e.g. As part of a test, when you must pass an
argument, but you know the argument will never be used.
In this EasyMock world, it is called a nice mock (Authorized mock = niceMock(Authorized.class)).
In the Mockito world, it’s just a mock (Authorized mock = mock(Authorized.class)).
In general, if a dummy is used, you will want it to throw an exception to tell you something is
wrong. So, with Mockito, you will in general get a NullPointerException (or not) if you do something like
if(mock.authorize(user, password)) // NPE
With EasyMock, you will generally prefer to use a normal mock (Authorized mock = mock(Authorized.class)) that
will make sure nothing unintended is called.
A class that returns a valid answer but always the same one.
In the EasyMock language, this is any mock with an expectation recorded (expect(mock.authorize(anyString(), anyString()).andStubReturn(true)).
In the Mockito language, this is a mock with behavior set on a method (when(mock.authorize(any(), any()).thenReturn(true).
You use a spy when you want to be sure that the authorize() method is called by the system.
In EasyMock, it means you are not stubbing anymore. You want to record a precise call (expect(mock.authorize(anyString(), anyString()).andReturn(true))
and then verify that the call actually occurred (verify(mock)).
In Mockito, you still stub the call and then verify the call occurred (verify(authorizer).authorize(any(), any())). Note that Mockito has its own
concept of a spy, which is different. A Mockito spy is a shell over an actual class that allows to verify calls to them. It is indeed useful
but it isn’t a mock. So don’t get lost in the semantic.
A true mock is a mock that knows how to verify itself. In fact, EasyMock and Mockito mocks are always true mocks. So their
implementations of a true mock is the same as for the spy.
A Fake has business behavior. You can drive a fake to behave in different ways by giving it different data. They are usually
used for integration testing to simulate other parts of your system.
I rarely use a mocking framework for them. It tends to make the code more complicated than coding by hand. Still, a mocking
framework can be used.
When jumping from one flavor to another, you should make sure you really need to. Because the more complicated your
mocking is, the more coupling you will have with the actual implementation. It makes the test more fragile. But you
still need to make sure everything is working as expected!
Modify to test
If your code isn’t easy to test, modify your code. Do whatever is needed. You will end up with a better design
anyway. A test should not be complicated. If it needs to, something is wrong.
Provide a testing framework
If you build something, you should provide a nice framework to test it. Spring has spring-test. You are
responsible for making what you do testable, mockable, etc.
Use as less mocks as possible
Usually, unit tests should use at worst 3 mocks. It you have more, you probably should split your code in
smaller parts. A lot of mocks makes the code unreadable.
Explain and document your tests
Tests are harder to understand than actual production code. When someone reads test code, he should understand
the purpose. So use a nice test name to explain what you wanted to do. Use javadoc. Use line comments to explain the flow.
I’m refactoring my tests a lot. A lot. Nice methods preventing copy & paste. Testing frameworks. Fixtures. Base test
classes. Everything to make it as pretty as my production code.
I felt on some code yesterday and had to think a bit about it before deciding that it wasn’t working as expected. And then went on to
wonder if I could make it work. I found it interesting so I thought I should tell you about it.
So. What’s going on here?
We have a list
A CompletableFuture is waiting for the list to be filled
We wait on the future until is has finished
If it takes too long, we timeout
It works. If the list is filled, the test will be successful, if the list is never filled, the get will timeout after
1 seconds (throwing a TimeoutException) and the test will fail.
The only problem is that if the test does fail, the future task itself will never finish. It is still stuck in the while
Because nothing can stop it. supplyAsync is submitting a task to the common pool. This task will run in a thread we are
not managing. The task won’t stop until the list isn’t empty anymore. That’s it.
A timeout of the CompletableFuture won’t change anything. It just means that we are not waiting on the get anymore. But
it has no power over the task itself.
What can we do?
Maybe we can interrupt it? Let’s try.
In the original loop, nothing could be interrupted. Now we introduce a sleep. It can be interrupted. However, it won’t.
The timeout on the get doesn’t trigger an interrupt on the thread running the task.
That doesn’t work either?
Can it be cancelled you say?
Here the code is a bit more complicated. We can’t access the future from the lambda directly. Because the lambda starts
before the assignment is made. So we use an AtomicReference, wait until its content isn’t null anymore and then wait
for cancellation… that never arrives.
Yes. The timeout on the get won’t trigger a cancellation. This is on purpose. There is nothing preventing you from waiting
a bit on the get, do something else, and come back to get again.
Enough of that! Tell me what works!
OK. OK. Calm down. I’ll show you but it’s not pretty.
So now we are cancelling the task ourselves. That works. The task correctly finishes. One funny thing to mention is that the
assert won’t fail. In fact, it’s the call to future.get() in assertThat that will throw a CancellationException and
make the test fail.
OK. We now have a pretty ugly and complicated solution that works.
Can we simplify?
You might have noticed that cancel() take a parameter named mayInterruptIfRunning. That sounds promising! We can get
an interruption! Let’s try.
No atomic reference anymore. But doesn’t work. The task doesn’t get interrupted. If I quote the javadoc for cancel():
mayInterruptIfRunning this value has no effect in this implementation because interrupts are not used to control processing.
Basically, that means CompletableFuture are not supposed to be interrupted. They are at a higher level of abstraction.
Here is the nicest solution I know about.
Yes, it’s just a simple flag. But it works nicely.
Still, you might ask me: “Why is it that complicated?”
In fact, I’m not totally sure. I think CompletableFuture are not meant to be used like this. They are supposed to
complete. Or to fail exceptionally. Normal Future are the ones that are supposed to loop like that.
But I’ll need more digging to be more conclusive. Right now, I only wanted to share my How to cancel a CompletableFuture?