/**
* 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 org.apache.aurora.scheduler.storage.db;
import java.io.IOException;
import java.util.Set;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import org.apache.aurora.gen.Attribute;
import org.apache.aurora.gen.HostAttributes;
import org.apache.aurora.gen.MaintenanceMode;
import org.apache.aurora.gen.ScheduledTask;
import org.apache.aurora.scheduler.base.JobKeys;
import org.apache.aurora.scheduler.base.TaskTestUtil;
import org.apache.aurora.scheduler.storage.Storage;
import org.apache.aurora.scheduler.storage.Storage.MutateWork.NoResult;
import org.apache.aurora.scheduler.storage.entities.IHostAttributes;
import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
import org.junit.Before;
import org.junit.Test;
import static org.apache.aurora.gen.MaintenanceMode.DRAINED;
import static org.junit.Assert.assertEquals;
public class DbAttributeStoreTest {
private static final String HOST_A = "hostA";
private static final String HOST_B = "hostB";
private static final String SLAVE_A = "slaveA";
private static final String SLAVE_B = "slaveB";
private static final Attribute ATTR1 = new Attribute("attr1", ImmutableSet.of("a", "b", "c"));
private static final Attribute ATTR2 = new Attribute("attr2", ImmutableSet.of("d", "e", "f"));
private static final Attribute ATTR3 = new Attribute("attr3", ImmutableSet.of("a", "d", "g"));
private static final IHostAttributes HOST_A_ATTRS =
IHostAttributes.build(new HostAttributes(HOST_A, ImmutableSet.of(ATTR1, ATTR2))
.setSlaveId(SLAVE_A)
.setAttributes(ImmutableSet.of())
.setMode(MaintenanceMode.NONE));
private static final IHostAttributes HOST_B_ATTRS =
IHostAttributes.build(new HostAttributes(HOST_B, ImmutableSet.of(ATTR2, ATTR3))
.setSlaveId(SLAVE_B)
.setAttributes(ImmutableSet.of())
.setMode(MaintenanceMode.DRAINING));
private Storage storage;
@Before
public void setUp() throws IOException {
storage = DbUtil.createStorage();
}
@Test
public void testCrud() {
assertEquals(Optional.absent(), read(HOST_A));
assertEquals(ImmutableSet.of(), readAll());
insert(HOST_A_ATTRS);
assertEquals(Optional.of(HOST_A_ATTRS), read(HOST_A));
assertEquals(ImmutableSet.of(HOST_A_ATTRS), readAll());
insert(HOST_B_ATTRS);
insert(HOST_B_ATTRS); // Double insert should be allowed.
assertEquals(Optional.of(HOST_B_ATTRS), read(HOST_B));
assertEquals(ImmutableSet.of(HOST_A_ATTRS, HOST_B_ATTRS), readAll());
IHostAttributes updatedA = IHostAttributes.build(
HOST_A_ATTRS.newBuilder().setAttributes(ImmutableSet.of(ATTR1, ATTR3)));
insert(updatedA);
assertEquals(Optional.of(updatedA), read(HOST_A));
assertEquals(ImmutableSet.of(updatedA, HOST_B_ATTRS), readAll());
IHostAttributes updatedMode = IHostAttributes.build(updatedA.newBuilder().setMode(DRAINED));
insert(updatedMode);
assertEquals(Optional.of(updatedMode), read(HOST_A));
assertEquals(ImmutableSet.of(updatedMode, HOST_B_ATTRS), readAll());
truncate();
assertEquals(Optional.absent(), read(HOST_A));
assertEquals(ImmutableSet.of(), readAll());
}
@Test(expected = IllegalArgumentException.class)
public void testEmptyAttributeValues() {
IHostAttributes attributes = IHostAttributes.build(HOST_A_ATTRS.newBuilder()
.setAttributes(ImmutableSet.of(new Attribute("attr1", ImmutableSet.of()))));
insert(attributes);
}
@Test
public void testNoAttributes() {
IHostAttributes attributes = IHostAttributes.build(
HOST_A_ATTRS.newBuilder().setAttributes(ImmutableSet.of()));
insert(attributes);
assertEquals(Optional.of(attributes), read(HOST_A));
}
@Test(expected = IllegalArgumentException.class)
public void testNoMode() {
HostAttributes noMode = HOST_A_ATTRS.newBuilder();
noMode.unsetMode();
insert(IHostAttributes.build(noMode));
}
@Test
public void testSaveAttributesEmpty() {
HostAttributes attributes = HOST_A_ATTRS.newBuilder();
attributes.unsetAttributes();
insert(IHostAttributes.build(attributes));
assertEquals(Optional.of(IHostAttributes.build(attributes)), read(HOST_A));
}
@Test
public void testSlaveIdChanges() {
insert(HOST_A_ATTRS);
IHostAttributes updated = IHostAttributes.build(HOST_A_ATTRS.newBuilder().setSlaveId(SLAVE_B));
insert(updated);
assertEquals(Optional.of(updated), read(HOST_A));
}
@Test
public void testUpdateAttributesWithRelations() {
// Test for regression of AURORA-1379, where host attribute mutation performed a delete,
// violating foreign key constraints.
insert(HOST_A_ATTRS);
ScheduledTask builder = TaskTestUtil.makeTask("a", JobKeys.from("role", "env", "job"))
.newBuilder();
builder.getAssignedTask()
.setSlaveHost(HOST_A_ATTRS.getHost())
.setSlaveId(HOST_A_ATTRS.getSlaveId());
final IScheduledTask taskA = IScheduledTask.build(builder);
storage.write((NoResult.Quiet)
storeProvider -> storeProvider.getUnsafeTaskStore().saveTasks(ImmutableSet.of(taskA)));
HostAttributes attributeBuilder = HOST_A_ATTRS.newBuilder().setMode(DRAINED);
attributeBuilder.addToAttributes(new Attribute("newAttr", ImmutableSet.of("a", "b")));
IHostAttributes hostAUpdated = IHostAttributes.build(attributeBuilder);
insert(hostAUpdated);
assertEquals(Optional.of(hostAUpdated), read(HOST_A));
}
private void insert(IHostAttributes attributes) {
storage.write(
storeProvider -> storeProvider.getAttributeStore().saveHostAttributes(attributes));
}
private Optional<IHostAttributes> read(String host) {
return storage.read(storeProvider -> storeProvider.getAttributeStore().getHostAttributes(host));
}
private Set<IHostAttributes> readAll() {
return storage.read(storeProvider -> storeProvider.getAttributeStore().getHostAttributes());
}
private void truncate() {
storage.write(
(NoResult.Quiet) storeProvider -> storeProvider.getAttributeStore().deleteHostAttributes());
}
}