Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions internal/util/convert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package util
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace on line. Remove the extra space after 'util' to maintain code cleanliness.

Suggested change
package util
package util

Copilot uses AI. Check for mistakes.

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/free5gc/openapi/models"
)

func TestSnssaiHexToModels(t *testing.T) {
t.Run("valid hex string with SST and SD", func(t *testing.T) {
hexStr := "01112233" // SST = 0x01 (1), SD = "112233"
expected := &models.Snssai{
Sst: 1,
Sd: "112233",
}

snssai, err := SnssaiHexToModels(hexStr)
require.NoError(t, err)
assert.Equal(t, expected, snssai)
})

t.Run("invalid hex string for SST", func(t *testing.T) {
hexStr := "ZZ112233" // invalid SST hex

snssai, err := SnssaiHexToModels(hexStr)
assert.Nil(t, snssai)
assert.Error(t, err)
})
}
func TestSnssaiModelsToHex(t *testing.T) {
t.Run("valid Snssai with Sst and Sd", func(t *testing.T) {
snssai := models.Snssai{
Sst: 1,
Sd: "112233",
}
expected := "01112233" // 01 (hex of 1) + Sd

hexStr := SnssaiModelsToHex(snssai)
assert.Equal(t, expected, hexStr)
})

t.Run("Sst with double digit value", func(t *testing.T) {
snssai := models.Snssai{
Sst: 26,
Sd: "abcdef",
}
expected := "1aabcdef" // 1a is hex of 26

hexStr := SnssaiModelsToHex(snssai)
assert.Equal(t, expected, hexStr)
})

t.Run("empty Sd field", func(t *testing.T) {
snssai := models.Snssai{
Sst: 15,
Sd: "",
}
expected := "0f" // just the hex of 15

hexStr := SnssaiModelsToHex(snssai)
assert.Equal(t, expected, hexStr)
})
}
func TestSeperateAmfId(t *testing.T) {
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name has a typo. 'Seperate' should be 'Separate'. The function being tested is actually named 'SeperateAmfId' which also contains the same typo, but the test name should be consistent with the function name or the function should be fixed first.

Copilot uses AI. Check for mistakes.
t.Run("valid AMF ID", func(t *testing.T) {
amfid := "12a1b2" // regionId = "12", rest = a1b2

regionId, setId, ptrId, err := SeperateAmfId(amfid)

assert.NoError(t, err)
assert.Equal(t, "12", regionId)
assert.Equal(t, "286", setId) // derived from bits
assert.Equal(t, "32", ptrId) // derived from bits
})

t.Run("invalid AMF ID length", func(t *testing.T) {
amfid := "1234"

regionId, setId, ptrId, err := SeperateAmfId(amfid)

assert.Error(t, err)
assert.Empty(t, regionId)
assert.Empty(t, setId)
assert.Empty(t, ptrId)
})

t.Run("invalid AMF ID hex characters", func(t *testing.T) {
amfid := "12zzzz" // invalid hex in last 4 characters

regionId, setId, ptrId, err := SeperateAmfId(amfid)

assert.Error(t, err)
assert.Equal(t, "12", regionId)
assert.Empty(t, setId)
assert.Empty(t, ptrId)
})
}

func TestPlmnIdStringToModels(t *testing.T) {
t.Run("valid 5-digit PLMN ID", func(t *testing.T) {
plmnStr := "28393" // MCC: 310, MNC: 15

expected := models.PlmnId{
Mcc: "283",
Mnc: "93",
}

result := PlmnIdStringToModels(plmnStr)

assert.Equal(t, expected, result)
})

t.Run("valid 6-digit PLMN ID", func(t *testing.T) {
plmnStr := "460011" // MCC: 460, MNC: 011

expected := models.PlmnId{
Mcc: "460",
Mnc: "011",
}

result := PlmnIdStringToModels(plmnStr)

assert.Equal(t, expected, result)
})

t.Run("invalid PLMN ID (too short)", func(t *testing.T) {
plmnStr := "12" // invalid

defer func() {
if r := recover(); r == nil {
t.Error("Expected panic due to short plmnId, but function did not panic")
}
}()

_ = PlmnIdStringToModels(plmnStr) // should panic on plmnId[:3]
})
}
func TestTACConfigToModels(t *testing.T) {
t.Run("valid TAC integer string", func(t *testing.T) {
input := "12345"
expected := "003039" // 12345 in hex is 0x3039

result := TACConfigToModels(input)

assert.Equal(t, expected, result)
})

t.Run("maximum 3-byte TAC value", func(t *testing.T) {
input := "16777215" // 0xFFFFFF
expected := "ffffff"

result := TACConfigToModels(input)

assert.Equal(t, expected, result)
})

t.Run("invalid TAC string (non-numeric)", func(t *testing.T) {
input := "abc"

result := TACConfigToModels(input)

// When ParseUint fails, it logs and returns empty hex string
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment incorrectly describes the expected behavior. When ParseUint fails with a non-numeric string, the function logs the error but tmp remains 0, resulting in "000000" (6 zeros), not an empty hex string as the comment states.

Suggested change
// When ParseUint fails, it logs and returns empty hex string
// When ParseUint fails, it logs the error and returns "000000" (since tmp is 0 if err != nil)

Copilot uses AI. Check for mistakes.
assert.Equal(t, "000000", result) // because tmp is 0 if err != nil
})
}
224 changes: 224 additions & 0 deletions pkg/service/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
package service

