1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.conscrypt;
18
19import static org.mockito.Mockito.any;
20import static org.mockito.Mockito.eq;
21import static org.mockito.Mockito.mock;
22import static org.mockito.Mockito.verify;
23import static org.mockito.Mockito.when;
24
25import java.security.cert.Certificate;
26import java.util.Collections;
27import java.util.Enumeration;
28import java.util.HashSet;
29import java.util.Set;
30import javax.net.ssl.SSLSession;
31import junit.framework.TestCase;
32import libcore.javax.net.ssl.FakeSSLSession;
33
34public final class ClientSessionContextTest extends TestCase {
35
36    public void testSimpleAddition() {
37        ClientSessionContext context = new ClientSessionContext();
38        SSLSession a = new ValidSSLSession("a");
39        SSLSession b = new ValidSSLSession("b");
40
41        context.putSession(a);
42        assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b });
43
44        context.putSession(b);
45        assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[0]);
46    }
47
48    public void testTrimToSize() {
49        ClientSessionContext context = new ClientSessionContext();
50        ValidSSLSession a = new ValidSSLSession("a");
51        ValidSSLSession b = new ValidSSLSession("b");
52        ValidSSLSession c = new ValidSSLSession("c");
53        ValidSSLSession d = new ValidSSLSession("d");
54
55        context.putSession(a);
56        assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b, c, d });
57
58        context.putSession(b);
59        assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[] { c, d });
60
61        context.putSession(c);
62        assertSessionContextContents(context, new SSLSession[] { a, b, c }, new SSLSession[] { d });
63
64        context.putSession(d);
65        assertSessionContextContents(context, new SSLSession[] { a, b, c, d }, new SSLSession[0]);
66
67        context.setSessionCacheSize(2);
68        assertSessionContextContents(context, new SSLSession[] { c, d }, new SSLSession[] { a, b });
69    }
70
71    public void testImplicitRemovalOfOldest() {
72        ClientSessionContext context = new ClientSessionContext();
73        context.setSessionCacheSize(2);
74        ValidSSLSession a = new ValidSSLSession("a");
75        ValidSSLSession b = new ValidSSLSession("b");
76        ValidSSLSession c = new ValidSSLSession("c");
77        ValidSSLSession d = new ValidSSLSession("d");
78
79        context.putSession(a);
80        assertSessionContextContents(context, new SSLSession[] { a }, new SSLSession[] { b, c, d });
81
82        context.putSession(b);
83        assertSessionContextContents(context, new SSLSession[] { a, b }, new SSLSession[] { c, d });
84
85        context.putSession(c);
86        assertSessionContextContents(context, new SSLSession[] { b, c }, new SSLSession[] { a, d });
87
88        context.putSession(d);
89        assertSessionContextContents(context, new SSLSession[] { c, d }, new SSLSession[] { a, b });
90    }
91
92    public void testSerializeSession_NoStatusResponses() throws Exception {
93        OpenSSLSessionImpl mockSession = mock(OpenSSLSessionImpl.class);
94        when(mockSession.getId()).thenReturn(new byte[] { 0x11, 0x09, 0x03, 0x20 });
95        when(mockSession.getPeerHost()).thenReturn("ssl.example.com");
96        when(mockSession.getPeerPort()).thenReturn(443);
97        when(mockSession.getEncoded()).thenReturn(new byte[] { 0x01, 0x02, 0x03 });
98        when(mockSession.getStatusResponses()).thenReturn(Collections.<byte[]>emptyList());
99
100        Certificate mockCert = mock(Certificate.class);
101        when(mockCert.getEncoded()).thenReturn(new byte[] { 0x05, 0x06, 0x07, 0x10 });
102
103        when(mockSession.getPeerCertificates()).thenReturn(new Certificate[] { mockCert });
104
105        SSLClientSessionCache mockCache = mock(SSLClientSessionCache.class);
106        ClientSessionContext context = new ClientSessionContext();
107        context.setPersistentCache(mockCache);
108
109        context.putSession(mockSession);
110        verify(mockCache).putSessionData(eq(mockSession), any(byte[].class));
111    }
112
113
114    private static void assertSessionContextContents(ClientSessionContext context,
115                                                     SSLSession[] contains,
116                                                     SSLSession[] exludes) {
117        assertEquals(contains.length, context.size());
118
119        for (SSLSession s : contains) {
120            assertSame(s.getPeerHost(), s, context.getSession(s.getId()));
121            assertSame(s.getPeerHost(), s, context.getSession(s.getPeerHost(), 443));
122        }
123        for (SSLSession s : exludes) {
124            assertNull(s.getPeerHost(), context.getSession(s.getId()));
125            assertNull(s.getPeerHost(), context.getSession(s.getPeerHost(), 443));
126        }
127
128        Set<SSLSession> sessions = new HashSet<SSLSession>();
129        Enumeration<byte[]> ids = context.getIds();
130        while (ids.hasMoreElements()) {
131            byte[] id = ids.nextElement();
132            sessions.add(context.getSession(id));
133        }
134
135        Set<SSLSession> expected = new HashSet<SSLSession>();
136        for (SSLSession s : sessions) {
137            expected.add(s);
138        }
139        assertEquals(expected, sessions);
140    }
141
142    static class ValidSSLSession extends FakeSSLSession {
143        ValidSSLSession(String host) {
144            super(host);
145        }
146        @Override public boolean isValid() {
147            return true;
148        }
149    }
150}
151