#!/usr/bin/env python3
# Copyright (c) 2018 Clevernet, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")

import unittest
from bcc import BPF

class TestLicense(unittest.TestCase):
    gpl_only_text = b"""
#include <uapi/linux/ptrace.h>
struct gpl_s {
    u64 ts;
};
BPF_PERF_OUTPUT(events);
int license_program(struct pt_regs *ctx) {
    struct gpl_s data = {};
    data.ts = bpf_ktime_get_ns();
    events.perf_submit(ctx, &data, sizeof(data));
    return 0;
}
"""

    proprietary_text = b"""
#include <uapi/linux/ptrace.h>
struct key_t {
    u64 ip;
    u32 pid;
    u32 uid;
    char comm[16];
};

BPF_HASH(counts, struct key_t);

int license_program(struct pt_regs *ctx) {
    struct key_t key = {};
    u64 zero = 0 , *val;
    u64 pid = bpf_get_current_pid_tgid();
    u32 uid = bpf_get_current_uid_gid();

    key.ip = PT_REGS_IP(ctx);
    key.pid = pid & 0xFFFFFFFF;
    key.uid = uid & 0xFFFFFFFF;
    bpf_get_current_comm(&(key.comm), 16);

    val = counts.lookup_or_try_init(&key, &zero);  // update counter
    if (val) {
        (*val)++;
    }
    return 0;
}
"""

    def license(self, lic):
        return b'''
#define BPF_LICENSE %s
''' % (lic.encode())

    def load_bpf_code(self, bpf_code):
        event_name = bpf_code.get_syscall_fnname(b"read")
        bpf_code.attach_kprobe(event=event_name, fn_name=b"license_program")
        bpf_code.detach_kprobe(event=event_name)

    def test_default(self):
        b = BPF(text=self.gpl_only_text)
        self.load_bpf_code(b)

    def test_gpl_helper_macro(self):
        b = BPF(text=self.gpl_only_text + self.license('GPL'))
        self.load_bpf_code(b)

    def test_proprietary_macro(self):
        b = BPF(text=self.proprietary_text + self.license('Proprietary'))
        self.load_bpf_code(b)

    def test_gpl_compatible_macro(self):
        b = BPF(text=self.gpl_only_text + self.license('Dual BSD/GPL'))
        self.load_bpf_code(b)

    def test_proprietary_words_macro(self):
        b = BPF(text=self.proprietary_text + self.license('Proprietary license'))
        self.load_bpf_code(b)

    @unittest.expectedFailure
    def test_cflags_fail(self):
        b = BPF(text=self.gpl_only_text, cflags=["-DBPF_LICENSE=GPL"])
        self.load_bpf_code(b)

    @unittest.expectedFailure
    def test_cflags_macro_fail(self):
        b = BPF(text=self.gpl_only_text + self.license('GPL'), cflags=["-DBPF_LICENSE=GPL"])
        self.load_bpf_code(b)

    @unittest.expectedFailure
    def test_empty_fail_macro(self):
        b = BPF(text=self.gpl_only_text + self.license(''))
        self.load_bpf_code(b)

    @unittest.expectedFailure
    def test_proprietary_fail_macro(self):
        b = BPF(text=self.gpl_only_text + self.license('Proprietary license'))
        self.load_bpf_code(b)

    @unittest.expectedFailure
    def test_proprietary_cflags_fail(self):
        b = BPF(text=self.proprietary_text, cflags=["-DBPF_LICENSE=Proprietary"])
        self.load_bpf_code(b)

if __name__ == "__main__":
    unittest.main()