import (
"context"
"os"
"testing"
"time"

amf_context "github.com/free5gc/amf/internal/context"
"github.com/free5gc/amf/internal/sbi"
"github.com/free5gc/amf/internal/sbi/consumer"
"github.com/free5gc/amf/internal/sbi/processor"
"github.com/free5gc/amf/pkg/factory"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/free5gc/openapi/models"
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation detected. This import line uses spaces instead of tabs, which is inconsistent with the other import lines. Go convention and this codebase use tabs for indentation.

Suggested change
"github.com/free5gc/openapi/models"
"github.com/free5gc/openapi/models"

Copilot uses AI. Check for mistakes.
)

func TestSetLogLevel(t *testing.T) {
config := &factory.Config{}
app := &AmfApp{cfg: config}

app.SetLogLevel("debug")
assert.Equal(t, "debug", app.cfg.GetLogLevel())

app.SetLogLevel("invalid") // should warn, but not panic
}

func TestSetLogEnable(t *testing.T) {
config := &factory.Config{}
app := &AmfApp{cfg: config}

app.SetLogEnable(true)
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion is incorrect. The test calls app.SetLogEnable(true) on line 33 but never sets it to false before the assertion on line 36. The test should verify that SetLogEnable(true) worked first, or this should be testing the false value that was just set.

Suggested change
app.SetLogEnable(true)
app.SetLogEnable(true)
assert.True(t, app.cfg.GetLogEnable())

Copilot uses AI. Check for mistakes.

app.SetLogEnable(false)
assert.False(t, app.cfg.GetLogEnable())
}

func TestSetReportCaller(t *testing.T) {
config := &factory.Config{}
app := &AmfApp{cfg: config}

app.SetReportCaller(true)
assert.True(t, app.cfg.GetLogReportCaller())

app.SetReportCaller(false)
assert.False(t, app.cfg.GetLogReportCaller())
}

func TestSetLogFilePath(t *testing.T) {
config := &factory.Config{}
app := &AmfApp{cfg: config}

logFilePath := "/tmp/test_amf_log.log"
f, err := os.Create(logFilePath)
assert.NoError(t, err)
defer f.Close()
defer os.Remove(logFilePath)

app.SetLogFilePath(f)

Check failure on line 60 in pkg/service/init_test.go

View workflow job for this annotation

GitHub Actions / lint (1.24)

app.SetLogFilePath undefined (type *AmfApp has no field or method SetLogFilePath) (typecheck)
assert.Equal(t, logFilePath, f.Name())
}

Comment on lines +50 to +63
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SetLogFilePath method does not exist in the AmfApp struct or the app.App interface. This test will fail to compile. The app.App interface only defines SetLogEnable, SetLogLevel, and SetReportCaller for logging configuration.

Suggested change
func TestSetLogFilePath(t *testing.T) {
config := &factory.Config{}
app := &AmfApp{cfg: config}
logFilePath := "/tmp/test_amf_log.log"
f, err := os.Create(logFilePath)
assert.NoError(t, err)
defer f.Close()
defer os.Remove(logFilePath)
app.SetLogFilePath(f)
assert.Equal(t, logFilePath, f.Name())
}

Copilot uses AI. Check for mistakes.
func TestTerminate(t *testing.T) {
config := &factory.Config{}
ctx, cancel := context.WithCancel(context.Background())
app := &AmfApp{cfg: config, ctx: ctx}
app.ctx, app.cancel = ctx, cancel

done := make(chan struct{})
go func() {
app.Terminate()
close(done)
}()

<-done
}

func TestCancelContext(t *testing.T) {
ctx := context.Background()
app := &AmfApp{
ctx: ctx,
}
assert.Equal(t, ctx, app.CancelContext())
}
func TestWaitRoutineStopped(t *testing.T) {
app := &AmfApp{}
app.wg.Add(1)
go func() {
time.Sleep(10 * time.Millisecond)
app.wg.Done()
}()
app.WaitRoutineStopped()
}

