summaryrefslogtreecommitdiffstats
path: root/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
blob: 01a7d5e02394efb6a94f052ad2b6211af643949f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.application;

import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
import com.yahoo.text.Utf8;
import com.yahoo.vespa.config.server.MockReloadHandler;

import com.yahoo.vespa.config.server.tenant.TenantRepository;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.mock.MockCurator;
import org.apache.curator.framework.CuratorFramework;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;

/**
 * @author Ulf Lilleengen
 */
public class TenantApplicationsTest {

    private static final TenantName tenantName = TenantName.from("tenant");

    private Curator curator;
    private CuratorFramework curatorFramework;

    @Before
    public void setup() {
        curator = new MockCurator();
        curatorFramework = curator.framework();
    }

    @Test
    public void require_that_applications_are_read_from_zookeeper() throws Exception {
        writeApplicationData(createApplicationId("foo"), 3L);
        writeApplicationData(createApplicationId("bar"), 4L);
        TenantApplications repo = createZKAppRepo();
        List<ApplicationId> applications = repo.activeApplications();
        assertThat(applications.size(), is(2));
        assertThat(applications.get(0).application().value(), is("foo"));
        assertThat(applications.get(1).application().value(), is("bar"));
        assertThat(repo.requireActiveSessionOf(applications.get(0)), is(3L));
        assertThat(repo.requireActiveSessionOf(applications.get(1)), is(4L));
    }

    @Test
    public void require_that_invalid_entries_are_skipped() throws Exception {
        writeApplicationData(createApplicationId("foo"), 3L);
        writeApplicationData("invalid", 3L);
        TenantApplications repo = createZKAppRepo();
        List<ApplicationId> applications = repo.activeApplications();
        assertThat(applications.size(), is(1));
        assertThat(applications.get(0).application().value(), is("foo"));
    }

    @Test(expected = IllegalArgumentException.class)
    public void require_that_requesting_session_for_unknown_application_throws_exception() throws Exception {
        TenantApplications repo = createZKAppRepo();
        repo.requireActiveSessionOf(createApplicationId("nonexistent"));
    }

    @Test(expected = IllegalArgumentException.class)
    public void require_that_requesting_session_for_empty_application_throws_exception() throws Exception {
        ApplicationId baz = createApplicationId("baz");
        // No data in node
        curatorFramework.create().creatingParentsIfNeeded()
                .forPath(TenantRepository.getApplicationsPath(tenantName).append(baz.serializedForm()).getAbsolute());
        TenantApplications repo = createZKAppRepo();
        repo.requireActiveSessionOf(baz);
    }

    @Test
    public void require_that_application_ids_can_be_written() throws Exception {
        TenantApplications repo = createZKAppRepo();
        ApplicationId myapp = createApplicationId("myapp");
        repo.createPutTransaction(myapp, 3l).commit();
        String path = TenantRepository.getApplicationsPath(tenantName).append(myapp.serializedForm()).getAbsolute();
        assertTrue(curatorFramework.checkExists().forPath(path) != null);
        assertThat(Utf8.toString(curatorFramework.getData().forPath(path)), is("3"));
        repo.createPutTransaction(myapp, 5l).commit();
        assertTrue(curatorFramework.checkExists().forPath(path) != null);
        assertThat(Utf8.toString(curatorFramework.getData().forPath(path)), is("5"));
    }

    @Test
    public void require_that_application_ids_can_be_deleted() throws Exception {
        TenantApplications repo = createZKAppRepo();
        ApplicationId id1 = createApplicationId("myapp");
        ApplicationId id2 = createApplicationId("myapp2");
        repo.createPutTransaction(id1, 1).commit();
        repo.createPutTransaction(id2, 1).commit();
        assertThat(repo.activeApplications().size(), is(2));
        repo.createDeleteTransaction(id1).commit();
        assertThat(repo.activeApplications().size(), is(1));
        repo.createDeleteTransaction(id2).commit();
        assertThat(repo.activeApplications().size(), is(0));
    }

    @Test
    public void require_that_reload_handler_is_called_when_apps_are_removed() throws Exception {
        ApplicationId foo = createApplicationId("foo");
        writeApplicationData(foo, 3L);
        writeApplicationData(createApplicationId("bar"), 4L);
        MockReloadHandler reloadHandler = new MockReloadHandler();
        TenantApplications repo = createZKAppRepo(reloadHandler);
        assertNull(reloadHandler.lastRemoved);
        repo.createDeleteTransaction(foo).commit();
        long endTime = System.currentTimeMillis() + 60_000;
        while (System.currentTimeMillis() < endTime && reloadHandler.lastRemoved == null) {
            Thread.sleep(100);
        }
        assertNotNull(reloadHandler.lastRemoved);
        assertThat(reloadHandler.lastRemoved.serializedForm(), is(foo.serializedForm()));
    }

    private TenantApplications createZKAppRepo() {
        return createZKAppRepo(new MockReloadHandler());
    }

    private TenantApplications createZKAppRepo(MockReloadHandler reloadHandler) {
        return TenantApplications.create(curator, reloadHandler, tenantName);
    }

    private static ApplicationId createApplicationId(String name) {
        return new ApplicationId.Builder()
                .tenant(tenantName.value())
                .applicationName(name)
                .instanceName("myinst")
                .build();
    }

    private void writeApplicationData(ApplicationId applicationId, long sessionId) throws Exception {
        writeApplicationData(applicationId.serializedForm(), sessionId);
    }

    private void writeApplicationData(String applicationId, long sessionId) throws Exception {
        curatorFramework
                .create()
                .creatingParentsIfNeeded()
                .forPath(TenantRepository.getApplicationsPath(tenantName).append(applicationId).getAbsolute(),
                         Utf8.toAsciiBytes(sessionId));
    }
}