func TestGetters(t *testing.T) {
cfg := &factory.Config{}
app := &AmfApp{
cfg: cfg,
amfCtx: &amf_context.AMFContext{},
consumer: &consumer.Consumer{},
processor: &processor.Processor{},
}
assert.Equal(t, cfg, app.Config())
assert.NotNil(t, app.Context())
assert.NotNil(t, app.Consumer())
assert.NotNil(t, app.Processor())
}
func TestNewApp(t *testing.T) {

tmpLog := "/tmp/amf_test.log"
_ = os.WriteFile(tmpLog, []byte{}, 0644)
defer os.Remove(tmpLog)

cfg := &factory.Config{
Configuration: &factory.Configuration{
ServiceNameList: []string{
string(models.ServiceName_NAMF_COMM),
string(models.ServiceName_NAMF_EVTS),
string(models.ServiceName_NAMF_MT),
string(models.ServiceName_NAMF_LOC),
string(models.ServiceName_NAMF_OAM),
},
},
}
factory.AmfConfig = cfg
app, err := NewApp(context.Background(), cfg, "")
assert.NoError(t, err)
assert.NotNil(t, app)
}
Comment on lines +109 to +130
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AMF global variable is being set in NewApp (line 91 of init.go), but this test doesn't verify that behavior. Consider adding an assertion to verify that the global AMF variable is properly set after NewApp is called.

Copilot uses AI. Check for mistakes.


Comment on lines +131 to +132
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace on empty line. This should be removed to maintain code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
type MockServerAmf struct {
mock.Mock

Ctx *amf_context.AMFContext
Cfg *factory.Config
Cons *consumer.Consumer
Proc *processor.Processor
}

func (m *MockServerAmf) Init() {}

func (m *MockServerAmf) Run() error {
return nil
}

func (m *MockServerAmf) Terminate() {}

func (m *MockServerAmf) Context() *amf_context.AMFContext {
amfCtx := amf_context.GetSelf()
amfCtx.NrfUri = "http://nrf.example.com"
m.Ctx = amfCtx
return m.Ctx
}

func (m *MockServerAmf) Config() *factory.Config {
return m.Cfg
}

// Wrap the mock inside a dummy real consumer
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is misleading. The Consumer method doesn't "wrap the mock inside a dummy real consumer" - it actually creates and returns a real Consumer instance. This could be confusing for future maintainers.

Suggested change
// Wrap the mock inside a dummy real consumer
// Creates and returns a real consumer.Consumer instance for use in tests

Copilot uses AI. Check for mistakes.
func (m *MockServerAmf) Consumer() *consumer.Consumer {
c, err := consumer.NewConsumer(AMF)
if err != nil {
panic("failed to create consumer: " + err.Error()) // fail fast in tests
}
m.Cons = c
return m.Cons
}
func (m *MockServerAmf) Processor() *processor.Processor {
return m.Proc
}
func (m *MockServerAmf) SetLogEnable(enable bool) {}
func (m *MockServerAmf) SetLogLevel(level string) {}
func (m *MockServerAmf) SetReportCaller(reportCaller bool) {}
func (m *MockServerAmf) Start() {}

// In package consumer
type DummySCTPListener struct{}

func (d *DummySCTPListener) Close() error {
// Pretend to close without doing anything
return nil
}
Comment on lines +178 to +184
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is misleading. The comment says "In package consumer" but this code is in the service package's test file. Additionally, DummySCTPListener is defined but never used in any test.

Suggested change
// In package consumer
type DummySCTPListener struct{}
func (d *DummySCTPListener) Close() error {
// Pretend to close without doing anything
return nil
}

Copilot uses AI. Check for mistakes.
func TestListenShutdownEvent_TriggersTerminate(t *testing.T) {

cfg := &factory.Config{
Configuration: &factory.Configuration{
NgapIpList: []string{"127.0.0.1"},
NgapPort: 38412,
ServedGumaiList: []models.Guami{},
NrfUri: "http://nrf.example.com",
SCTP: &factory.Sctp{},
},
}
factory.AmfConfig = cfg
amfCtx := amf_context.GetSelf()
amfCtx.NrfUri = "http://nrf.example.com"
c, err := consumer.NewConsumer(&MockServerAmf{})
assert.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())

app := &AmfApp{
cfg: cfg,
ctx: ctx,
cancel: cancel,
amfCtx: amfCtx,
consumer: c,
processor: &processor.Processor{}, // Can mock if needed
sbiServer: &sbi.Server{}, // Optional
}

app.wg.Add(1)

go app.listenShutdownEvent()

// trigger shutdown
cancel()
// wait for termination to complete
app.wg.Wait()
}



Comment on lines +223 to +224
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace on empty line. This should be removed to maintain code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
Loading